commit: 2a78a15de6e5d90da0657bf74929993b1b51a337
Author: Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Thu Jun 8 05:48:02 2023 +0000
Commit: Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Fri Jun 9 06:57:10 2023 +0000
URL:
https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=2a78a15d
Add a chdir() function to act as a safer alternative to the cd builtin
To run cd "$dir" is problematic because:
1) it may consider its operand as an option
2) it will search CDPATH for an operand not beginning with ./, ../ or /
3) it will switch to OLDPWD if the operand is -
4) cdable_vars causes bash to treat the operand as a potential varname
This commit introduces a chdir() function that addresses all of these
pitfalls.
Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
Signed-off-by: Sam James <sam <AT> gentoo.org>
functions.sh | 18 +++++++++++++++++
test-functions | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/functions.sh b/functions.sh
index 7838c90..154c8a4 100644
--- a/functions.sh
+++ b/functions.sh
@@ -534,6 +534,24 @@ is_int() {
esac
}
+#
+# A safe wrapper for the cd builtin. To run cd "$dir" is problematic because:
+#
+# 1) it may consider its operand as an option
+# 2) it will search CDPATH for an operand not beginning with ./, ../ or /
+# 3) it will switch to OLDPWD if the operand is -
+# 4) cdable_vars causes bash to treat the operand as a potential variable
name
+#
+chdir() {
+ if [ "$BASH" ]; then
+ shopt -u cdable_vars
+ fi
+ if [ "$1" = - ]; then
+ set -- ./-
+ fi
+ CDPATH= cd -- "$@"
+}
+
#
# Determine whether the first operand contains any visible characters.
#
diff --git a/test-functions b/test-functions
index b80587b..5a6b23b 100755
--- a/test-functions
+++ b/test-functions
@@ -14,7 +14,7 @@ bailout() {
assign_tmpdir() {
# shellcheck disable=1007
dir=$(mktemp -d) \
- && CDPATH= cd -- "${dir}" \
+ && chdir "${dir}" \
|| bailout "Couldn't create or change to the temp dir"
}
@@ -24,6 +24,49 @@ cleanup_tmpdir() {
fi
}
+test_chdir() {
+ set -- \
+ 1 grandchild \
+ 1 var \
+ 0 -L \
+ 0 -p \
+ 0 -e \
+ 0 -@ \
+ 0 - \
+ 0 child
+
+ if ! mkdir -p -- -L -p -e -@ - child child/grandchild; then
+ bailout "Couldn't set up all test directories"
+ fi
+
+ callback() {
+ shift
+ test_description="chdir $(print_args "$@")"
+ if [ "$BASH" ]; then
+ shopt -s cdable_vars
+ fi
+ CDPATH=child var=$CDPATH chdir "$@" \
+ && test "$PWD" != "$OLDPWD" \
+ && cd - >/dev/null
+ }
+
+ iterate_tests 2 "$@"
+}
+
+test_chdir_noop() {
+ set -- 0 ''
+
+ callback() {
+ shift
+ test_description="chdir $(print_args "$@")"
+ chdir "$@" \
+ && test "$PWD" = "$OLDPWD" \
+ || { cd - >/dev/null; false; }
+ }
+
+ iterate_tests 2 "$@"
+}
+
test_is_older_than() {
set -- \
1 N/A N/A \
@@ -317,12 +360,24 @@ iterate_tests() {
fi
done
eval "${code}"
- if [ "$?" -eq "$1" ]; then
+ case $? in
+ 0)
+ test "$?" -eq "$1"
+ ;;
+ *)
+ test "$?" -ge "$1"
+ esac
+ if [ "$?" -eq 0 ]; then
passed=$((passed + 1))
else
printf 'not '
fi
- printf 'ok %d - %s (expecting %d)\n' "${i}"
"${test_description}" "$1"
+ if [ "$1" -eq 0 ]; then
+ expected=$1
+ else
+ expected=">=$1"
+ fi
+ printf 'ok %d - %s (expecting %s)\n' "${i}"
"${test_description}" "${expected}"
shift "${slice_width}"
done
return "$(( passed < total ))"
@@ -359,6 +414,8 @@ export TEST_GENFUNCS=1
export TZ=UTC
rc=0
+test_chdir || rc=1
+test_chdir_noop || rc=1
( ewarn() { true; }; test_is_older_than ) || rc=1
test_get_bootparam || rc=1
test_esyslog || rc=1