From 53a9d8763500e7cf260378f9f535d6820b1eef60 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 6 Oct 2023 11:20:49 -0600 Subject: [PATCH 01/19] Add support for a single lower dir merge --- try | 82 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/try b/try index cdfa5a88..35b1399c 100755 --- a/try +++ b/try @@ -56,6 +56,33 @@ try() { findmnt --real -r -o target -n >>"$DIRS_AND_MOUNTS" sort -u -o "$DIRS_AND_MOUNTS" "$DIRS_AND_MOUNTS" + # Update DIRS_AND_MOUNTS based on LOWER_DIRS + UPDATED_DIRS_AND_MOUNTS="$(mktemp)" + export UPDATED_DIRS_AND_MOUNTS + while IFS="" read -r mountpoint + do + new_mountpoint="" + # Split LOWER_DIRS into lines, then read each line in a loop + echo "$LOWER_DIRS" | tr ':' '\n' | while IFS="" read -r lower_dir + do + + # Form the new mountpoint + temp_mountpoint="$lower_dir/upperdir$mountpoint" + + # Check if the new mountpoint is a directory and is non-empty + if [ ! -d "$temp_mountpoint" ] || [ -z "$(find "$temp_mountpoint" -mindepth 1 -maxdepth 1 -print -quit)" ]; then + new_mountpoint="$mountpoint" + else + new_mountpoint="$new_mountpoint$temp_mountpoint:$mountpoint" + fi + echo "$new_mountpoint" >> "$UPDATED_DIRS_AND_MOUNTS" + + done + done <"$DIRS_AND_MOUNTS" + cat $UPDATED_DIRS_AND_MOUNTS + + # mv "$UPDATED_DIRS_AND_MOUNTS" "$DIRS_AND_MOUNTS" # replace DIRS_AND_MOUNTS with the updated list + # we will overlay-mount each root directory separately (instead of all at once) because some directories cannot be overlayed # so we set up the mount points now # @@ -70,12 +97,15 @@ try() { # then we want to exclude the root partition "/" while IFS="" read -r mountpoint do + echo $mountpoint ## Only make the directory if the original is a directory too if [ -d "$mountpoint" ] then mkdir -p "${SANDBOX_DIR}/upperdir/${mountpoint}" "${SANDBOX_DIR}/workdir/${mountpoint}" "${SANDBOX_DIR}/temproot/${mountpoint}" fi done <"$DIRS_AND_MOUNTS" + echo "---" + ls "${SANDBOX_DIR}/temproot/${mountpoint}" mount_and_execute="$(mktemp)" chroot_executable="$(mktemp)" @@ -94,11 +124,17 @@ TRY_COMMAND="$TRY_COMMAND($0)" ## A wrapper of `mount -t overlay` to have cleaner looking code make_overlay() { sandbox_dir="$1" - lowerdir="$2" + lowerdirs="$2" mountpoint="$3" - mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdir,upperdir=$sandbox_dir/upperdir/$mountpoint,workdir=$sandbox_dir/workdir/$mountpoint" "$sandbox_dir/temproot/$mountpoint" + # echo "-"$lowerdirs + ls + + echo mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdirs,upperdir=$sandbox_dir/upperdir/$mountpoint,workdir=$sandbox_dir/workdir/$mountpoint" "$sandbox_dir/temproot/$mountpoint" + # exit + mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdirs,upperdir=$sandbox_dir/upperdir/$mountpoint,workdir=$sandbox_dir/workdir/$mountpoint" "$sandbox_dir/temproot/$mountpoint" } + devices_to_mount="tty null zero full random urandom" ## Mounts and unmounts a few select devices instead of the whole `/dev` @@ -138,24 +174,29 @@ then fi # actually mount the overlays -for mountpoint in $(cat "$DIRS_AND_MOUNTS") +for mountpoint in $(cat "$UPDATED_DIRS_AND_MOUNTS") do + # echo $mountpoint + pure_mountpoint=$(echo "$mountpoint" | awk -F':' '{print $NF}') + + # echo pure $pure_mountpoint + ## We are not interested in mounts that are not directories - if ! [ -d "$mountpoint" ] + if ! [ -d "$pure_mountpoint" ] then continue fi ## Don't do anything for the root ## and skip if it is /dev or /proc, we will mount it later - if [ "$mountpoint" = "/" ] || - [ "$mountpoint" = "/dev" ] || [ "$mountpoint" = "/proc" ] + if [ "$pure_mountpoint" = "/" ] || + [ "$pure_mountpoint" = "/dev" ] || [ "$pure_mountpoint" = "/proc" ] then continue fi # Try mounting everything normally - make_overlay "$SANDBOX_DIR" "/$mountpoint" "$mountpoint" 2>>"$try_mount_log" + make_overlay "$SANDBOX_DIR" "$mountpoint" "$pure_mountpoint" 2>>"$try_mount_log" # If mounting everything normally fails, we try using either using mergerfs or unionfs to mount them. if [ "$?" -ne 0 ] then @@ -476,18 +517,18 @@ error() { usage() { cat >&2 <&2 exit 0;; (U) if ! [ -x "$OPTARG" ] From 4ccda07bb2a6a132d00a2cd595484621c778699a Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 6 Oct 2023 13:20:25 -0600 Subject: [PATCH 02/19] Handle multiple merged directories --- try | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/try b/try index 35b1399c..e087ac19 100755 --- a/try +++ b/try @@ -45,7 +45,7 @@ try() { fi ## Make any directories that don't already exist, this is OK to do here - ## because we have already checked if it valid. + ## because we have already checked if it valid. export SANDBOX_DIR mkdir -p "$SANDBOX_DIR/upperdir" "$SANDBOX_DIR/workdir" "$SANDBOX_DIR/temproot" @@ -56,32 +56,35 @@ try() { findmnt --real -r -o target -n >>"$DIRS_AND_MOUNTS" sort -u -o "$DIRS_AND_MOUNTS" "$DIRS_AND_MOUNTS" - # Update DIRS_AND_MOUNTS based on LOWER_DIRS + # Calculate UPDATED_DIRS_AND_MOUNTS that contains the merge arguments in LOWER_DIRS UPDATED_DIRS_AND_MOUNTS="$(mktemp)" export UPDATED_DIRS_AND_MOUNTS while IFS="" read -r mountpoint do new_mountpoint="" - # Split LOWER_DIRS into lines, then read each line in a loop - echo "$LOWER_DIRS" | tr ':' '\n' | while IFS="" read -r lower_dir + temp_file=$(mktemp) + echo "$LOWER_DIRS" | tr ':' '\n' > "$temp_file" # Split LOWER_DIRS into lines + + while IFS="" read -r lower_dir do - - # Form the new mountpoint temp_mountpoint="$lower_dir/upperdir$mountpoint" - # Check if the new mountpoint is a directory and is non-empty - if [ ! -d "$temp_mountpoint" ] || [ -z "$(find "$temp_mountpoint" -mindepth 1 -maxdepth 1 -print -quit)" ]; then - new_mountpoint="$mountpoint" - else - new_mountpoint="$new_mountpoint$temp_mountpoint:$mountpoint" + if [ -d "$temp_mountpoint" ] && [ "$(find "$temp_mountpoint" -mindepth 1 -maxdepth 1 -print -quit)" ]; then + if [ -n "$new_mountpoint" ]; then + new_mountpoint="$new_mountpoint:$temp_mountpoint" # If new_mountpoint is not empty, append : and the temp_mountpoint + else + new_mountpoint="$temp_mountpoint" # If new_mountpoint is empty, just set it to temp_mountpoint + fi fi - echo "$new_mountpoint" >> "$UPDATED_DIRS_AND_MOUNTS" + done < "$temp_file" - done - done <"$DIRS_AND_MOUNTS" - cat $UPDATED_DIRS_AND_MOUNTS + rm "$temp_file" # Clean up the temporary file - # mv "$UPDATED_DIRS_AND_MOUNTS" "$DIRS_AND_MOUNTS" # replace DIRS_AND_MOUNTS with the updated list + new_mountpoint="${new_mountpoint:+$new_mountpoint:}$mountpoint" # Add the original mountpoint at the end + + echo "$new_mountpoint" >> "$UPDATED_DIRS_AND_MOUNTS" # Write the new mountpoint to the updated list + + done <"$DIRS_AND_MOUNTS" # we will overlay-mount each root directory separately (instead of all at once) because some directories cannot be overlayed # so we set up the mount points now @@ -97,15 +100,12 @@ try() { # then we want to exclude the root partition "/" while IFS="" read -r mountpoint do - echo $mountpoint ## Only make the directory if the original is a directory too if [ -d "$mountpoint" ] then mkdir -p "${SANDBOX_DIR}/upperdir/${mountpoint}" "${SANDBOX_DIR}/workdir/${mountpoint}" "${SANDBOX_DIR}/temproot/${mountpoint}" fi done <"$DIRS_AND_MOUNTS" - echo "---" - ls "${SANDBOX_DIR}/temproot/${mountpoint}" mount_and_execute="$(mktemp)" chroot_executable="$(mktemp)" @@ -126,11 +126,6 @@ make_overlay() { sandbox_dir="$1" lowerdirs="$2" mountpoint="$3" - # echo "-"$lowerdirs - ls - - echo mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdirs,upperdir=$sandbox_dir/upperdir/$mountpoint,workdir=$sandbox_dir/workdir/$mountpoint" "$sandbox_dir/temproot/$mountpoint" - # exit mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdirs,upperdir=$sandbox_dir/upperdir/$mountpoint,workdir=$sandbox_dir/workdir/$mountpoint" "$sandbox_dir/temproot/$mountpoint" } @@ -176,11 +171,8 @@ fi # actually mount the overlays for mountpoint in $(cat "$UPDATED_DIRS_AND_MOUNTS") do - # echo $mountpoint pure_mountpoint=$(echo "$mountpoint" | awk -F':' '{print $NF}') - # echo pure $pure_mountpoint - ## We are not interested in mounts that are not directories if ! [ -d "$pure_mountpoint" ] then From b6582bde07fdf30f7ee5ee2fe17628710118687a Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 6 Oct 2023 15:45:29 -0600 Subject: [PATCH 03/19] Remove trailing whitespace --- try | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/try b/try index e087ac19..610d9561 100755 --- a/try +++ b/try @@ -56,7 +56,7 @@ try() { findmnt --real -r -o target -n >>"$DIRS_AND_MOUNTS" sort -u -o "$DIRS_AND_MOUNTS" "$DIRS_AND_MOUNTS" - # Calculate UPDATED_DIRS_AND_MOUNTS that contains the merge arguments in LOWER_DIRS + # Calculate UPDATED_DIRS_AND_MOUNTS that contains the merge arguments in LOWER_DIRS UPDATED_DIRS_AND_MOUNTS="$(mktemp)" export UPDATED_DIRS_AND_MOUNTS while IFS="" read -r mountpoint @@ -64,7 +64,7 @@ try() { new_mountpoint="" temp_file=$(mktemp) echo "$LOWER_DIRS" | tr ':' '\n' > "$temp_file" # Split LOWER_DIRS into lines - + while IFS="" read -r lower_dir do temp_mountpoint="$lower_dir/upperdir$mountpoint" @@ -520,7 +520,7 @@ Usage: $TRY_COMMAND [-nvhy] [-i PATTERN] [-D DIR] [-U PATH] [-L "dir1:dir2:..."] -v show version information (and exit) -h show this usage message (and exit) - + Subcommands: $TRY_COMMAND summary DIR show the summary for the overlay in DIR $TRY_COMMAND commit DIR commit the overlay in DIR From acc9c5b0da691e91812cb0b90ff3caba7b116a30 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 6 Oct 2023 15:57:05 -0600 Subject: [PATCH 04/19] Add the -L flag in the manpages --- docs/try.1.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/try.1.md b/docs/try.1.md index d3cbd076..7d113c4e 100644 --- a/docs/try.1.md +++ b/docs/try.1.md @@ -6,7 +6,7 @@ try - run a command in an overlay # SYNOPSIS -| try [-ny] [-i PATTERN] [-D DIR] [-U PATH] CMD [ARG ...] +| try [-ny] [-i PATTERN] [-D DIR] [-U PATH] [-L LOWER_DIRS] CMD [ARG ...] | try summary [DIR] | try commit [DIR] | try explore @@ -53,6 +53,11 @@ While using *try* you can choose to commit the result to the filesystem or compl : Use the unionfs helper implementation defined in the *PATH* (e.g., mergerfs, unionfs-fuse) instead of the default. This option is recommended in case OverlayFS fails. +-L *LOWER_DIRS* + +: Specify a colon-separated list of directories to be used as lower directories for the overlay, formatted as "dir1:dir2:...:dirn". + + ## Subcommands try summary *DIR* @@ -124,6 +129,12 @@ Alternatively, you can specify your own overlay directory as follows (note that try -D try_dir gunzip file.txt.gz ``` +To use multiple lower directories for overlay (by merging them), you can use the `-L` flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right: + +``` +try -L /lowerdir1:/lowerdir2:/lowerdir3 gunzip file.txt.gz +``` + You can inspect the changes made inside a given overlay directory: ``` From 8655218341c806d53a21faa143fb159ca2e94fdd Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 6 Oct 2023 16:12:02 -0600 Subject: [PATCH 05/19] Update README with -L example and explanation --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 0501a45e..c27b965a 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,27 @@ $ try commit rustup-sandbox You can also run `try explore` to open your current shell in try, or `/try explore /tmp/tmp.X6OQb5tJwr` to explore an existing sandbox. +To specify multiple lower directories for overlay (by merging them together), you can use the `-L` flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right: + +```ShellSession +$ try -D rustup-sandbox "curl https://sh.rustup.rs > rustup.sh" +... +$ try -L rustup-sandbox "sh rustup.sh" + +Changes detected in the following files: + +rustup-sandbox//upperdir/home/ubuntu/.profile (modified/added) +rustup-sandbox//upperdir/home/ubuntu/.bashrc (modified/added) +rustup-sandbox//upperdir/home/ubuntu/.rustup/update-hashes/stable-x86_64-unknown-linux-gnu (modified/added) +... + +Commit these changes? [y/N] y + +``` + +In this example, `try`` will merge `/lowerdir1`, `/lowerdir2` and `/lowerdir3` together before mounting the overlay. This way, you can combine the contents of multiple `try` sandboxes . + + ## Known Issues Any command that interacts with other users/groups will fail since only the current user's UID/GID are mapped. However, the [future From caa173cf642269e119bbe20344ef0a00f114920c Mon Sep 17 00:00:00 2001 From: gliargovas Date: Sat, 7 Oct 2023 01:39:29 -0600 Subject: [PATCH 06/19] Add better example to demonstrate multi-dir merging --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c27b965a..a749b1cd 100644 --- a/README.md +++ b/README.md @@ -158,22 +158,20 @@ explore /tmp/tmp.X6OQb5tJwr` to explore an existing sandbox. To specify multiple lower directories for overlay (by merging them together), you can use the `-L` flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right: ```ShellSession -$ try -D rustup-sandbox "curl https://sh.rustup.rs > rustup.sh" +$ try -D sandbox1 "echo 'File 1 Contents - sandbox1' > file1.txt" ... -$ try -L rustup-sandbox "sh rustup.sh" - -Changes detected in the following files: - -rustup-sandbox//upperdir/home/ubuntu/.profile (modified/added) -rustup-sandbox//upperdir/home/ubuntu/.bashrc (modified/added) -rustup-sandbox//upperdir/home/ubuntu/.rustup/update-hashes/stable-x86_64-unknown-linux-gnu (modified/added) +$ try -D sandbox2 "echo 'File 2 Contents - sandbox2' > file2.txt" +... +$ try -D sandbox3 "echo 'File 2 Contents - sandbox3' > file2.txt" ... -Commit these changes? [y/N] y - +# Now use the -L flag to merge both sandbox directories together, with sandbox3 having precedence over sandbox2 +$ try -L "sandbox3:sandbox2:sandbox1" "cat file1.txt file2.txt" +File 1 Contents - sandbox1 +File 2 Contents - sandbox3 ``` -In this example, `try`` will merge `/lowerdir1`, `/lowerdir2` and `/lowerdir3` together before mounting the overlay. This way, you can combine the contents of multiple `try` sandboxes . +In this example, `try` will merge `/sandbox1`, `/sandbox2` and `/sandbox3` together before mounting the overlay. This way, you can combine the contents of multiple `try` sandboxes. ## Known Issues From 0b25c5888854d7472ce5797633bb48b362eb7b0b Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 11 Oct 2023 09:20:30 -0600 Subject: [PATCH 07/19] Simplify UPDATED_DIRS_AND_MOUNTS set resolution --- try | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/try b/try index 610d9561..0f523280 100755 --- a/try +++ b/try @@ -62,30 +62,29 @@ try() { while IFS="" read -r mountpoint do new_mountpoint="" - temp_file=$(mktemp) - echo "$LOWER_DIRS" | tr ':' '\n' > "$temp_file" # Split LOWER_DIRS into lines - while IFS="" read -r lower_dir + IFS=":" + + for lower_dir in $LOWER_DIRS do temp_mountpoint="$lower_dir/upperdir$mountpoint" # Check if the new mountpoint is a directory and is non-empty if [ -d "$temp_mountpoint" ] && [ "$(find "$temp_mountpoint" -mindepth 1 -maxdepth 1 -print -quit)" ]; then if [ -n "$new_mountpoint" ]; then - new_mountpoint="$new_mountpoint:$temp_mountpoint" # If new_mountpoint is not empty, append : and the temp_mountpoint + # If new_mountpoint is not empty, append : and the temp_mountpoint + new_mountpoint="$new_mountpoint:$temp_mountpoint" else - new_mountpoint="$temp_mountpoint" # If new_mountpoint is empty, just set it to temp_mountpoint + # If new_mountpoint is empty, just set it to temp_mountpoint + new_mountpoint="$temp_mountpoint" fi fi - done < "$temp_file" - - rm "$temp_file" # Clean up the temporary file - - new_mountpoint="${new_mountpoint:+$new_mountpoint:}$mountpoint" # Add the original mountpoint at the end - - echo "$new_mountpoint" >> "$UPDATED_DIRS_AND_MOUNTS" # Write the new mountpoint to the updated list - + done + # Add the original mountpoint at the end + new_mountpoint="${new_mountpoint:+$new_mountpoint:}$mountpoint" + echo "$new_mountpoint" >> "$UPDATED_DIRS_AND_MOUNTS" done <"$DIRS_AND_MOUNTS" + # we will overlay-mount each root directory separately (instead of all at once) because some directories cannot be overlayed # so we set up the mount points now # From efac2b295bb31a82f19b004e7438609fd6d3fefa Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 11 Oct 2023 09:36:21 -0600 Subject: [PATCH 08/19] Put sandboxes under /tmp in the -L option example --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a749b1cd..372a160c 100644 --- a/README.md +++ b/README.md @@ -158,15 +158,12 @@ explore /tmp/tmp.X6OQb5tJwr` to explore an existing sandbox. To specify multiple lower directories for overlay (by merging them together), you can use the `-L` flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right: ```ShellSession -$ try -D sandbox1 "echo 'File 1 Contents - sandbox1' > file1.txt" -... -$ try -D sandbox2 "echo 'File 2 Contents - sandbox2' > file2.txt" -... -$ try -D sandbox3 "echo 'File 2 Contents - sandbox3' > file2.txt" -... +$ try -D /tmp/sandbox1 "echo 'File 1 Contents - sandbox1' > file1.txt" +$ try -D /tmp/sandbox2 "echo 'File 2 Contents - sandbox2' > file2.txt" +$ try -D /tmp/sandbox3 "echo 'File 2 Contents - sandbox3' > file2.txt" # Now use the -L flag to merge both sandbox directories together, with sandbox3 having precedence over sandbox2 -$ try -L "sandbox3:sandbox2:sandbox1" "cat file1.txt file2.txt" +$ try -L "/tmp/sandbox3:/tmp/sandbox2:/tmp/sandbox1" "cat file1.txt file2.txt" File 1 Contents - sandbox1 File 2 Contents - sandbox3 ``` From 4f7ebaae71a41ca4f4d0141a1d97846b7e14f677 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 11 Oct 2023 12:39:31 -0600 Subject: [PATCH 09/19] Usepure shell instead of bash and follow coding conventions --- try | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/try b/try index 0f523280..34d4d3a7 100755 --- a/try +++ b/try @@ -62,7 +62,7 @@ try() { while IFS="" read -r mountpoint do new_mountpoint="" - + OLDIFS=$IFS IFS=":" for lower_dir in $LOWER_DIRS @@ -79,6 +79,8 @@ try() { fi fi done + + IFS=$OLDIFS # Add the original mountpoint at the end new_mountpoint="${new_mountpoint:+$new_mountpoint:}$mountpoint" echo "$new_mountpoint" >> "$UPDATED_DIRS_AND_MOUNTS" @@ -170,7 +172,7 @@ fi # actually mount the overlays for mountpoint in $(cat "$UPDATED_DIRS_AND_MOUNTS") do - pure_mountpoint=$(echo "$mountpoint" | awk -F':' '{print $NF}') + pure_mountpoint=${mountpoint##*:} ## We are not interested in mounts that are not directories if ! [ -d "$pure_mountpoint" ] @@ -179,12 +181,11 @@ do fi ## Don't do anything for the root - ## and skip if it is /dev or /proc, we will mount it later - if [ "$pure_mountpoint" = "/" ] || - [ "$pure_mountpoint" = "/dev" ] || [ "$pure_mountpoint" = "/proc" ] - then - continue - fi + ## and skip if it is /dev or /proc, we will mount it later + case "$pure_mountpoint" in + (/|/dev|/proc) continue;; + esac + # Try mounting everything normally make_overlay "$SANDBOX_DIR" "$mountpoint" "$pure_mountpoint" 2>>"$try_mount_log" From 4e9807e65df867380508a0cb13ddd01579e1fcee Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 11 Oct 2023 16:32:06 -0600 Subject: [PATCH 10/19] Remove unnecessary empty merge dir check --- try | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/try b/try index 34d4d3a7..2b491e5b 100755 --- a/try +++ b/try @@ -68,18 +68,14 @@ try() { for lower_dir in $LOWER_DIRS do temp_mountpoint="$lower_dir/upperdir$mountpoint" - # Check if the new mountpoint is a directory and is non-empty - if [ -d "$temp_mountpoint" ] && [ "$(find "$temp_mountpoint" -mindepth 1 -maxdepth 1 -print -quit)" ]; then - if [ -n "$new_mountpoint" ]; then - # If new_mountpoint is not empty, append : and the temp_mountpoint - new_mountpoint="$new_mountpoint:$temp_mountpoint" - else - # If new_mountpoint is empty, just set it to temp_mountpoint - new_mountpoint="$temp_mountpoint" - fi + if [ -n "$new_mountpoint" ]; then + # If new_mountpoint is not empty, append : and the temp_mountpoint + new_mountpoint="$new_mountpoint:$temp_mountpoint" + else + # If new_mountpoint is empty, just set it to temp_mountpoint + new_mountpoint="$temp_mountpoint" fi done - IFS=$OLDIFS # Add the original mountpoint at the end new_mountpoint="${new_mountpoint:+$new_mountpoint:}$mountpoint" From 1df84e754411721232cc81776346251ca6d73e01 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 11 Oct 2023 17:37:17 -0600 Subject: [PATCH 11/19] Add test for multi-dir merging --- test/merge_multiple_dirs.sh | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 test/merge_multiple_dirs.sh diff --git a/test/merge_multiple_dirs.sh b/test/merge_multiple_dirs.sh new file mode 100644 index 00000000..47fe597a --- /dev/null +++ b/test/merge_multiple_dirs.sh @@ -0,0 +1,77 @@ +#!/bin/sh + +TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree)}" +TRY="$TRY_TOP/try" + +cleanup() { + cd / + + if [ -d "$try_workspace" ] + then + rm -rf "$try_workspace" >/dev/null 2>&1 + fi + + if [ -f "$try_example_dir1" ] + then + rm "$try_example_dir1" + fi + + if [ -f "$try_example_dir2" ] + then + rm "$try_example_dir2" + fi + + if [ -f "$try_example_dir3" ] + then + rm "$try_example_dir3" + fi + + if [ -f "$expected1" ] + then + rm "$expected1" + fi + + if [ -f "$expected2" ] + then + rm "$expected2" + fi + + if [ -f "$expected3" ] + then + rm "$expected3" + fi + + if [ -f "$expected4" ] + then + rm "$expected4" + fi +} + +trap 'cleanup' EXIT + +try_workspace="$(mktemp -d -p .)" +cp "$TRY_TOP/test/resources/file.txt.gz" "$try_workspace/" +cd $try_workspace + +try_example_dir1="$(mktemp -d)" +try_example_dir2="$(mktemp -d)" +try_example_dir3="$(mktemp -d)" + +expected1="$(mktemp)" +expected2="$(mktemp)" +expected3="$(mktemp)" + +touch "$expected1" +echo "test2" > $expected2 +echo "test3" > $expected3 + +"$TRY" -D "$try_example_dir1" "touch file_1.txt; echo test > file_2.txt; rm file.txt.gz" || return 1 +"$TRY" -D "$try_example_dir2" "echo test2 > file_2.txt" || return 2 +"$TRY" -D "$try_example_dir3" "echo test3 > file_3.txt" || return 3 +"$TRY" -L "$try_example_dir3:$try_example_dir2:$try_example_dir1" -y "cat file_1.txt > out1; cat file_2.txt > out2; cat file_3.txt > out3"|| return 4 + +diff -q "$expected1" out1 || return 5 +diff -q "$expected2" out2 || return 6 +diff -q "$expected3" out3 || return 7 + +! [ -f out4 ] || return 8 From 133b36a3194514ae8d5cb63fc61e6bef26319fad Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 13 Oct 2023 11:15:35 -0600 Subject: [PATCH 12/19] Fix mergerfs call inside try --- try | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/try b/try index 2b491e5b..a0f184b0 100755 --- a/try +++ b/try @@ -122,8 +122,8 @@ TRY_COMMAND="$TRY_COMMAND($0)" make_overlay() { sandbox_dir="$1" lowerdirs="$2" - mountpoint="$3" - mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdirs,upperdir=$sandbox_dir/upperdir/$mountpoint,workdir=$sandbox_dir/workdir/$mountpoint" "$sandbox_dir/temproot/$mountpoint" + overlay_mountpoint="$3" + mount -t overlay overlay -o userxattr -o "lowerdir=$lowerdirs,upperdir=$sandbox_dir/upperdir/$overlay_mountpoint,workdir=$sandbox_dir/workdir/$overlay_mountpoint" "$sandbox_dir/temproot/$overlay_mountpoint" } @@ -182,7 +182,6 @@ do (/|/dev|/proc) continue;; esac - # Try mounting everything normally make_overlay "$SANDBOX_DIR" "$mountpoint" "$pure_mountpoint" 2>>"$try_mount_log" # If mounting everything normally fails, we try using either using mergerfs or unionfs to mount them. @@ -209,9 +208,7 @@ do ## Create a union directory "$UNION_HELPER" $mountpoint $merger_dir 2>>"$try_mount_log" || printf "%s: Warning: Failed mounting $mountpoint via $UNION_HELPER, see \"$try_mount_log\"\n" "$TRY_COMMAND" >&2 - - ## Make the overlay on the union directory which works as a lowerdir for overlay - make_overlay "$SANDBOX_DIR" "$merger_dir" "$mountpoint" 2>>"$try_mount_log" || + make_overlay "$SANDBOX_DIR" "$merger_dir" "$pure_mountpoint" 2>>"$try_mount_log" || printf "%s: Warning: Failed mounting $mountpoint as an overlay via $UNION_HELPER, see \"$try_mount_log\"\n" "$TRY_COMMAND" >&2 fi fi From 8bc51592d2b42f15fd152b0c7f47129e5ad4906c Mon Sep 17 00:00:00 2001 From: gliargovas Date: Fri, 20 Oct 2023 07:50:10 -0600 Subject: [PATCH 13/19] Add completions for -L flag --- completions/try.bash | 5 ++++- try | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/completions/try.bash b/completions/try.bash index faedb84f..8f6a0a68 100644 --- a/completions/try.bash +++ b/completions/try.bash @@ -17,13 +17,16 @@ _try() { case "${cmd}" in (try) - opts="-n -y -v -h -i -D -U summary commit explore" + opts="-n -y -v -h -i -D -U -L summary commit explore" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + (-L) + COMPREPLY=($(compgen -d "${cur}")) + return 0;; (-D) COMPREPLY=($(compgen -d "${cur}")) return 0;; diff --git a/try b/try index a0f184b0..50028f7e 100755 --- a/try +++ b/try @@ -509,7 +509,7 @@ Usage: $TRY_COMMAND [-nvhy] [-i PATTERN] [-D DIR] [-U PATH] [-L "dir1:dir2:..."] -i PATTERN ignore paths that match PATTERN on summary and commit -D DIR work in DIR (implies -n) -U PATH path to unionfs helper (e.g., mergerfs, unionfs-fuse) - -L "dir1:dir2:..." specify multiple lower directories to merge (colon-separated) + -L "dir1:dir2:..." specify multiple lower directories to merge (colon-separated, implies -n) -v show version information (and exit) -h show this usage message (and exit) @@ -546,7 +546,8 @@ do fi SANDBOX_DIR="$OPTARG" NO_COMMIT="quiet";; - (L) LOWER_DIRS="$OPTARG";; + (L) LOWER_DIRS="$OPTARG" + NO_COMMIT="quiet";; (v) echo "$TRY_COMMAND version $TRY_VERSION" >&2 exit 0;; (U) if ! [ -x "$OPTARG" ] From 3bceede38f5a6fb5cf7ac77f3373bdc08a5bc824 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 15 Nov 2023 02:08:35 -0500 Subject: [PATCH 14/19] Tiny tweaks to docs about -L --- README.md | 2 +- docs/try.1.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 372a160c..9354f58e 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ $ try commit rustup-sandbox You can also run `try explore` to open your current shell in try, or `/try explore /tmp/tmp.X6OQb5tJwr` to explore an existing sandbox. -To specify multiple lower directories for overlay (by merging them together), you can use the `-L` flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right: +To specify multiple lower directories for overlay (by merging them together), you can use the `-L` (implies `-n`) flag followed by a colon-separated list of directories. The directories on the left have higher precedence and can overwrite the directories on the right: ```ShellSession $ try -D /tmp/sandbox1 "echo 'File 1 Contents - sandbox1' > file1.txt" diff --git a/docs/try.1.md b/docs/try.1.md index 7d113c4e..861ae2b8 100644 --- a/docs/try.1.md +++ b/docs/try.1.md @@ -55,7 +55,7 @@ This option is recommended in case OverlayFS fails. -L *LOWER_DIRS* -: Specify a colon-separated list of directories to be used as lower directories for the overlay, formatted as "dir1:dir2:...:dirn". +: Specify a colon-separated list of directories to be used as lower directories for the overlay, formatted as "dir1:dir2:...:dirn" (implies -n). ## Subcommands From 4dc1f541b08c8ffc8c1ddd79cc515de855f8fccf Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 15 Nov 2023 02:11:10 -0500 Subject: [PATCH 15/19] Add check for specifying -L multiple times --- try | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/try b/try index 50028f7e..c9b502a5 100755 --- a/try +++ b/try @@ -546,7 +546,11 @@ do fi SANDBOX_DIR="$OPTARG" NO_COMMIT="quiet";; - (L) LOWER_DIRS="$OPTARG" + (L) if [ -n "$LOWER_DIRS" ]; then + error "the -L option has been specified multiple times." 2 + exit 1 + fi + LOWER_DIRS="$OPTARG" NO_COMMIT="quiet";; (v) echo "$TRY_COMMAND version $TRY_VERSION" >&2 exit 0;; From 46b52739a23afef320f38f002948b6ef67e59a46 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 15 Nov 2023 09:34:48 -0500 Subject: [PATCH 16/19] Fix lint typo --- test/merge_multiple_dirs.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/merge_multiple_dirs.sh b/test/merge_multiple_dirs.sh index 47fe597a..bbf9de69 100644 --- a/test/merge_multiple_dirs.sh +++ b/test/merge_multiple_dirs.sh @@ -35,7 +35,6 @@ cleanup() { then rm "$expected2" fi - if [ -f "$expected3" ] then rm "$expected3" From 5f749deac17e7e89f477a825bcfb33511924d1a9 Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 15 Nov 2023 10:01:42 -0500 Subject: [PATCH 17/19] Address shellcheck warnings --- test/merge_multiple_dirs.sh | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/test/merge_multiple_dirs.sh b/test/merge_multiple_dirs.sh index bbf9de69..79524413 100644 --- a/test/merge_multiple_dirs.sh +++ b/test/merge_multiple_dirs.sh @@ -39,18 +39,13 @@ cleanup() { then rm "$expected3" fi - - if [ -f "$expected4" ] - then - rm "$expected4" - fi } trap 'cleanup' EXIT try_workspace="$(mktemp -d -p .)" cp "$TRY_TOP/test/resources/file.txt.gz" "$try_workspace/" -cd $try_workspace +cd "$try_workspace" || return 1 try_example_dir1="$(mktemp -d)" try_example_dir2="$(mktemp -d)" @@ -61,16 +56,16 @@ expected2="$(mktemp)" expected3="$(mktemp)" touch "$expected1" -echo "test2" > $expected2 -echo "test3" > $expected3 +echo "test2" > "$expected2" +echo "test3" > "$expected3" -"$TRY" -D "$try_example_dir1" "touch file_1.txt; echo test > file_2.txt; rm file.txt.gz" || return 1 -"$TRY" -D "$try_example_dir2" "echo test2 > file_2.txt" || return 2 -"$TRY" -D "$try_example_dir3" "echo test3 > file_3.txt" || return 3 -"$TRY" -L "$try_example_dir3:$try_example_dir2:$try_example_dir1" -y "cat file_1.txt > out1; cat file_2.txt > out2; cat file_3.txt > out3"|| return 4 +"$TRY" -D "$try_example_dir1" "touch file_1.txt; echo test > file_2.txt; rm file.txt.gz" || return 2 +"$TRY" -D "$try_example_dir2" "echo test2 > file_2.txt" || return 3 +"$TRY" -D "$try_example_dir3" "echo test3 > file_3.txt" || return 4 +"$TRY" -L "$try_example_dir3:$try_example_dir2:$try_example_dir1" -y "cat file_1.txt > out1; cat file_2.txt > out2; cat file_3.txt > out3"|| return 5 -diff -q "$expected1" out1 || return 5 -diff -q "$expected2" out2 || return 6 -diff -q "$expected3" out3 || return 7 +diff -q "$expected1" out1 || return 6 +diff -q "$expected2" out2 || return 7 +diff -q "$expected3" out3 || return 8 -! [ -f out4 ] || return 8 +! [ -f out4 ] || return 9 From 7b0e233ab4b5898eb2c6e16b2c3c2191cb140d1b Mon Sep 17 00:00:00 2001 From: gliargovas Date: Wed, 15 Nov 2023 10:06:23 -0500 Subject: [PATCH 18/19] Address shellcheck warnings on try script --- try | 1 - 1 file changed, 1 deletion(-) diff --git a/try b/try index c9b502a5..7a270dda 100755 --- a/try +++ b/try @@ -548,7 +548,6 @@ do NO_COMMIT="quiet";; (L) if [ -n "$LOWER_DIRS" ]; then error "the -L option has been specified multiple times." 2 - exit 1 fi LOWER_DIRS="$OPTARG" NO_COMMIT="quiet";; From 0207669e4a5a0227660779b8617f2b5a52570cd3 Mon Sep 17 00:00:00 2001 From: Ezri Zhu Date: Sat, 13 Jan 2024 05:10:14 -0500 Subject: [PATCH 19/19] nitpicks fixes --- try | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/try b/try index 1f04d6bb..1e8e7622 100755 --- a/try +++ b/try @@ -68,7 +68,8 @@ try() { for lower_dir in $LOWER_DIRS do temp_mountpoint="$lower_dir/upperdir$mountpoint" - if [ -n "$new_mountpoint" ]; then + if [ -n "$new_mountpoint" ] + then # If new_mountpoint is not empty, append : and the temp_mountpoint new_mountpoint="$new_mountpoint:$temp_mountpoint" else @@ -176,10 +177,9 @@ do continue fi - ## Don't do anything for the root - ## and skip if it is /dev or /proc, we will mount it later + ## Don't do anything for the root and skip if it is /dev or /proc, we will mount it later case "$pure_mountpoint" in - (/|/dev|/proc) continue;; + (/|/dev|/proc) continue;; esac # Try mounting everything normally @@ -503,17 +503,17 @@ error() { usage() { cat >&2 <