From a24bd3de69ac0a7a27da31a3b99b692db4b9cd40 Mon Sep 17 00:00:00 2001 From: Michael Greenberg Date: Tue, 19 Nov 2024 11:16:36 -0500 Subject: [PATCH 1/3] minimize tempfile churn, add test --- test/tempfiles.sh | 27 +++++++++++++++++++++++++++ try | 32 ++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 10 deletions(-) create mode 100755 test/tempfiles.sh diff --git a/test/tempfiles.sh b/test/tempfiles.sh new file mode 100755 index 0000000..bc2cb73 --- /dev/null +++ b/test/tempfiles.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree 2>/dev/null || echo "${0%/*}")}" +TRY="$TRY_TOP/try" + +initial_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" + +sandbox=$($TRY -n "touch $HOME/foo") +[ $? -eq 0 ] || exit 2 + +post_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" + +# just one new tempfile +[ "$((initial_count + 1))" -eq "$post_count" ] || exit 3 +[ -f "$sandbox/upperdir$HOME/foo" ] || exit 4 + +# deliberately not the pattern of try sandboxes +sandbox="$(mktemp -d --suffix "custom-XXXXXX")" +$TRY -D "$sandbox" "touch $HOME/bar" || exit 5 +[ $? -eq 0 ] || exit 6 + +final_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" + +# no new tempfiles! +echo $post_count $final_count +[ "$post_count" -eq "$final_count" ] || exit 7 +[ -f "$sandbox/upperdir$HOME/bar" ] || exit 8 diff --git a/try b/try index 5774ae3..7bae1c6 100755 --- a/try +++ b/try @@ -37,7 +37,7 @@ try() { ! [ -d "$SANDBOX_DIR" ] && { error "could not find sandbox directory $SANDBOX_DIR" 2; } else ## Create a new sandbox if one was not given - SANDBOX_DIR=$(mktemp -d --suffix ".try-$EXECID") + SANDBOX_DIR="$(mktemp -d --suffix ".try-$EXECID")" fi ## If the sandbox is not valid we exit early @@ -50,7 +50,11 @@ try() { ## because we have already checked if it valid. export SANDBOX_DIR - try_mount_log="$(mktemp --suffix ".try-$EXECID")" + # We created "$IGNORE_FILE" up front, but now we can stash it in the sandbox. + mv "$IGNORE_FILE" "$SANDBOX_DIR"/ignore + IGNORE_FILE="$SANDBOX_DIR"/ignore + + try_mount_log="$SANDBOX_DIR"/mount.log export try_mount_log # If we're in a docker container, we want to mount tmpfs on sandbox_dir, #136 @@ -66,14 +70,14 @@ try() { mkdir -p "$SANDBOX_DIR/upperdir" "$SANDBOX_DIR/workdir" "$SANDBOX_DIR/temproot" ## Find all the directories and mounts that need to be mounted - DIRS_AND_MOUNTS="$(mktemp --suffix ".try-$EXECID")" + DIRS_AND_MOUNTS="$SANDBOX_DIR"/mounts export DIRS_AND_MOUNTS find / -maxdepth 1 >"$DIRS_AND_MOUNTS" 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 - UPDATED_DIRS_AND_MOUNTS="$(mktemp --suffix ".try-$EXECID")" + UPDATED_DIRS_AND_MOUNTS="$SANDBOX_DIR"/mounts.updated export UPDATED_DIRS_AND_MOUNTS while IFS="" read -r mountpoint do @@ -124,9 +128,9 @@ try() { chmod "$(stat -c %a /)" "$SANDBOX_DIR/temproot" - mount_and_execute="$(mktemp --suffix ".try-$EXECID")" - chroot_executable="$(mktemp --suffix ".try-$EXECID")" - script_to_execute="$(mktemp --suffix ".try-$EXECID")" + mount_and_execute="$SANDBOX_DIR"/mount_and_execute.sh + chroot_executable="$SANDBOX_DIR"/chroot_executable.sh + script_to_execute="$SANDBOX_DIR"/script_to_execute.sh export chroot_executable export script_to_execute @@ -227,7 +231,8 @@ do ## We can ignore this mountpoint, if the user program tries to use it, it will crash, but if not we can run normally printf "%s: Warning: Failed mounting $mountpoint as an overlay and mergerfs or unionfs not set and could not be found, see \"$try_mount_log\"\n" "$TRY_COMMAND" >&2 else - merger_dir=$(mktemp -d --suffix ".try-$EXECID") + merger_dir="$SANDBOX_DIR"/mergerdir."$(echo "$pure_mountpoint" | tr '/' '.')" + mkdir "$merger_dir" ## Create a union directory "$UNION_HELPER" $mountpoint $merger_dir 2>>"$try_mount_log" || @@ -612,6 +617,9 @@ EOF NO_COMMIT="interactive" # Includes all patterns given using the `-i` flag; will be used with `grep -f` +# +# We have to create this temporary up front. +# We move it to $SANDBOX_DIR/ignore in `try()`, but delete it when we don't move it. IGNORE_FILE="$(mktemp --suffix ".try-$EXECID")" while getopts ":yvnhxi:D:U:L:" opt @@ -657,9 +665,13 @@ fi TRY_EXIT_STATUS=1 case "$1" in (summary) : "${SANDBOX_DIR=$2}" - summary;; + summary + rm "$IGNORE_FILE" # we didn't move it to the sandbox, so clean up + ;; (commit) : "${SANDBOX_DIR=$2}" - commit;; + commit + rm "$IGNORE_FILE" # we didn't move it to the sandbox, so clean up + ;; (explore) : "${SANDBOX_DIR=$2}" try "$SHELL";; (--) shift From 14696fd5f6f779205ef0bef2d63d1ebcb7b23a5d Mon Sep 17 00:00:00 2001 From: Michael Greenberg Date: Tue, 19 Nov 2024 11:23:45 -0500 Subject: [PATCH 2/3] satisfy shellcheck --- test/tempfiles.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/tempfiles.sh b/test/tempfiles.sh index bc2cb73..66daae6 100755 --- a/test/tempfiles.sh +++ b/test/tempfiles.sh @@ -1,4 +1,5 @@ #!/bin/sh +# shellcheck disable=SC2010,SC2126,SC2181 TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree 2>/dev/null || echo "${0%/*}")}" TRY="$TRY_TOP/try" @@ -17,11 +18,9 @@ post_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" # deliberately not the pattern of try sandboxes sandbox="$(mktemp -d --suffix "custom-XXXXXX")" $TRY -D "$sandbox" "touch $HOME/bar" || exit 5 -[ $? -eq 0 ] || exit 6 final_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" # no new tempfiles! -echo $post_count $final_count -[ "$post_count" -eq "$final_count" ] || exit 7 -[ -f "$sandbox/upperdir$HOME/bar" ] || exit 8 +[ "$post_count" -eq "$final_count" ] || exit 6 +[ -f "$sandbox/upperdir$HOME/bar" ] || exit 7 From 948ed3f1fab2a5e02cd8f4f12df2475300e4ad07 Mon Sep 17 00:00:00 2001 From: Michael Greenberg Date: Tue, 19 Nov 2024 12:33:33 -0500 Subject: [PATCH 3/3] capture absolute path of sandbox dir, cleanup --- test/tempfiles.sh | 12 ++++++++---- try | 7 ++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/test/tempfiles.sh b/test/tempfiles.sh index 66daae6..25e6adb 100755 --- a/test/tempfiles.sh +++ b/test/tempfiles.sh @@ -4,6 +4,9 @@ TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree 2>/dev/null || echo "${0%/*}")}" TRY="$TRY_TOP/try" +workdir="$(mktemp -d)" +cd "$workdir" || exit 1 + initial_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" sandbox=$($TRY -n "touch $HOME/foo") @@ -16,11 +19,12 @@ post_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" [ -f "$sandbox/upperdir$HOME/foo" ] || exit 4 # deliberately not the pattern of try sandboxes -sandbox="$(mktemp -d --suffix "custom-XXXXXX")" -$TRY -D "$sandbox" "touch $HOME/bar" || exit 5 +sandbox=local +mkdir "$sandbox" || exit 5 +$TRY -D "$sandbox" "touch $HOME/bar" || exit 6 final_count="$(ls "${TMPDIR-/tmp}" | grep -e "^.*\.try-[0-9]*$" | wc -l)" # no new tempfiles! -[ "$post_count" -eq "$final_count" ] || exit 6 -[ -f "$sandbox/upperdir$HOME/bar" ] || exit 7 +[ "$post_count" -eq "$final_count" ] || exit 7 +[ -f "$sandbox/upperdir$HOME/bar" ] || exit 8 diff --git a/try b/try index 7bae1c6..3f8e059 100755 --- a/try +++ b/try @@ -34,7 +34,12 @@ try() { if [ "$SANDBOX_DIR" ] then ## If the name of a sandbox is given then we need to exit prematurely if its directory doesn't exist - ! [ -d "$SANDBOX_DIR" ] && { error "could not find sandbox directory $SANDBOX_DIR" 2; } + [ -d "$SANDBOX_DIR" ] || error "could not find sandbox directory $SANDBOX_DIR" 2 + # Force absolute path + SANDBOX_DIR="$(cd "$SANDBOX_DIR" && pwd)" + + # shellcheck disable=SC2181 + [ "$?" -eq 0 ] || error "could not find sandbox directory $SANDBOX_DIR (could not cd in)" 2 else ## Create a new sandbox if one was not given SANDBOX_DIR="$(mktemp -d --suffix ".try-$EXECID")"