diff --git a/aux/unit.sh b/aux/unit.sh index 5277045..221c3b0 100644 --- a/aux/unit.sh +++ b/aux/unit.sh @@ -1,7 +1,7 @@ #! /bin/bash -# unit.sh version 20210803 +# unit.sh version 20220105 set -o errexit @@ -54,7 +54,7 @@ run () { # -------------------------------------------------------- run echo " status $status" echo echo " expect '$expect'" - echo " actual '$( echo "$actual" | head -n 1)'" + echo " actual '$( echo "$actual" | head -n 1)' length ${#actual}" local f=' %-9s %s\n' echo @@ -112,6 +112,18 @@ prepare_users () { # ------------------------------------ prepare_users echo 'unit.sh done prepare_users' ; } +etc_passwd () { # ------------------------------------------ etc_passwd + + # usage: etc_passwd none # use an empty /etc/passwd + # etc_passwd orig # use the original /etc/passwd + # etc_passwd user2 # use a custom /etc/passwd + + pushd "$unit/nr/etc" + cp group-"$1" group + cp passwd-"$1" passwd + popd ; } + + home_make () { # -------------------------------------------- home_make mkdir -p "$unit/nr/home/$USER" mkdir -p "$unit/nr/home/user1" @@ -123,6 +135,7 @@ home_make () { # -------------------------------------------- home_make home_remove () { # ---------------------------------------- home_remove rm_soft "$unit/nr/home/user2/foo" + rm_soft "$unit/nr/root/aaa/bbb" rm_soft "$unit/nr/root/foo" rm_soft "$unit/nr/home/$USER/.ash_history" rm_soft "$unit/nr/home/user1/.ash_history" @@ -133,16 +146,11 @@ home_remove () { # ---------------------------------------- home_remove rmdir_soft "$unit/nr/home/user2/ape" rmdir_soft "$unit/nr/home/user2" rmdir_soft "$unit/nr/home/user3" + rmdir_soft "$unit/nr/root/aaa" rmdir_soft "$unit/nr/root" return ; } -user_activate () { # ------------------------------------ user_activate - pushd "$unit/nr/etc" - cp group-"$1" group - cp passwd-"$1" passwd - popd ; } - phase_one () { # -------------------------------------------- phase_one @@ -169,7 +177,7 @@ test_no_home () { # -------------------------------------- test_no_home echo ; echo "- test_no_home" - user_activate none + etc_passwd none home_remove phase_one @@ -202,7 +210,7 @@ test_no_home () { # -------------------------------------- test_no_home # test $unit/nr/etc/passwd-user2 - user_activate user2 + etc_passwd user2 run2 '/home/user2' -- /bin/sh -c 'echo $HOME' run2 'user2' -- /bin/sh -c 'echo $LOGNAME' @@ -212,7 +220,7 @@ test_no_home () { # -------------------------------------- test_no_home # test explicit environment variables - user_activate orig + etc_passwd orig run3 '/home/user3' -- /bin/sh -c 'echo $HOME' run3 'user3' -- /bin/sh -c 'echo $LOGNAME' @@ -233,37 +241,55 @@ test_home () { # -------------------------------------------- test_home echo ; echo "- test_home" - user_activate none # nr/etc/passwd miss + etc_passwd none # nr/etc/passwd miss home_make phase_one + # run1 enivornment variables none + # run2 environment variables fixed + # run3 environment variables fixed, but overriden by n=v options # 20210624 The two below commented tests are too restrictive. - # run1 "$HOME" -- /bin/sh -c 'echo $HOME' # /etc/passwd + # run1 "$HOME" -- /bin/sh -c 'echo $HOME' # host /etc/passwd run2 "/home/user1" -- /bin/sh -c 'echo $HOME' # host env run3 '/home/user3' -- /bin/sh -c 'echo $HOME' # explicit n=v - # run1 "$HOME" -- pwd # /etc/passwd + # run1 "$HOME" -- pwd # host /etc/passwd run2 '/home/user1' -- pwd # host env run3 '/home/user3' -- pwd # explicit n=v - user_activate user2 # nr/etc/passwd hit + etc_passwd user2 # nr/etc/passwd hit - run1 '/home/user2' -- /bin/sh -c 'echo $HOME' # nr/etc/passwd - run2 '/home/user2' -- /bin/sh -c 'echo $HOME' # nr/etc/passwd + run1 '/home/user2' -- /bin/sh -c 'echo $HOME' # nr /etc/passwd + run2 '/home/user2' -- /bin/sh -c 'echo $HOME' # nr /etc/passwd run3 '/home/user3' -- /bin/sh -c 'echo $HOME' # explicit n=v - run1 "/home/user2" -- pwd # nr/etc/passwd - run2 '/home/user2' -- pwd # nr/etc/passwd + run1 "/home/user2" -- pwd # nr /etc/passwd + run2 '/home/user2' -- pwd # nr /etc/passwd run3 '/home/user3' -- pwd # explicit n=v - # as root, nr/etc/passwd hit + return ; } + + +test_home_root () { # ---------------------------------- test_home_root + + home_make + phase_one + + etc_passwd orig # use original /etc/passwd - user_activate orig + run1 '/root' -r -- /bin/sh -c 'echo $HOME' # nr /etc/passwd + run2 '/root' -r -- /bin/sh -c 'echo $HOME' # nr /etc/passwd + run3 '/home/user3' -r -- /bin/sh -c 'echo $HOME' # explicit n=v + run1 '/root' -r -- pwd # nr /etc/passwd + run2 '/root' -r -- pwd # nr /etc/passwd + run3 '/home/user3' -r -- pwd # explicit n=v - run1 '/root' -r -- /bin/sh -c 'echo $HOME' # nr/etc/passwd - run2 '/root' -r -- /bin/sh -c 'echo $HOME' # nr/etc/passwd + etc_passwd none # use empty /etc/passwd + + run1 '/root' -r -- /bin/sh -c 'echo $HOME' # host /etc/passwd + run2 '/root' -r -- /bin/sh -c 'echo $HOME' # host /etc/passwd run3 '/home/user3' -r -- /bin/sh -c 'echo $HOME' # explicit n=v - run1 '/root' -r -- pwd # nr/etc/passwd - run2 '/root' -r -- pwd # nr/etc/passwd + run1 '/root' -r -- pwd # host /etc/passwd + run2 '/root' -r -- pwd # host /etc/passwd run3 '/home/user3' -r -- pwd # explicit n=v return ; } @@ -273,7 +299,7 @@ test_readauto () { # ------------------------------------ test_readauto echo ; echo "- test_readauto" - user_activate user2 + etc_passwd user2 home_make env1=( env - ) lxr1=() cmd1=() @@ -527,15 +553,43 @@ test_chdir () { # ------------------------------------------ test_chdir run1 '/ape' ./lxr ro nr wd /ape -- pwd run1 '' ./lxr ro nr wd /ape -- touch foo + run1 '/tmp' ./lxr ro nr cd /tmp -- pwd + run1 '/tmp' ./lxr ro nr wd /tmp -- pwd + run1 'err 1-' ./lxr ro nr cd /tmp -- touch foo + run1 '' ./lxr ro nr wd /tmp -- touch foo + run1 'err 1-' ./lxr ro nr wd /tmp -- touch /foo run1 'err 1-' ./lxr ro nr wd /tmp -- touch /ape/foo run1 '' ./lxr ro nr wd /tmp -- touch /tmp/foo - run1 '/tmp' ./lxr ro nr wd /tmp -- pwd - run1 '' ./lxr ro nr wd /tmp -- touch foo + return ; } + + +test_chdir_root () { # -------------------------------- test_chdir_root + + # env1=() lxr1=() cmd1=() # 20220105 + env1=( env - ) lxr1=() cmd1=() + + mkdir -p nr/root/aaa + echo 'ccc' > nr/root/aaa/bbb + + etc_passwd orig # original inner /etc/passwd + + run1 '/root' ./lxr -r nr -- /bin/sh -c 'echo $HOME' + run1 '/root' ./lxr -r nr -- pwd + run1 '/root/aaa' ./lxr -r nr cd aaa -- pwd + run1 'ccc' ./lxr -r nr cd aaa -- cat bbb + run1 'ccc' ./lxr -r nr wd aaa -- cat bbb + + etc_passwd none # empty inner /etc/passwd + + run1 '/root' ./lxr -r nr -- /bin/sh -c 'echo $HOME' + run1 '/root' ./lxr -r nr -- pwd + run1 '/root/aaa' ./lxr -r nr cd aaa -- pwd + run1 'ccc' ./lxr -r nr cd aaa -- cat bbb + run1 'ccc' ./lxr -r nr wd aaa -- cat bbb - # 20210623 - # run1 'err 1-' ./lxr ro nr wd /tmp --trace -- touch foo + # etc_passwd user2 ; test_chdir_2_inner return ; } @@ -559,7 +613,7 @@ test_options () { # -------------------------------------- test_options echo ; echo "- test_options" - user_activate user2 + etc_passwd user2 home_make if [ -d '/tmp/.X11-unix' ] ; then test_x11 ; fi @@ -640,11 +694,13 @@ main () { # ------------------------------------------------------ main test_no_home test_home + test_home_root test_readauto test_full_overlay test_partial_overlay test_bind test_chdir + test_chdir_root test_options # echo ; echo 'unit.sh additional tests disabled' ; exit 1 diff --git a/changelog.txt b/changelog.txt index 6ad7b6a..2e06597 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,12 +1,13 @@ +20220108 +Version bump to 0.22.0, in order to publish the below 'cd path' improvement. +20220105 +With the 'cd path' option, a relative path is now relative to $HOME. 20211226 - Set version number to 0.21.0, in preparation for first GitHub release. - 20211115 - Retired 'master' branch. Created new 'main' branch. The above two chanegs were done for copyright/authorship reasons. @@ -15,14 +16,10 @@ Rebuilt demo3. Shifted parts of demo3 from Makefile to aux/demo.sh. The above demo3 changes fixed Issue #7. Fixed enum vs. #define MS_ vs ST_ bug. (Fixing issue #6.) - 20211030 - Moved C++ unit tests to unit.cpp. - 20211028 - Ipmelmented proper fix of GitHub issue #3, via statfs(). Moved demo.sh and unit.sh to aux/ directory. Added static.sh to aux/ to aux/ directory. @@ -30,9 +27,7 @@ Improved Makefile help text. Moved help strings from lxroot.cpp to help.cpp. Moved string classes from lxroot.cpp to str.cpp. - 20211019 - moved string implementation to str.cpp name changes related to char * and/or mutability vs. immutability renamed struct mstr to struct mStr @@ -42,82 +37,58 @@ name changes related to char * and/or mutability vs. immutability introduced typedef opt introduced typedef str - 20210803 - In anticipation of binding files, '--' is now required before command. - 20210801 - Rebuilt Logic :: binds(). It is now simpler and (more?) correct. Specifically: I believe Lxroot now ignores (i.e. skips) overbound binds. This is beneficial, for example, when using multiple, partially-overlapping full-overlays. - 20210630 - Added '/usr/local/games:/usr/games' to $PATH. - 20210627 - Implemented environment passthru via -e or --env. Added 'e' and 'w' indicators to command prompt. Omit the newroot-option to remain in the external mount namespace. - 20210624 - Fix GitHub issue #3, as follows: If remount readonly fails, retry with different flags until success. Split Lxroot::env() into two parts. Second part happens after umount2(). Disabled some poorly-formed (i.e. overly-restrictive) unit tests. - 20210621 - Replaced abstract "Processor" interfaces with std :: function + lambdas. Implemented the 'cd' and 'wd' command line options. Moved logic into class Logic, thereby separating logic from side effects. A Bind with mode o_none now inherits its mode from its parent. Converted Opendir iterator to Logic.scandir() function. - 20210617 - Shell prompt guestname is now the basename of last overlay. (Previously, it was the basename of newroot. Using the last overlay is more informative.) - 20210612 - Added read-auto exposure of /var/tmp. - 20210608 - Added Demo #3 to demo.sh. Improved readme.md. - 20210605 - Significant internal refactoring to improve readability and future maintainability. CLI interface unchanged. Minor improvements/fixes to readauto mode. - 20210530 - Major overhaul. CLI interface changed. Added read-auto mode. Removed profiles. Added unit.sh and demo.sh. Changed license to GPLv3. - 20200908 - Major overhaul. Many parts refactored into a C++ style. Command line interface redesigned. Improvements and changes to profiles. Added tracking of cwd and chdir() to cwd inside the namespace if possible. diff --git a/lxroot.cpp b/lxroot.cpp index c4f3578..51fc8aa 100644 --- a/lxroot.cpp +++ b/lxroot.cpp @@ -5,7 +5,7 @@ // Distributed under GPLv3 (see end of file) WITHOUT ANY WARRANTY. -#define LXROOT_VERSION "0.21.0" // version 20211226 +#define LXROOT_VERSION "0.22.0" // version 20220108 // Welcome to the source code for lxroot. @@ -424,8 +424,8 @@ struct State { // xxst --------------------------------- struct State Argv argv; Env env; // specifies the new environment - const uid_t uid = getuid(); - const gid_t gid = getgid(); + const uid_t uid = getuid(); // uid prior to unshare() + const gid_t gid = getgid(); // gid prior to unshare() Fgetpwent outside ; // from /etc/passwd outside the lxroot Fgetpwent inside ; // from /etc/passwd inside the lxroot mopt opt_env = o_none; // pass in environment @@ -1140,9 +1140,12 @@ struct Env_Tool : Lib { // xxen --------------------- struct Env_Tool const Fgetpwent & in = st .inside; const Fgetpwent & out = st .outside; - mut .env .soft ( "HOME", in.dir || getenv("HOME") || out.dir ); - mut .env .soft ( "LOGNAME", in.name || getenv("LOGNAME") || out.name ); - mut .env .soft ( "USER", in.name || getenv("USER") || out.name ); + auto get = [] ( Str name ) { + return st .opt_root ? nullptr : Lib :: getenv ( name ); }; + + mut .env .soft ( "HOME", in.dir || get("HOME") || out.dir ); + mut .env .soft ( "LOGNAME", in.name || get("LOGNAME") || out.name ); + mut .env .soft ( "USER", in.name || get("USER") || out.name ); auto vars = { "LANG", "LC_COLLATE", "TERM", "TZ" }; for ( auto s : vars ) { mut .env .soft_copy ( s ); } } @@ -1308,7 +1311,7 @@ class Lxroot : Lib { // xxlx ------------------------- class Lxroot void fgetpwent () { // --------------------------- Lxroot fgetpwent - mut .outside .fgetpwent ( "/etc/passwd", st .uid ); + mut .outside .fgetpwent ( "/etc/passwd", getuid() ); mut .inside .fgetpwent ( st.newroot + "/etc/passwd", getuid() ); Env_Tool :: before_pivot(); } @@ -1422,10 +1425,18 @@ class Lxroot : Lib { // xxlx ------------------------- class Lxroot void chdir () { // ----------------------------------- Lxroot chdir - if ( st .chdir ) { sys .chdir ( st .chdir ); return; } - if ( st .workdir ) { sys .chdir ( st .workdir ); return; } - Str home = st .env .get ( "HOME" ); - if ( st .newroot && is_dir ( home ) ) { sys .chdir ( home ); } } + + auto chdir_home = [&] () { + Str home = st .env .get ( "HOME" ); + if ( st .newroot && is_dir ( home ) ) { sys .chdir ( home ); } }; + + auto chdir2 = [&] ( Str s ) { + if ( s[0] != '/' ) { chdir_home(); } + sys .chdir ( s ); }; + + if ( st .chdir ) { chdir2 ( st .chdir ); return; } + if ( st .workdir ) { chdir2 ( st .workdir ); return; } + chdir_home(); } void xray () { // ------------------------------------- Lxroot xray @@ -1473,7 +1484,7 @@ class Lxroot : Lib { // xxlx ------------------------- class Lxroot umount2(); // after proc /* pivot to umount2 should be as tight as possible */ env(); // after pivot, therefore after umount2 - chdir(); // after umount2 ( because put_old may shadow $HOME !! ) + chdir(); // after env xray(); exec(); // last return 1; } // exec failed!