diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c5b62fd..9ea8193 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -153,7 +153,7 @@ All JuNest issues are tracked as [GitHub issues](https://guides.github.com/featu #### Unit Tests #### To run unit tests: ```sh -./tests/unit-tests.sh +./tests/unit-tests/unit-tests.sh ``` #### Integration Tests #### diff --git a/lib/core.sh b/lib/core.sh index 7012391..dbb81d2 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -87,6 +87,8 @@ CHOWN="chown" LN=ln RM=rm MKDIR=mkdir +GETENT=getent +CP=cp LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -98,6 +100,14 @@ function ln_cmd(){ $LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@ } +function getent_cmd(){ + $GETENT $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT $@ +} + +function cp_cmd(){ + $CP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP $@ +} + function rm_cmd(){ $RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@ } @@ -357,6 +367,7 @@ function run_env_as_user(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + _build_passwd_and_group _provide_bindings_as_user local bindings="$RESULT" unset RESULT @@ -365,6 +376,9 @@ function run_env_as_user(){ ####################################### # Provide the proot binding options for the normal user. +# The list of bindings can be found in `proot --help`. This function excludes +# /etc/mtab file so that it will not give conflicts with the related +# symlink in the image. # # Globals: # HOME (RO) : The home directory. @@ -377,16 +391,48 @@ function run_env_as_user(){ # None ####################################### function _provide_bindings_as_user(){ - # The list of bindings can be found in `proot --help`. This function excludes - # /etc/mtab file so that it will not give conflicts with the related - # symlink in the image. RESULT="" - for bind in "/etc/host.conf" "/etc/hosts" "/etc/hosts.equiv" "/etc/netgroup" "/etc/networks" "/etc/passwd" "/etc/group" "/etc/nsswitch.conf" "/etc/resolv.conf" "/etc/localtime" "/dev" "/sys" "/proc" "/tmp" "$HOME" + local re='(.*):.*' + for bind in "/etc/host.conf" "/etc/hosts" "/etc/hosts.equiv" "/etc/netgroup" "/etc/networks" "${JUNEST_HOME}/etc/junest/passwd:/etc/passwd" "${JUNEST_HOME}/etc/junest/group:/etc/group" "/etc/nsswitch.conf" "/etc/resolv.conf" "/etc/localtime" "/dev" "/sys" "/proc" "/tmp" "$HOME" do - [ -e "$bind" ] && RESULT="-b $bind $RESULT" + if [[ $bind =~ $re ]] + then + [ -e "${BASH_REMATCH[1]}" ] && RESULT="-b $bind $RESULT" + else + [ -e "$bind" ] && RESULT="-b $bind $RESULT" + fi done } +####################################### +# Build passwd and group files using getent command. +# If getent fails the function fallbacks by copying the content from /etc/passwd +# and /etc/group. +# +# The generated passwd and group will be stored in $JUNEST_HOME/etc/junest. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# Arguments: +# None +# Returns: +# None +# Output: +# None +####################################### +function _build_passwd_and_group(){ + if ! getent_cmd passwd > ${JUNEST_HOME}/etc/junest/passwd + then + warn "getent command failed or does not exist. Binding directly from /etc/passwd." + cp_cmd /etc/passwd ${JUNEST_HOME}/etc/junest/passwd + fi + if ! getent_cmd group > ${JUNEST_HOME}/etc/junest/group + then + warn "getent command failed or does not exist. Binding directly from /etc/group." + cp_cmd /etc/group ${JUNEST_HOME}/etc/junest/group + fi +} + ####################################### # Remove an existing JuNest system. # diff --git a/tests/unit-tests/test-core.sh b/tests/unit-tests/test-core.sh index 46072e1..a009510 100755 --- a/tests/unit-tests/test-core.sh +++ b/tests/unit-tests/test-core.sh @@ -55,6 +55,26 @@ function test_ln(){ LN=false LD_EXEC=false assertCommandFail ln_cmd } +function test_getent(){ + GETENT=echo assertCommandSuccess getent_cmd passwd + assertEquals "passwd" "$(cat $STDOUTF)" + + GETENT=false assertCommandSuccess getent_cmd passwd + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)" + + GETENT=false LD_EXEC=false assertCommandFail getent_cmd +} + +function test_cp(){ + CP=echo assertCommandSuccess cp_cmd passwd + assertEquals "passwd" "$(cat $STDOUTF)" + + CP=false assertCommandSuccess cp_cmd passwd + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)" + + CP=false LD_EXEC=false assertCommandFail cp_cmd +} + function test_download(){ WGET=/bin/true CURL=/bin/false @@ -222,6 +242,45 @@ function test_run_env_as_user(){ assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" } +function test_provide_bindings_as_user_no_junest_home(){ + _provide_bindings_as_user + echo "$RESULT" | grep -q "$JUNEST_HOME/etc/junest/passwd" + assertEquals 1 $? + echo "$RESULT" | grep -q "$JUNEST_HOME/etc/junest/group" + assertEquals 1 $? +} + +function test_provide_bindings_as_user(){ + touch $JUNEST_HOME/etc/junest/passwd + touch $JUNEST_HOME/etc/junest/group + _provide_bindings_as_user + echo "$RESULT" | grep -q "$JUNEST_HOME/etc/junest/passwd" + assertEquals 0 $? + echo "$RESULT" | grep -q "$JUNEST_HOME/etc/junest/group" + assertEquals 0 $? +} + +function test_build_passwd_and_group(){ + getent_cmd_mock() { + echo $@ + } + GETENT=getent_cmd_mock assertCommandSuccess _build_passwd_and_group + assertEquals "passwd" "$(cat $JUNEST_HOME/etc/junest/passwd)" + assertEquals "group" "$(cat $JUNEST_HOME/etc/junest/group)" +} + +function test_build_passwd_and_group_fallback(){ + cp_cmd_mock() { + echo $@ + } + CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _build_passwd_and_group + assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME/etc/junest/passwd\n/etc/group $JUNEST_HOME/etc/junest/group")" "$(cat $STDOUTF)" +} + +function test_build_passwd_and_group_failure(){ + CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _build_passwd_and_group +} + function test_run_env_as_fakeroot(){ _run_env_with_qemu() { echo $@