From f0b6f0962e453a2dc3ea3da9b2f334a03c568dfb Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 4 Jan 2021 15:34:52 +0100 Subject: [PATCH] Use true fakechroot/fakeroot in ns fakeroot mode --- README.md | 12 ---------- bin/junest | 6 +---- lib/core/chroot.sh | 22 ++++++++---------- lib/core/common.sh | 14 +++++------ lib/core/namespace.sh | 37 +++++++++++------------------- lib/core/proot.sh | 20 +++++++--------- tests/unit-tests/test-chroot.sh | 8 +++---- tests/unit-tests/test-namespace.sh | 12 +++++----- 8 files changed, 49 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index 1d950d5..48337a6 100644 --- a/README.md +++ b/README.md @@ -392,18 +392,6 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht ## Could not change the root directory in pacman -> **Q**: In ns fakeroot mode when installing package I get the following error: - - could not change the root directory (Operation not permitted) - error: command failed to execute correctly - -> **A**: This is one of the last step executed in `pacman`. -> In any case, the package will still be installed correctly even though this -> message is showed. -> If you use `sudo` -> instead, the error should not appear given that the fake sudo script uses -> `fakechroot` internally. - ## No servers configured for repository ## > **Q**: Why I cannot install packages? diff --git a/bin/junest b/bin/junest index 2671e86..7040197 100755 --- a/bin/junest +++ b/bin/junest @@ -190,11 +190,7 @@ function _parse_proot_opts() { esac done - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done + ARGS=("$@") } function _parse_build_opts() { diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index 635137b..afabc71 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -20,8 +20,8 @@ function _run_env_as_xroot(){ # SUDO_USER is more reliable compared to SUDO_UID [ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID - local main_cmd="${SH[@]}" - [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" + local args=() + [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") # With chown the ownership of the files is assigned to the real user trap - QUIT EXIT ABRT KILL TERM INT @@ -32,7 +32,7 @@ function _run_env_as_xroot(){ copy_common_files fi - JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" + JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" } ####################################### @@ -43,13 +43,13 @@ function _run_env_as_xroot(){ # UID (RO) : The user ID. # SUDO_USER (RO) : The sudo user ID. # SUDO_GID (RO) : The sudo group ID. -# SH (RO) : Contains the default command to run in JuNest. +# DEFAULT_SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to backend program # no_copy_files ($2?) : If false it will copy some files in /etc # from host to JuNest environment. # cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. +# Default command is defined by DEFAULT_SH variable. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. # Output: @@ -58,13 +58,11 @@ function _run_env_as_xroot(){ function run_env_as_groot(){ check_nested_env - local backend_command="$1" + local backend_command="${1:-$GROOT}" local backend_args="$2" local no_copy_files="$3" shift 3 - [[ -z "$backend_command" ]] && backend_command="$GROOT" - provide_common_bindings local bindings=${RESULT} unset RESULT @@ -80,13 +78,13 @@ function run_env_as_groot(){ # UID (RO) : The user ID. # SUDO_USER (RO) : The sudo user ID. # SUDO_GID (RO) : The sudo group ID. -# SH (RO) : Contains the default command to run in JuNest. +# DEFAULT_SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to backend program # no_copy_files ($2?) : If false it will copy some files in /etc # from host to JuNest environment. # cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. +# Default command is defined by DEFAULT_SH variable. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. # Output: @@ -95,12 +93,10 @@ function run_env_as_groot(){ function run_env_as_chroot(){ check_nested_env - local backend_command="$1" + local backend_command="${1:-chroot_cmd}" local backend_args="$2" local no_copy_files="$3" shift 3 - [[ -z "$backend_command" ]] && backend_command=chroot_cmd - _run_env_as_xroot "$backend_command" "$backend_args" "$no_copy_files" "$@" } diff --git a/lib/core/common.sh b/lib/core/common.sh index 624a33c..a496522 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -64,7 +64,7 @@ ORIGIN_WD=$(pwd) # different locations in the host OS. # List of executables that are run inside JuNest: -SH=("/bin/sh" "--login") +DEFAULT_SH=("/bin/sh" "--login") # List of executables that are run in the host OS: PROOT="${JUNEST_HOME}/usr/bin/proot-${ARCH}" @@ -132,12 +132,12 @@ function unshare_cmd(){ # with --user option available. # Hence, give priority to the `unshare` executable in JuNest image. # Also, unshare provides an environment in which /bin/sh maps to dash shell, - # therefore it ignores all the remaining SH arguments (i.e. --login) as + # therefore it ignores all the remaining DEFAULT_SH arguments (i.e. --login) as # they are not supported by dash. - if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${SH[0]}" "-c" ":" + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" then $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE "${@}" - elif $UNSHARE --user "${SH[0]}" "-c" ":" + elif $UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" then $UNSHARE "$@" else @@ -146,7 +146,7 @@ function unshare_cmd(){ } function bwrap_cmd(){ - if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${SH[0]}" "-c" ":" + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":" then $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP "${@}" else @@ -157,10 +157,10 @@ function bwrap_cmd(){ function proot_cmd(){ local proot_args="$1" shift - if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" + if ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":" then ${PROOT} ${proot_args} "${@}" - elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" + elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":" then warn "Warn: Proot is not properly working. Disabling SECCOMP and expect the application to run slowly in particular when it uses syscalls intensively." warn "Try to use Linux namespace instead as it is more reliable: junest ns" diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 6be2c5f..45c7c09 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -55,34 +55,19 @@ function _check_user_namespace() { set -e } -function _run_env_with_bwrap(){ - local backend_command="$1" - local backend_args="$2" - shift 2 - - [[ -z "$backend_command" ]] && backend_command=bwrap_cmd - - if [[ "$1" != "" ]] - then - JUNEST_ENV=1 "$backend_command" --bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try ${backend_args} "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" - else - JUNEST_ENV=1 "$backend_command" --bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try ${backend_args} "${SH[@]}" - fi - -} ####################################### # Run JuNest as fakeroot via bwrap # # Globals: # JUNEST_HOME (RO) : The JuNest home directory. -# SH (RO) : Contains the default command to run in JuNest. +# DEFAULT_SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to bwrap # no_copy_files ($2?) : If false it will copy some files in /etc # from host to JuNest environment. # cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. +# Default command is defined by DEFAULT_SH variable. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. # $ROOT_ACCESS_ERROR : If the user is the real root. @@ -92,7 +77,7 @@ function _run_env_with_bwrap(){ function run_env_as_bwrap_fakeroot(){ check_nested_env - local backend_command="$1" + local backend_command="${1:-bwrap_cmd}" local backend_args="$2" local no_copy_files="$3" shift 3 @@ -106,7 +91,10 @@ function run_env_as_bwrap_fakeroot(){ copy_common_files fi - _run_env_with_bwrap "$backend_command" "--uid 0 --gid 0 $backend_args" "$@" + local args=() + [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + + JUNEST_ENV=1 "$backend_command" --bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" } @@ -115,13 +103,13 @@ function run_env_as_bwrap_fakeroot(){ # # Globals: # JUNEST_HOME (RO) : The JuNest home directory. -# SH (RO) : Contains the default command to run in JuNest. +# DEFAULT_SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to bwrap # no_copy_files ($2?) : If false it will copy some files in /etc # from host to JuNest environment. # cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. +# Default command is defined by DEFAULT_SH variable. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. # Output: @@ -130,7 +118,7 @@ function run_env_as_bwrap_fakeroot(){ function run_env_as_bwrap_user() { check_nested_env - local backend_command="$1" + local backend_command="${1:-bwrap_cmd}" local backend_args="$2" local no_copy_files="$3" shift 3 @@ -150,7 +138,10 @@ function run_env_as_bwrap_user() { copy_passwd_and_group fi - _run_env_with_bwrap "$backend_command" "$backend_args" "$@" + local args=() + [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + + JUNEST_ENV=1 "$backend_command" --bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try $backend_args "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index bce8295..1e258f2 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -9,18 +9,14 @@ # vim: ft=sh function _run_env_with_proot(){ - local backend_command="$1" + local backend_command="${1:-proot_cmd}" local backend_args="$2" shift 2 - [[ -z "$backend_command" ]] && backend_command=proot_cmd + local args=() + [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - if [ "$1" != "" ] - then - JUNEST_ENV=1 "${backend_command}" "${backend_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" - else - JUNEST_ENV=1 "${backend_command}" "${backend_args}" "${SH[@]}" - fi + JUNEST_ENV=1 "${backend_command}" "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}" } function _run_env_with_qemu(){ @@ -52,13 +48,13 @@ function _run_env_with_qemu(){ # Globals: # JUNEST_HOME (RO) : The JuNest home directory. # EUID (RO) : The user ID. -# SH (RO) : Contains the default command to run in JuNest. +# DEFAULT_SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to proot # no_copy_files ($2?) : If false it will copy some files in /etc # from host to JuNest environment. # cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. +# Default command is defined by DEFAULT_SH variable. # Returns: # $ROOT_ACCESS_ERROR : If the user is the real root. # Output: @@ -94,13 +90,13 @@ function run_env_as_proot_fakeroot(){ # Globals: # JUNEST_HOME (RO) : The JuNest home directory. # EUID (RO) : The user ID. -# SH (RO) : Contains the default command to run in JuNest. +# DEFAULT_SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to proot # no_copy_files ($2?) : If false it will copy some files in /etc # from host to JuNest environment. # cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. +# Default command is defined by DEFAULT_SH variable. # Returns: # $ROOT_ACCESS_ERROR : If the user is the real root. # Output: diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 4556671..44999f7 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -44,12 +44,12 @@ function test_run_env_as_groot_cmd(){ function test_run_env_as_groot_no_cmd(){ assertCommandSuccess run_env_as_groot "" "" "false" "" - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" } function test_run_env_as_groot_with_backend_command(){ assertCommandSuccess run_env_as_groot "mychroot" "" "false" "" - assertEquals "mychroot -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mychroot -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" } function test_run_env_as_groot_no_copy(){ @@ -84,12 +84,12 @@ function test_run_env_as_chroot_cmd(){ function test_run_env_as_chroot_no_cmd(){ assertCommandSuccess run_env_as_chroot "" "" "false" "" - assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" } function test_run_env_as_chroot_with_backend_command(){ assertCommandSuccess run_env_as_chroot "mychroot" "" "false" "" - assertEquals "mychroot $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mychroot $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" } function test_run_env_as_chroot_no_copy(){ diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 02149b4..e24311f 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -104,14 +104,14 @@ function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ function test_run_env_as_bwrap_fakeroot() { assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_fakeroot_with_backend_command() { assertCommandSuccess run_env_as_bwrap_fakeroot "mybwrap" "" "false" - assertEquals "mybwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mybwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } @@ -134,7 +134,7 @@ function test_run_env_as_bwrap_user_with_backend_command() { function test_run_env_as_bwrap_fakeroot_no_copy() { assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "true" "" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -186,7 +186,7 @@ function test_run_env_as_bwrap_user_no_copy() { function test_run_env_as_bwrap_fakeroot_with_backend_args() { assertCommandSuccess run_env_as_bwrap_fakeroot "" "--bind /usr /usr" "false" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } @@ -201,7 +201,7 @@ function test_run_env_as_bwrap_user_with_backend_args() { function test_run_env_as_bwrap_fakeroot_with_command() { assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false" "ls -la" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } @@ -216,7 +216,7 @@ function test_run_env_as_bwrap_user_with_command() { function test_run_env_as_bwrap_fakeroot_with_backend_args_and_command() { assertCommandSuccess run_env_as_bwrap_fakeroot "" "--bind /usr /usr" "false" "ls -la" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files }