source ../common/vars-and-functions.sh

# The new Linux mount interface does not seem to support remounting
# OverlayFS mount points.
#
# It is not clear whether this is intentional or not:
#
# The  kernel source code [1] would seem to indicate merely remounting
# while *changing* mount options is now an error because it erroneously
# succeeded (by ignoring those new options) before. However, we are
# *not* trying to remount with changed options, and are still hitting
# the failure when using the new interface.
#
# For further details, see these `util-linux` issues:
#
#  - https://github.com/util-linux/util-linux/issues/2528
#  - https://github.com/util-linux/util-linux/issues/2576
#
# In the meantime, setting this environment variable to "always" will
# force the use of the old mount interface, keeping the remounting
# working and these tests passing.
#
# [1]: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/overlayfs/params.c?id=3006adf3be79cde4d14b1800b963b82b6e5572e0#n549
export LIBMOUNT_FORCE_MOUNT2=always

requireEnvironment () {
  requireSandboxSupport
  [[ $busybox =~ busybox ]] || skipTest "no busybox"
  if [[ $(uname) != Linux ]]; then skipTest "Need Linux for overlayfs"; fi
  needLocalStore "The test uses --store always so we would just be bypassing the daemon"
}

addConfig () {
    echo "$1" >> "$NIX_CONF_DIR/nix.conf"
}

setupConfig () {
  addConfig "require-drop-supplementary-groups = false"
  addConfig "build-users-group = "
  enableFeatures "local-overlay-store"
}

setupStoreDirs () {
  # Attempt to create store dirs on tmpfs volume.
  # This ensures lowerdir, upperdir and workdir will be on
  # a consistent filesystem that fully supports OverlayFS.
  storeVolume="$TEST_ROOT/stores"
  mkdir -p "$storeVolume"
  mount -t tmpfs tmpfs "$storeVolume" || true  # But continue anyway if that fails.

  storeA="$storeVolume/store-a"
  storeBTop="$storeVolume/store-b"
  storeBRoot="$storeVolume/merged-store"
  storeB="local-overlay://?root=$storeBRoot&lower-store=$storeA&upper-layer=$storeBTop"
  # Creating testing directories
  mkdir -p "$storeVolume"/{store-a/nix/store,store-b,merged-store/nix/store,workdir}
}

# Mounting Overlay Store
mountOverlayfs () {
  mount -t overlay overlay \
    -o lowerdir="$storeA/nix/store" \
    -o upperdir="$storeBTop" \
    -o workdir="$storeVolume/workdir" \
    "$storeBRoot/nix/store" \
    || skipTest "overlayfs is not supported"

  cleanupOverlay () {
    umount "$storeBRoot/nix/store"
    rm -r $storeVolume/workdir
  }
  trap cleanupOverlay EXIT
}

remountOverlayfs () {
  mount -o remount "$storeBRoot/nix/store"
}

toRealPath () {
  storeDir=$1; shift
  storePath=$1; shift
  echo $storeDir$(echo $storePath | sed "s^${NIX_STORE_DIR:-/nix/store}^^")
}

initLowerStore () {
  # Init lower store with some stuff
  nix-store --store "$storeA" --add ../dummy

  # Build something in lower store
  drvPath=$(nix-instantiate --store $storeA ../hermetic.nix --arg withFinalRefs true --arg busybox "$busybox" --arg seed 1)
  pathInLowerStore=$(nix-store --store "$storeA" --realise $drvPath)
}

execUnshare () {
  exec unshare --mount --map-root-user "$SHELL" "$@"
}

addTextToStore() {
  storeDir=$1; shift
  filename=$1; shift
  content=$1; shift
  filePath="$TEST_HOME/$filename"
  echo "$content" > "$filePath"
  nix-store --store "$storeDir" --add "$filePath"
}