From 356bb1ca98e0633cf73c0a30a0208e396d62dff9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 16 Nov 2014 17:53:46 +0100 Subject: [PATCH 001/326] issue #4: Allow to specify specific command --- bin/juju | 18 ++++++++++++------ lib/core.sh | 20 +++++++++++++++----- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/bin/juju b/bin/juju index 6f5e68c..d1bce75 100755 --- a/bin/juju +++ b/bin/juju @@ -29,7 +29,7 @@ source "$(dirname $0)/../lib/core.sh" usage() { echo -e "JuJu: The portable GNU/Linux distribution" - echo -e "Usage: $NAME [options]" + echo -e "Usage: $NAME [options] [command]" echo -e "Options:" echo -e "-i, --setup-from-file Setup the JuJu image in ${JUJU_HOME}" echo -e "-f, --fakeroot Run JuJu with fakeroot privileges" @@ -79,13 +79,19 @@ check_cli(){ die "The JuJu version option must be used exclusively" fi fi - if $OPT_FAKEROOT && $OPT_ROOT then die "You must access to JuJu with either fakeroot or root permissions" fi - [ "$ARGS" != "" ] && die "No arguments are needed. For the CLI syntax run: $NAME --help" + if [ "$ARGS" != "" ] + then + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ + $OPT_VERSION + then + die "No arguments are needed. For the CLI syntax run: $NAME --help" + fi + fi return 0 } @@ -156,11 +162,11 @@ elif $OPT_SETUP_FROM_FILE; then fi if $OPT_FAKEROOT; then - run_juju_as_fakeroot + run_juju_as_fakeroot ${ARGS[@]} elif $OPT_ROOT; then - run_juju_as_root + run_juju_as_root ${ARGS[@]} else - run_juju_as_user + run_juju_as_user ${ARGS[@]} fi # vim: set ts=4 sw=4 noet: diff --git a/lib/core.sh b/lib/core.sh index 925696d..42d4838 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -141,31 +141,41 @@ function setup_from_file_juju(){ } +function _define_command(){ + local comm=$@ + [ "$comm" == "" ] && comm=${SH} + echo "$comm" +} + + function run_juju_as_root(){ [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" + local comm=$(_define_command $@) mkdir -p ${JUJU_HOME}/${HOME} - ${JUJU_HOME}/usr/bin/arch-chroot $JUJU_HOME /usr/bin/bash -c 'mkdir -p /run/lock && /bin/sh' + ${JUJU_HOME}/usr/bin/arch-chroot $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && ${comm}" } function _run_juju_with_proot(){ if ${PROOT} ${JUJU_HOME}/usr/bin/true &> /dev/null then - JUJU_ENV=1 ${PROOT} $@ ${JUJU_HOME} ${SH} + JUJU_ENV=1 ${PROOT} $@ else - JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT} $@ ${JUJU_HOME} ${SH} + JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT} $@ fi } function run_juju_as_fakeroot(){ - _run_juju_with_proot "-S" + local comm=$(_define_command $@) + _run_juju_with_proot "-S" ${JUJU_HOME} ${comm} } function run_juju_as_user(){ - _run_juju_with_proot "-R" + local comm=$(_define_command $@) + _run_juju_with_proot "-R" ${JUJU_HOME} ${comm} } From 811c140fed4e065901d6d751da6cd850cf781322 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 16 Nov 2014 19:32:40 +0100 Subject: [PATCH 002/326] issue #7: Expose the Proot args to JuJu cli --- README.md | 16 ++++++++++++++-- bin/juju | 27 +++++++++++++++++++-------- lib/core.sh | 17 +++++++++++------ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index a492cbf..c52057f 100644 --- a/README.md +++ b/README.md @@ -52,10 +52,11 @@ JuJu can only works on GNU/Linux OS with kernel version greater or equal Advanced usage -------------- +### Build image ### You can build a new JuJu image from scratch by running the following command: - +``` # juju -b - +``` In this way the script will create a directory containing all the essentials files in order to make JuJu working properly (such as pacman, yaourt, arch-chroot and proot). Remember that the script to build the image must run in an ArchLinux OS with @@ -66,6 +67,17 @@ After creating the image juju-x86\_64.tar.gz you can install it by running: # juju -i juju-x86_64.tar.gz +### Bind directories ### +To bind and host directory to a guest location, you can use proot arguments: +``` + $ juju -p "-b /mnt/mydata:/home/user/mydata" +``` + +Check out the proot options with: +``` + $ juju -p "--help" +``` + Dependencies ------------ JuJu comes with a very short list of dependencies in order to be installed in most diff --git a/bin/juju b/bin/juju index d1bce75..8f12cdc 100755 --- a/bin/juju +++ b/bin/juju @@ -34,6 +34,7 @@ usage() { echo -e "-i, --setup-from-file Setup the JuJu image in ${JUJU_HOME}" echo -e "-f, --fakeroot Run JuJu with fakeroot privileges" echo -e "-r, --root Run JuJu with root privileges" + echo -e "-p, --proot-args Proot arguments" echo -e "-b, --build-image Build a JuJu image (must run in ArchLinux)" echo -e "-d, --delete Delete JuJu from ${JUJU_HOME}" echo -e "-h, --help Show this help message" @@ -83,15 +84,22 @@ check_cli(){ then die "You must access to JuJu with either fakeroot or root permissions" fi - - if [ "$ARGS" != "" ] - then + if $OPT_PROOT_ARGS + then + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ + $OPT_ROOT || $OPT_VERSION + then + die "Invalid syntax: Proot args are not allowed with the other options" + fi + fi + if [ "$ARGS" != "" ] + then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ $OPT_VERSION then - die "No arguments are needed. For the CLI syntax run: $NAME --help" + die "No arguments are needed. For the CLI syntax run: $NAME --help" fi - fi + fi return 0 } @@ -101,7 +109,7 @@ check_cli(){ ### MAIN PROGRAM ### ################################### -TEMP=`getopt -o drfbi:hv --long delete,root,fakeroot,build-image,setup-from-file:,help,version -n 'juju' -- "$@"` +TEMP=`getopt -o drp:fbi:hv --long delete,root,proot-args:,fakeroot,build-image,setup-from-file:,help,version -n 'juju' -- "$@"` if [ $? != 0 ] ; then error "Error on parsing the command line. Try juju -h." ; exit ; fi @@ -112,6 +120,8 @@ OPT_SETUP_FROM_FILE=false IMAGE_FILE="" OPT_FAKEROOT=false OPT_ROOT=false +OPT_PROOT_ARGS=false +PROOT_ARGS="" OPT_BUILD_IMAGE=false OPT_DELETE=false OPT_HELP=false @@ -121,6 +131,7 @@ while true ; do -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; -r|--root) OPT_ROOT=true ; shift ;; + -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; @@ -162,11 +173,11 @@ elif $OPT_SETUP_FROM_FILE; then fi if $OPT_FAKEROOT; then - run_juju_as_fakeroot ${ARGS[@]} + run_juju_as_fakeroot "${PROOT_ARGS}" ${ARGS[@]} elif $OPT_ROOT; then run_juju_as_root ${ARGS[@]} else - run_juju_as_user ${ARGS[@]} + run_juju_as_user "${PROOT_ARGS}" ${ARGS[@]} fi # vim: set ts=4 sw=4 noet: diff --git a/lib/core.sh b/lib/core.sh index 42d4838..f447ce4 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -142,16 +142,21 @@ function setup_from_file_juju(){ function _define_command(){ - local comm=$@ - [ "$comm" == "" ] && comm=${SH} - echo "$comm" + local proot_args="$1" + local comm=${SH} + if [ "$2" != "" ] + then + shift + comm="$@" + fi + echo "$proot_args" "${comm[@]}" } function run_juju_as_root(){ [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" - local comm=$(_define_command $@) + local comm=$(_define_command "$@") mkdir -p ${JUJU_HOME}/${HOME} ${JUJU_HOME}/usr/bin/arch-chroot $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && ${comm}" } @@ -168,13 +173,13 @@ function _run_juju_with_proot(){ function run_juju_as_fakeroot(){ - local comm=$(_define_command $@) + local comm=$(_define_command "$@") _run_juju_with_proot "-S" ${JUJU_HOME} ${comm} } function run_juju_as_user(){ - local comm=$(_define_command $@) + local comm=$(_define_command "$@") _run_juju_with_proot "-R" ${JUJU_HOME} ${comm} } From fdebd2aa32b60fc2ddbce9691b3e9590a2ba95b0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 16 Nov 2014 23:29:17 +0100 Subject: [PATCH 003/326] issue #3: Validate the image built --- lib/core.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index 925696d..b1774fc 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -248,6 +248,12 @@ function build_image_juju(){ echo 'export PATH=$PATH:/opt/juju/bin' > ${maindir}/root/etc/profile.d/juju.sh chmod +x ${maindir}/root/etc/profile.d/juju.sh + info "Validating JuJu image..." + arch-chroot ${maindir}/root pacman -Qi pacman &> /dev/null + arch-chroot ${maindir}/root yaourt -V &> /dev/null + arch-chroot ${maindir}/root proot --help &> /dev/null + arch-chroot ${maindir}/root arch-chroot --help &> /dev/null + builtin cd ${ORIGIN_WD} local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." From 0f6d7aaff0416aa8b1b6a1d834e57583eb39b4d1 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Nov 2014 21:54:41 +0100 Subject: [PATCH 004/326] Improve function for getting the chroot and proot arguments --- lib/core.sh | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index cd16d27..72f5ffe 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -141,14 +141,17 @@ function setup_from_file_juju(){ } -function _define_command(){ - local proot_args="$1" +function _define_chroot_args(){ local comm=${SH} - if [ "$2" != "" ] - then - shift - comm="$@" - fi + [ "$1" != "" ] && comm="$@" + echo $comm +} + + +function _define_proot_args(){ + local proot_args="$1" + shift + local comm=$(_define_chroot_args "$@") echo "$proot_args" "${comm[@]}" } @@ -156,9 +159,8 @@ function _define_command(){ function run_juju_as_root(){ [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" - local comm=$(_define_command "$@") mkdir -p ${JUJU_HOME}/${HOME} - ${JUJU_HOME}/usr/bin/arch-chroot $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && ${comm}" + ${JUJU_HOME}/usr/bin/arch-chroot $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" } @@ -173,13 +175,13 @@ function _run_juju_with_proot(){ function run_juju_as_fakeroot(){ - local comm=$(_define_command "$@") + local comm=$(_define_proot_args "$@") _run_juju_with_proot "-S" ${JUJU_HOME} ${comm} } function run_juju_as_user(){ - local comm=$(_define_command "$@") + local comm=$(_define_proot_args "$@") _run_juju_with_proot "-R" ${JUJU_HOME} ${comm} } From 8982cb5a24ae5e450e9cdf3cc3df24c50214bffc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Nov 2014 21:56:40 +0100 Subject: [PATCH 005/326] Make some functions in core private --- lib/core.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 72f5ffe..631931d 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -83,7 +83,7 @@ function is_juju_installed(){ } -function cleanup_build_directory(){ +function _cleanup_build_directory(){ # $1: maindir (optional) - str: build directory to get rid local maindir=$1 builtin cd $ORIGIN_WD @@ -92,7 +92,7 @@ function cleanup_build_directory(){ } -function prepare_build_directory(){ +function _prepare_build_directory(){ trap - QUIT EXIT ABRT KILL TERM INT trap "rm -rf ${maindir}; die \"Error occurred when installing JuJu\"" EXIT QUIT ABRT KILL TERM INT } @@ -113,7 +113,7 @@ function setup_juju(){ [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) - prepare_build_directory + _prepare_build_directory info "Downloading JuJu..." builtin cd ${maindir} @@ -123,7 +123,7 @@ function setup_juju(){ info "Installing JuJu..." _setup_juju ${maindir}/${imagefile} - cleanup_build_directory ${maindir} + _cleanup_build_directory ${maindir} } @@ -229,7 +229,7 @@ function build_image_juju(){ _check_package git local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) mkdir -p ${maindir}/root - prepare_build_directory + _prepare_build_directory info "Installing pacman and its dependencies..." pacstrap -d ${maindir}/root pacman arch-install-scripts binutils libunistring @@ -275,5 +275,5 @@ function build_image_juju(){ local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." tar -zcpf ${imagefile} -C ${maindir}/root . - cleanup_build_directory ${maindir} + _cleanup_build_directory ${maindir} } From 3a51433f0b86c80bd656d462a5ec51116c344564 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 20 Nov 2014 00:01:11 +0100 Subject: [PATCH 006/326] Add tests for util.sh #12 --- lib/util.sh | 4 +++- tests/util.sh | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/util.sh diff --git a/lib/util.sh b/lib/util.sh index 15fd48c..dc88506 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -17,7 +17,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -echoerr() { echo "$@" 1>&2; } +function echoerr(){ + echo "$@" 1>&2 +} function die(){ # $@: msg (mandatory) - str: Message to print error $@ diff --git a/tests/util.sh b/tests/util.sh new file mode 100644 index 0000000..0e39ad1 --- /dev/null +++ b/tests/util.sh @@ -0,0 +1,63 @@ +source "$(dirname $0)/../lib/util.sh" + +function is_equal(){ + [ "$1" == "$2" ] || return 1 && return 0 +} + +function test_echoerr(){ + local actual=$(echoerr "Test" 2>&1) + is_equal "$actual" "Test" || return 1 + return 0 +} + +function test_error(){ + local actual=$(error "Test" 2>&1) + local expected=$(echo -e "\033[1;31mTest\033[0m") + is_equal "$actual" "$expected" || return 1 + return 0 +} + +function test_warn(){ + local actual=$(warn "Test" 2>&1) + local expected=$(echo -e "\033[1;33mTest\033[0m") + is_equal "$actual" "$expected" || return 1 + return 0 +} + +function test_info(){ + local actual=$(info "Test") + local expected=$(echo -e "\033[1;37mTest\033[0m") + is_equal "$actual" "$expected" || return 1 + return 0 +} + +function test_die(){ + local actual=$(die "Test" 2>&1) + local expected=$(echo -e "\033[1;31mTest\033[0m") + is_equal "$actual" "$expected" || return 1 + return 0 +} + +function test_ask(){ + echo "Y" | ask "Test" &> /dev/null + is_equal $? 0 || return 1 + echo "y" | ask "Test" &> /dev/null + is_equal $? 0 || return 1 + echo "N" | ask "Test" &> /dev/null + is_equal $? 1 || return 1 + echo "n" | ask "Test" &> /dev/null + is_equal $? 1 || return 1 + echo -e "\n" | ask "Test" &> /dev/null + is_equal $? 0 || return 1 + echo -e "\n" | ask "Test" "N" &> /dev/null + is_equal $? 1 || return 1 + echo -e "asdf\n\n" | ask "Test" "N" &> /dev/null + is_equal $? 1 || return 1 + return 0 +} + + +for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) +do + $func && echo -e "${func}...\033[1;32mOK\033[0m" || echo -e "${func}...\033[1;31mFAIL\033[0m" +done From b0a06625752d03ddb6e0bbbdfe1768172b804d39 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 24 Nov 2014 02:03:00 +0100 Subject: [PATCH 007/326] Add tests for core.sh #13 Included the tests for die as well. --- lib/core.sh | 8 +- tests/test_all.sh | 5 ++ tests/test_core.sh | 154 ++++++++++++++++++++++++++++++++ tests/{util.sh => test_util.sh} | 8 +- tests/utils.sh | 51 +++++++++++ 5 files changed, 220 insertions(+), 6 deletions(-) create mode 100755 tests/test_all.sh create mode 100755 tests/test_core.sh rename tests/{util.sh => test_util.sh} (93%) mode change 100644 => 100755 create mode 100644 tests/utils.sh diff --git a/lib/core.sh b/lib/core.sh index 631931d..c6cc042 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -75,6 +75,10 @@ then else die "The variable JUJU_ENV is not properly set" fi + +CHROOT=${JUJU_HOME}/usr/bin/arch-chroot +TRUE=${JUJU_HOME}/usr/bin/true + ################################# MAIN FUNCTIONS ############################## function is_juju_installed(){ @@ -160,12 +164,12 @@ function run_juju_as_root(){ [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" mkdir -p ${JUJU_HOME}/${HOME} - ${JUJU_HOME}/usr/bin/arch-chroot $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" + ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" } function _run_juju_with_proot(){ - if ${PROOT} ${JUJU_HOME}/usr/bin/true &> /dev/null + if ${PROOT} ${TRUE} &> /dev/null then JUJU_ENV=1 ${PROOT} $@ else diff --git a/tests/test_all.sh b/tests/test_all.sh new file mode 100755 index 0000000..684e6fd --- /dev/null +++ b/tests/test_all.sh @@ -0,0 +1,5 @@ + +for tst in $(ls $(dirname $0)/test_* | grep -v $(basename $0)) +do + $tst +done diff --git a/tests/test_core.sh b/tests/test_core.sh new file mode 100755 index 0000000..1a1dc77 --- /dev/null +++ b/tests/test_core.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# To test this module you need to run it inside a Archlinux system. Also, the following packages needs to be installed: +# bash +# pacman +# arch-install-scripts +# proot +# coreutils +# grep +# sudo + +source "$(dirname $0)/utils.sh" +CURRPWD=$PWD +JUJU_HOME="" + +function set_up(){ + cd $CURRPWD + JUJU_HOME=$(TMPDIR=/tmp mktemp -d -t jujuhome.XXXXXXXXXX) + source "$(dirname $0)/../lib/core.sh" + ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t jujuowd.XXXXXXXXXX) + cd $ORIGIN_WD + JUJU_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t jujutemp.XXXXXXXXXX) +} + + +function tear_down(){ + rm -rf $JUJU_HOME + rm -rf $ORIGIN_WD + rm -rf $JUJU_TEMPDIR +} + +function test_is_juju_installed(){ + is_juju_installed + is_equal $? 1 || return 1 + touch $JUJU_HOME/just_file + is_juju_installed + is_equal $? 0 || return 1 +} + + +function test_setup_juju(){ + wget_mock(){ + # Proof that the setup is happening + # inside $JUJU_TEMPDIR + local cwd=${PWD#${JUJU_TEMPDIR}} + local parent_dir=${PWD%${cwd}} + is_equal $JUJU_TEMPDIR ${parent_dir} || return 1 + touch file + tar -czvf juju-${ARCH}.tar.gz file + } + WGET=wget_mock + setup_juju 1> /dev/null + [ -e $JUJU_HOME/file ] || return 1 + [ -e $JUJU_HOME/run/lock ] || return 1 + + export -f setup_juju + JUJU_ENV=1 bash -ic "setup_juju" &> /dev/null + is_equal $? 1 || return 1 +} + + +function test_setup_from_file_juju(){ + touch file + tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null + setup_from_file_juju juju-${ARCH}.tar.gz 1> /dev/null + [ -e $JUJU_HOME/file ] || return 1 + [ -e $JUJU_HOME/run/lock ] || return 1 + + export -f setup_from_file_juju + bash -ic "setup_from_file_juju noexist.tar.gz" &> /dev/null + is_equal $? 1 || return 1 + + export -f setup_from_file_juju + JUJU_ENV=1 bash -ic "setup_from_file_juju" &> /dev/null + is_equal $? 1 || return 1 +} + + +function test_run_juju_as_root(){ + install_mini_juju + CHROOT="sudo $CHROOT" + SH="type -t type" + local output=$(run_juju_as_root) + is_equal $output "builtin" || return 1 + local output=$(run_juju_as_root pwd) + is_equal $output "/" || return 1 + run_juju_as_root "[ -e /run/lock ]" + is_equal $? 0 || return 1 + [ -e $JUJU_HOME/${HOME} ] || return 1 + + export -f run_juju_as_root + JUJU_ENV=1 bash -ic "run_juju_as_root" &> /dev/null + is_equal $? 1 || return 1 +} + +function test_run_juju_as_user(){ + install_mini_juju + local output=$(run_juju_as_user "" "mkdir -v /newdir2") + is_equal "$output" "/usr/bin/mkdir: created directory '/newdir2'" || return 1 + [ -e $JUJU_HOME/newdir2 ] + is_equal $? 0 || return 1 + + SH="mkdir -v /newdir" + local output=$(run_juju_as_user "") + is_equal "$output" "/usr/bin/mkdir: created directory '/newdir'" || return 1 + [ -e $JUJU_HOME/newdir ] + is_equal $? 0 || return 1 +} + +function test_run_juju_as_user_proot_args(){ + install_mini_juju + run_juju_as_user "--help" "" 1> /dev/null + is_equal $? 0 || return 1 + run_juju_as_user "--helps" "" &> /dev/null + is_equal $? 1 || return 1 + + mkdir $JUJU_TEMPDIR/newdir + touch $JUJU_TEMPDIR/newdir/newfile + run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir" "ls -l /newdir/newfile" 1> /dev/null + is_equal $? 0 || return 1 +} + +#function test_run_juju_as_user_seccomp(){ + #install_mini_juju + #TRUE="/usr/bin/false" + #run_juju_as_user "" "env" "|" "grep" "PROOT_NO_SECCOMP" +#} + +#function test_run_juju_as_fakeroot(){ + #install_mini_juju + #local output=$(run_juju_as_fakeroot "" "bash") + #is_equal "$output" "root" || return 1 +#} + +function test_delete_juju(){ + install_mini_juju + echo "N" | delete_juju 1> /dev/null + is_juju_installed + is_equal $? 0 || return 1 + echo "Y" | delete_juju 1> /dev/null + is_juju_installed + is_equal $? 1 || return 1 + + export -f delete_juju + JUJU_ENV=1 bash -ic "delete_juju" &> /dev/null + is_equal $? 1 || return 1 +} + + +for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) +do + set_up + $func && echo -e "${func}...\033[1;32mOK\033[0m" || echo -e "${func}...\033[1;31mFAIL\033[0m" + tear_down +done diff --git a/tests/util.sh b/tests/test_util.sh old mode 100644 new mode 100755 similarity index 93% rename from tests/util.sh rename to tests/test_util.sh index 0e39ad1..757f08f --- a/tests/util.sh +++ b/tests/test_util.sh @@ -1,9 +1,7 @@ +#!/bin/bash +source "$(dirname $0)/utils.sh" source "$(dirname $0)/../lib/util.sh" -function is_equal(){ - [ "$1" == "$2" ] || return 1 && return 0 -} - function test_echoerr(){ local actual=$(echoerr "Test" 2>&1) is_equal "$actual" "Test" || return 1 @@ -35,6 +33,8 @@ function test_die(){ local actual=$(die "Test" 2>&1) local expected=$(echo -e "\033[1;31mTest\033[0m") is_equal "$actual" "$expected" || return 1 + bash -ic "die Dying" &> /dev/null + is_equal $? 1 || return 1 return 0 } diff --git a/tests/utils.sh b/tests/utils.sh new file mode 100644 index 0000000..bd12d4e --- /dev/null +++ b/tests/utils.sh @@ -0,0 +1,51 @@ +function install_executable(){ + for i in $( ldd $* | grep -v dynamic | cut -d " " -f 3 | sed 's/://' | sort | uniq ) + do + cp --parents $i $JUJU_HOME + done + # ARCH amd64 + if [ -f /lib64/ld-linux-x86-64.so.2 ]; then + cp --parents /lib64/ld-linux-x86-64.so.2 $JUJU_HOME + fi + # ARCH i386 + if [ -f /lib/ld-linux.so.2 ]; then + cp --parents /lib/ld-linux.so.2 $JUJU_HOME + fi + cp --parent $* $JUJU_HOME/ +} + +function install_package(){ + pacman -Ql $1 | grep "/$" | sed 's/.* //' | xargs -I {} mkdir -p $JUJU_HOME/{} + pacman -Ql $1 | grep -v "/$" | sed 's/.* //' | xargs -I {} cp -f -a --parents {} $JUJU_HOME + #export -f install_executable + #export JUJU_HOME + #pacman -Ql $1 | sed 's/.* //' | grep "^/usr/bin/" | xargs -I {} bash -ic "install_executable {}" +} + +function install_mini_juju(){ + mkdir -p ${JUJU_HOME}/{proc,bin,sys,dev,run,tmp,etc} + touch ${JUJU_HOME}/etc/resolv.conf + mkdir -p ${JUJU_HOME}/usr/bin + #echo "root:x:0:0:root:/root:/bin/bash" > ${JUJU_HOME}/etc/passwd + #cp /etc/nsswitch.conf ${JUJU_HOME} + cp /usr/bin/arch-chroot ${JUJU_HOME}/usr/bin + install_executable /usr/bin/bash + install_executable /usr/bin/ls + install_executable /usr/bin/whoami + install_executable /usr/bin/grep + install_executable /usr/bin/mkdir + install_executable /usr/bin/proot + install_package bash + install_package talloc + install_package proot + install_package coreutils + install_package grep + ln -s /usr/bin/bash $JUJU_HOME/bin/sh +} + + +function is_equal(){ + [ "$1" == "$2" ] || return 1 && return 0 +} + + From 82824d79bfd0838be0fa65c4a09655f8a77d54d5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Nov 2014 00:28:47 +0100 Subject: [PATCH 008/326] Add test for run juju as fakeroot and for SECCOMP --- tests/test_core.sh | 25 +++++++++++++++---------- tests/utils.sh | 2 -- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index 1a1dc77..c83ad2d 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -7,6 +7,7 @@ # coreutils # grep # sudo +# gawk source "$(dirname $0)/utils.sh" CURRPWD=$PWD @@ -119,17 +120,21 @@ function test_run_juju_as_user_proot_args(){ is_equal $? 0 || return 1 } -#function test_run_juju_as_user_seccomp(){ - #install_mini_juju - #TRUE="/usr/bin/false" - #run_juju_as_user "" "env" "|" "grep" "PROOT_NO_SECCOMP" -#} +function test_run_juju_as_user_seccomp(){ + install_mini_juju + local output=$(run_juju_as_user "" "env" | grep "PROOT_NO_SECCOMP") + is_equal $output "" || return 1 -#function test_run_juju_as_fakeroot(){ - #install_mini_juju - #local output=$(run_juju_as_fakeroot "" "bash") - #is_equal "$output" "root" || return 1 -#} + TRUE="/usr/bin/false" + local output=$(run_juju_as_user "" "env" | grep "PROOT_NO_SECCOMP") + is_equal $output "PROOT_NO_SECCOMP=1" || return 1 +} + +function test_run_juju_as_fakeroot(){ + install_mini_juju + local output=$(run_juju_as_fakeroot "" "id" | awk '{print $1}') + is_equal "$output" "uid=0" || return 1 +} function test_delete_juju(){ install_mini_juju diff --git a/tests/utils.sh b/tests/utils.sh index bd12d4e..0ca7144 100644 --- a/tests/utils.sh +++ b/tests/utils.sh @@ -26,8 +26,6 @@ function install_mini_juju(){ mkdir -p ${JUJU_HOME}/{proc,bin,sys,dev,run,tmp,etc} touch ${JUJU_HOME}/etc/resolv.conf mkdir -p ${JUJU_HOME}/usr/bin - #echo "root:x:0:0:root:/root:/bin/bash" > ${JUJU_HOME}/etc/passwd - #cp /etc/nsswitch.conf ${JUJU_HOME} cp /usr/bin/arch-chroot ${JUJU_HOME}/usr/bin install_executable /usr/bin/bash install_executable /usr/bin/ls From 9f66f1682a45b1ea8f90828886de81084fd68a22 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Nov 2014 01:16:06 +0100 Subject: [PATCH 009/326] Improve the mini pearl script for core unit tests --- tests/test_core.sh | 4 ++++ tests/utils.sh | 43 ++++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index c83ad2d..5c85925 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -20,6 +20,9 @@ function set_up(){ ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t jujuowd.XXXXXXXXXX) cd $ORIGIN_WD JUJU_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t jujutemp.XXXXXXXXXX) + + trap - QUIT EXIT ABRT KILL TERM INT + trap "rm -rf ${JUJU_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUJU_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT } @@ -27,6 +30,7 @@ function tear_down(){ rm -rf $JUJU_HOME rm -rf $ORIGIN_WD rm -rf $JUJU_TEMPDIR + trap - QUIT EXIT ABRT KILL TERM INT } function test_is_juju_installed(){ diff --git a/tests/utils.sh b/tests/utils.sh index 0ca7144..9f6f263 100644 --- a/tests/utils.sh +++ b/tests/utils.sh @@ -1,44 +1,45 @@ function install_executable(){ for i in $( ldd $* | grep -v dynamic | cut -d " " -f 3 | sed 's/://' | sort | uniq ) - do - cp --parents $i $JUJU_HOME - done + do + cp -f --parents $i $JUJU_HOME + done + # ARCH amd64 if [ -f /lib64/ld-linux-x86-64.so.2 ]; then - cp --parents /lib64/ld-linux-x86-64.so.2 $JUJU_HOME + cp -f --parents /lib64/ld-linux-x86-64.so.2 $JUJU_HOME fi + # ARCH i386 if [ -f /lib/ld-linux.so.2 ]; then - cp --parents /lib/ld-linux.so.2 $JUJU_HOME + cp -f --parents /lib/ld-linux.so.2 $JUJU_HOME fi - cp --parent $* $JUJU_HOME/ + + cp -f --parents $* $JUJU_HOME/ } function install_package(){ + # Copy the directories pacman -Ql $1 | grep "/$" | sed 's/.* //' | xargs -I {} mkdir -p $JUJU_HOME/{} - pacman -Ql $1 | grep -v "/$" | sed 's/.* //' | xargs -I {} cp -f -a --parents {} $JUJU_HOME + + # Copy the files + pacman -Ql $1 | grep -v "/$" | sed 's/.* //' | xargs -I {} cp -f --parents {} $JUJU_HOME + + # Copy the dynamic libraries of the executables #export -f install_executable #export JUJU_HOME - #pacman -Ql $1 | sed 's/.* //' | grep "^/usr/bin/" | xargs -I {} bash -ic "install_executable {}" + #pacman -Ql $1 | grep -v "/$" | sed 's/.* //' | grep "^/usr/bin/" | xargs -I {} bash -ic "install_executable {}" } function install_mini_juju(){ - mkdir -p ${JUJU_HOME}/{proc,bin,sys,dev,run,tmp,etc} - touch ${JUJU_HOME}/etc/resolv.conf - mkdir -p ${JUJU_HOME}/usr/bin - cp /usr/bin/arch-chroot ${JUJU_HOME}/usr/bin - install_executable /usr/bin/bash - install_executable /usr/bin/ls - install_executable /usr/bin/whoami - install_executable /usr/bin/grep - install_executable /usr/bin/mkdir - install_executable /usr/bin/proot + install_package filesystem 2> /dev/null + install_package arch-install-scripts install_package bash - install_package talloc install_package proot install_package coreutils - install_package grep - ln -s /usr/bin/bash $JUJU_HOME/bin/sh + install_executable /usr/bin/bash + install_executable /usr/bin/ls + install_executable /usr/bin/mkdir + install_executable /usr/bin/proot } From d4ccad692ba55a6079340018085f7b605888b988 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Nov 2014 21:45:47 +0100 Subject: [PATCH 010/326] Add test for juju script #11 --- bin/juju | 131 +++++++++++++++++++++----------------------- tests/test_juju.sh | 134 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+), 68 deletions(-) create mode 100755 tests/test_juju.sh diff --git a/bin/juju b/bin/juju index 8f12cdc..c00da88 100755 --- a/bin/juju +++ b/bin/juju @@ -105,79 +105,74 @@ check_cli(){ } -################################### -### MAIN PROGRAM ### -################################### +function parse_arguments(){ + TEMP=$(getopt -o drp:fbi:hv --long delete,root,proot-args:,fakeroot,build-image,setup-from-file:,help,version -n 'juju' -- "$@") + eval set -- "$TEMP" -TEMP=`getopt -o drp:fbi:hv --long delete,root,proot-args:,fakeroot,build-image,setup-from-file:,help,version -n 'juju' -- "$@"` + OPT_SETUP_FROM_FILE=false + IMAGE_FILE="" + OPT_FAKEROOT=false + OPT_ROOT=false + OPT_PROOT_ARGS=false + PROOT_ARGS="" + OPT_BUILD_IMAGE=false + OPT_DELETE=false + OPT_HELP=false + OPT_VERSION=false + while true ; do + case "$1" in + -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; + -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; + -r|--root) OPT_ROOT=true ; shift ;; + -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; + -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; + -d|--delete) OPT_DELETE=true ; shift ;; + -h|--help) OPT_HELP=true ; shift ;; + -v|--version) OPT_VERSION=true ; shift ;; + --) shift ; break ;; + *) die "Internal error!" ;; + esac + done -if [ $? != 0 ] ; then error "Error on parsing the command line. Try juju -h." ; exit ; fi + ARGS=() + for arg do + ARGS+=($arg) + done +} -# Note the quotes around `$TEMP': they are essential! -eval set -- "$TEMP" +function execute_operation(){ + $OPT_HELP && usage && return + $OPT_VERSION && version && return -OPT_SETUP_FROM_FILE=false -IMAGE_FILE="" -OPT_FAKEROOT=false -OPT_ROOT=false -OPT_PROOT_ARGS=false -PROOT_ARGS="" -OPT_BUILD_IMAGE=false -OPT_DELETE=false -OPT_HELP=false -OPT_VERSION=false -while true ; do - case "$1" in - -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; - -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -r|--root) OPT_ROOT=true ; shift ;; - -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; - -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; - -d|--delete) OPT_DELETE=true ; shift ;; - -h|--help) OPT_HELP=true ; shift ;; - -v|--version) OPT_VERSION=true ; shift ;; - --) shift ; break ;; - *) error "Internal error!" ; exit 1 ;; - esac -done + if $OPT_BUILD_IMAGE; then + build_image_juju + return + elif $OPT_DELETE; then + delete_juju + return + fi -ARGS=() -for arg do - ARGS+=($arg) -done + if ! is_juju_installed + then + if $OPT_SETUP_FROM_FILE; then + setup_from_file_juju $IMAGE_FILE + else + setup_juju + fi + elif $OPT_SETUP_FROM_FILE; then + die "Error: The image cannot be installed since $JUJU_HOME is not empty." + fi -check_cli || exit 1 - -################ DEFINE ACTION ######################## - -$OPT_HELP && usage && exit -$OPT_VERSION && version && exit - -if $OPT_BUILD_IMAGE; then - build_image_juju - exit -elif $OPT_DELETE; then - delete_juju - exit -fi - -if ! is_juju_installed -then - if $OPT_SETUP_FROM_FILE; then - setup_from_file_juju $IMAGE_FILE - else - setup_juju - fi -elif $OPT_SETUP_FROM_FILE; then - die "Error: The image cannot be installed since $JUJU_HOME is not empty." -fi - -if $OPT_FAKEROOT; then - run_juju_as_fakeroot "${PROOT_ARGS}" ${ARGS[@]} -elif $OPT_ROOT; then - run_juju_as_root ${ARGS[@]} -else - run_juju_as_user "${PROOT_ARGS}" ${ARGS[@]} -fi + if $OPT_FAKEROOT; then + run_juju_as_fakeroot "${PROOT_ARGS}" ${ARGS[@]} + elif $OPT_ROOT; then + run_juju_as_root ${ARGS[@]} + else + run_juju_as_user "${PROOT_ARGS}" ${ARGS[@]} + fi +} +parse_arguments $@ +check_cli +execute_operation # vim: set ts=4 sw=4 noet: diff --git a/tests/test_juju.sh b/tests/test_juju.sh new file mode 100755 index 0000000..8d9a94a --- /dev/null +++ b/tests/test_juju.sh @@ -0,0 +1,134 @@ +#!/bin/bash +source "$(dirname $0)/utils.sh" +source $(dirname $0)/../bin/juju -h &> /dev/null +## Mock functions ## +function usage(){ + echo "usage" +} +function version(){ + echo "version" +} +function build_image_juju(){ + echo "build_image_juju" +} +function delete_juju(){ + echo "delete_juju" +} +function is_juju_installed(){ + return 0 +} +function setup_from_file_juju(){ + echo "setup_from_file_juju $@" +} +function setup_juju(){ + echo "setup_juju" +} +function run_juju_as_fakeroot(){ + echo "run_juju_as_fakeroot $@" +} +function run_juju_as_root(){ + echo "run_juju_as_root $@" +} +function run_juju_as_user(){ + echo "run_juju_as_user $@" +} + +function wrap_juju(){ + parse_arguments $@ + check_cli + execute_operation +} + + +function set_up(){ + echo > /dev/null +} + +function tear_down(){ + echo > /dev/null +} + + +function test_help(){ + local output=$(wrap_juju -h) + is_equal $output "usage" || return 1 + local output=$(wrap_juju --help) + is_equal $output "usage" || return 1 +} +function test_version(){ + local output=$(wrap_juju -v) + is_equal $output "version" || return 1 + local output=$(wrap_juju --version) + is_equal $output "version" || return 1 +} +function test_build_image_juju(){ + local output=$(wrap_juju -b) + is_equal $output "build_image_juju" || return 1 + local output=$(wrap_juju --build-image) + is_equal $output "build_image_juju" || return 1 +} +function test_delete_juju(){ + local output=$(wrap_juju -d) + is_equal $output "delete_juju" || return 1 + local output=$(wrap_juju --delete) + is_equal $output "delete_juju" || return 1 +} +function test_run_juju_as_fakeroot(){ + local output=$(wrap_juju -f) + is_equal $output "run_juju_as_fakeroot" || return 1 + local output=$(wrap_juju --fakeroot) + is_equal $output "run_juju_as_fakeroot" || return 1 + + local output=$(wrap_juju -f -p "-b arg") + is_equal "${output[@]}" "run_juju_as_fakeroot -b arg" || return 1 + local output=$(wrap_juju -f -p "-b arg" -- command) + is_equal "${output[@]}" "run_juju_as_fakeroot -b arg command" || return 1 + local output=$(wrap_juju -f command) + is_equal "${output[@]}" "run_juju_as_fakeroot command" || return 1 +} +function test_run_juju_as_user(){ + local output=$(wrap_juju) + is_equal $output "run_juju_as_user" || return 1 + + local output=$(wrap_juju -p "-b arg") + is_equal "${output[@]}" "run_juju_as_user -b arg" || return 1 + local output=$(wrap_juju -p "-b arg" -- command) + is_equal "${output[@]}" "run_juju_as_user -b arg command" || return 1 + local output=$(wrap_juju command) + is_equal "${output[@]}" "run_juju_as_user command" || return 1 +} +function test_run_juju_as_root(){ + local output=$(wrap_juju -r) + is_equal $output "run_juju_as_root" || return 1 + + local output=$(wrap_juju -r command) + is_equal "${output[@]}" "run_juju_as_root command" || return 1 +} + +function test_check_cli(){ + export -f check_cli + export -f parse_arguments + export -f execute_operation + export -f wrap_juju + bash -ic "wrap_juju -b -h" &> /dev/null + is_equal $? 1 || return 1 + bash -ic "wrap_juju -d -r" &> /dev/null + is_equal $? 1 || return 1 + bash -ic "wrap_juju -h -f" &> /dev/null + is_equal $? 1 || return 1 + bash -ic "wrap_juju -v -i fsd" &> /dev/null + is_equal $? 1 || return 1 + bash -ic "wrap_juju -f -r" &> /dev/null + is_equal $? 1 || return 1 + bash -ic "wrap_juju -p args -v" &> /dev/null + is_equal $? 1 || return 1 + bash -ic "wrap_juju -d args" &> /dev/null + is_equal $? 1 || return 1 +} + +for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) +do + set_up + $func && echo -e "${func}...\033[1;32mOK\033[0m" || echo -e "${func}...\033[1;31mFAIL\033[0m" + tear_down +done From 4d32bf4ad85967cc004c202e4e7442ccfdfddfac Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 26 Nov 2014 23:47:06 +0100 Subject: [PATCH 011/326] Close issue #20 --- tests/test_core.sh | 25 ++++++++++------------ tests/utils.sh | 53 ++++++---------------------------------------- 2 files changed, 18 insertions(+), 60 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index 5c85925..2aacca6 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -1,18 +1,15 @@ #!/bin/bash -# To test this module you need to run it inside a Archlinux system. Also, the following packages needs to be installed: -# bash -# pacman -# arch-install-scripts -# proot -# coreutils -# grep -# sudo -# gawk source "$(dirname $0)/utils.sh" CURRPWD=$PWD +JUJU_MAIN_HOME=/tmp/jujutesthome +[ -e $JUJU_MAIN_HOME ] || JUJU_HOME=$JUJU_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_juju" JUJU_HOME="" +function install_mini_juju(){ + cp -rfa $JUJU_MAIN_HOME/* $JUJU_HOME +} + function set_up(){ cd $CURRPWD JUJU_HOME=$(TMPDIR=/tmp mktemp -d -t jujuhome.XXXXXXXXXX) @@ -99,14 +96,14 @@ function test_run_juju_as_root(){ function test_run_juju_as_user(){ install_mini_juju - local output=$(run_juju_as_user "" "mkdir -v /newdir2") - is_equal "$output" "/usr/bin/mkdir: created directory '/newdir2'" || return 1 + local output=$(run_juju_as_user "" "mkdir -v /newdir2" | awk -F: '{print $1}') + is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir2 ] is_equal $? 0 || return 1 SH="mkdir -v /newdir" - local output=$(run_juju_as_user "") - is_equal "$output" "/usr/bin/mkdir: created directory '/newdir'" || return 1 + local output=$(run_juju_as_user "" | awk -F: '{print $1}') + is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir ] is_equal $? 0 || return 1 } @@ -137,7 +134,7 @@ function test_run_juju_as_user_seccomp(){ function test_run_juju_as_fakeroot(){ install_mini_juju local output=$(run_juju_as_fakeroot "" "id" | awk '{print $1}') - is_equal "$output" "uid=0" || return 1 + is_equal "$output" "uid=0(root)" || return 1 } function test_delete_juju(){ diff --git a/tests/utils.sh b/tests/utils.sh index 9f6f263..094c055 100644 --- a/tests/utils.sh +++ b/tests/utils.sh @@ -1,50 +1,11 @@ -function install_executable(){ - for i in $( ldd $* | grep -v dynamic | cut -d " " -f 3 | sed 's/://' | sort | uniq ) - do - cp -f --parents $i $JUJU_HOME - done - - # ARCH amd64 - if [ -f /lib64/ld-linux-x86-64.so.2 ]; then - cp -f --parents /lib64/ld-linux-x86-64.so.2 $JUJU_HOME - fi - - # ARCH i386 - if [ -f /lib/ld-linux.so.2 ]; then - cp -f --parents /lib/ld-linux.so.2 $JUJU_HOME - fi - - cp -f --parents $* $JUJU_HOME/ -} - -function install_package(){ - # Copy the directories - pacman -Ql $1 | grep "/$" | sed 's/.* //' | xargs -I {} mkdir -p $JUJU_HOME/{} - - # Copy the files - pacman -Ql $1 | grep -v "/$" | sed 's/.* //' | xargs -I {} cp -f --parents {} $JUJU_HOME - - # Copy the dynamic libraries of the executables - #export -f install_executable - #export JUJU_HOME - #pacman -Ql $1 | grep -v "/$" | sed 's/.* //' | grep "^/usr/bin/" | xargs -I {} bash -ic "install_executable {}" -} - -function install_mini_juju(){ - install_package filesystem 2> /dev/null - install_package arch-install-scripts - install_package bash - install_package proot - install_package coreutils - install_executable /usr/bin/bash - install_executable /usr/bin/ls - install_executable /usr/bin/mkdir - install_executable /usr/bin/proot -} - - function is_equal(){ - [ "$1" == "$2" ] || return 1 && return 0 + if [ "$1" == "$2" ] + then + return 0 + else + echo "$1!=$2" + return 1 + fi } From 95d933234c795ae27856541e6fd2867a4da90b2e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 27 Nov 2014 00:46:43 +0100 Subject: [PATCH 012/326] Fix issue #6 --- lib/core.sh | 17 +++++++++++------ tests/test_core.sh | 10 +++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index c6cc042..e72219c 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -78,6 +78,7 @@ fi CHROOT=${JUJU_HOME}/usr/bin/arch-chroot TRUE=${JUJU_HOME}/usr/bin/true +ID="${JUJU_HOME}/usr/bin/id -u" ################################# MAIN FUNCTIONS ############################## @@ -169,12 +170,16 @@ function run_juju_as_root(){ function _run_juju_with_proot(){ - if ${PROOT} ${TRUE} &> /dev/null - then - JUJU_ENV=1 ${PROOT} $@ - else - JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT} $@ - fi + ${PROOT} ${TRUE} &> /dev/null || export PROOT_NO_SECCOMP=1 + + [ "$(${PROOT} ${ID} 2> /dev/null )" == "0" ] && \ + die "You cannot access with root privileges. Use --root option instead." + + JUJU_ENV=1 ${PROOT} $@ + local ret=$? + export -n PROOT_NO_SECCOMP + + return $ret } diff --git a/tests/test_core.sh b/tests/test_core.sh index 2aacca6..bce0368 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -57,6 +57,7 @@ function test_setup_juju(){ export -f setup_juju JUJU_ENV=1 bash -ic "setup_juju" &> /dev/null is_equal $? 1 || return 1 + unset setup_juju } @@ -71,9 +72,9 @@ function test_setup_from_file_juju(){ bash -ic "setup_from_file_juju noexist.tar.gz" &> /dev/null is_equal $? 1 || return 1 - export -f setup_from_file_juju JUJU_ENV=1 bash -ic "setup_from_file_juju" &> /dev/null is_equal $? 1 || return 1 + unset setup_from_file_juju } @@ -92,6 +93,7 @@ function test_run_juju_as_root(){ export -f run_juju_as_root JUJU_ENV=1 bash -ic "run_juju_as_root" &> /dev/null is_equal $? 1 || return 1 + unset run_juju_as_root } function test_run_juju_as_user(){ @@ -119,6 +121,11 @@ function test_run_juju_as_user_proot_args(){ touch $JUJU_TEMPDIR/newdir/newfile run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir" "ls -l /newdir/newfile" 1> /dev/null is_equal $? 0 || return 1 + + export -f _run_juju_with_proot + ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null + is_equal $? 1 || return 1 + unset _run_juju_with_proot } function test_run_juju_as_user_seccomp(){ @@ -149,6 +156,7 @@ function test_delete_juju(){ export -f delete_juju JUJU_ENV=1 bash -ic "delete_juju" &> /dev/null is_equal $? 1 || return 1 + unset delete_juju } From 24a1b2b397232b43713e83a9ba92e0101623ae87 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 27 Nov 2014 22:48:48 +0100 Subject: [PATCH 013/326] Fix issue #21 --- tests/test_core.sh | 5 +++++ tests/test_juju.sh | 7 +++++++ tests/test_util.sh | 3 +++ 3 files changed, 15 insertions(+) diff --git a/tests/test_core.sh b/tests/test_core.sh index bce0368..fac8dbc 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -57,6 +57,7 @@ function test_setup_juju(){ export -f setup_juju JUJU_ENV=1 bash -ic "setup_juju" &> /dev/null is_equal $? 1 || return 1 + export -n setup_juju unset setup_juju } @@ -74,6 +75,7 @@ function test_setup_from_file_juju(){ JUJU_ENV=1 bash -ic "setup_from_file_juju" &> /dev/null is_equal $? 1 || return 1 + export -n setup_from_file_juju unset setup_from_file_juju } @@ -93,6 +95,7 @@ function test_run_juju_as_root(){ export -f run_juju_as_root JUJU_ENV=1 bash -ic "run_juju_as_root" &> /dev/null is_equal $? 1 || return 1 + export -n run_juju_as_root unset run_juju_as_root } @@ -125,6 +128,7 @@ function test_run_juju_as_user_proot_args(){ export -f _run_juju_with_proot ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 + export -n _run_juju_with_proot unset _run_juju_with_proot } @@ -157,6 +161,7 @@ function test_delete_juju(){ JUJU_ENV=1 bash -ic "delete_juju" &> /dev/null is_equal $? 1 || return 1 unset delete_juju + unset delete_juju } diff --git a/tests/test_juju.sh b/tests/test_juju.sh index 8d9a94a..38806f7 100755 --- a/tests/test_juju.sh +++ b/tests/test_juju.sh @@ -110,6 +110,7 @@ function test_check_cli(){ export -f parse_arguments export -f execute_operation export -f wrap_juju + export -f die bash -ic "wrap_juju -b -h" &> /dev/null is_equal $? 1 || return 1 bash -ic "wrap_juju -d -r" &> /dev/null @@ -124,6 +125,12 @@ function test_check_cli(){ is_equal $? 1 || return 1 bash -ic "wrap_juju -d args" &> /dev/null is_equal $? 1 || return 1 + export -n check_cli + export -n parse_arguments + export -n execute_operation + export -n wrap_juju + export -n die + unset die } for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) diff --git a/tests/test_util.sh b/tests/test_util.sh index 757f08f..e7cfc1b 100755 --- a/tests/test_util.sh +++ b/tests/test_util.sh @@ -33,8 +33,11 @@ function test_die(){ local actual=$(die "Test" 2>&1) local expected=$(echo -e "\033[1;31mTest\033[0m") is_equal "$actual" "$expected" || return 1 + export -f die bash -ic "die Dying" &> /dev/null is_equal $? 1 || return 1 + export -n die + unset die return 0 } From ab74adb59d0bc2d76a2947c7156b4c40b927e07b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 28 Nov 2014 00:03:19 +0100 Subject: [PATCH 014/326] Fix issue #25 --- tests/test_core.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index fac8dbc..d90e816 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -55,10 +55,13 @@ function test_setup_juju(){ [ -e $JUJU_HOME/run/lock ] || return 1 export -f setup_juju + export -f die JUJU_ENV=1 bash -ic "setup_juju" &> /dev/null is_equal $? 1 || return 1 export -n setup_juju unset setup_juju + export -n die + unset die } @@ -70,6 +73,7 @@ function test_setup_from_file_juju(){ [ -e $JUJU_HOME/run/lock ] || return 1 export -f setup_from_file_juju + export -f die bash -ic "setup_from_file_juju noexist.tar.gz" &> /dev/null is_equal $? 1 || return 1 @@ -77,6 +81,8 @@ function test_setup_from_file_juju(){ is_equal $? 1 || return 1 export -n setup_from_file_juju unset setup_from_file_juju + export -n die + unset die } @@ -158,10 +164,13 @@ function test_delete_juju(){ is_equal $? 1 || return 1 export -f delete_juju + export -f die JUJU_ENV=1 bash -ic "delete_juju" &> /dev/null is_equal $? 1 || return 1 + export -n delete_juju unset delete_juju - unset delete_juju + export -n die + unset die } From e96431a346f05fa83fba17ea3fda29e0ff62b9a5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 28 Nov 2014 16:05:18 +0100 Subject: [PATCH 015/326] Fix #25 tests for old bash version --- tests/test_core.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index d90e816..fba5f0d 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -99,10 +99,13 @@ function test_run_juju_as_root(){ [ -e $JUJU_HOME/${HOME} ] || return 1 export -f run_juju_as_root + export -f die JUJU_ENV=1 bash -ic "run_juju_as_root" &> /dev/null is_equal $? 1 || return 1 export -n run_juju_as_root unset run_juju_as_root + export -n die + unset die } function test_run_juju_as_user(){ @@ -132,19 +135,24 @@ function test_run_juju_as_user_proot_args(){ is_equal $? 0 || return 1 export -f _run_juju_with_proot + export PROOT + export TRUE ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot unset _run_juju_with_proot + export -n PROOT + export -n TRUE } function test_run_juju_as_user_seccomp(){ install_mini_juju - local output=$(run_juju_as_user "" "env" | grep "PROOT_NO_SECCOMP") + PROOT="" + local output=$(_run_juju_with_proot "" "env" | grep "PROOT_NO_SECCOMP") is_equal $output "" || return 1 TRUE="/usr/bin/false" - local output=$(run_juju_as_user "" "env" | grep "PROOT_NO_SECCOMP") + local output=$(_run_juju_with_proot "" "env" | grep "PROOT_NO_SECCOMP") is_equal $output "PROOT_NO_SECCOMP=1" || return 1 } From 5fadb34f94b4f35e9c88c0785c6c15393f63bcf8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 29 Nov 2014 16:35:39 +0100 Subject: [PATCH 016/326] Fix issue #5 --- lib/core.sh | 11 ++--------- tests/test_core.sh | 36 ++++-------------------------------- 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index e72219c..11a1f69 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -70,8 +70,7 @@ then SH="/bin/sh --login" elif [ "$JUJU_ENV" == "1" ] then - PROOT="$LD_LIB" - SH="/bin/sh" + die "Error: Nested JuJu environments are not allowed" else die "The variable JUJU_ENV is not properly set" fi @@ -115,7 +114,6 @@ function _setup_juju(){ function setup_juju(){ # Setup the JuJu environment - [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) _prepare_build_directory @@ -134,7 +132,6 @@ function setup_juju(){ function setup_from_file_juju(){ # Setup from file the JuJu environment - [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" local imagefile=$1 [ ! -e ${imagefile} ] && die "Error: The JuJu image file ${imagefile} does not exist" @@ -162,10 +159,8 @@ function _define_proot_args(){ function run_juju_as_root(){ - [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" - mkdir -p ${JUJU_HOME}/${HOME} - ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" + JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" } @@ -196,8 +191,6 @@ function run_juju_as_user(){ function delete_juju(){ - [ "$JUJU_ENV" == "1" ] && die "Error: The operation is not allowed inside JuJu environment" - ! ask "Are you sure to delete JuJu located in ${JUJU_HOME}" "N" && return if mountpoint -q ${JUJU_HOME} then diff --git a/tests/test_core.sh b/tests/test_core.sh index fba5f0d..1a4be0c 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -53,15 +53,6 @@ function test_setup_juju(){ setup_juju 1> /dev/null [ -e $JUJU_HOME/file ] || return 1 [ -e $JUJU_HOME/run/lock ] || return 1 - - export -f setup_juju - export -f die - JUJU_ENV=1 bash -ic "setup_juju" &> /dev/null - is_equal $? 1 || return 1 - export -n setup_juju - unset setup_juju - export -n die - unset die } @@ -76,13 +67,6 @@ function test_setup_from_file_juju(){ export -f die bash -ic "setup_from_file_juju noexist.tar.gz" &> /dev/null is_equal $? 1 || return 1 - - JUJU_ENV=1 bash -ic "setup_from_file_juju" &> /dev/null - is_equal $? 1 || return 1 - export -n setup_from_file_juju - unset setup_from_file_juju - export -n die - unset die } @@ -97,15 +81,6 @@ function test_run_juju_as_root(){ run_juju_as_root "[ -e /run/lock ]" is_equal $? 0 || return 1 [ -e $JUJU_HOME/${HOME} ] || return 1 - - export -f run_juju_as_root - export -f die - JUJU_ENV=1 bash -ic "run_juju_as_root" &> /dev/null - is_equal $? 1 || return 1 - export -n run_juju_as_root - unset run_juju_as_root - export -n die - unset die } function test_run_juju_as_user(){ @@ -170,15 +145,12 @@ function test_delete_juju(){ echo "Y" | delete_juju 1> /dev/null is_juju_installed is_equal $? 1 || return 1 +} - export -f delete_juju - export -f die - JUJU_ENV=1 bash -ic "delete_juju" &> /dev/null +function test_nested_juju(){ + install_mini_juju + JUJU_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null is_equal $? 1 || return 1 - export -n delete_juju - unset delete_juju - export -n die - unset die } From b2dacdc3531fdf450e54afa2c9776722d6c97399 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 30 Nov 2014 16:52:53 +0100 Subject: [PATCH 017/326] Update the version to 2.5.6 (Lion) --- bin/juju | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/bin/juju b/bin/juju index c00da88..83eef6a 100755 --- a/bin/juju +++ b/bin/juju @@ -18,8 +18,14 @@ # along with this program. If not, see . # -NAME='juju' -VERSION='1.0' +NAME='JuJu' +CMD='juju' +VERSION='2.5.6' +CODE_NAME='Lion' +DESCRIPTION='The GNU/Linux distribution container for non-root users' +AUTHOR='Filippo Squillace ' +HOMEPAGE='https://github.com/fsquillace/juju' +COPYRIGHT='2012-2014' source "$(dirname $0)/../lib/core.sh" @@ -28,23 +34,23 @@ source "$(dirname $0)/../lib/core.sh" ################################### usage() { - echo -e "JuJu: The portable GNU/Linux distribution" - echo -e "Usage: $NAME [options] [command]" + echo -e "$NAME: $DESCRIPTION" + echo -e "Usage: $CMD [options] [command]" echo -e "Options:" - echo -e "-i, --setup-from-file Setup the JuJu image in ${JUJU_HOME}" - echo -e "-f, --fakeroot Run JuJu with fakeroot privileges" - echo -e "-r, --root Run JuJu with root privileges" + echo -e "-i, --setup-from-file Setup the $NAME image in ${JUJU_HOME}" + echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" + echo -e "-r, --root Run $NAME with root privileges" echo -e "-p, --proot-args Proot arguments" - echo -e "-b, --build-image Build a JuJu image (must run in ArchLinux)" - echo -e "-d, --delete Delete JuJu from ${JUJU_HOME}" + echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" + echo -e "-d, --delete Delete $NAME from ${JUJU_HOME}" echo -e "-h, --help Show this help message" echo -e "-v, --version Show the $NAME version" } version() { - echo -e "JuJu ($VERSION): The portable GNU/Linux distribution" - echo -e "Copyright (c) 2012-2014 Filippo Squillace " - echo -e "Homepage: http://github.com/fsquillace/juju" + echo -e "$NAME $VERSION ($CODE_NAME): $DESCRIPTION" + echo -e "Copyright (c) $COPYRIGHT $AUTHOR" + echo -e "Homepage: $HOMEPAGE" } check_cli(){ @@ -61,7 +67,7 @@ check_cli(){ if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ $OPT_FAKEROOT || $OPT_ROOT then - die "The JuJu delete option must be used exclusively" + die "The $NAME delete option must be used exclusively" fi fi if $OPT_HELP @@ -69,7 +75,7 @@ check_cli(){ if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ $OPT_FAKEROOT || $OPT_ROOT then - die "The JuJu help option must be used exclusively" + die "The $NAME help option must be used exclusively" fi fi if $OPT_VERSION @@ -77,12 +83,12 @@ check_cli(){ if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ $OPT_FAKEROOT || $OPT_ROOT then - die "The JuJu version option must be used exclusively" + die "The $NAME version option must be used exclusively" fi fi if $OPT_FAKEROOT && $OPT_ROOT then - die "You must access to JuJu with either fakeroot or root permissions" + die "You must access to $NAME with either fakeroot or root permissions" fi if $OPT_PROOT_ARGS then @@ -97,7 +103,7 @@ check_cli(){ if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ $OPT_VERSION then - die "No arguments are needed. For the CLI syntax run: $NAME --help" + die "No arguments are needed. For the CLI syntax run: $CMD --help" fi fi @@ -106,7 +112,7 @@ check_cli(){ function parse_arguments(){ - TEMP=$(getopt -o drp:fbi:hv --long delete,root,proot-args:,fakeroot,build-image,setup-from-file:,help,version -n 'juju' -- "$@") + TEMP=$(getopt -o drp:fbi:hv --long delete,root,proot-args:,fakeroot,build-image,setup-from-file:,help,version -n "$CMD" -- "$@") eval set -- "$TEMP" OPT_SETUP_FROM_FILE=false From 54f762941700a851a2f6b0fafaa2fd4e61dbbc33 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 30 Nov 2014 23:56:17 +0100 Subject: [PATCH 018/326] Fix issue #32 --- README.md | 22 ++++++++++++++++++++++ lib/core.sh | 5 ++++- tests/test_core.sh | 4 ++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c52057f..1b4b863 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,28 @@ permissions. Since JuJu gives the possibility to install packages either as root or as normal user you need to remember that and remove the package with the right user! +###No servers configured for repository### +-**Q**: Why I cannot install packages? +``` + pacman -S lsof + Packages (1): lsof-4.88-2 + + Total Download Size: 0.09 MiB + Total Installed Size: 0.21 MiB + + error: no servers configured for repository: core + error: no servers configured for repository: community + error: failed to commit transaction (no servers configured for repository) + Errors occurred, no packages were upgraded. +``` + +-**A**: You need simply to update the mirrorlist file according to your location: +``` + # Uncomment the repository line according to your location + nano /etc/pacman.d/mirrorlist + pacman -Syy +``` + License ------- Copyright (c) 2012-2014 diff --git a/lib/core.sh b/lib/core.sh index 11a1f69..b881f47 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -108,6 +108,9 @@ function _setup_juju(){ imagepath=$1 tar -zxpf ${imagepath} -C ${JUJU_HOME} mkdir -p ${JUJU_HOME}/run/lock + warn "Warn: Change the mirrorlist file according to your location:" + info " nano /etc/pacman.d/mirrorlist" + info " pacman -Syy" info "JuJu installed successfully" } @@ -233,7 +236,7 @@ function build_image_juju(){ mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -d ${maindir}/root pacman arch-install-scripts binutils libunistring + pacstrap -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano info "Generating the locales..." ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime diff --git a/tests/test_core.sh b/tests/test_core.sh index 1a4be0c..9f8da7c 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -50,7 +50,7 @@ function test_setup_juju(){ tar -czvf juju-${ARCH}.tar.gz file } WGET=wget_mock - setup_juju 1> /dev/null + setup_juju &> /dev/null [ -e $JUJU_HOME/file ] || return 1 [ -e $JUJU_HOME/run/lock ] || return 1 } @@ -59,7 +59,7 @@ function test_setup_juju(){ function test_setup_from_file_juju(){ touch file tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null - setup_from_file_juju juju-${ARCH}.tar.gz 1> /dev/null + setup_from_file_juju juju-${ARCH}.tar.gz &> /dev/null [ -e $JUJU_HOME/file ] || return 1 [ -e $JUJU_HOME/run/lock ] || return 1 From b5ad28b4b1fbdccbd056d304da40ba6350d3035e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 2 Dec 2014 02:38:07 +0100 Subject: [PATCH 019/326] Fix issue #31 --- lib/core.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 11a1f69..4a6b250 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -233,7 +233,7 @@ function build_image_juju(){ mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -d ${maindir}/root pacman arch-install-scripts binutils libunistring + pacstrap -G -d ${maindir}/root pacman arch-install-scripts binutils libunistring info "Generating the locales..." ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime @@ -260,19 +260,24 @@ function build_image_juju(){ makepkg -sfcA --asroot pacman --noconfirm --root ${maindir}/root -U proot*.pkg.tar.xz - rm ${maindir}/root/var/cache/pacman/pkg/* - info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju echo 'export PATH=$PATH:/opt/juju/bin' > ${maindir}/root/etc/profile.d/juju.sh chmod +x ${maindir}/root/etc/profile.d/juju.sh + info "Setting up the pacman keyring (this might take a while!)..." + pacman --root ${maindir}/root --noconfirm -S psmisc + arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux; killall gpg-agent" + pacman --root ${maindir}/root --noconfirm -Rsn psmisc + info "Validating JuJu image..." arch-chroot ${maindir}/root pacman -Qi pacman &> /dev/null arch-chroot ${maindir}/root yaourt -V &> /dev/null arch-chroot ${maindir}/root proot --help &> /dev/null arch-chroot ${maindir}/root arch-chroot --help &> /dev/null + rm ${maindir}/root/var/cache/pacman/pkg/* + builtin cd ${ORIGIN_WD} local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." From 0b0c3be4dc1a4f12b95ee83e7da00c592ba2e8f9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 2 Dec 2014 23:28:20 +0100 Subject: [PATCH 020/326] Remove the juju.sh profile since juju could be used internally --- lib/core.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index e72a562..c4c6618 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -265,8 +265,6 @@ function build_image_juju(){ info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju - echo 'export PATH=$PATH:/opt/juju/bin' > ${maindir}/root/etc/profile.d/juju.sh - chmod +x ${maindir}/root/etc/profile.d/juju.sh info "Setting up the pacman keyring (this might take a while!)..." pacman --root ${maindir}/root --noconfirm -S psmisc From 03e0f483e98046cabc12a196d1f562f9b124011b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 13 Dec 2014 19:56:08 +0100 Subject: [PATCH 021/326] Small fix on the juju temp dir variable --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c52057f..1b88da3 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ In this way the script will create a directory containing all the essentials files in order to make JuJu working properly (such as pacman, yaourt, arch-chroot and proot). Remember that the script to build the image must run in an ArchLinux OS with arch-install-scripts, package-query, git and the base-devel packages installed. -To change the build directory just use the *JUJU_TMPDIR* (by default /tmp). +To change the build directory just use the *JUJU_TEMPDIR* (by default /tmp). After creating the image juju-x86\_64.tar.gz you can install it by running: From 1444bcd6499e9797f14d41f6822a29889bb6ffb4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 15 Dec 2014 20:56:57 +0100 Subject: [PATCH 022/326] Add sed command to JuJu image --- lib/core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index c4c6618..24d302d 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -236,7 +236,7 @@ function build_image_juju(){ mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano + pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano sed info "Generating the locales..." ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime From 5823e4c55394fd7c2edc56847f35110efb4bd8c5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 15 Dec 2014 21:22:34 +0100 Subject: [PATCH 023/326] Fix issue #35 --- lib/core.sh | 2 +- tests/test_core.sh | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 11a1f69..31c52f2 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -137,7 +137,7 @@ function setup_from_file_juju(){ [ ! -e ${imagefile} ] && die "Error: The JuJu image file ${imagefile} does not exist" info "Installing JuJu from ${imagefile}..." - _setup_juju ${ORIGIN_WD}/${imagefile} + _setup_juju ${imagefile} builtin cd $ORIGIN_WD } diff --git a/tests/test_core.sh b/tests/test_core.sh index 1a4be0c..1555303 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -69,6 +69,13 @@ function test_setup_from_file_juju(){ is_equal $? 1 || return 1 } +function test_setup_from_file_juju_with_absolute_path(){ + touch file + tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null + setup_from_file_juju ${ORIGIN_WD}/juju-${ARCH}.tar.gz &> /dev/null + [ -e $JUJU_HOME/file ] || return 1 + [ -e $JUJU_HOME/run/lock ] || return 1 +} function test_run_juju_as_root(){ install_mini_juju From ecb885206af6e16a4b5a4d6d0dbd74613e722713 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 15 Dec 2014 21:32:22 +0100 Subject: [PATCH 024/326] Fix issue #37 --- lib/core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 31c52f2..03babed 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -233,7 +233,7 @@ function build_image_juju(){ mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -d ${maindir}/root pacman arch-install-scripts binutils libunistring + pacstrap -d ${maindir}/root pacman arch-install-scripts binutils libunistring sed info "Generating the locales..." ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime From 6163bc3d4657d0b371d2b6437e17f341fc4c1395 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 21 Dec 2014 20:48:01 +0100 Subject: [PATCH 025/326] Add link to README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1b4b863..a306108 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,9 @@ After creating the image juju-x86\_64.tar.gz you can install it by running: # juju -i juju-x86_64.tar.gz +Related wiki page: +- [How to build a JuJu image using QEMU](https://github.com/fsquillace/juju/wiki/How-to-build-a-JuJu-image-using-QEMU) + ### Bind directories ### To bind and host directory to a guest location, you can use proot arguments: ``` From 97c03a59615a8e6c0df71da96d115f622328184a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 20 Dec 2014 16:10:41 +0100 Subject: [PATCH 026/326] Add proot compat binary --- lib/core.sh | 65 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 24d302d..52ed541 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -28,6 +28,15 @@ set -e source "$(dirname ${BASH_ARGV[0]})/util.sh" ################################# VARIABLES ############################## + +if [ "$JUJU_ENV" == "1" ] +then + die "Error: Nested JuJu environments are not allowed" +elif [ ! -z $JUJU_ENV ] && [ "$JUJU_ENV" != "0" ] +then + die "The variable JUJU_ENV is not properly set" +fi + [ -z ${JUJU_HOME} ] && JUJU_HOME=~/.juju if [ -z ${JUJU_TEMPDIR} ] || [ ! -d ${JUJU_TEMPDIR} ] then @@ -48,37 +57,36 @@ else fi TAR=tar -ARCH=$(uname -m) -[[ $ARCH =~ .*(armv6).* ]] && ARCH=${BASH_REMATCH[1]} +HOST_ARCH=$(uname -m) -if [ $ARCH == "i686" ] +if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then + ARCH="x86" LD_LIB="${JUJU_HOME}/lib/ld-linux.so.2" -elif [ $ARCH == "x86_64" ] +elif [ $HOST_ARCH == "x86_64" ] then + ARCH="x86_64" LD_LIB="${JUJU_HOME}/lib64/ld-linux-x86-64.so.2" -elif [ $ARCH == "armv6" ] +elif [[ $HOST_ARCH =~ .*(arm).* ]] then + ARCH="arm" LD_LIB="${JUJU_HOME}/lib/ld-linux-armhf.so.3" else die "Unknown architecture ${ARCH}" fi -if [ -z $JUJU_ENV ] || [ "$JUJU_ENV" == "0" ] -then - PROOT="$LD_LIB --library-path ${JUJU_HOME}/usr/lib:${JUJU_HOME}/lib ${JUJU_HOME}/usr/bin/proot" - SH="/bin/sh --login" -elif [ "$JUJU_ENV" == "1" ] -then - die "Error: Nested JuJu environments are not allowed" -else - die "The variable JUJU_ENV is not properly set" -fi +PROOT_BIN="${JUJU_HOME}/usr/bin/proot" +PROOT_COMPAT_BIN="${JUJU_HOME}/opt/proot/proot-${ARCH}" +PROOT="$LD_LIB --library-path ${JUJU_HOME}/usr/lib:${JUJU_HOME}/lib ${PROOT_BIN}" +PROOT_COMPAT="${PROOT_COMPAT_BIN}" +PROOT_LINK=http://static.proot.me/proot-${ARCH} +SH="/bin/sh --login" CHROOT=${JUJU_HOME}/usr/bin/arch-chroot TRUE=${JUJU_HOME}/usr/bin/true ID="${JUJU_HOME}/usr/bin/id -u" + ################################# MAIN FUNCTIONS ############################## function is_juju_installed(){ @@ -168,12 +176,27 @@ function run_juju_as_root(){ function _run_juju_with_proot(){ - ${PROOT} ${TRUE} &> /dev/null || export PROOT_NO_SECCOMP=1 + local proot_bin=${PROOT} + if ! ${proot_bin} ${TRUE} &> /dev/null + then + if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null + then + export PROOT_NO_SECCOMP=1 + else + proot_bin=${PROOT_COMPAT} + if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null + then + export PROOT_NO_SECCOMP=1 + else + die "Proot cannot be executed." + fi + fi + fi - [ "$(${PROOT} ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(${proot_bin} ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - JUJU_ENV=1 ${PROOT} $@ + JUJU_ENV=1 ${proot_bin} $@ local ret=$? export -n PROOT_NO_SECCOMP @@ -263,6 +286,12 @@ function build_image_juju(){ makepkg -sfcA --asroot pacman --noconfirm --root ${maindir}/root -U proot*.pkg.tar.xz + info "Installing compatibility binary proot" + mkdir -p ${maindir}/root/opt/proot + builtin cd ${maindir}/root/opt/proot + $WGET $PROOT_LINK + chmod +x proot-$ARCH + info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju From be1bd7b48717f6559e9938a13796d782456e4bad Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 21 Dec 2014 21:34:24 +0100 Subject: [PATCH 027/326] Fix issue #38 --- lib/core.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index 24d302d..4a84f61 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -204,6 +204,8 @@ function delete_juju(){ die "Try to delete juju using root permissions" fi fi + # the CA directories are read only and can be deleted only by changing the mod + chmod -R +w ${JUJU_HOME}/etc/ca-certificates if rm -rf ${JUJU_HOME}/* then info "JuJu deleted in ${JUJU_HOME}" From 410b7512d4a99b229602e5e5d4f1454a8cdbb044 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 01:55:22 +0100 Subject: [PATCH 028/326] Fix issue #36 - Add tests for proot compat --- lib/core.sh | 42 +++++++++++++++--------------------- tests/test_core.sh | 54 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 52ed541..dd3cdf5 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -83,10 +83,8 @@ PROOT_LINK=http://static.proot.me/proot-${ARCH} SH="/bin/sh --login" CHROOT=${JUJU_HOME}/usr/bin/arch-chroot -TRUE=${JUJU_HOME}/usr/bin/true ID="${JUJU_HOME}/usr/bin/id -u" - ################################# MAIN FUNCTIONS ############################## function is_juju_installed(){ @@ -174,33 +172,27 @@ function run_juju_as_root(){ JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" } +function _run_proot(){ + if ! JUJU_ENV=1 ${@} + then + info "Trying execute proot with PROOT_NO_SECCOMP=1 " + JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${@} + fi +} + function _run_juju_with_proot(){ - local proot_bin=${PROOT} - if ! ${proot_bin} ${TRUE} &> /dev/null - then - if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null - then - export PROOT_NO_SECCOMP=1 - else - proot_bin=${PROOT_COMPAT} - if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null - then - export PROOT_NO_SECCOMP=1 - else - die "Proot cannot be executed." - fi - fi - fi - - [ "$(${proot_bin} ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - JUJU_ENV=1 ${proot_bin} $@ - local ret=$? - export -n PROOT_NO_SECCOMP - - return $ret + if ! _run_proot ${PROOT} ${@} + then + info "Trying to execute proot compat binary" + if ! _run_proot ${PROOT_COMPAT} ${@} + then + die "Proot cannot be executed: Try to use juju -p \"-k 3.10\"" + fi + fi } diff --git a/tests/test_core.sh b/tests/test_core.sh index 9f8da7c..c84f78c 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -101,8 +101,6 @@ function test_run_juju_as_user_proot_args(){ install_mini_juju run_juju_as_user "--help" "" 1> /dev/null is_equal $? 0 || return 1 - run_juju_as_user "--helps" "" &> /dev/null - is_equal $? 1 || return 1 mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile @@ -110,24 +108,57 @@ function test_run_juju_as_user_proot_args(){ is_equal $? 0 || return 1 export -f _run_juju_with_proot + export -f _run_proot + export -f info export PROOT - export TRUE + export PROOT_COMPAT + ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + is_equal $? 1 || return 1 + export -n _run_juju_with_proot + export -n _run_proot + export -n info + export -n PROOT + export -n PROOT_COMPAT +} + +function test_run_juju_with_proot_with_compat(){ + install_mini_juju + PROOT="/usr/bin/true" + PROOT_COMPAT="/usr/bin/false" + _run_juju_with_proot "" "" 1> /dev/null + is_equal $? 0 || return 1 + + PROOT="/usr/bin/false" + PROOT_COMPAT="/usr/bin/true" + _run_juju_with_proot "" "" 1> /dev/null + is_equal $? 0 || return 1 + + export -f _run_juju_with_proot + export -f _run_proot + export -f info + PROOT="/usr/bin/false" PROOT_COMPAT="/usr/bin/false" ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + is_equal $? 1 || return 1 + export -n _run_juju_with_proot + export -n _run_proot + export -n info +} + +function test_run_juju_with_proot_as_root(){ + export -f _run_juju_with_proot ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot unset _run_juju_with_proot - export -n PROOT - export -n TRUE } -function test_run_juju_as_user_seccomp(){ - install_mini_juju - PROOT="" - local output=$(_run_juju_with_proot "" "env" | grep "PROOT_NO_SECCOMP") +function test_run_proot_seccomp(){ + local output=$(_run_proot "env" | grep "^PROOT_NO_SECCOMP") is_equal $output "" || return 1 - TRUE="/usr/bin/false" - local output=$(_run_juju_with_proot "" "env" | grep "PROOT_NO_SECCOMP") + envv(){ + env | grep "^PROOT_NO_SECCOMP" + } + local output=$(_run_proot "envv" | grep "^PROOT_NO_SECCOMP") is_equal $output "PROOT_NO_SECCOMP=1" || return 1 } @@ -153,7 +184,6 @@ function test_nested_juju(){ is_equal $? 1 || return 1 } - for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) do set_up From 460a0a595e35f811281755f640c76d21b4b770a2 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 13:25:25 +0100 Subject: [PATCH 029/326] Change test for compatibility with old environment --- lib/core.sh | 6 +++--- tests/test_core.sh | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index dd3cdf5..340e8b3 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -175,7 +175,7 @@ function run_juju_as_root(){ function _run_proot(){ if ! JUJU_ENV=1 ${@} then - info "Trying execute proot with PROOT_NO_SECCOMP=1 " + warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${@} fi } @@ -187,10 +187,10 @@ function _run_juju_with_proot(){ if ! _run_proot ${PROOT} ${@} then - info "Trying to execute proot compat binary" + warn "Proot error: Trying to execute proot compatible binary..." if ! _run_proot ${PROOT_COMPAT} ${@} then - die "Proot cannot be executed: Try to use juju -p \"-k 3.10\"" + die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" fi fi } diff --git a/tests/test_core.sh b/tests/test_core.sh index c84f78c..5ceb561 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -85,13 +85,13 @@ function test_run_juju_as_root(){ function test_run_juju_as_user(){ install_mini_juju - local output=$(run_juju_as_user "" "mkdir -v /newdir2" | awk -F: '{print $1}') + local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir -v /newdir2" 2> /dev/null | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir2 ] is_equal $? 0 || return 1 - SH="mkdir -v /newdir" - local output=$(run_juju_as_user "" | awk -F: '{print $1}') + SH="/usr/bin/mkdir -v /newdir" + local output=$(run_juju_as_user "-k 3.10" 2> /dev/null | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir ] is_equal $? 0 || return 1 @@ -99,12 +99,12 @@ function test_run_juju_as_user(){ function test_run_juju_as_user_proot_args(){ install_mini_juju - run_juju_as_user "--help" "" 1> /dev/null + run_juju_as_user "--help" "" &> /dev/null is_equal $? 0 || return 1 mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile - run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir" "ls -l /newdir/newfile" 1> /dev/null + run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls -l /newdir/newfile" &> /dev/null is_equal $? 0 || return 1 export -f _run_juju_with_proot @@ -112,7 +112,7 @@ function test_run_juju_as_user_proot_args(){ export -f info export PROOT export PROOT_COMPAT - ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -123,20 +123,20 @@ function test_run_juju_as_user_proot_args(){ function test_run_juju_with_proot_with_compat(){ install_mini_juju - PROOT="/usr/bin/true" - PROOT_COMPAT="/usr/bin/false" - _run_juju_with_proot "" "" 1> /dev/null + PROOT="/bin/true" + PROOT_COMPAT="/bin/false" + _run_juju_with_proot "" "" &> /dev/null is_equal $? 0 || return 1 - PROOT="/usr/bin/false" - PROOT_COMPAT="/usr/bin/true" - _run_juju_with_proot "" "" 1> /dev/null + PROOT="/bin/false" + PROOT_COMPAT="/bin/true" + _run_juju_with_proot "" "" &> /dev/null is_equal $? 0 || return 1 export -f _run_juju_with_proot export -f _run_proot export -f info - PROOT="/usr/bin/false" PROOT_COMPAT="/usr/bin/false" ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + PROOT="/bin/false" PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -145,7 +145,7 @@ function test_run_juju_with_proot_with_compat(){ function test_run_juju_with_proot_as_root(){ export -f _run_juju_with_proot - ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null + ID="/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot unset _run_juju_with_proot @@ -158,13 +158,13 @@ function test_run_proot_seccomp(){ envv(){ env | grep "^PROOT_NO_SECCOMP" } - local output=$(_run_proot "envv" | grep "^PROOT_NO_SECCOMP") + local output=$(_run_proot "envv" 2> /dev/null | grep "^PROOT_NO_SECCOMP") is_equal $output "PROOT_NO_SECCOMP=1" || return 1 } function test_run_juju_as_fakeroot(){ install_mini_juju - local output=$(run_juju_as_fakeroot "" "id" | awk '{print $1}') + local output=$(run_juju_as_fakeroot "-k 3.10" "id" 2> /dev/null | awk '{print $1}') is_equal "$output" "uid=0(root)" || return 1 } From a91729820e16c8b17ec8d4149c5bdab964de021a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 14:48:22 +0100 Subject: [PATCH 030/326] Fix tests --- tests/test_core.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index 5ceb561..c6613d3 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -109,14 +109,16 @@ function test_run_juju_as_user_proot_args(){ export -f _run_juju_with_proot export -f _run_proot - export -f info + export -f warn + export -f die export PROOT export PROOT_COMPAT ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot - export -n info + export -n warn + export -n die export -n PROOT export -n PROOT_COMPAT } @@ -135,12 +137,14 @@ function test_run_juju_with_proot_with_compat(){ export -f _run_juju_with_proot export -f _run_proot - export -f info + export -f warn + export -f die PROOT="/bin/false" PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot - export -n info + export -n warn + export -n die } function test_run_juju_with_proot_as_root(){ From 63d242344981717a2dac68d053d2b868400120b6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 15:23:41 +0100 Subject: [PATCH 031/326] Update doc for the new compat binary --- README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a306108..52567f0 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,8 @@ Just clone JuJu somewhere (for example in ~/juju): $ git clone git://github.com/fsquillace/juju ~/juju $ export PATH=~/juju/bin:$PATH -JuJu can only works on GNU/Linux OS with kernel version greater or equal -2.6.32 on 64 bit 32 bit and ARMv6 architectures. +JuJu can works on GNU/Linux OS with kernel version greater or equal +2.6.0 (JuJu was not tested on kernel versions older than this) on 64 bit 32 bit and ARMv6 architectures. Advanced usage -------------- @@ -84,12 +84,15 @@ Check out the proot options with: Dependencies ------------ JuJu comes with a very short list of dependencies in order to be installed in most -of GNU/Linux distributions. The dependencies needed in the host OS are: +of GNU/Linux distributions. The needed executables in the host OS are: - bash - wget or curl - tar +- getopt +- id - mkdir -- linux kernel 2.6.32+ + +The minimum recommended linux kernel is 2.6.0+ Troubleshooting --------------- @@ -110,9 +113,17 @@ that contains all the essential packages for compiling source code (such as gcc, ###Kernel too old### - **Q**: Why do I get the error: "FATAL: kernel too old"? - **A**: This is because the executable from the precompiled package cannot -always run if the kernel is old. -In order to check if the executable can be compatible with the kernel of -the host OS just use file command, for instance: +properly run if the kernel is old. +JuJu contains two different PRoot binaries, and one of them is highly compatible +with old linux kernel versions. JuJu will detect which PRoot binary need to be +executed but you may need to specify the PRoot *-k* option if the guest rootfs +requires a newer kernel version: +``` + juju -p "-k 3.10" +``` + +In order to check if an executable inside JuJu environment can be compatible +with the kernel of the host OS just use the *file* command, for instance: ``` file ~/.juju/usr/bin/bash From 6ec61a938a90c55b4afb55f1420d93f621b6e0a5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 30 Nov 2014 23:56:17 +0100 Subject: [PATCH 032/326] Fix issue #32 --- README.md | 22 ++++++++++++++++++++++ lib/core.sh | 5 ++++- tests/test_core.sh | 4 ++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b88da3..fd80118 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,28 @@ permissions. Since JuJu gives the possibility to install packages either as root or as normal user you need to remember that and remove the package with the right user! +###No servers configured for repository### +-**Q**: Why I cannot install packages? +``` + pacman -S lsof + Packages (1): lsof-4.88-2 + + Total Download Size: 0.09 MiB + Total Installed Size: 0.21 MiB + + error: no servers configured for repository: core + error: no servers configured for repository: community + error: failed to commit transaction (no servers configured for repository) + Errors occurred, no packages were upgraded. +``` + +-**A**: You need simply to update the mirrorlist file according to your location: +``` + # Uncomment the repository line according to your location + nano /etc/pacman.d/mirrorlist + pacman -Syy +``` + License ------- Copyright (c) 2012-2014 diff --git a/lib/core.sh b/lib/core.sh index 03babed..0b26363 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -108,6 +108,9 @@ function _setup_juju(){ imagepath=$1 tar -zxpf ${imagepath} -C ${JUJU_HOME} mkdir -p ${JUJU_HOME}/run/lock + warn "Warn: Change the mirrorlist file according to your location:" + info " nano /etc/pacman.d/mirrorlist" + info " pacman -Syy" info "JuJu installed successfully" } @@ -233,7 +236,7 @@ function build_image_juju(){ mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -d ${maindir}/root pacman arch-install-scripts binutils libunistring sed + pacstrap -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano info "Generating the locales..." ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime diff --git a/tests/test_core.sh b/tests/test_core.sh index 1555303..afae1a6 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -50,7 +50,7 @@ function test_setup_juju(){ tar -czvf juju-${ARCH}.tar.gz file } WGET=wget_mock - setup_juju 1> /dev/null + setup_juju &> /dev/null [ -e $JUJU_HOME/file ] || return 1 [ -e $JUJU_HOME/run/lock ] || return 1 } @@ -59,7 +59,7 @@ function test_setup_juju(){ function test_setup_from_file_juju(){ touch file tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null - setup_from_file_juju juju-${ARCH}.tar.gz 1> /dev/null + setup_from_file_juju juju-${ARCH}.tar.gz &> /dev/null [ -e $JUJU_HOME/file ] || return 1 [ -e $JUJU_HOME/run/lock ] || return 1 From c0a41ca1ca25d8bdcd6f190ab6cad23465a7646e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 2 Dec 2014 02:38:07 +0100 Subject: [PATCH 033/326] Fix issue #31 --- lib/core.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 0b26363..0f37225 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -263,19 +263,24 @@ function build_image_juju(){ makepkg -sfcA --asroot pacman --noconfirm --root ${maindir}/root -U proot*.pkg.tar.xz - rm ${maindir}/root/var/cache/pacman/pkg/* - info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju echo 'export PATH=$PATH:/opt/juju/bin' > ${maindir}/root/etc/profile.d/juju.sh chmod +x ${maindir}/root/etc/profile.d/juju.sh + info "Setting up the pacman keyring (this might take a while!)..." + pacman --root ${maindir}/root --noconfirm -S psmisc + arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux; killall gpg-agent" + pacman --root ${maindir}/root --noconfirm -Rsn psmisc + info "Validating JuJu image..." arch-chroot ${maindir}/root pacman -Qi pacman &> /dev/null arch-chroot ${maindir}/root yaourt -V &> /dev/null arch-chroot ${maindir}/root proot --help &> /dev/null arch-chroot ${maindir}/root arch-chroot --help &> /dev/null + rm ${maindir}/root/var/cache/pacman/pkg/* + builtin cd ${ORIGIN_WD} local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." From 92f4ad8976b27dda85325952a56edea83df7392f Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 2 Dec 2014 23:28:20 +0100 Subject: [PATCH 034/326] Remove the juju.sh profile since juju could be used internally --- lib/core.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 0f37225..e74dac0 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -265,8 +265,6 @@ function build_image_juju(){ info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju - echo 'export PATH=$PATH:/opt/juju/bin' > ${maindir}/root/etc/profile.d/juju.sh - chmod +x ${maindir}/root/etc/profile.d/juju.sh info "Setting up the pacman keyring (this might take a while!)..." pacman --root ${maindir}/root --noconfirm -S psmisc From f6cac03cc1004fefe2cc242005491ff5b0b552e1 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 15 Dec 2014 20:56:57 +0100 Subject: [PATCH 035/326] Add sed command to JuJu image --- lib/core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index e74dac0..c63ab2a 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -236,7 +236,7 @@ function build_image_juju(){ mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano + pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano sed info "Generating the locales..." ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime From 2a1e4477f5dd10149750c75533a5d652fe6fe387 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 21 Dec 2014 20:48:01 +0100 Subject: [PATCH 036/326] Add link to README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index fd80118..569a978 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,9 @@ After creating the image juju-x86\_64.tar.gz you can install it by running: # juju -i juju-x86_64.tar.gz +Related wiki page: +- [How to build a JuJu image using QEMU](https://github.com/fsquillace/juju/wiki/How-to-build-a-JuJu-image-using-QEMU) + ### Bind directories ### To bind and host directory to a guest location, you can use proot arguments: ``` From 12507bfaede30ce5f80ba38d554ec059bdbb860d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 21 Dec 2014 21:34:24 +0100 Subject: [PATCH 037/326] Fix issue #38 --- lib/core.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index c63ab2a..96dfb4e 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -204,6 +204,8 @@ function delete_juju(){ die "Try to delete juju using root permissions" fi fi + # the CA directories are read only and can be deleted only by changing the mod + chmod -R +w ${JUJU_HOME}/etc/ca-certificates if rm -rf ${JUJU_HOME}/* then info "JuJu deleted in ${JUJU_HOME}" From d25799652acd3c99096f3c8bedb80993f2b58924 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 20 Dec 2014 16:10:41 +0100 Subject: [PATCH 038/326] Add proot compat binary --- lib/core.sh | 65 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 96dfb4e..c1280f6 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -28,6 +28,15 @@ set -e source "$(dirname ${BASH_ARGV[0]})/util.sh" ################################# VARIABLES ############################## + +if [ "$JUJU_ENV" == "1" ] +then + die "Error: Nested JuJu environments are not allowed" +elif [ ! -z $JUJU_ENV ] && [ "$JUJU_ENV" != "0" ] +then + die "The variable JUJU_ENV is not properly set" +fi + [ -z ${JUJU_HOME} ] && JUJU_HOME=~/.juju if [ -z ${JUJU_TEMPDIR} ] || [ ! -d ${JUJU_TEMPDIR} ] then @@ -48,37 +57,36 @@ else fi TAR=tar -ARCH=$(uname -m) -[[ $ARCH =~ .*(armv6).* ]] && ARCH=${BASH_REMATCH[1]} +HOST_ARCH=$(uname -m) -if [ $ARCH == "i686" ] +if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then + ARCH="x86" LD_LIB="${JUJU_HOME}/lib/ld-linux.so.2" -elif [ $ARCH == "x86_64" ] +elif [ $HOST_ARCH == "x86_64" ] then + ARCH="x86_64" LD_LIB="${JUJU_HOME}/lib64/ld-linux-x86-64.so.2" -elif [ $ARCH == "armv6" ] +elif [[ $HOST_ARCH =~ .*(arm).* ]] then + ARCH="arm" LD_LIB="${JUJU_HOME}/lib/ld-linux-armhf.so.3" else die "Unknown architecture ${ARCH}" fi -if [ -z $JUJU_ENV ] || [ "$JUJU_ENV" == "0" ] -then - PROOT="$LD_LIB --library-path ${JUJU_HOME}/usr/lib:${JUJU_HOME}/lib ${JUJU_HOME}/usr/bin/proot" - SH="/bin/sh --login" -elif [ "$JUJU_ENV" == "1" ] -then - die "Error: Nested JuJu environments are not allowed" -else - die "The variable JUJU_ENV is not properly set" -fi +PROOT_BIN="${JUJU_HOME}/usr/bin/proot" +PROOT_COMPAT_BIN="${JUJU_HOME}/opt/proot/proot-${ARCH}" +PROOT="$LD_LIB --library-path ${JUJU_HOME}/usr/lib:${JUJU_HOME}/lib ${PROOT_BIN}" +PROOT_COMPAT="${PROOT_COMPAT_BIN}" +PROOT_LINK=http://static.proot.me/proot-${ARCH} +SH="/bin/sh --login" CHROOT=${JUJU_HOME}/usr/bin/arch-chroot TRUE=${JUJU_HOME}/usr/bin/true ID="${JUJU_HOME}/usr/bin/id -u" + ################################# MAIN FUNCTIONS ############################## function is_juju_installed(){ @@ -168,12 +176,27 @@ function run_juju_as_root(){ function _run_juju_with_proot(){ - ${PROOT} ${TRUE} &> /dev/null || export PROOT_NO_SECCOMP=1 + local proot_bin=${PROOT} + if ! ${proot_bin} ${TRUE} &> /dev/null + then + if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null + then + export PROOT_NO_SECCOMP=1 + else + proot_bin=${PROOT_COMPAT} + if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null + then + export PROOT_NO_SECCOMP=1 + else + die "Proot cannot be executed." + fi + fi + fi - [ "$(${PROOT} ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(${proot_bin} ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - JUJU_ENV=1 ${PROOT} $@ + JUJU_ENV=1 ${proot_bin} $@ local ret=$? export -n PROOT_NO_SECCOMP @@ -265,6 +288,12 @@ function build_image_juju(){ makepkg -sfcA --asroot pacman --noconfirm --root ${maindir}/root -U proot*.pkg.tar.xz + info "Installing compatibility binary proot" + mkdir -p ${maindir}/root/opt/proot + builtin cd ${maindir}/root/opt/proot + $WGET $PROOT_LINK + chmod +x proot-$ARCH + info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju From c34eba1b0a1e8befe50abdc393a99531a71cdb03 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 01:55:22 +0100 Subject: [PATCH 039/326] Fix issue #36 - Add tests for proot compat --- lib/core.sh | 42 +++++++++++++++--------------------- tests/test_core.sh | 54 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index c1280f6..8d5acf0 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -83,10 +83,8 @@ PROOT_LINK=http://static.proot.me/proot-${ARCH} SH="/bin/sh --login" CHROOT=${JUJU_HOME}/usr/bin/arch-chroot -TRUE=${JUJU_HOME}/usr/bin/true ID="${JUJU_HOME}/usr/bin/id -u" - ################################# MAIN FUNCTIONS ############################## function is_juju_installed(){ @@ -174,33 +172,27 @@ function run_juju_as_root(){ JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" } +function _run_proot(){ + if ! JUJU_ENV=1 ${@} + then + info "Trying execute proot with PROOT_NO_SECCOMP=1 " + JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${@} + fi +} + function _run_juju_with_proot(){ - local proot_bin=${PROOT} - if ! ${proot_bin} ${TRUE} &> /dev/null - then - if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null - then - export PROOT_NO_SECCOMP=1 - else - proot_bin=${PROOT_COMPAT} - if PROOT_NO_SECCOMP=1 ${proot_bin} ${TRUE} &> /dev/null - then - export PROOT_NO_SECCOMP=1 - else - die "Proot cannot be executed." - fi - fi - fi - - [ "$(${proot_bin} ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - JUJU_ENV=1 ${proot_bin} $@ - local ret=$? - export -n PROOT_NO_SECCOMP - - return $ret + if ! _run_proot ${PROOT} ${@} + then + info "Trying to execute proot compat binary" + if ! _run_proot ${PROOT_COMPAT} ${@} + then + die "Proot cannot be executed: Try to use juju -p \"-k 3.10\"" + fi + fi } diff --git a/tests/test_core.sh b/tests/test_core.sh index afae1a6..d433933 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -108,8 +108,6 @@ function test_run_juju_as_user_proot_args(){ install_mini_juju run_juju_as_user "--help" "" 1> /dev/null is_equal $? 0 || return 1 - run_juju_as_user "--helps" "" &> /dev/null - is_equal $? 1 || return 1 mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile @@ -117,24 +115,57 @@ function test_run_juju_as_user_proot_args(){ is_equal $? 0 || return 1 export -f _run_juju_with_proot + export -f _run_proot + export -f info export PROOT - export TRUE + export PROOT_COMPAT + ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + is_equal $? 1 || return 1 + export -n _run_juju_with_proot + export -n _run_proot + export -n info + export -n PROOT + export -n PROOT_COMPAT +} + +function test_run_juju_with_proot_with_compat(){ + install_mini_juju + PROOT="/usr/bin/true" + PROOT_COMPAT="/usr/bin/false" + _run_juju_with_proot "" "" 1> /dev/null + is_equal $? 0 || return 1 + + PROOT="/usr/bin/false" + PROOT_COMPAT="/usr/bin/true" + _run_juju_with_proot "" "" 1> /dev/null + is_equal $? 0 || return 1 + + export -f _run_juju_with_proot + export -f _run_proot + export -f info + PROOT="/usr/bin/false" PROOT_COMPAT="/usr/bin/false" ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + is_equal $? 1 || return 1 + export -n _run_juju_with_proot + export -n _run_proot + export -n info +} + +function test_run_juju_with_proot_as_root(){ + export -f _run_juju_with_proot ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot unset _run_juju_with_proot - export -n PROOT - export -n TRUE } -function test_run_juju_as_user_seccomp(){ - install_mini_juju - PROOT="" - local output=$(_run_juju_with_proot "" "env" | grep "PROOT_NO_SECCOMP") +function test_run_proot_seccomp(){ + local output=$(_run_proot "env" | grep "^PROOT_NO_SECCOMP") is_equal $output "" || return 1 - TRUE="/usr/bin/false" - local output=$(_run_juju_with_proot "" "env" | grep "PROOT_NO_SECCOMP") + envv(){ + env | grep "^PROOT_NO_SECCOMP" + } + local output=$(_run_proot "envv" | grep "^PROOT_NO_SECCOMP") is_equal $output "PROOT_NO_SECCOMP=1" || return 1 } @@ -160,7 +191,6 @@ function test_nested_juju(){ is_equal $? 1 || return 1 } - for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) do set_up From d94a9562c8d2d3f842b5368a500590cba9332d51 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 13:25:25 +0100 Subject: [PATCH 040/326] Change test for compatibility with old environment --- lib/core.sh | 6 +++--- tests/test_core.sh | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 8d5acf0..428068f 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -175,7 +175,7 @@ function run_juju_as_root(){ function _run_proot(){ if ! JUJU_ENV=1 ${@} then - info "Trying execute proot with PROOT_NO_SECCOMP=1 " + warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${@} fi } @@ -187,10 +187,10 @@ function _run_juju_with_proot(){ if ! _run_proot ${PROOT} ${@} then - info "Trying to execute proot compat binary" + warn "Proot error: Trying to execute proot compatible binary..." if ! _run_proot ${PROOT_COMPAT} ${@} then - die "Proot cannot be executed: Try to use juju -p \"-k 3.10\"" + die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" fi fi } diff --git a/tests/test_core.sh b/tests/test_core.sh index d433933..fc1ec1a 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -92,13 +92,13 @@ function test_run_juju_as_root(){ function test_run_juju_as_user(){ install_mini_juju - local output=$(run_juju_as_user "" "mkdir -v /newdir2" | awk -F: '{print $1}') + local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir -v /newdir2" 2> /dev/null | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir2 ] is_equal $? 0 || return 1 - SH="mkdir -v /newdir" - local output=$(run_juju_as_user "" | awk -F: '{print $1}') + SH="/usr/bin/mkdir -v /newdir" + local output=$(run_juju_as_user "-k 3.10" 2> /dev/null | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir ] is_equal $? 0 || return 1 @@ -106,12 +106,12 @@ function test_run_juju_as_user(){ function test_run_juju_as_user_proot_args(){ install_mini_juju - run_juju_as_user "--help" "" 1> /dev/null + run_juju_as_user "--help" "" &> /dev/null is_equal $? 0 || return 1 mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile - run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir" "ls -l /newdir/newfile" 1> /dev/null + run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls -l /newdir/newfile" &> /dev/null is_equal $? 0 || return 1 export -f _run_juju_with_proot @@ -119,7 +119,7 @@ function test_run_juju_as_user_proot_args(){ export -f info export PROOT export PROOT_COMPAT - ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -130,20 +130,20 @@ function test_run_juju_as_user_proot_args(){ function test_run_juju_with_proot_with_compat(){ install_mini_juju - PROOT="/usr/bin/true" - PROOT_COMPAT="/usr/bin/false" - _run_juju_with_proot "" "" 1> /dev/null + PROOT="/bin/true" + PROOT_COMPAT="/bin/false" + _run_juju_with_proot "" "" &> /dev/null is_equal $? 0 || return 1 - PROOT="/usr/bin/false" - PROOT_COMPAT="/usr/bin/true" - _run_juju_with_proot "" "" 1> /dev/null + PROOT="/bin/false" + PROOT_COMPAT="/bin/true" + _run_juju_with_proot "" "" &> /dev/null is_equal $? 0 || return 1 export -f _run_juju_with_proot export -f _run_proot export -f info - PROOT="/usr/bin/false" PROOT_COMPAT="/usr/bin/false" ID="/usr/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + PROOT="/bin/false" PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -152,7 +152,7 @@ function test_run_juju_with_proot_with_compat(){ function test_run_juju_with_proot_as_root(){ export -f _run_juju_with_proot - ID="/usr/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null + ID="/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot unset _run_juju_with_proot @@ -165,13 +165,13 @@ function test_run_proot_seccomp(){ envv(){ env | grep "^PROOT_NO_SECCOMP" } - local output=$(_run_proot "envv" | grep "^PROOT_NO_SECCOMP") + local output=$(_run_proot "envv" 2> /dev/null | grep "^PROOT_NO_SECCOMP") is_equal $output "PROOT_NO_SECCOMP=1" || return 1 } function test_run_juju_as_fakeroot(){ install_mini_juju - local output=$(run_juju_as_fakeroot "" "id" | awk '{print $1}') + local output=$(run_juju_as_fakeroot "-k 3.10" "id" 2> /dev/null | awk '{print $1}') is_equal "$output" "uid=0(root)" || return 1 } From 2068df5126bbb4f7fc8427d5b0edb47a08e78aae Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 14:48:22 +0100 Subject: [PATCH 041/326] Fix tests --- tests/test_core.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index fc1ec1a..ff1dec5 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -116,14 +116,16 @@ function test_run_juju_as_user_proot_args(){ export -f _run_juju_with_proot export -f _run_proot - export -f info + export -f warn + export -f die export PROOT export PROOT_COMPAT ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot - export -n info + export -n warn + export -n die export -n PROOT export -n PROOT_COMPAT } @@ -142,12 +144,14 @@ function test_run_juju_with_proot_with_compat(){ export -f _run_juju_with_proot export -f _run_proot - export -f info + export -f warn + export -f die PROOT="/bin/false" PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot - export -n info + export -n warn + export -n die } function test_run_juju_with_proot_as_root(){ From 022e4f909477a8fea81fa1d8bc80c7d9b1605ac0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Dec 2014 15:23:41 +0100 Subject: [PATCH 042/326] Update doc for the new compat binary --- README.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 569a978..1f71b8c 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,8 @@ Just clone JuJu somewhere (for example in ~/juju): $ git clone git://github.com/fsquillace/juju ~/juju $ export PATH=~/juju/bin:$PATH -JuJu can only works on GNU/Linux OS with kernel version greater or equal -2.6.32 on 64 bit 32 bit and ARMv6 architectures. +JuJu can works on GNU/Linux OS with kernel version greater or equal +2.6.0 (JuJu was not tested on kernel versions older than this) on 64 bit 32 bit and ARMv6 architectures. Advanced usage -------------- @@ -84,12 +84,15 @@ Check out the proot options with: Dependencies ------------ JuJu comes with a very short list of dependencies in order to be installed in most -of GNU/Linux distributions. The dependencies needed in the host OS are: +of GNU/Linux distributions. The needed executables in the host OS are: - bash - wget or curl - tar +- getopt +- id - mkdir -- linux kernel 2.6.32+ + +The minimum recommended linux kernel is 2.6.0+ Troubleshooting --------------- @@ -110,9 +113,17 @@ that contains all the essential packages for compiling source code (such as gcc, ###Kernel too old### - **Q**: Why do I get the error: "FATAL: kernel too old"? - **A**: This is because the executable from the precompiled package cannot -always run if the kernel is old. -In order to check if the executable can be compatible with the kernel of -the host OS just use file command, for instance: +properly run if the kernel is old. +JuJu contains two different PRoot binaries, and one of them is highly compatible +with old linux kernel versions. JuJu will detect which PRoot binary need to be +executed but you may need to specify the PRoot *-k* option if the guest rootfs +requires a newer kernel version: +``` + juju -p "-k 3.10" +``` + +In order to check if an executable inside JuJu environment can be compatible +with the kernel of the host OS just use the *file* command, for instance: ``` file ~/.juju/usr/bin/bash From 1c30ed26cbbd2af25910a936efff8be86a6ceb69 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 4 Jan 2015 22:22:32 +0100 Subject: [PATCH 043/326] Fix issue #40 --- lib/core.sh | 36 +++++++++++++++++------------------- tests/test_core.sh | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 428068f..b8cb8c2 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -45,16 +45,9 @@ fi JUJU_REPO=https://bitbucket.org/fsquillace/juju-repo/raw/master ORIGIN_WD=$(pwd) -# The essentials executables that MUST exist in the host OS are (wget|curl), bash, mkdir -if command -v wget > /dev/null 2>&1 -then - WGET="wget --no-check-certificate" -elif command -v curl > /dev/null 2>&1 -then - WGET="curl -J -O -k" -else - die "Error: Either wget or curl commands must be installed" -fi +WGET="wget --no-check-certificate" +CURL="curl -J -O -k" + TAR=tar HOST_ARCH=$(uname -m) @@ -87,6 +80,11 @@ ID="${JUJU_HOME}/usr/bin/id -u" ################################# MAIN FUNCTIONS ############################## +function download(){ + $WGET $1 || $CURL $1 || \ + die "Error: Both wget and curl commands have failed on downloading $1" +} + function is_juju_installed(){ [ -d "$JUJU_HOME" ] && [ "$(ls -A $JUJU_HOME)" ] && return 0 return 1 @@ -130,7 +128,7 @@ function setup_juju(){ info "Downloading JuJu..." builtin cd ${maindir} local imagefile=juju-${ARCH}.tar.gz - $WGET ${JUJU_REPO}/${imagefile} + download ${JUJU_REPO}/${imagefile} info "Installing JuJu..." _setup_juju ${maindir}/${imagefile} @@ -265,25 +263,25 @@ function build_image_juju(){ mkdir -p ${maindir}/packages/{package-query,yaourt,proot} builtin cd ${maindir}/packages/package-query - $WGET https://aur.archlinux.org/packages/pa/package-query/PKGBUILD + download https://aur.archlinux.org/packages/pa/package-query/PKGBUILD makepkg -sfc --asroot pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz builtin cd ${maindir}/packages/yaourt - $WGET https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD + download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD makepkg -sfc --asroot pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz info "Compiling and installing proot..." builtin cd ${maindir}/packages/proot - $WGET https://aur.archlinux.org/packages/pr/proot/PKGBUILD + download https://aur.archlinux.org/packages/pr/proot/PKGBUILD makepkg -sfcA --asroot pacman --noconfirm --root ${maindir}/root -U proot*.pkg.tar.xz info "Installing compatibility binary proot" mkdir -p ${maindir}/root/opt/proot builtin cd ${maindir}/root/opt/proot - $WGET $PROOT_LINK + download $PROOT_LINK chmod +x proot-$ARCH info "Copying JuJu scripts..." @@ -295,10 +293,10 @@ function build_image_juju(){ pacman --root ${maindir}/root --noconfirm -Rsn psmisc info "Validating JuJu image..." - arch-chroot ${maindir}/root pacman -Qi pacman &> /dev/null - arch-chroot ${maindir}/root yaourt -V &> /dev/null - arch-chroot ${maindir}/root proot --help &> /dev/null - arch-chroot ${maindir}/root arch-chroot --help &> /dev/null + arch-chroot ${maindir}/root pacman -Qi pacman 1> /dev/null + arch-chroot ${maindir}/root yaourt -V 1> /dev/null + arch-chroot ${maindir}/root proot --help 1> /dev/null + arch-chroot ${maindir}/root arch-chroot --help 1> /dev/null rm ${maindir}/root/var/cache/pacman/pkg/* diff --git a/tests/test_core.sh b/tests/test_core.sh index ff1dec5..2320ce5 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -30,6 +30,7 @@ function tear_down(){ trap - QUIT EXIT ABRT KILL TERM INT } + function test_is_juju_installed(){ is_juju_installed is_equal $? 1 || return 1 @@ -39,6 +40,25 @@ function test_is_juju_installed(){ } +function test_download(){ + WGET=/bin/true + CURL=/bin/false + download + is_equal $? 0 || return 1 + WGET=/bin/false + CURL=/bin/true + download + is_equal $? 0 || return 1 + + export -f download + export -f die + WGET=/bin/false CURL=/bin/false bash -ic "download something" 2> /dev/null + is_equal $? 1 || return 1 + export -n die + export -n download +} + + function test_setup_juju(){ wget_mock(){ # Proof that the setup is happening From 4cf8cadd20f4f658c751a68add1e5f63d755b2d7 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 6 Jan 2015 00:16:12 +0100 Subject: [PATCH 044/326] Fix issue #42 --- lib/core.sh | 19 +++---------------- tests/test_core.sh | 19 +++++-------------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index b8cb8c2..28a31d7 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -68,10 +68,7 @@ else die "Unknown architecture ${ARCH}" fi -PROOT_BIN="${JUJU_HOME}/usr/bin/proot" -PROOT_COMPAT_BIN="${JUJU_HOME}/opt/proot/proot-${ARCH}" -PROOT="$LD_LIB --library-path ${JUJU_HOME}/usr/lib:${JUJU_HOME}/lib ${PROOT_BIN}" -PROOT_COMPAT="${PROOT_COMPAT_BIN}" +PROOT_COMPAT="${JUJU_HOME}/opt/proot/proot-${ARCH}" PROOT_LINK=http://static.proot.me/proot-${ARCH} SH="/bin/sh --login" @@ -183,13 +180,9 @@ function _run_juju_with_proot(){ [ "$(${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - if ! _run_proot ${PROOT} ${@} + if ! _run_proot ${PROOT_COMPAT} ${@} then - warn "Proot error: Trying to execute proot compatible binary..." - if ! _run_proot ${PROOT_COMPAT} ${@} - then - die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" - fi + die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" fi } @@ -272,12 +265,6 @@ function build_image_juju(){ makepkg -sfc --asroot pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz - info "Compiling and installing proot..." - builtin cd ${maindir}/packages/proot - download https://aur.archlinux.org/packages/pr/proot/PKGBUILD - makepkg -sfcA --asroot - pacman --noconfirm --root ${maindir}/root -U proot*.pkg.tar.xz - info "Installing compatibility binary proot" mkdir -p ${maindir}/root/opt/proot builtin cd ${maindir}/root/opt/proot diff --git a/tests/test_core.sh b/tests/test_core.sh index 2320ce5..5d2e1a2 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -112,13 +112,13 @@ function test_run_juju_as_root(){ function test_run_juju_as_user(){ install_mini_juju - local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir -v /newdir2" 2> /dev/null | awk -F: '{print $1}') + local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir2 ] is_equal $? 0 || return 1 SH="/usr/bin/mkdir -v /newdir" - local output=$(run_juju_as_user "-k 3.10" 2> /dev/null | awk -F: '{print $1}') + local output=$(run_juju_as_user "-k 3.10" | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir ] is_equal $? 0 || return 1 @@ -138,7 +138,6 @@ function test_run_juju_as_user_proot_args(){ export -f _run_proot export -f warn export -f die - export PROOT export PROOT_COMPAT ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 @@ -146,18 +145,10 @@ function test_run_juju_as_user_proot_args(){ export -n _run_proot export -n warn export -n die - export -n PROOT export -n PROOT_COMPAT } -function test_run_juju_with_proot_with_compat(){ - install_mini_juju - PROOT="/bin/true" - PROOT_COMPAT="/bin/false" - _run_juju_with_proot "" "" &> /dev/null - is_equal $? 0 || return 1 - - PROOT="/bin/false" +function test_run_juju_with_proot_compat(){ PROOT_COMPAT="/bin/true" _run_juju_with_proot "" "" &> /dev/null is_equal $? 0 || return 1 @@ -166,7 +157,7 @@ function test_run_juju_with_proot_with_compat(){ export -f _run_proot export -f warn export -f die - PROOT="/bin/false" PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -195,7 +186,7 @@ function test_run_proot_seccomp(){ function test_run_juju_as_fakeroot(){ install_mini_juju - local output=$(run_juju_as_fakeroot "-k 3.10" "id" 2> /dev/null | awk '{print $1}') + local output=$(run_juju_as_fakeroot "-k 3.10" "id" | awk '{print $1}') is_equal "$output" "uid=0(root)" || return 1 } From b4dfd798199228928a970fbe34b006f4b8701e75 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 8 Jan 2015 00:45:41 +0100 Subject: [PATCH 045/326] Fix issue #45 --- bin/juju | 2 +- tests/test_juju.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/juju b/bin/juju index 83eef6a..80ea83c 100755 --- a/bin/juju +++ b/bin/juju @@ -178,7 +178,7 @@ function execute_operation(){ fi } -parse_arguments $@ +parse_arguments "$@" check_cli execute_operation # vim: set ts=4 sw=4 noet: diff --git a/tests/test_juju.sh b/tests/test_juju.sh index 38806f7..58d641a 100755 --- a/tests/test_juju.sh +++ b/tests/test_juju.sh @@ -34,7 +34,7 @@ function run_juju_as_user(){ } function wrap_juju(){ - parse_arguments $@ + parse_arguments "$@" check_cli execute_operation } From 91832ba2b86709e36cd9d96ff67d485fd619752a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 6 Jan 2015 00:52:39 +0100 Subject: [PATCH 046/326] Refactor _run_proot function --- lib/core.sh | 8 ++++---- tests/test_core.sh | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 28a31d7..b269d3d 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -168,19 +168,19 @@ function run_juju_as_root(){ } function _run_proot(){ - if ! JUJU_ENV=1 ${@} + if ! JUJU_ENV=1 ${PROOT_COMPAT} ${@} then warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." - JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${@} + JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${@} fi } function _run_juju_with_proot(){ - [ "$(${ID} 2> /dev/null )" == "0" ] && \ + [ "$(_run_proot ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - if ! _run_proot ${PROOT_COMPAT} ${@} + if ! _run_proot ${@} then die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" fi diff --git a/tests/test_core.sh b/tests/test_core.sh index 5d2e1a2..7ea32d5 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -174,13 +174,15 @@ function test_run_juju_with_proot_as_root(){ } function test_run_proot_seccomp(){ - local output=$(_run_proot "env" | grep "^PROOT_NO_SECCOMP") + PROOT_COMPAT=env + local output=$(_run_proot | grep "^PROOT_NO_SECCOMP") is_equal $output "" || return 1 envv(){ env | grep "^PROOT_NO_SECCOMP" } - local output=$(_run_proot "envv" 2> /dev/null | grep "^PROOT_NO_SECCOMP") + PROOT_COMPAT=envv + local output=$(_run_proot 2> /dev/null | grep "^PROOT_NO_SECCOMP") is_equal $output "PROOT_NO_SECCOMP=1" || return 1 } From ccb4fa63258522fcf6a3ccf3e6fd60533db78cea Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 6 Jan 2015 01:16:52 +0100 Subject: [PATCH 047/326] Fix issue #43 --- lib/core.sh | 34 +++++++++++++++++----------------- tests/test_core.sh | 1 + 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index b269d3d..1bf38b0 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -73,6 +73,7 @@ PROOT_LINK=http://static.proot.me/proot-${ARCH} SH="/bin/sh --login" CHROOT=${JUJU_HOME}/usr/bin/arch-chroot +TRUE=${JUJU_HOME}/usr/bin/true ID="${JUJU_HOME}/usr/bin/id -u" ################################# MAIN FUNCTIONS ############################## @@ -154,24 +155,22 @@ function _define_chroot_args(){ } -function _define_proot_args(){ - local proot_args="$1" - shift - local comm=$(_define_chroot_args "$@") - echo "$proot_args" "${comm[@]}" -} - - function run_juju_as_root(){ mkdir -p ${JUJU_HOME}/${HOME} JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" } function _run_proot(){ - if ! JUJU_ENV=1 ${PROOT_COMPAT} ${@} + local proot_args="$1" + if ${PROOT_COMPAT} $proot_args ${TRUE} &> /dev/null + then + JUJU_ENV=1 ${PROOT_COMPAT} ${@} + elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} &> /dev/null then warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${@} + else + die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" fi } @@ -180,22 +179,23 @@ function _run_juju_with_proot(){ [ "$(_run_proot ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - if ! _run_proot ${@} - then - die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" - fi + _run_proot "${@}" } function run_juju_as_fakeroot(){ - local comm=$(_define_proot_args "$@") - _run_juju_with_proot "-S" ${JUJU_HOME} ${comm} + local proot_args="$1" + shift + local comm=$(_define_chroot_args "$@") + _run_juju_with_proot "-S ${JUJU_HOME} ${proot_args}" ${comm} } function run_juju_as_user(){ - local comm=$(_define_proot_args "$@") - _run_juju_with_proot "-R" ${JUJU_HOME} ${comm} + local proot_args="$1" + shift + local comm=$(_define_chroot_args "$@") + _run_juju_with_proot "-R ${JUJU_HOME} $proot_args" ${comm} } diff --git a/tests/test_core.sh b/tests/test_core.sh index 7ea32d5..6dc4705 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -174,6 +174,7 @@ function test_run_juju_with_proot_as_root(){ } function test_run_proot_seccomp(){ + TRUE="" PROOT_COMPAT=env local output=$(_run_proot | grep "^PROOT_NO_SECCOMP") is_equal $output "" || return 1 From 7610e752600ea72f2145b9e91016eb2e3258b593 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 8 Jan 2015 02:04:04 +0100 Subject: [PATCH 048/326] Fix issue #46: Deprecate getopt --- README.md | 1 - bin/juju | 9 ++++----- tests/test_juju.sh | 34 +++++++++++++++++++--------------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 1f71b8c..7bba017 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,6 @@ of GNU/Linux distributions. The needed executables in the host OS are: - bash - wget or curl - tar -- getopt - id - mkdir diff --git a/bin/juju b/bin/juju index 80ea83c..065fd04 100755 --- a/bin/juju +++ b/bin/juju @@ -112,9 +112,6 @@ check_cli(){ function parse_arguments(){ - TEMP=$(getopt -o drp:fbi:hv --long delete,root,proot-args:,fakeroot,build-image,setup-from-file:,help,version -n "$CMD" -- "$@") - eval set -- "$TEMP" - OPT_SETUP_FROM_FILE=false IMAGE_FILE="" OPT_FAKEROOT=false @@ -125,7 +122,8 @@ function parse_arguments(){ OPT_DELETE=false OPT_HELP=false OPT_VERSION=false - while true ; do + for opt in $@ + do case "$1" in -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; @@ -136,7 +134,8 @@ function parse_arguments(){ -h|--help) OPT_HELP=true ; shift ;; -v|--version) OPT_VERSION=true ; shift ;; --) shift ; break ;; - *) die "Internal error!" ;; + -*) die "Invalid option $1" ;; + *) break ;; esac done diff --git a/tests/test_juju.sh b/tests/test_juju.sh index 58d641a..0c2e748 100755 --- a/tests/test_juju.sh +++ b/tests/test_juju.sh @@ -24,13 +24,17 @@ function setup_juju(){ echo "setup_juju" } function run_juju_as_fakeroot(){ - echo "run_juju_as_fakeroot $@" + local proot_args="$1" + shift + echo "run_juju_as_fakeroot($proot_args,$@)" } function run_juju_as_root(){ echo "run_juju_as_root $@" } function run_juju_as_user(){ - echo "run_juju_as_user $@" + local proot_args="$1" + shift + echo "run_juju_as_user($proot_args,$@)" } function wrap_juju(){ @@ -75,27 +79,27 @@ function test_delete_juju(){ } function test_run_juju_as_fakeroot(){ local output=$(wrap_juju -f) - is_equal $output "run_juju_as_fakeroot" || return 1 + is_equal $output "run_juju_as_fakeroot(,)" || return 1 local output=$(wrap_juju --fakeroot) - is_equal $output "run_juju_as_fakeroot" || return 1 + is_equal $output "run_juju_as_fakeroot(,)" || return 1 local output=$(wrap_juju -f -p "-b arg") - is_equal "${output[@]}" "run_juju_as_fakeroot -b arg" || return 1 - local output=$(wrap_juju -f -p "-b arg" -- command) - is_equal "${output[@]}" "run_juju_as_fakeroot -b arg command" || return 1 - local output=$(wrap_juju -f command) - is_equal "${output[@]}" "run_juju_as_fakeroot command" || return 1 + is_equal "${output[@]}" "run_juju_as_fakeroot(-b arg,)" || return 1 + local output=$(wrap_juju -f -p "-b arg" -- command -kv) + is_equal "${output[@]}" "run_juju_as_fakeroot(-b arg,command -kv)" || return 1 + local output=$(wrap_juju -f command --as) + is_equal "${output[@]}" "run_juju_as_fakeroot(,command --as)" || return 1 } function test_run_juju_as_user(){ local output=$(wrap_juju) - is_equal $output "run_juju_as_user" || return 1 + is_equal $output "run_juju_as_user(,)" || return 1 local output=$(wrap_juju -p "-b arg") - is_equal "${output[@]}" "run_juju_as_user -b arg" || return 1 - local output=$(wrap_juju -p "-b arg" -- command) - is_equal "${output[@]}" "run_juju_as_user -b arg command" || return 1 - local output=$(wrap_juju command) - is_equal "${output[@]}" "run_juju_as_user command" || return 1 + is_equal "${output[@]}" "run_juju_as_user(-b arg,)" || return 1 + local output=$(wrap_juju -p "-b arg" -- command -ll) + is_equal "${output[@]}" "run_juju_as_user(-b arg,command -ll)" || return 1 + local output=$(wrap_juju command -ls) + is_equal "${output[@]}" "run_juju_as_user(,command -ls)" || return 1 } function test_run_juju_as_root(){ local output=$(wrap_juju -r) From 80333679884166941f0436481af8d7f30cd42411 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 9 Jan 2015 20:33:02 +0100 Subject: [PATCH 049/326] Fix issue #49: Adapt image with the new pacman version --- lib/core.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 1bf38b0..e7bfee7 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -236,11 +236,13 @@ function build_image_juju(){ # base-devel # package-query # git +# sudo _check_package arch-install-scripts _check_package gcc _check_package package-query _check_package git - local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) + _check_package sudo + local maindir=$(TMPDIR=$JUJU_TEMPDIR sudo -u $SUDO_USER mktemp -d -t juju.XXXXXXXXXX) mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." @@ -253,16 +255,16 @@ function build_image_juju(){ echo 'LANG = "en_US.UTF-8"' >> ${maindir}/root/etc/locale.conf info "Compiling and installing yaourt..." - mkdir -p ${maindir}/packages/{package-query,yaourt,proot} + sudo -u $SUDO_USER mkdir -p ${maindir}/packages/{package-query,yaourt} builtin cd ${maindir}/packages/package-query download https://aur.archlinux.org/packages/pa/package-query/PKGBUILD - makepkg -sfc --asroot + sudo -u $SUDO_USER makepkg -sfc pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz builtin cd ${maindir}/packages/yaourt download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD - makepkg -sfc --asroot + sudo -u $SUDO_USER makepkg -sfc pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz info "Installing compatibility binary proot" @@ -275,14 +277,12 @@ function build_image_juju(){ git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju info "Setting up the pacman keyring (this might take a while!)..." - pacman --root ${maindir}/root --noconfirm -S psmisc - arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux; killall gpg-agent" - pacman --root ${maindir}/root --noconfirm -Rsn psmisc + arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" info "Validating JuJu image..." arch-chroot ${maindir}/root pacman -Qi pacman 1> /dev/null arch-chroot ${maindir}/root yaourt -V 1> /dev/null - arch-chroot ${maindir}/root proot --help 1> /dev/null + arch-chroot ${maindir}/root /opt/proot/proot-$ARCH --help 1> /dev/null arch-chroot ${maindir}/root arch-chroot --help 1> /dev/null rm ${maindir}/root/var/cache/pacman/pkg/* From 01bf1738a691ce4f5ab4d720aec47c7a1c0adfb3 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 10 Jan 2015 21:37:31 +0100 Subject: [PATCH 050/326] Fix issue #49: Optimize image and docs - Remove sed command from the image - Use proot for faking the user on compiling of packages - Add link to README for pacman rosetta --- README.md | 3 +++ lib/core.sh | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 7bba017..0c06d0e 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,9 @@ The first time you execute it, the script will download the JuJu image and place to the default directory ~/.juju. You can change the default directory by changing the environment variable *JUJU\_HOME*. +If you are new on Archlinux and you are not familiar with *pacman* package manager +visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). + Installation ------------ Just clone JuJu somewhere (for example in ~/juju): diff --git a/lib/core.sh b/lib/core.sh index e7bfee7..6bf6644 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -236,36 +236,24 @@ function build_image_juju(){ # base-devel # package-query # git -# sudo _check_package arch-install-scripts _check_package gcc _check_package package-query _check_package git - _check_package sudo - local maindir=$(TMPDIR=$JUJU_TEMPDIR sudo -u $SUDO_USER mktemp -d -t juju.XXXXXXXXXX) + local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) mkdir -p ${maindir}/root _prepare_build_directory info "Installing pacman and its dependencies..." - pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano sed + pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano info "Generating the locales..." + # sed command is required for locale-gen + pacman --noconfirm --root ${maindir}/root -S sed ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime echo "en_US.UTF-8 UTF-8" >> ${maindir}/root/etc/locale.gen arch-chroot ${maindir}/root locale-gen echo 'LANG = "en_US.UTF-8"' >> ${maindir}/root/etc/locale.conf - - info "Compiling and installing yaourt..." - sudo -u $SUDO_USER mkdir -p ${maindir}/packages/{package-query,yaourt} - - builtin cd ${maindir}/packages/package-query - download https://aur.archlinux.org/packages/pa/package-query/PKGBUILD - sudo -u $SUDO_USER makepkg -sfc - pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz - - builtin cd ${maindir}/packages/yaourt - download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD - sudo -u $SUDO_USER makepkg -sfc - pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz + pacman --noconfirm --root ${maindir}/root -Rsn sed info "Installing compatibility binary proot" mkdir -p ${maindir}/root/opt/proot @@ -273,6 +261,20 @@ function build_image_juju(){ download $PROOT_LINK chmod +x proot-$ARCH + # AUR packages requires non-root user to be compiled. proot fakes the user to 10 + info "Compiling and installing yaourt..." + mkdir -p ${maindir}/packages/{package-query,yaourt} + + builtin cd ${maindir}/packages/package-query + download https://aur.archlinux.org/packages/pa/package-query/PKGBUILD + ${maindir}/root/opt/proot/proot-$ARCH -i 10 makepkg -sfc + pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz + + builtin cd ${maindir}/packages/yaourt + download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD + ${maindir}/root/opt/proot/proot-$ARCH -i 10 makepkg -sfc + pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz + info "Copying JuJu scripts..." git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju From 740824c8929bf766bfbfaa94d717520b78f31169 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 11 Jan 2015 02:11:20 +0100 Subject: [PATCH 051/326] Fix issue #51: Enable curl redirection --- lib/core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 6bf6644..2272311 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -46,7 +46,7 @@ JUJU_REPO=https://bitbucket.org/fsquillace/juju-repo/raw/master ORIGIN_WD=$(pwd) WGET="wget --no-check-certificate" -CURL="curl -J -O -k" +CURL="curl -L -J -O -k" TAR=tar From aa76e6cff56116b73f694dca245f2ce1d1f934b1 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 12 Jan 2015 23:18:05 +0100 Subject: [PATCH 052/326] Wrap the tar into a variable --- lib/core.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 2272311..cf4a8d7 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -108,7 +108,7 @@ function _setup_juju(){ is_juju_installed && die "Error: JuJu has been already installed in $JUJU_HOME" mkdir -p "${JUJU_HOME}" imagepath=$1 - tar -zxpf ${imagepath} -C ${JUJU_HOME} + $TAR -zxpf ${imagepath} -C ${JUJU_HOME} mkdir -p ${JUJU_HOME}/run/lock warn "Warn: Change the mirrorlist file according to your location:" info " nano /etc/pacman.d/mirrorlist" @@ -292,6 +292,6 @@ function build_image_juju(){ builtin cd ${ORIGIN_WD} local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." - tar -zcpf ${imagefile} -C ${maindir}/root . + $TAR -zcpf ${imagefile} -C ${maindir}/root . _cleanup_build_directory ${maindir} } From cf9eaed98baa47160311932b6b913d4b6c0a6127 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 13 Jan 2015 01:45:16 +0100 Subject: [PATCH 053/326] Fix issue #52: Add new installation method in README --- README.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0c06d0e..e99bc2c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The main advantages on using JuJu are: - Install packages without root privileges. - Isolated environment in which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain a limited repositories (such as CentOS and RedHat). -- Available for x86\_64, i686 and ARMv6 architectures but you can build you own image from scratch too! +- Available for x86\_64, x86 and ARM architectures but you can build you own image from scratch too! - All ArchLinux lovers can have their favourite distro everywhere! Quickstart @@ -36,8 +36,8 @@ $ juju -f # juju -r ``` -The first time you execute it, the script will download the JuJu image and place it -to the default directory ~/.juju. +If the JuJu image has not been downloaded yet, the script will download +the JuJu image and will place it to the default directory ~/.juju. You can change the default directory by changing the environment variable *JUJU\_HOME*. If you are new on Archlinux and you are not familiar with *pacman* package manager @@ -45,13 +45,20 @@ visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rose Installation ------------ -Just clone JuJu somewhere (for example in ~/juju): +Just clone the JuJu repo somewhere (for example in ~/juju): $ git clone git://github.com/fsquillace/juju ~/juju $ export PATH=~/juju/bin:$PATH +Alternatively, another installation method would be to directly download the JuJu image and place it to the default directory ~/.juju: + + $ ARCH= + $ mkdir ~/.juju + $ curl https://bitbucket.org/fsquillace/juju-repo/raw/master/juju-${ARCH}.tar.gz | tar -xz -C ~/.juju + $ export PATH=~/.juju/opt/juju/bin:$PATH + JuJu can works on GNU/Linux OS with kernel version greater or equal -2.6.0 (JuJu was not tested on kernel versions older than this) on 64 bit 32 bit and ARMv6 architectures. +2.6.0 (JuJu was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. Advanced usage -------------- From 58e6143db0b6c0f7e499e3f279a5732048b5c65a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 15 Jan 2015 01:10:48 +0100 Subject: [PATCH 054/326] Fix issue #49: Change the permission to build the image and adapt for arm architecture --- lib/core.sh | 63 +++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index cf4a8d7..061beaf 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -230,36 +230,36 @@ function _check_package(){ function build_image_juju(){ -# The function must runs on ArchLinux -# The dependencies are: -# arch-install-scripts -# base-devel -# package-query -# git +# The function must runs on ArchLinux with non-root privileges. + [ "$(id -u)" == "0" ] && \ + die "You cannot build with root privileges." + _check_package arch-install-scripts _check_package gcc _check_package package-query _check_package git local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) - mkdir -p ${maindir}/root - _prepare_build_directory + sudo mkdir -p ${maindir}/root + trap - QUIT EXIT ABRT KILL TERM INT + trap "sudo rm -rf ${maindir}; die \"Error occurred when installing JuJu\"" EXIT QUIT ABRT KILL TERM INT info "Installing pacman and its dependencies..." - pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano + # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux + sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano archlinux-keyring info "Generating the locales..." # sed command is required for locale-gen - pacman --noconfirm --root ${maindir}/root -S sed - ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime - echo "en_US.UTF-8 UTF-8" >> ${maindir}/root/etc/locale.gen - arch-chroot ${maindir}/root locale-gen - echo 'LANG = "en_US.UTF-8"' >> ${maindir}/root/etc/locale.conf - pacman --noconfirm --root ${maindir}/root -Rsn sed + sudo pacman --noconfirm --root ${maindir}/root -S sed + sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime + sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" + sudo arch-chroot ${maindir}/root locale-gen + sudo bash -c "echo 'LANG = \"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" + sudo pacman --noconfirm --root ${maindir}/root -Rsn sed info "Installing compatibility binary proot" - mkdir -p ${maindir}/root/opt/proot + sudo mkdir -p ${maindir}/root/opt/proot builtin cd ${maindir}/root/opt/proot - download $PROOT_LINK - chmod +x proot-$ARCH + sudo $CURL $PROOT_LINK + sudo chmod +x proot-$ARCH # AUR packages requires non-root user to be compiled. proot fakes the user to 10 info "Compiling and installing yaourt..." @@ -267,31 +267,32 @@ function build_image_juju(){ builtin cd ${maindir}/packages/package-query download https://aur.archlinux.org/packages/pa/package-query/PKGBUILD - ${maindir}/root/opt/proot/proot-$ARCH -i 10 makepkg -sfc - pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz + makepkg -sfc + sudo pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz builtin cd ${maindir}/packages/yaourt download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD - ${maindir}/root/opt/proot/proot-$ARCH -i 10 makepkg -sfc - pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz + makepkg -sfc + sudo pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz info "Copying JuJu scripts..." - git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju + sudo git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju info "Setting up the pacman keyring (this might take a while!)..." - arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" + sudo arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" info "Validating JuJu image..." - arch-chroot ${maindir}/root pacman -Qi pacman 1> /dev/null - arch-chroot ${maindir}/root yaourt -V 1> /dev/null - arch-chroot ${maindir}/root /opt/proot/proot-$ARCH --help 1> /dev/null - arch-chroot ${maindir}/root arch-chroot --help 1> /dev/null + sudo arch-chroot ${maindir}/root pacman -Qi pacman 1> /dev/null + sudo arch-chroot ${maindir}/root yaourt -V 1> /dev/null + sudo arch-chroot ${maindir}/root /opt/proot/proot-$ARCH --help 1> /dev/null + sudo arch-chroot ${maindir}/root arch-chroot --help 1> /dev/null - rm ${maindir}/root/var/cache/pacman/pkg/* + sudo rm ${maindir}/root/var/cache/pacman/pkg/* builtin cd ${ORIGIN_WD} local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." - $TAR -zcpf ${imagefile} -C ${maindir}/root . - _cleanup_build_directory ${maindir} + sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . + trap - QUIT EXIT ABRT KILL TERM INT + sudo rm -fr "$maindir" } From 239230ebf37b6dd13ed26d8317825cb9ef259bc4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 15 Jan 2015 23:29:34 +0100 Subject: [PATCH 055/326] Update the version to 3.6.9 (Snake) --- bin/juju | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/juju b/bin/juju index 065fd04..903ca8f 100755 --- a/bin/juju +++ b/bin/juju @@ -20,8 +20,8 @@ NAME='JuJu' CMD='juju' -VERSION='2.5.6' -CODE_NAME='Lion' +VERSION='3.6.9' +CODE_NAME='Snake' DESCRIPTION='The GNU/Linux distribution container for non-root users' AUTHOR='Filippo Squillace ' HOMEPAGE='https://github.com/fsquillace/juju' From ca3be673a420581f2baae7fcf825553e3588a7ec Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 17 Jan 2015 19:14:12 +0100 Subject: [PATCH 056/326] Fix issue #54: tests and the check for root access to proot --- lib/core.sh | 2 +- tests/test_core.sh | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 061beaf..e6a5481 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -176,7 +176,7 @@ function _run_proot(){ function _run_juju_with_proot(){ - [ "$(_run_proot ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(_run_proot "" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." _run_proot "${@}" diff --git a/tests/test_core.sh b/tests/test_core.sh index 6dc4705..035e9f9 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -24,6 +24,8 @@ function set_up(){ function tear_down(){ + # the CA directories are read only and can be deleted only by changing the mod + [ -d ${JUJU_HOME}/etc/ca-certificates ] && chmod -R +w ${JUJU_HOME}/etc/ca-certificates rm -rf $JUJU_HOME rm -rf $ORIGIN_WD rm -rf $JUJU_TEMPDIR From fd4c8ae02e43a9823b94d4910ca3bfa72e25d7ad Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 18 Jan 2015 13:54:49 +0100 Subject: [PATCH 057/326] Fix test for running proot as root --- tests/test_core.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_core.sh b/tests/test_core.sh index 035e9f9..8696b95 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -168,9 +168,14 @@ function test_run_juju_with_proot_compat(){ } function test_run_juju_with_proot_as_root(){ + install_mini_juju export -f _run_juju_with_proot + export TRUE + export PROOT_COMPAT ID="/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null is_equal $? 1 || return 1 + export -n TRUE + export -n PROOT_COMPAT export -n _run_juju_with_proot unset _run_juju_with_proot } From 3283c59e94378745b3884c93da9d03e810e32e58 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 19 Jan 2015 01:08:17 +0100 Subject: [PATCH 058/326] Issue #49: Fix yaourt and makepkg by applying patches --- lib/core.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index e6a5481..cecde49 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -244,16 +244,15 @@ function build_image_juju(){ trap "sudo rm -rf ${maindir}; die \"Error occurred when installing JuJu\"" EXIT QUIT ABRT KILL TERM INT info "Installing pacman and its dependencies..." # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux - sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano archlinux-keyring + # yaourt requires sed + sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano archlinux-keyring sed info "Generating the locales..." # sed command is required for locale-gen - sudo pacman --noconfirm --root ${maindir}/root -S sed sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" sudo arch-chroot ${maindir}/root locale-gen sudo bash -c "echo 'LANG = \"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" - sudo pacman --noconfirm --root ${maindir}/root -Rsn sed info "Installing compatibility binary proot" sudo mkdir -p ${maindir}/root/opt/proot @@ -274,6 +273,14 @@ function build_image_juju(){ download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD makepkg -sfc sudo pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz + # Apply patches for yaourt and makepkg + sudo mkdir -p ${maindir}/root/opt/yaourt/bin/ + sudo cp ${maindir}/root/usr/bin/yaourt ${maindir}/root/opt/yaourt/bin/ + sudo sed -i -e 's/"--asroot"//' ${maindir}/root/opt/yaourt/bin/yaourt + sudo cp ${maindir}/root/usr/bin/makepkg ${maindir}/root/opt/yaourt/bin/ + sudo sed -i -e 's/EUID\s==\s0/false/' ${maindir}/root/opt/yaourt/bin/makepkg + sudo bash -c "echo 'export PATH=/opt/yaourt/bin:$PATH' > ${maindir}/root/etc/profile.d/juju.sh" + sudo chmod +x ${maindir}/root/etc/profile.d/juju.sh info "Copying JuJu scripts..." sudo git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju From 30d8931ec545ac992b2eeb9755e865b2aae70a35 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 25 Jan 2015 20:41:39 +0100 Subject: [PATCH 059/326] Issue #56: Fix arguments --- bin/juju | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/juju b/bin/juju index 903ca8f..8573445 100755 --- a/bin/juju +++ b/bin/juju @@ -122,7 +122,7 @@ function parse_arguments(){ OPT_DELETE=false OPT_HELP=false OPT_VERSION=false - for opt in $@ + for opt in "$@" do case "$1" in -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; @@ -140,8 +140,9 @@ function parse_arguments(){ done ARGS=() - for arg do - ARGS+=($arg) + for arg in "$@" + do + ARGS+=("$arg") done } @@ -169,11 +170,11 @@ function execute_operation(){ fi if $OPT_FAKEROOT; then - run_juju_as_fakeroot "${PROOT_ARGS}" ${ARGS[@]} + run_juju_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" elif $OPT_ROOT; then - run_juju_as_root ${ARGS[@]} + run_juju_as_root "${ARGS[@]}" else - run_juju_as_user "${PROOT_ARGS}" ${ARGS[@]} + run_juju_as_user "${PROOT_ARGS}" "${ARGS[@]}" fi } From 30f630973d1f57af529217314316df9b4355c8b4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 27 Jan 2015 00:44:41 +0100 Subject: [PATCH 060/326] Issue #56: Allow quotes on command passed to CLI --- lib/core.sh | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index cecde49..30af5e1 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -71,7 +71,7 @@ fi PROOT_COMPAT="${JUJU_HOME}/opt/proot/proot-${ARCH}" PROOT_LINK=http://static.proot.me/proot-${ARCH} -SH="/bin/sh --login" +SH=("/bin/sh" "--login") CHROOT=${JUJU_HOME}/usr/bin/arch-chroot TRUE=${JUJU_HOME}/usr/bin/true ID="${JUJU_HOME}/usr/bin/id -u" @@ -149,7 +149,7 @@ function setup_from_file_juju(){ function _define_chroot_args(){ - local comm=${SH} + local comm=${SH[@]} [ "$1" != "" ] && comm="$@" echo $comm } @@ -162,13 +162,14 @@ function run_juju_as_root(){ function _run_proot(){ local proot_args="$1" + shift if ${PROOT_COMPAT} $proot_args ${TRUE} &> /dev/null then - JUJU_ENV=1 ${PROOT_COMPAT} ${@} + JUJU_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} &> /dev/null then warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." - JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${@} + JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" else die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" fi @@ -176,26 +177,33 @@ function _run_proot(){ function _run_juju_with_proot(){ - [ "$(_run_proot "" ${ID} 2> /dev/null )" == "0" ] && \ - die "You cannot access with root privileges. Use --root option instead." + local proot_args="$1" + shift - _run_proot "${@}" + if [ "$1" != "" ] + then + _run_proot "${proot_args}" "${@}" + else + _run_proot "${proot_args}" "${SH[@]}" + fi } function run_juju_as_fakeroot(){ local proot_args="$1" shift - local comm=$(_define_chroot_args "$@") - _run_juju_with_proot "-S ${JUJU_HOME} ${proot_args}" ${comm} + [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + die "You cannot access with root privileges. Use --root option instead." + _run_juju_with_proot "-S ${JUJU_HOME} $proot_args" "${@}" } function run_juju_as_user(){ local proot_args="$1" shift - local comm=$(_define_chroot_args "$@") - _run_juju_with_proot "-R ${JUJU_HOME} $proot_args" ${comm} + [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + die "You cannot access with root privileges. Use --root option instead." + _run_juju_with_proot "-R ${JUJU_HOME} $proot_args" "${@}" } From e82cc672f64239e59c28df749863fdfae452f0bd Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 27 Jan 2015 01:03:51 +0100 Subject: [PATCH 061/326] Issue #56: Fix tests --- tests/test_core.sh | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index 8696b95..6421d09 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -114,18 +114,26 @@ function test_run_juju_as_root(){ function test_run_juju_as_user(){ install_mini_juju - local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') + local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir2 ] is_equal $? 0 || return 1 - SH="/usr/bin/mkdir -v /newdir" + SH=("/usr/bin/mkdir" "-v" "/newdir") local output=$(run_juju_as_user "-k 3.10" | awk -F: '{print $1}') is_equal "$output" "/usr/bin/mkdir" || return 1 [ -e $JUJU_HOME/newdir ] is_equal $? 0 || return 1 } +function test_run_juju_with_quotes(){ + install_mini_juju + local output=$(run_juju_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') + is_equal "$output" "/usr/bin/mkdir" || return 1 + [ -e $JUJU_HOME/newdir2 ] + is_equal $? 0 || return 1 +} + function test_run_juju_as_user_proot_args(){ install_mini_juju run_juju_as_user "--help" "" &> /dev/null @@ -133,7 +141,7 @@ function test_run_juju_as_user_proot_args(){ mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile - run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls -l /newdir/newfile" &> /dev/null + run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null is_equal $? 0 || return 1 export -f _run_juju_with_proot @@ -141,7 +149,7 @@ function test_run_juju_as_user_proot_args(){ export -f warn export -f die export PROOT_COMPAT - ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -159,7 +167,7 @@ function test_run_juju_with_proot_compat(){ export -f _run_proot export -f warn export -f die - PROOT_COMPAT="/bin/false" ID="/bin/echo 1" bash -ic "_run_juju_with_proot --helps" &> /dev/null + PROOT_COMPAT="/bin/false" bash -ic "_run_juju_with_proot --helps" &> /dev/null is_equal $? 1 || return 1 export -n _run_juju_with_proot export -n _run_proot @@ -169,15 +177,23 @@ function test_run_juju_with_proot_compat(){ function test_run_juju_with_proot_as_root(){ install_mini_juju - export -f _run_juju_with_proot + export -f _run_proot + export -f run_juju_as_user + export -f run_juju_as_fakeroot export TRUE export PROOT_COMPAT - ID="/bin/echo 0" bash -ic "_run_juju_with_proot" &> /dev/null + ID="/bin/echo 0" bash -ic "run_juju_as_user" &> /dev/null + is_equal $? 1 || return 1 + ID="/bin/echo 0" bash -ic "run_juju_as_fakeroot" &> /dev/null is_equal $? 1 || return 1 export -n TRUE export -n PROOT_COMPAT - export -n _run_juju_with_proot - unset _run_juju_with_proot + export -n _run_proot + export -n run_juju_as_user + export -n run_juju_as_fakeroot + unset _run_proot + unset run_juju_as_user + unset run_juju_as_fakeroot } function test_run_proot_seccomp(){ From 41a6236313082fbe4ab48ad8e7f1d3d8eb4191e4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 25 Jan 2015 20:39:58 +0100 Subject: [PATCH 062/326] Issue #53: Validation test for JuJu image --- lib/core.sh | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 30af5e1..d5d9a27 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -296,18 +296,46 @@ function build_image_juju(){ info "Setting up the pacman keyring (this might take a while!)..." sudo arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" - info "Validating JuJu image..." - sudo arch-chroot ${maindir}/root pacman -Qi pacman 1> /dev/null - sudo arch-chroot ${maindir}/root yaourt -V 1> /dev/null - sudo arch-chroot ${maindir}/root /opt/proot/proot-$ARCH --help 1> /dev/null - sudo arch-chroot ${maindir}/root arch-chroot --help 1> /dev/null - sudo rm ${maindir}/root/var/cache/pacman/pkg/* - builtin cd ${ORIGIN_WD} + mkdir -p ${maindir}/output + builtin cd ${maindir}/output local imagefile="juju-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . + + info "Validating JuJu image..." + mkdir -p ${maindir}/root_test + $TAR -zxpf ${imagefile} -C ${maindir}/root_test + mkdir -p ${maindir}/root_test/run/lock + sed -i -e "s/#Server/Server/" ${maindir}/root_test/etc/pacman.d/mirrorlist + ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -Syy + + sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test pacman -Qi pacman 1> /dev/null + sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test yaourt -V 1> /dev/null + sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test /opt/proot/proot-$ARCH --help 1> /dev/null + sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test arch-chroot --help 1> /dev/null + + ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S base-devel + local yaourt_package=tcptraceroute + info "Installing ${yaourt_package} package from AUR repo using proot..." + ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test sh --login -c "yaourt --noconfirm -S ${yaourt_package}" + sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test tcptraceroute localhost + + local repo_package=sysstat + info "Installing ${repo_package} package from official repo using proot..." + ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S ${repo_package} + ${maindir}/root/opt/proot/proot-$ARCH -R ${maindir}/root_test iostat + ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test iostat + + local repo_package=iftop + info "Installing ${repo_package} package from official repo using root..." + ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S ${repo_package} + sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test iftop -t -s 5 + + sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} + + builtin cd ${ORIGIN_WD} trap - QUIT EXIT ABRT KILL TERM INT sudo rm -fr "$maindir" } From c241e2329dbb07052b532f05aa4d1db309ce855e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 30 Jan 2015 18:07:05 +0100 Subject: [PATCH 063/326] Issue #29: Changing ownership of the files at exit of chroot --- README.md | 28 ++++++++++++---------------- lib/core.sh | 32 ++++++++++++++++++++------------ tests/test_core.sh | 11 +++++++++-- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e99bc2c..7e0344f 100644 --- a/README.md +++ b/README.md @@ -98,8 +98,8 @@ of GNU/Linux distributions. The needed executables in the host OS are: - bash - wget or curl - tar -- id - mkdir +- chown (for root access only) The minimum recommended linux kernel is 2.6.0+ @@ -171,24 +171,20 @@ To quick fix this, you can just install a fonts package: pacman -S gnu-free-fonts ``` -###Missing permissions on removing a package### -- **Q**: Why I cannot remove the package I have installed? +###Differences between filesystem and package ownership### +- **Q**: Why do I get warning when I install a package using root privileges? ``` - pacman -Rsn lsof - checking dependencies... - - Packages (1): lsof-4.88-1 - - Total Removed Size: 0.21 MiB - - error: cannot remove /usr/share/licenses/lsof/LICENSE (Permission denied) - error: could not remove database entry lsof-4.88-1 + pacman -S systat + ... + warning: directory ownership differs on /usr/ + filesystem: 1000:100 package: 0:0 + ... ``` -- **A**: This is probably because you have installed the package with root -permissions. Since JuJu gives the possibility to install packages -either as root or as normal user you need to remember that and remove -the package with the right user! +- **A**: In these cases the package installation went smoothly anyway. +This should happen every time you install package with root privileges +since JuJu will try to preserve the JuJu environment by assigning ownership +of the files to the real user. ###No servers configured for repository### -**Q**: Why I cannot install packages? diff --git a/lib/core.sh b/lib/core.sh index d5d9a27..de17eaf 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -73,8 +73,9 @@ PROOT_LINK=http://static.proot.me/proot-${ARCH} SH=("/bin/sh" "--login") CHROOT=${JUJU_HOME}/usr/bin/arch-chroot -TRUE=${JUJU_HOME}/usr/bin/true -ID="${JUJU_HOME}/usr/bin/id -u" +TRUE=/usr/bin/true +ID="/usr/bin/id -u" +CHOWN="/usr/bin/chown" ################################# MAIN FUNCTIONS ############################## @@ -148,16 +149,23 @@ function setup_from_file_juju(){ } -function _define_chroot_args(){ - local comm=${SH[@]} - [ "$1" != "" ] && comm="$@" - echo $comm -} - - function run_juju_as_root(){ - mkdir -p ${JUJU_HOME}/${HOME} - JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "mkdir -p /run/lock && $(_define_chroot_args "$@")" + local main_cmd="${SH[@]}" + [ "$1" != "" ] && main_cmd="$@" + + local uid=$UID + [ -z $SUDO_UID ] || uid=$SUDO_UID:$SUDO_GID + + local cmd=" +mkdir -p ${JUJU_HOME}/${HOME} +mkdir -p /run/lock +${main_cmd} +" + + JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "${cmd}" + + # The ownership of the files in JuJu is assigned to the real user + [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} } function _run_proot(){ @@ -239,7 +247,7 @@ function _check_package(){ function build_image_juju(){ # The function must runs on ArchLinux with non-root privileges. - [ "$(id -u)" == "0" ] && \ + [ "$(${ID})" == "0" ] && \ die "You cannot build with root privileges." _check_package arch-install-scripts diff --git a/tests/test_core.sh b/tests/test_core.sh index 6421d09..f84b17d 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -102,14 +102,21 @@ function test_setup_from_file_juju_with_absolute_path(){ function test_run_juju_as_root(){ install_mini_juju CHROOT="sudo $CHROOT" - SH="type -t type" + CHOWN="sudo $CHOWN" + SH=("type" "-t" "type") local output=$(run_juju_as_root) is_equal $output "builtin" || return 1 local output=$(run_juju_as_root pwd) is_equal $output "/" || return 1 run_juju_as_root "[ -e /run/lock ]" is_equal $? 0 || return 1 - [ -e $JUJU_HOME/${HOME} ] || return 1 + run_juju_as_root "[ -e $HOME ]" + is_equal $? 0 || return 1 + + # test that normal user has ownership of the files created by root + run_juju_as_root "touch /a_root_file" + local output=$(run_juju_as_root "stat -c '%u' /a_root_file") + is_equal $output "$UID" || return 1 } function test_run_juju_as_user(){ From ce2ad7afb177eaeffc21c8cdf95089d1c6761567 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 31 Jan 2015 13:24:37 +0100 Subject: [PATCH 064/326] Improve the README file --- README.md | 63 ++++++++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 7e0344f..049414f 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,39 @@ JuJu ==== -**JuJu**: the GNU/Linux distribution container for non-root users +**JuJu**: the Arch Linux based distro that runs upon any Linux distros without root access Description ----------- -**JuJu** is a small ArchLinux based GNU/Linux distribution. +**JuJu** is a lightweight Arch Linux based distribution. It allows to have an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. -JuJu contains just the package managers (called pacman and yaourt) that allows to access -to a wide range of packages from ArchLinux repositories. +JuJu contains mainly the package managers (called pacman and yaourt) that allows to access +to a wide range of packages from Arch Linux repositories. The main advantages on using JuJu are: - Install packages without root privileges. - Isolated environment in which you can install packages without affecting a production system. -- Access to a wide range of packages in particular on GNU/Linux distros that may contain a limited repositories (such as CentOS and RedHat). -- Available for x86\_64, x86 and ARM architectures but you can build you own image from scratch too! -- All ArchLinux lovers can have their favourite distro everywhere! +- Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). +- Available for x86\_64, x86 and ARM architectures but you can build your own image from scratch too! +- All Arch Linux lovers can have their favourite distro everywhere! Quickstart ---------- There are three different ways you can run JuJu: - As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): -``` -$ juju -``` + + juju + - As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): -``` -$ juju -f -``` + + juju -f + - As root - Allow to have fully root privileges inside JuJu environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): -``` -# juju -r -``` + + juju -r If the JuJu image has not been downloaded yet, the script will download the JuJu image and will place it to the default directory ~/.juju. @@ -47,15 +46,15 @@ Installation ------------ Just clone the JuJu repo somewhere (for example in ~/juju): - $ git clone git://github.com/fsquillace/juju ~/juju - $ export PATH=~/juju/bin:$PATH + git clone git://github.com/fsquillace/juju ~/juju + export PATH=~/juju/bin:$PATH Alternatively, another installation method would be to directly download the JuJu image and place it to the default directory ~/.juju: - $ ARCH= - $ mkdir ~/.juju - $ curl https://bitbucket.org/fsquillace/juju-repo/raw/master/juju-${ARCH}.tar.gz | tar -xz -C ~/.juju - $ export PATH=~/.juju/opt/juju/bin:$PATH + ARCH= + mkdir ~/.juju + curl https://bitbucket.org/fsquillace/juju-repo/raw/master/juju-${ARCH}.tar.gz | tar -xz -C ~/.juju + export PATH=~/.juju/opt/juju/bin:$PATH JuJu can works on GNU/Linux OS with kernel version greater or equal 2.6.0 (JuJu was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. @@ -64,32 +63,30 @@ Advanced usage -------------- ### Build image ### You can build a new JuJu image from scratch by running the following command: -``` - # juju -b -``` + + juju -b + In this way the script will create a directory containing all the essentials files in order to make JuJu working properly (such as pacman, yaourt, arch-chroot and proot). -Remember that the script to build the image must run in an ArchLinux OS with +Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. To change the build directory just use the *JUJU_TEMPDIR* (by default /tmp). After creating the image juju-x86\_64.tar.gz you can install it by running: - # juju -i juju-x86_64.tar.gz + juju -i juju-x86_64.tar.gz Related wiki page: - [How to build a JuJu image using QEMU](https://github.com/fsquillace/juju/wiki/How-to-build-a-JuJu-image-using-QEMU) ### Bind directories ### To bind and host directory to a guest location, you can use proot arguments: -``` - $ juju -p "-b /mnt/mydata:/home/user/mydata" -``` + + juju -p "-b /mnt/mydata:/home/user/mydata" Check out the proot options with: -``` - $ juju -p "--help" -``` + + juju -p "--help" Dependencies ------------ From 8c896aea8a80b9490d318f7215ea7b9d68110c7b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 1 Feb 2015 18:40:23 +0100 Subject: [PATCH 065/326] Update copyright year --- README.md | 13 ++++++------- bin/juju | 4 ++-- lib/core.sh | 4 ++-- lib/util.sh | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 049414f..1f066d4 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,12 @@ JuJu Description ----------- -**JuJu** is a lightweight Arch Linux based distribution. - -It allows to have an isolated GNU/Linux environment inside any generic host GNU/Linux OS +**JuJu** is a lightweight Arch Linux based distribution that allows to have +an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. JuJu contains mainly the package managers (called pacman and yaourt) that allows to access -to a wide range of packages from Arch Linux repositories. +to a wide range of packages from the Arch Linux repositories. The main advantages on using JuJu are: - Install packages without root privileges. @@ -80,7 +79,7 @@ Related wiki page: - [How to build a JuJu image using QEMU](https://github.com/fsquillace/juju/wiki/How-to-build-a-JuJu-image-using-QEMU) ### Bind directories ### -To bind and host directory to a guest location, you can use proot arguments: +To bind a host directory to a guest location, you can use proot arguments: juju -p "-b /mnt/mydata:/home/user/mydata" @@ -160,7 +159,7 @@ with the following command: - **Q**: Why I do not see any characters in the application I have installed? - **A**: This is probably because there are no -[https://wiki.archlinux.org/index.php/Font_Configuration](fonts) installed in +[fonts](https://wiki.archlinux.org/index.php/Font_Configuration) installed in the system. To quick fix this, you can just install a fonts package: @@ -207,7 +206,7 @@ of the files to the real user. License ------- -Copyright (c) 2012-2014 +Copyright (c) 2012-2015 This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published diff --git a/bin/juju b/bin/juju index 8573445..41a37fa 100755 --- a/bin/juju +++ b/bin/juju @@ -1,8 +1,8 @@ #!/usr/bin/env bash # -# This file is part of JuJu: The portable GNU/Linux distribution +# This file is part of JuJu (https://github.com/fsquillace/juju). # -# Copyright (c) 2012-2014 Filippo Squillace +# Copyright (c) 2012-2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published diff --git a/lib/core.sh b/lib/core.sh index de17eaf..8d070af 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # -# This file is part of JuJu: The portable GNU/Linux distribution +# This file is part of JuJu (https://github.com/fsquillace/juju). # -# Copyright (c) 2012-2014 Filippo Squillace +# Copyright (c) 2012-2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published diff --git a/lib/util.sh b/lib/util.sh index dc88506..9f411a3 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # -# This file is part of JuJu: The portable GNU/Linux distribution +# This file is part of JuJu (https://github.com/fsquillace/juju) # -# Copyright (c) 2012-2014 Filippo Squillace +# Copyright (c) 2012-2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published From 5405d4fb91362d339b797c92295750d20f93a16f Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 12 Feb 2015 01:29:31 +0100 Subject: [PATCH 066/326] Issue #61: Add disable validation option --- README.md | 9 +++++---- bin/juju | 23 +++++++++++++++++------ lib/core.sh | 21 +++++++++++++++------ tests/test_juju.sh | 2 ++ 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 1f066d4..9ba7a95 100644 --- a/README.md +++ b/README.md @@ -63,10 +63,11 @@ Advanced usage ### Build image ### You can build a new JuJu image from scratch by running the following command: - juju -b + juju -b [-n] -In this way the script will create a directory containing all the essentials +The script will create a directory containing all the essentials files in order to make JuJu working properly (such as pacman, yaourt, arch-chroot and proot). +The option `-n` will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. To change the build directory just use the *JUJU_TEMPDIR* (by default /tmp). @@ -183,7 +184,7 @@ since JuJu will try to preserve the JuJu environment by assigning ownership of the files to the real user. ###No servers configured for repository### --**Q**: Why I cannot install packages? +- **Q**: Why I cannot install packages? ``` pacman -S lsof Packages (1): lsof-4.88-2 @@ -197,7 +198,7 @@ of the files to the real user. Errors occurred, no packages were upgraded. ``` --**A**: You need simply to update the mirrorlist file according to your location: +- **A**: You need simply to update the mirrorlist file according to your location: ``` # Uncomment the repository line according to your location nano /etc/pacman.d/mirrorlist diff --git a/bin/juju b/bin/juju index 41a37fa..8ff792b 100755 --- a/bin/juju +++ b/bin/juju @@ -42,6 +42,7 @@ usage() { echo -e "-r, --root Run $NAME with root privileges" echo -e "-p, --proot-args Proot arguments" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" + echo -e "-n, --disable-validation Disable the $NAME image validation" echo -e "-d, --delete Delete $NAME from ${JUJU_HOME}" echo -e "-h, --help Show this help message" echo -e "-v, --version Show the $NAME version" @@ -62,10 +63,18 @@ check_cli(){ die "The build image option must be used exclusively" fi fi + if $OPT_DISABLE_VALIDATION + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT + then + die "The disable validation option must be used with the build image option only" + fi + fi if $OPT_DELETE then if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME delete option must be used exclusively" fi @@ -73,7 +82,7 @@ check_cli(){ if $OPT_HELP then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME help option must be used exclusively" fi @@ -81,7 +90,7 @@ check_cli(){ if $OPT_VERSION then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME version option must be used exclusively" fi @@ -93,7 +102,7 @@ check_cli(){ if $OPT_PROOT_ARGS then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_ROOT || $OPT_VERSION + $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION then die "Invalid syntax: Proot args are not allowed with the other options" fi @@ -101,7 +110,7 @@ check_cli(){ if [ "$ARGS" != "" ] then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_VERSION + $OPT_VERSION || $OPT_DISABLE_VALIDATION then die "No arguments are needed. For the CLI syntax run: $CMD --help" fi @@ -119,6 +128,7 @@ function parse_arguments(){ OPT_PROOT_ARGS=false PROOT_ARGS="" OPT_BUILD_IMAGE=false + OPT_DISABLE_VALIDATION=false OPT_DELETE=false OPT_HELP=false OPT_VERSION=false @@ -130,6 +140,7 @@ function parse_arguments(){ -r|--root) OPT_ROOT=true ; shift ;; -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; + -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -v|--version) OPT_VERSION=true ; shift ;; @@ -151,7 +162,7 @@ function execute_operation(){ $OPT_VERSION && version && return if $OPT_BUILD_IMAGE; then - build_image_juju + build_image_juju $OPT_DISABLE_VALIDATION return elif $OPT_DELETE; then delete_juju diff --git a/lib/core.sh b/lib/core.sh index 8d070af..8580c1e 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -254,6 +254,9 @@ function build_image_juju(){ _check_package gcc _check_package package-query _check_package git + + local disable_validation=$1 + local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) sudo mkdir -p ${maindir}/root trap - QUIT EXIT ABRT KILL TERM INT @@ -312,6 +315,18 @@ function build_image_juju(){ info "Compressing image to ${imagefile}..." sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . + $disable_validation || validate_image "${maindir}" "${imagefile}" + + sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} + + builtin cd ${ORIGIN_WD} + trap - QUIT EXIT ABRT KILL TERM INT + sudo rm -fr "$maindir" +} + +function validate_image(){ + local maindir=$1 + local imagefile=$2 info "Validating JuJu image..." mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C ${maindir}/root_test @@ -340,10 +355,4 @@ function build_image_juju(){ info "Installing ${repo_package} package from official repo using root..." ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S ${repo_package} sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test iftop -t -s 5 - - sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} - - builtin cd ${ORIGIN_WD} - trap - QUIT EXIT ABRT KILL TERM INT - sudo rm -fr "$maindir" } diff --git a/tests/test_juju.sh b/tests/test_juju.sh index 0c2e748..6665432 100755 --- a/tests/test_juju.sh +++ b/tests/test_juju.sh @@ -117,6 +117,8 @@ function test_check_cli(){ export -f die bash -ic "wrap_juju -b -h" &> /dev/null is_equal $? 1 || return 1 + bash -ic "wrap_juju -n -v" &> /dev/null + is_equal $? 1 || return 1 bash -ic "wrap_juju -d -r" &> /dev/null is_equal $? 1 || return 1 bash -ic "wrap_juju -h -f" &> /dev/null From e058c3523dbe60ee3c8b3f7e9f5bcf7c5c7d315f Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Feb 2015 16:39:04 +0100 Subject: [PATCH 067/326] Issue #18: Update README for JuJu as a container --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 9ba7a95..7daa55e 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,21 @@ Check out the proot options with: juju -p "--help" +### JuJu as a container ### +Although JuJu has not been designed to be a complete container, it is even possible to +virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). +The JuJu containter allows to run services inside the container that can be +visible from the host OS through the network. +The drawbacks of this are that the host OS must use systemd as a service manager, +and the container can only be executed using root privileges. + +To boot a JuJu container: + + sudo systemd-nspawn -bD ~/.juju + +Related wiki page: +- [How to run juju as a container](https://github.com/fsquillace/juju/wiki/How-to-run-JuJu-as-a-container) + Dependencies ------------ JuJu comes with a very short list of dependencies in order to be installed in most From f53f6353e62c322ec63b92a6bd5c5bf2c3b80a2b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 25 Mar 2015 20:43:57 +0100 Subject: [PATCH 068/326] Issue #68: First travis.yml version --- .travis.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f811385 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: bash + +install: + - PATH=$PWD/bin:$PATH + - juju -f echo 'Installing juju' + +script: + - sed -i -e "s/#Server/Server/" ~/.juju/etc/pacman.d/mirrorlist + - juju -f pacman --noconfirm -Syy + - juju -f pacman --noconfirm -S base-devel +# Test on installing package from AUR (issue #58) + #- juju -f yaourt --noconfirm -S tcptraceroute + #- juju -f tcptraceroute localhost +# Test on installing package from official repo + - juju -f pacman --noconfirm -S sysstat + - juju -f iostat From c7d3b150ab7ca0d63216b1f153786b3159282641 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 25 Mar 2015 21:00:49 +0100 Subject: [PATCH 069/326] Issue #68: Update README with build status --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 7daa55e..838d1e4 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ JuJu ==== **JuJu**: the Arch Linux based distro that runs upon any Linux distros without root access +![Build status](https://api.travis-ci.org/fsquillace/juju.png?branch=master) + Description ----------- **JuJu** is a lightweight Arch Linux based distribution that allows to have @@ -24,15 +26,21 @@ There are three different ways you can run JuJu: - As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): +```sh juju +``` - As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): +```sh juju -f +``` - As root - Allow to have fully root privileges inside JuJu environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): +```sh juju -r +``` If the JuJu image has not been downloaded yet, the script will download the JuJu image and will place it to the default directory ~/.juju. From 180d154f6b6e093328790968faa8bdaec2d0e758 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 25 Mar 2015 21:22:10 +0100 Subject: [PATCH 070/326] Issue #68: Check the JuJu deletion --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f811385..eb0e0d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,14 +3,18 @@ language: bash install: - PATH=$PWD/bin:$PATH - juju -f echo 'Installing juju' - -script: - sed -i -e "s/#Server/Server/" ~/.juju/etc/pacman.d/mirrorlist - juju -f pacman --noconfirm -Syy - - juju -f pacman --noconfirm -S base-devel + +script: # Test on installing package from AUR (issue #58) + #- juju -f pacman --noconfirm -S base-devel #- juju -f yaourt --noconfirm -S tcptraceroute #- juju -f tcptraceroute localhost # Test on installing package from official repo - juju -f pacman --noconfirm -S sysstat - juju -f iostat +# Test on installing package from official repo with root access (TODO: may not work in ubuntu) + #- juju -f pacman --noconfirm -S iftop + #- sudo bin/juju -r iftop -t -s 5 + - yes | juju -d From 3d26d98154189e0665224f2c44805421c7284ee1 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 27 Mar 2015 00:26:19 +0100 Subject: [PATCH 071/326] Issue #67: Add shunit for test_util --- tests/shunit2 | 1048 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_util.sh | 38 +- 2 files changed, 1062 insertions(+), 24 deletions(-) create mode 100755 tests/shunit2 diff --git a/tests/shunit2 b/tests/shunit2 new file mode 100755 index 0000000..8862ffd --- /dev/null +++ b/tests/shunit2 @@ -0,0 +1,1048 @@ +#! /bin/sh +# $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# shUnit2 -- Unit testing framework for Unix shell scripts. +# http://code.google.com/p/shunit2/ +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is +# based on the popular JUnit unit testing framework for Java. + +# return if shunit already loaded +[ -n "${SHUNIT_VERSION:-}" ] && exit 0 + +SHUNIT_VERSION='2.1.6' + +SHUNIT_TRUE=0 +SHUNIT_FALSE=1 +SHUNIT_ERROR=2 + +# enable strict mode by default +SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} + +_shunit_warn() { echo "shunit2:WARN $@" >&2; } +_shunit_error() { echo "shunit2:ERROR $@" >&2; } +_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } + +# specific shell checks +if [ -n "${ZSH_VERSION:-}" ]; then + setopt |grep "^shwordsplit$" >/dev/null + if [ $? -ne ${SHUNIT_TRUE} ]; then + _shunit_fatal 'zsh shwordsplit option is required for proper operation' + fi + if [ -z "${SHUNIT_PARENT:-}" ]; then + _shunit_fatal "zsh does not pass \$0 through properly. please declare \ +\"SHUNIT_PARENT=\$0\" before calling shUnit2" + fi +fi + +# +# constants +# + +__SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' +__SHUNIT_MODE_SOURCED='sourced' +__SHUNIT_MODE_STANDALONE='standalone' +__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} + +# set the constants readonly +shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` +echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ + shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` +for shunit_constant_ in ${shunit_constants_}; do + shunit_ro_opts_='' + case ${ZSH_VERSION:-} in + '') ;; # this isn't zsh + [123].*) ;; # early versions (1.x, 2.x, 3.x) + *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally + esac + readonly ${shunit_ro_opts_} ${shunit_constant_} +done +unset shunit_constant_ shunit_constants_ shunit_ro_opts_ + +# variables +__shunit_lineno='' # line number of executed test +__shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode +__shunit_reportGenerated=${SHUNIT_FALSE} # is report generated +__shunit_script='' # filename of unittest script (standalone mode) +__shunit_skip=${SHUNIT_FALSE} # is skipping enabled +__shunit_suite='' # suite of tests to execute + +# counts of tests +__shunit_testSuccess=${SHUNIT_TRUE} +__shunit_testsTotal=0 +__shunit_testsPassed=0 +__shunit_testsFailed=0 + +# counts of asserts +__shunit_assertsTotal=0 +__shunit_assertsPassed=0 +__shunit_assertsFailed=0 +__shunit_assertsSkipped=0 + +# macros +_SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' + +#----------------------------------------------------------------------------- +# assert functions +# + +# Assert that two values are equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertEquals() requires two or three arguments; $# given" + _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then + _shunit_assertPass + else + failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' + +# Assert that two values are not equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotEquals() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then + _shunit_assertPass + else + failSame "${shunit_message_}" "$@" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' + +# Assert that a value is null (i.e. an empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertTrue "${shunit_message_}" "[ -z '$1' ]" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' + +# Assert that a value is not null (i.e. a non-empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null + _shunit_error "assertNotNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` + test -n "${shunit_actual_}" + assertTrue "${shunit_message_}" $? + shunit_return=$? + + unset shunit_actual_ shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' + +# Assert that two values are the same (i.e. equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' + +# Assert that two values are not the same (i.e. not equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_:-}$1" + shift + fi + assertNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is true. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertTrue 0 +# assertTrue "[ 34 -gt 23 ]" +# The folloing test will fail with a message: +# assertTrue 123 +# assertTrue "test failed" "[ -r '/non/existant/file' ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertTrue() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then + _shunit_error "assertTrue() takes one two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is false. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertFalse 1 +# assertFalse "[ 'apples' = 'oranges' ]" +# The folloing test will fail with a message: +# assertFalse 0 +# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertFalse() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertFalse() quires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# failure functions +# + +# Records a test failure. +# +# Args: +# message: string: failure message [optional] +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +fail() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 1 ]; then + _shunit_error "fail() requires zero or one arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 1 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_}" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_='eval fail --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${SHUNIT_FALSE} +} +_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' + +# Records a test failure, stating two values should have been the same. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# This is functionally equivalent to calling failNotEquals(). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + failNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# skipping functions +# + +# Force remaining assert and fail functions to be "skipped". +# +# This function forces the remaining assert and fail functions to be "skipped", +# i.e. they will have no effect. Each function skipped will be recorded so that +# the total of asserts and fails will not be altered. +# +# Args: +# None +startSkipping() +{ + __shunit_skip=${SHUNIT_TRUE} +} + +# Resume the normal recording behavior of assert and fail calls. +# +# Args: +# None +endSkipping() +{ + __shunit_skip=${SHUNIT_FALSE} +} + +# Returns the state of assert and fail call skipping. +# +# Args: +# None +# Returns: +# boolean: (TRUE/FALSE constant) +isSkipping() +{ + return ${__shunit_skip} +} + +#----------------------------------------------------------------------------- +# suite functions +# + +# Stub. This function should contains all unit test calls to be made. +# +# DEPRECATED (as of 2.1.0) +# +# This function can be optionally overridden by the user in their test suite. +# +# If this function exists, it will be called when shunit2 is sourced. If it +# does not exist, shunit2 will search the parent script for all functions +# beginning with the word 'test', and they will be added dynamically to the +# test suite. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Adds a function name to the list of tests schedule for execution. +# +# This function should only be called from within the suite() function. +# +# Args: +# function: string: name of a function to add to current unit test suite +suite_addTest() +{ + shunit_func_=${1:-} + + __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" + __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` + + unset shunit_func_ +} + +# Stub. This function will be called once before any tests are run. +# +# Common one-time environment preparation tasks shared by all tests can be +# defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called once after all tests are finished. +# +# Common one-time environment cleanup tasks shared by all tests can be defined +# here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called before each test is run. +# +# Common environment preparation tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#setUp() { :; } + +# Note: see _shunit_mktempFunc() for actual implementation +# Stub. This function will be called after each test is run. +# +# Common environment cleanup tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +#------------------------------------------------------------------------------ +# internal shUnit2 functions +# + +# Create a temporary directory to store various run-time files in. +# +# This function is a cross-platform temporary directory creation tool. Not all +# OSes have the mktemp function, so one is included here. +# +# Args: +# None +# Outputs: +# string: the temporary directory that was created +_shunit_mktempDir() +{ + # try the standard mktemp function + ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return + + # the standard mktemp didn't work. doing our own. + if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then + _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" +#! /bin/sh +exit ${SHUNIT_TRUE} +EOF + chmod +x "${_shunit_file_}" + done + + unset _shunit_file_ +} + +# Final cleanup function to leave things as we found them. +# +# Besides removing the temporary directory, this function is in charge of the +# final exit code of the unit test. The exit code is based on how the script +# was ended (e.g. normal exit, or via Ctrl-C). +# +# Args: +# name: string: name of the trap called (specified when trap defined) +_shunit_cleanup() +{ + _shunit_name_=$1 + + case ${_shunit_name_} in + EXIT) _shunit_signal_=0 ;; + INT) _shunit_signal_=2 ;; + TERM) _shunit_signal_=15 ;; + *) + _shunit_warn "unrecognized trap value (${_shunit_name_})" + _shunit_signal_=0 + ;; + esac + + # do our work + rm -fr "${__shunit_tmpDir}" + + # exit for all non-EXIT signals + if [ ${_shunit_name_} != 'EXIT' ]; then + _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" + # disable EXIT trap + trap 0 + # add 128 to signal and exit + exit `expr ${_shunit_signal_} + 128` + elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then + _shunit_assertFail 'Unknown failure encountered running a test' + _shunit_generateReport + exit ${SHUNIT_ERROR} + fi + + unset _shunit_name_ _shunit_signal_ +} + +# The actual running of the tests happens here. +# +# Args: +# None +_shunit_execSuite() +{ + for _shunit_test_ in ${__shunit_suite}; do + __shunit_testSuccess=${SHUNIT_TRUE} + + # disable skipping + endSkipping + + # execute the per-test setup function + setUp + + # execute the test + echo "${_shunit_test_}" + eval ${_shunit_test_} + + # execute the per-test tear-down function + tearDown + + # update stats + if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then + __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` + else + __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` + fi + done + + unset _shunit_test_ +} + +# Generates the user friendly report with appropriate OK/FAILED message. +# +# Args: +# None +# Output: +# string: the report of successful and failed tests, as well as totals. +_shunit_generateReport() +{ + _shunit_ok_=${SHUNIT_TRUE} + + # if no exit code was provided one, determine an appropriate one + [ ${__shunit_testsFailed} -gt 0 \ + -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ + && _shunit_ok_=${SHUNIT_FALSE} + + echo + if [ ${__shunit_testsTotal} -eq 1 ]; then + echo "Ran ${__shunit_testsTotal} test." + else + echo "Ran ${__shunit_testsTotal} tests." + fi + + _shunit_failures_='' + _shunit_skipped_='' + [ ${__shunit_assertsFailed} -gt 0 ] \ + && _shunit_failures_="failures=${__shunit_assertsFailed}" + [ ${__shunit_assertsSkipped} -gt 0 ] \ + && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" + + if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then + _shunit_msg_='OK' + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" + else + _shunit_msg_="FAILED (${_shunit_failures_}" + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" + _shunit_msg_="${_shunit_msg_})" + fi + + echo + echo ${_shunit_msg_} + __shunit_reportGenerated=${SHUNIT_TRUE} + + unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ +} + +# Test for whether a function should be skipped. +# +# Args: +# None +# Returns: +# boolean: whether the test should be skipped (TRUE/FALSE constant) +_shunit_shouldSkip() +{ + [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} + _shunit_assertSkip +} + +# Records a successful test. +# +# Args: +# None +_shunit_assertPass() +{ + __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Records a test failure. +# +# Args: +# message: string: failure message to provide user +_shunit_assertFail() +{ + _shunit_msg_=$1 + + __shunit_testSuccess=${SHUNIT_FALSE} + __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` + echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" + + unset _shunit_msg_ +} + +# Records a skipped test. +# +# Args: +# None +_shunit_assertSkip() +{ + __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Prepare a script filename for sourcing. +# +# Args: +# script: string: path to a script to source +# Returns: +# string: filename prefixed with ./ (if necessary) +_shunit_prepForSourcing() +{ + _shunit_script_=$1 + case "${_shunit_script_}" in + /*|./*) echo "${_shunit_script_}" ;; + *) echo "./${_shunit_script_}" ;; + esac + unset _shunit_script_ +} + +# Escape a character in a string. +# +# Args: +# c: string: unescaped character +# s: string: to escape character in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharInStr() +{ + [ -n "$2" ] || return # no point in doing work on an empty string + + # Note: using shorter variable names to prevent conflicts with + # _shunit_escapeCharactersInString(). + _shunit_c_=$1 + _shunit_s_=$2 + + + # escape the character + echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' + + unset _shunit_c_ _shunit_s_ +} + +# Escape a character in a string. +# +# Args: +# str: string: to escape characters in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharactersInString() +{ + [ -n "$1" ] || return # no point in doing work on an empty string + + _shunit_str_=$1 + + # Note: using longer variable names to prevent conflicts with + # _shunit_escapeCharInStr(). + for _shunit_char_ in '"' '$' "'" '`'; do + _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` + done + + echo "${_shunit_str_}" + unset _shunit_char_ _shunit_str_ +} + +# Extract list of functions to run tests against. +# +# Args: +# script: string: name of script to extract functions from +# Returns: +# string: of function names +_shunit_extractTestFunctions() +{ + _shunit_script_=$1 + + # extract the lines with test function names, strip of anything besides the + # function name, and output everything on a single line. + _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' + egrep "${_shunit_regex_}" "${_shunit_script_}" \ + |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ + |xargs + + unset _shunit_regex_ _shunit_script_ +} + +#------------------------------------------------------------------------------ +# main +# + +# determine the operating mode +if [ $# -eq 0 ]; then + __shunit_script=${__SHUNIT_PARENT} + __shunit_mode=${__SHUNIT_MODE_SOURCED} +else + __shunit_script=$1 + [ -r "${__shunit_script}" ] || \ + _shunit_fatal "unable to read from ${__shunit_script}" + __shunit_mode=${__SHUNIT_MODE_STANDALONE} +fi + +# create a temporary storage location +__shunit_tmpDir=`_shunit_mktempDir` + +# provide a public temporary directory for unit test scripts +# TODO(kward): document this +SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" +mkdir "${SHUNIT_TMPDIR}" + +# setup traps to clean up after ourselves +trap '_shunit_cleanup EXIT' 0 +trap '_shunit_cleanup INT' 2 +trap '_shunit_cleanup TERM' 15 + +# create phantom functions to work around issues with Cygwin +_shunit_mktempFunc +PATH="${__shunit_tmpDir}:${PATH}" + +# make sure phantom functions are executable. this will bite if /tmp (or the +# current $TMPDIR) points to a path on a partition that was mounted with the +# 'noexec' option. the noexec command was created with _shunit_mktempFunc(). +noexec 2>/dev/null || _shunit_fatal \ + 'please declare TMPDIR with path on partition with exec permission' + +# we must manually source the tests in standalone mode +if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then + . "`_shunit_prepForSourcing \"${__shunit_script}\"`" +fi + +# execute the oneTimeSetUp function (if it exists) +oneTimeSetUp + +# execute the suite function defined in the parent test script +# deprecated as of 2.1.0 +suite + +# if no suite function was defined, dynamically build a list of functions +if [ -z "${__shunit_suite}" ]; then + shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` + for shunit_func_ in ${shunit_funcs_}; do + suite_addTest ${shunit_func_} + done +fi +unset shunit_func_ shunit_funcs_ + +# execute the tests +_shunit_execSuite + +# execute the oneTimeTearDown function (if it exists) +oneTimeTearDown + +# generate the report +_shunit_generateReport + +# that's it folks +[ ${__shunit_testsFailed} -eq 0 ] +exit $? diff --git a/tests/test_util.sh b/tests/test_util.sh index e7cfc1b..4b0640c 100755 --- a/tests/test_util.sh +++ b/tests/test_util.sh @@ -1,41 +1,36 @@ #!/bin/bash -source "$(dirname $0)/utils.sh" source "$(dirname $0)/../lib/util.sh" function test_echoerr(){ local actual=$(echoerr "Test" 2>&1) - is_equal "$actual" "Test" || return 1 - return 0 + assertEquals "$actual" "Test" } function test_error(){ local actual=$(error "Test" 2>&1) local expected=$(echo -e "\033[1;31mTest\033[0m") - is_equal "$actual" "$expected" || return 1 - return 0 + assertEquals "$actual" "$expected" } function test_warn(){ local actual=$(warn "Test" 2>&1) local expected=$(echo -e "\033[1;33mTest\033[0m") - is_equal "$actual" "$expected" || return 1 - return 0 + assertEquals "$actual" "$expected" } function test_info(){ local actual=$(info "Test") local expected=$(echo -e "\033[1;37mTest\033[0m") - is_equal "$actual" "$expected" || return 1 - return 0 + assertEquals "$actual" "$expected" } function test_die(){ local actual=$(die "Test" 2>&1) local expected=$(echo -e "\033[1;31mTest\033[0m") - is_equal "$actual" "$expected" || return 1 + assertEquals "$actual" "$expected" export -f die bash -ic "die Dying" &> /dev/null - is_equal $? 1 || return 1 + assertEquals $? 1 export -n die unset die return 0 @@ -43,24 +38,19 @@ function test_die(){ function test_ask(){ echo "Y" | ask "Test" &> /dev/null - is_equal $? 0 || return 1 + assertEquals $? 0 echo "y" | ask "Test" &> /dev/null - is_equal $? 0 || return 1 + assertEquals $? 0 echo "N" | ask "Test" &> /dev/null - is_equal $? 1 || return 1 + assertEquals $? 1 echo "n" | ask "Test" &> /dev/null - is_equal $? 1 || return 1 + assertEquals $? 1 echo -e "\n" | ask "Test" &> /dev/null - is_equal $? 0 || return 1 + assertEquals $? 0 echo -e "\n" | ask "Test" "N" &> /dev/null - is_equal $? 1 || return 1 + assertEquals $? 1 echo -e "asdf\n\n" | ask "Test" "N" &> /dev/null - is_equal $? 1 || return 1 - return 0 + assertEquals $? 1 } - -for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) -do - $func && echo -e "${func}...\033[1;32mOK\033[0m" || echo -e "${func}...\033[1;31mFAIL\033[0m" -done +source $(dirname $0)/shunit2 From 32e986ee0e5c89ea8a3d2cde5745c7737ce674a5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 27 Mar 2015 01:53:35 +0100 Subject: [PATCH 072/326] Issue #67: Add shunit for test_juju --- tests/test_juju.sh | 103 ++++++++++++++++++--------------------------- tests/test_util.sh | 9 ++-- 2 files changed, 44 insertions(+), 68 deletions(-) diff --git a/tests/test_juju.sh b/tests/test_juju.sh index 6665432..e16a648 100755 --- a/tests/test_juju.sh +++ b/tests/test_juju.sh @@ -1,6 +1,9 @@ #!/bin/bash -source "$(dirname $0)/utils.sh" source $(dirname $0)/../bin/juju -h &> /dev/null + +# Disable the exiterr +set +e + ## Mock functions ## function usage(){ echo "usage" @@ -43,105 +46,79 @@ function wrap_juju(){ execute_operation } - -function set_up(){ - echo > /dev/null -} - -function tear_down(){ - echo > /dev/null -} - - function test_help(){ local output=$(wrap_juju -h) - is_equal $output "usage" || return 1 + assertEquals $output "usage" local output=$(wrap_juju --help) - is_equal $output "usage" || return 1 + assertEquals $output "usage" } function test_version(){ local output=$(wrap_juju -v) - is_equal $output "version" || return 1 + assertEquals $output "version" local output=$(wrap_juju --version) - is_equal $output "version" || return 1 + assertEquals $output "version" } function test_build_image_juju(){ local output=$(wrap_juju -b) - is_equal $output "build_image_juju" || return 1 + assertEquals $output "build_image_juju" local output=$(wrap_juju --build-image) - is_equal $output "build_image_juju" || return 1 + assertEquals $output "build_image_juju" } function test_delete_juju(){ local output=$(wrap_juju -d) - is_equal $output "delete_juju" || return 1 + assertEquals $output "delete_juju" local output=$(wrap_juju --delete) - is_equal $output "delete_juju" || return 1 + assertEquals $output "delete_juju" } function test_run_juju_as_fakeroot(){ local output=$(wrap_juju -f) - is_equal $output "run_juju_as_fakeroot(,)" || return 1 + assertEquals $output "run_juju_as_fakeroot(,)" local output=$(wrap_juju --fakeroot) - is_equal $output "run_juju_as_fakeroot(,)" || return 1 + assertEquals $output "run_juju_as_fakeroot(,)" local output=$(wrap_juju -f -p "-b arg") - is_equal "${output[@]}" "run_juju_as_fakeroot(-b arg,)" || return 1 + assertEquals "${output[@]}" "run_juju_as_fakeroot(-b arg,)" local output=$(wrap_juju -f -p "-b arg" -- command -kv) - is_equal "${output[@]}" "run_juju_as_fakeroot(-b arg,command -kv)" || return 1 + assertEquals "${output[@]}" "run_juju_as_fakeroot(-b arg,command -kv)" local output=$(wrap_juju -f command --as) - is_equal "${output[@]}" "run_juju_as_fakeroot(,command --as)" || return 1 + assertEquals "${output[@]}" "run_juju_as_fakeroot(,command --as)" } function test_run_juju_as_user(){ local output=$(wrap_juju) - is_equal $output "run_juju_as_user(,)" || return 1 + assertEquals $output "run_juju_as_user(,)" local output=$(wrap_juju -p "-b arg") - is_equal "${output[@]}" "run_juju_as_user(-b arg,)" || return 1 + assertEquals "$output" "run_juju_as_user(-b arg,)" local output=$(wrap_juju -p "-b arg" -- command -ll) - is_equal "${output[@]}" "run_juju_as_user(-b arg,command -ll)" || return 1 + assertEquals "$output" "run_juju_as_user(-b arg,command -ll)" local output=$(wrap_juju command -ls) - is_equal "${output[@]}" "run_juju_as_user(,command -ls)" || return 1 + assertEquals "$output" "run_juju_as_user(,command -ls)" } function test_run_juju_as_root(){ local output=$(wrap_juju -r) - is_equal $output "run_juju_as_root" || return 1 + assertEquals $output "run_juju_as_root" local output=$(wrap_juju -r command) - is_equal "${output[@]}" "run_juju_as_root command" || return 1 + assertEquals "${output[@]}" "run_juju_as_root command" } function test_check_cli(){ - export -f check_cli - export -f parse_arguments - export -f execute_operation - export -f wrap_juju - export -f die - bash -ic "wrap_juju -b -h" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -n -v" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -d -r" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -h -f" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -v -i fsd" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -f -r" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -p args -v" &> /dev/null - is_equal $? 1 || return 1 - bash -ic "wrap_juju -d args" &> /dev/null - is_equal $? 1 || return 1 - export -n check_cli - export -n parse_arguments - export -n execute_operation - export -n wrap_juju - export -n die - unset die + $(wrap_juju -b -h 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -n -v 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -d -r 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -h -f 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -v -i fsd 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -f -r 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -p args -v 2> /dev/null) + assertEquals $? 1 + $(wrap_juju -d args 2> /dev/null) + assertEquals $? 1 } -for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) -do - set_up - $func && echo -e "${func}...\033[1;32mOK\033[0m" || echo -e "${func}...\033[1;31mFAIL\033[0m" - tear_down -done +source $(dirname $0)/shunit2 diff --git a/tests/test_util.sh b/tests/test_util.sh index 4b0640c..f0a5447 100755 --- a/tests/test_util.sh +++ b/tests/test_util.sh @@ -1,6 +1,9 @@ #!/bin/bash source "$(dirname $0)/../lib/util.sh" +# Disable the exiterr +set +e + function test_echoerr(){ local actual=$(echoerr "Test" 2>&1) assertEquals "$actual" "Test" @@ -28,12 +31,8 @@ function test_die(){ local actual=$(die "Test" 2>&1) local expected=$(echo -e "\033[1;31mTest\033[0m") assertEquals "$actual" "$expected" - export -f die - bash -ic "die Dying" &> /dev/null + $(die Dying 2> /dev/null) assertEquals $? 1 - export -n die - unset die - return 0 } function test_ask(){ From 119d3c3430372ed57da95b5d177e78cfeb3af8e6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 27 Mar 2015 14:11:15 +0100 Subject: [PATCH 073/326] Issue #67: Add shunit for test_core --- .travis.yml | 1 + tests/test_core.sh | 156 +++++++++++++++++---------------------------- tests/utils.sh | 11 ---- 3 files changed, 61 insertions(+), 107 deletions(-) delete mode 100644 tests/utils.sh diff --git a/.travis.yml b/.travis.yml index eb0e0d2..66f859f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ install: - juju -f pacman --noconfirm -Syy script: + - SKIP_ROOT_TESTS=1 ./tests/test_all.sh # Test on installing package from AUR (issue #58) #- juju -f pacman --noconfirm -S base-devel #- juju -f yaourt --noconfirm -S tcptraceroute diff --git a/tests/test_core.sh b/tests/test_core.sh index f84b17d..bf66e80 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -1,16 +1,19 @@ #!/bin/bash -source "$(dirname $0)/utils.sh" -CURRPWD=$PWD -JUJU_MAIN_HOME=/tmp/jujutesthome -[ -e $JUJU_MAIN_HOME ] || JUJU_HOME=$JUJU_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_juju" -JUJU_HOME="" +function oneTimeSetUp(){ + [ -z "$SKIP_ROOT_TESTS" ] && SKIP_ROOT_TESTS=0 + + CURRPWD=$PWD + JUJU_MAIN_HOME=/tmp/jujutesthome + [ -e $JUJU_MAIN_HOME ] || JUJU_HOME=$JUJU_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_juju" + JUJU_HOME="" +} function install_mini_juju(){ cp -rfa $JUJU_MAIN_HOME/* $JUJU_HOME } -function set_up(){ +function setUp(){ cd $CURRPWD JUJU_HOME=$(TMPDIR=/tmp mktemp -d -t jujuhome.XXXXXXXXXX) source "$(dirname $0)/../lib/core.sh" @@ -18,12 +21,14 @@ function set_up(){ cd $ORIGIN_WD JUJU_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t jujutemp.XXXXXXXXXX) + set +e + trap - QUIT EXIT ABRT KILL TERM INT trap "rm -rf ${JUJU_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUJU_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT } -function tear_down(){ +function tearDown(){ # the CA directories are read only and can be deleted only by changing the mod [ -d ${JUJU_HOME}/etc/ca-certificates ] && chmod -R +w ${JUJU_HOME}/etc/ca-certificates rm -rf $JUJU_HOME @@ -35,10 +40,10 @@ function tear_down(){ function test_is_juju_installed(){ is_juju_installed - is_equal $? 1 || return 1 + assertEquals $? 1 touch $JUJU_HOME/just_file is_juju_installed - is_equal $? 0 || return 1 + assertEquals $? 0 } @@ -46,18 +51,15 @@ function test_download(){ WGET=/bin/true CURL=/bin/false download - is_equal $? 0 || return 1 + assertEquals $? 0 + WGET=/bin/false CURL=/bin/true download - is_equal $? 0 || return 1 + assertEquals $? 0 - export -f download - export -f die - WGET=/bin/false CURL=/bin/false bash -ic "download something" 2> /dev/null - is_equal $? 1 || return 1 - export -n die - export -n download + $(WGET=/bin/false CURL=/bin/false download something 2> /dev/null) + assertEquals $? 1 } @@ -67,14 +69,14 @@ function test_setup_juju(){ # inside $JUJU_TEMPDIR local cwd=${PWD#${JUJU_TEMPDIR}} local parent_dir=${PWD%${cwd}} - is_equal $JUJU_TEMPDIR ${parent_dir} || return 1 + assertEquals "$JUJU_TEMPDIR" "${parent_dir}" touch file tar -czvf juju-${ARCH}.tar.gz file } WGET=wget_mock setup_juju &> /dev/null - [ -e $JUJU_HOME/file ] || return 1 - [ -e $JUJU_HOME/run/lock ] || return 1 + assertTrue "[ -e $JUJU_HOME/file ]" + assertTrue "[ -e $JUJU_HOME/run/lock ]" } @@ -82,166 +84,128 @@ function test_setup_from_file_juju(){ touch file tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null setup_from_file_juju juju-${ARCH}.tar.gz &> /dev/null - [ -e $JUJU_HOME/file ] || return 1 - [ -e $JUJU_HOME/run/lock ] || return 1 + assertTrue "[ -e $JUJU_HOME/file ]" + assertTrue "[ -e $JUJU_HOME/run/lock ]" - export -f setup_from_file_juju - export -f die - bash -ic "setup_from_file_juju noexist.tar.gz" &> /dev/null - is_equal $? 1 || return 1 + $(setup_from_file_juju noexist.tar.gz 2> /dev/null) + assertEquals $? 1 } function test_setup_from_file_juju_with_absolute_path(){ touch file tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null setup_from_file_juju ${ORIGIN_WD}/juju-${ARCH}.tar.gz &> /dev/null - [ -e $JUJU_HOME/file ] || return 1 - [ -e $JUJU_HOME/run/lock ] || return 1 + assertTrue "[ -e $JUJU_HOME/file ]" + assertTrue "[ -e $JUJU_HOME/run/lock ]" } function test_run_juju_as_root(){ + [ $SKIP_ROOT_TESTS -eq 1 ] && return + install_mini_juju CHROOT="sudo $CHROOT" CHOWN="sudo $CHOWN" SH=("type" "-t" "type") local output=$(run_juju_as_root) - is_equal $output "builtin" || return 1 + assertEquals $output "builtin" local output=$(run_juju_as_root pwd) - is_equal $output "/" || return 1 + assertEquals $output "/" run_juju_as_root "[ -e /run/lock ]" - is_equal $? 0 || return 1 + assertEquals $? 0 run_juju_as_root "[ -e $HOME ]" - is_equal $? 0 || return 1 + assertEquals $? 0 # test that normal user has ownership of the files created by root run_juju_as_root "touch /a_root_file" local output=$(run_juju_as_root "stat -c '%u' /a_root_file") - is_equal $output "$UID" || return 1 + assertEquals $output "$UID" } function test_run_juju_as_user(){ install_mini_juju local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') - is_equal "$output" "/usr/bin/mkdir" || return 1 - [ -e $JUJU_HOME/newdir2 ] - is_equal $? 0 || return 1 + assertEquals "$output" "/usr/bin/mkdir" + assertTrue "[ -e $JUJU_HOME/newdir2 ]" SH=("/usr/bin/mkdir" "-v" "/newdir") local output=$(run_juju_as_user "-k 3.10" | awk -F: '{print $1}') - is_equal "$output" "/usr/bin/mkdir" || return 1 - [ -e $JUJU_HOME/newdir ] - is_equal $? 0 || return 1 + assertEquals "$output" "/usr/bin/mkdir" + assertTrue "[ -e $JUJU_HOME/newdir ]" } function test_run_juju_with_quotes(){ install_mini_juju local output=$(run_juju_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') - is_equal "$output" "/usr/bin/mkdir" || return 1 - [ -e $JUJU_HOME/newdir2 ] - is_equal $? 0 || return 1 + assertEquals "$output" "/usr/bin/mkdir" + assertTrue "[ -e $JUJU_HOME/newdir2 ]" } function test_run_juju_as_user_proot_args(){ install_mini_juju run_juju_as_user "--help" "" &> /dev/null - is_equal $? 0 || return 1 + assertEquals $? 0 mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null - is_equal $? 0 || return 1 + assertEquals $? 0 - export -f _run_juju_with_proot - export -f _run_proot - export -f warn - export -f die - export PROOT_COMPAT - bash -ic "_run_juju_with_proot --helps" &> /dev/null - is_equal $? 1 || return 1 - export -n _run_juju_with_proot - export -n _run_proot - export -n warn - export -n die - export -n PROOT_COMPAT + $(_run_juju_with_proot --helps 2> /dev/null) + assertEquals $? 1 } function test_run_juju_with_proot_compat(){ PROOT_COMPAT="/bin/true" _run_juju_with_proot "" "" &> /dev/null - is_equal $? 0 || return 1 + assertEquals $? 0 - export -f _run_juju_with_proot - export -f _run_proot - export -f warn - export -f die - PROOT_COMPAT="/bin/false" bash -ic "_run_juju_with_proot --helps" &> /dev/null - is_equal $? 1 || return 1 - export -n _run_juju_with_proot - export -n _run_proot - export -n warn - export -n die + $(PROOT_COMPAT="/bin/false" _run_juju_with_proot --helps 2> /dev/null) + assertEquals $? 1 } function test_run_juju_with_proot_as_root(){ install_mini_juju - export -f _run_proot - export -f run_juju_as_user - export -f run_juju_as_fakeroot - export TRUE - export PROOT_COMPAT - ID="/bin/echo 0" bash -ic "run_juju_as_user" &> /dev/null - is_equal $? 1 || return 1 - ID="/bin/echo 0" bash -ic "run_juju_as_fakeroot" &> /dev/null - is_equal $? 1 || return 1 - export -n TRUE - export -n PROOT_COMPAT - export -n _run_proot - export -n run_juju_as_user - export -n run_juju_as_fakeroot - unset _run_proot - unset run_juju_as_user - unset run_juju_as_fakeroot + + $(ID="/bin/echo 0" run_juju_as_user 2> /dev/null) + assertEquals $? 1 + $(ID="/bin/echo 0" run_juju_as_fakeroot 2> /dev/null) + assertEquals $? 1 } function test_run_proot_seccomp(){ TRUE="" PROOT_COMPAT=env local output=$(_run_proot | grep "^PROOT_NO_SECCOMP") - is_equal $output "" || return 1 + assertEquals "$output" "" envv(){ env | grep "^PROOT_NO_SECCOMP" } PROOT_COMPAT=envv local output=$(_run_proot 2> /dev/null | grep "^PROOT_NO_SECCOMP") - is_equal $output "PROOT_NO_SECCOMP=1" || return 1 + assertEquals "$output" "PROOT_NO_SECCOMP=1" } function test_run_juju_as_fakeroot(){ install_mini_juju local output=$(run_juju_as_fakeroot "-k 3.10" "id" | awk '{print $1}') - is_equal "$output" "uid=0(root)" || return 1 + assertEquals "$output" "uid=0(root)" } function test_delete_juju(){ install_mini_juju echo "N" | delete_juju 1> /dev/null is_juju_installed - is_equal $? 0 || return 1 + assertEquals $? 0 echo "Y" | delete_juju 1> /dev/null is_juju_installed - is_equal $? 1 || return 1 + assertEquals $? 1 } function test_nested_juju(){ install_mini_juju JUJU_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null - is_equal $? 1 || return 1 + assertEquals $? 1 } -for func in $(declare -F | grep test_ | awk '{print $3}' | xargs) -do - set_up - $func && echo -e "${func}...\033[1;32mOK\033[0m" || echo -e "${func}...\033[1;31mFAIL\033[0m" - tear_down -done +source $(dirname $0)/shunit2 diff --git a/tests/utils.sh b/tests/utils.sh deleted file mode 100644 index 094c055..0000000 --- a/tests/utils.sh +++ /dev/null @@ -1,11 +0,0 @@ -function is_equal(){ - if [ "$1" == "$2" ] - then - return 0 - else - echo "$1!=$2" - return 1 - fi -} - - From 166a6290867ce4ff63a2e605a2e813ff9ba7d1c7 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 29 Mar 2015 22:17:36 +0200 Subject: [PATCH 074/326] Update travis link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 838d1e4..983fb5a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ JuJu ==== **JuJu**: the Arch Linux based distro that runs upon any Linux distros without root access -![Build status](https://api.travis-ci.org/fsquillace/juju.png?branch=master) +[![Build status](https://api.travis-ci.org/fsquillace/juju.png?branch=master)](https://travis-ci.org/fsquillace/juju) Description ----------- From 8d9dda24536e676d7d2199843e1b617971d0d3bf Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 4 Apr 2015 16:29:55 +0200 Subject: [PATCH 075/326] Issue #58: Fix the command execution under CLI --- lib/core.sh | 2 +- lib/util.sh | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 8580c1e..eb89283 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -190,7 +190,7 @@ function _run_juju_with_proot(){ if [ "$1" != "" ] then - _run_proot "${proot_args}" "${@}" + insert_quotes "${@}" | _run_proot "${proot_args}" "${SH[@]}" else _run_proot "${proot_args}" "${SH[@]}" fi diff --git a/lib/util.sh b/lib/util.sh index 9f411a3..0322138 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -67,3 +67,14 @@ function ask(){ fi } + +function insert_quotes(){ +# It inserts quotes between arguments. +# Useful to preserve quotes on command +# to be used inside sh -c/bash -c + C='' + for i in "$@"; do + C="$C \"${i//\"/\\\"}\"" + done + echo ${C} +} From 0a0aac52f51cc105940d41bb709628f770ec0162 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 4 Apr 2015 16:32:40 +0200 Subject: [PATCH 076/326] Fix the test_all.sh --- tests/test_all.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_all.sh b/tests/test_all.sh index 684e6fd..48f9262 100755 --- a/tests/test_all.sh +++ b/tests/test_all.sh @@ -1,5 +1,7 @@ - +tests_succeded=true for tst in $(ls $(dirname $0)/test_* | grep -v $(basename $0)) do - $tst + $tst || tests_succeded=false done + +$tests_succeded From 4214206da07b40d307aa8f073a0a0e0490b4ecb8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 4 Apr 2015 16:34:30 +0200 Subject: [PATCH 077/326] Issue #58: Update travis for install AUR packages --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 66f859f..1d79584 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,12 @@ install: - juju -f echo 'Installing juju' - sed -i -e "s/#Server/Server/" ~/.juju/etc/pacman.d/mirrorlist - juju -f pacman --noconfirm -Syy + - juju -f pacman --noconfirm -S base-devel script: - SKIP_ROOT_TESTS=1 ./tests/test_all.sh -# Test on installing package from AUR (issue #58) - #- juju -f pacman --noconfirm -S base-devel - #- juju -f yaourt --noconfirm -S tcptraceroute - #- juju -f tcptraceroute localhost +# Test on installing package from AUR + - juju -f yaourt --noconfirm -S tcptraceroute # Test on installing package from official repo - juju -f pacman --noconfirm -S sysstat - juju -f iostat From 3180cd63f8aaa7ca4bb10103cf6d4e27579bfa84 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 9 Apr 2015 03:10:15 +0200 Subject: [PATCH 078/326] Issue #58: Fix on root access --- lib/core.sh | 15 +++++---------- lib/util.sh | 15 +++++++++++---- tests/test_core.sh | 26 +++++++++++++++++--------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index eb89283..5b909fb 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -150,19 +150,14 @@ function setup_from_file_juju(){ function run_juju_as_root(){ - local main_cmd="${SH[@]}" - [ "$1" != "" ] && main_cmd="$@" - local uid=$UID [ -z $SUDO_UID ] || uid=$SUDO_UID:$SUDO_GID - local cmd=" -mkdir -p ${JUJU_HOME}/${HOME} -mkdir -p /run/lock -${main_cmd} -" + local main_cmd="${SH[@]}" + [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" + local cmd="mkdir -p ${JUJU_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" - JUJU_ENV=1 ${CHROOT} $JUJU_HOME /usr/bin/bash -c "${cmd}" + JUJU_ENV=1 ${CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" # The ownership of the files in JuJu is assigned to the real user [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} @@ -190,7 +185,7 @@ function _run_juju_with_proot(){ if [ "$1" != "" ] then - insert_quotes "${@}" | _run_proot "${proot_args}" "${SH[@]}" + _run_proot "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else _run_proot "${proot_args}" "${SH[@]}" fi diff --git a/lib/util.sh b/lib/util.sh index 0322138..52e1b24 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -68,13 +68,20 @@ function ask(){ } -function insert_quotes(){ +function insert_quotes_on_spaces(){ # It inserts quotes between arguments. # Useful to preserve quotes on command # to be used inside sh -c/bash -c C='' - for i in "$@"; do - C="$C \"${i//\"/\\\"}\"" + whitespace="[[:space:]]" + for i in "$@" + do + if [[ $i =~ $whitespace ]] + then + C="$C \"$i\"" + else + C="$C $i" + fi done - echo ${C} + echo $C } diff --git a/tests/test_core.sh b/tests/test_core.sh index bf66e80..0549fff 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -105,20 +105,28 @@ function test_run_juju_as_root(){ install_mini_juju CHROOT="sudo $CHROOT" CHOWN="sudo $CHOWN" - SH=("type" "-t" "type") - local output=$(run_juju_as_root) - assertEquals $output "builtin" + local output=$(run_juju_as_root pwd) - assertEquals $output "/" - run_juju_as_root "[ -e /run/lock ]" + assertEquals "$output" "/" + run_juju_as_root [ -e /run/lock ] assertEquals $? 0 - run_juju_as_root "[ -e $HOME ]" + run_juju_as_root [ -e $HOME ] assertEquals $? 0 # test that normal user has ownership of the files created by root - run_juju_as_root "touch /a_root_file" - local output=$(run_juju_as_root "stat -c '%u' /a_root_file") - assertEquals $output "$UID" + run_juju_as_root touch /a_root_file + local output=$(run_juju_as_root stat -c '%u' /a_root_file) + assertEquals "$output" "$UID" + + SH=("sh" "--login" "-c" "type -t type") + local output=$(run_juju_as_root) + assertEquals "$output" "builtin" + SH=("sh" "--login" "-c" "[ -e /run/lock ]") + run_juju_as_root + assertEquals $? 0 + SH=("sh" "--login" "-c" "[ -e $HOME ]") + run_juju_as_root + assertEquals $? 0 } function test_run_juju_as_user(){ From fa440287fe12c16b756e953c3b6f0c96958e8360 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 9 Apr 2015 03:16:10 +0200 Subject: [PATCH 079/326] Ensure to have assign ownership to the user on root access --- lib/core.sh | 7 +++++++ tests/test_util.sh | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index 5b909fb..5b5a8c1 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -157,10 +157,17 @@ function run_juju_as_root(){ [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" local cmd="mkdir -p ${JUJU_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" + trap - QUIT EXIT ABRT KILL TERM INT + trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME}" EXIT QUIT ABRT KILL TERM INT + JUJU_ENV=1 ${CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" + local ret=$? # The ownership of the files in JuJu is assigned to the real user [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} + + trap - QUIT EXIT ABRT KILL TERM INT + return $? } function _run_proot(){ diff --git a/tests/test_util.sh b/tests/test_util.sh index f0a5447..c10a095 100755 --- a/tests/test_util.sh +++ b/tests/test_util.sh @@ -52,4 +52,12 @@ function test_ask(){ assertEquals $? 1 } +function test_insert_quotes_on_spaces(){ + local actual=$(insert_quotes_on_spaces this is "a test") + assertEquals "this is \"a test\"" "$actual" + + local actual=$(insert_quotes_on_spaces this is 'a test') + assertEquals "this is \"a test\"" "$actual" +} + source $(dirname $0)/shunit2 From 9ae8bf787c8d5cd6259c357875d7988e92e92c1e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 15 Apr 2015 04:01:51 +0200 Subject: [PATCH 080/326] Issue #69: Add default mirror URL --- lib/core.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 5b5a8c1..3296b38 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -50,6 +50,8 @@ CURL="curl -L -J -O -k" TAR=tar +DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' + HOST_ARCH=$(uname -m) if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] @@ -111,8 +113,10 @@ function _setup_juju(){ imagepath=$1 $TAR -zxpf ${imagepath} -C ${JUJU_HOME} mkdir -p ${JUJU_HOME}/run/lock - warn "Warn: Change the mirrorlist file according to your location:" + warn "Warn: The default mirror URL is ${DEFAULT_MIRROR}." + warn "To change it:" info " nano /etc/pacman.d/mirrorlist" + info "Remember to refresh the package databases from the server:" info " pacman -Syy" info "JuJu installed successfully" } @@ -267,6 +271,7 @@ function build_image_juju(){ # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # yaourt requires sed sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano archlinux-keyring sed + sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." # sed command is required for locale-gen From ad19933d0026197a4d863eb4d1eb6927da83d498 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 16 Apr 2015 01:52:39 +0200 Subject: [PATCH 081/326] Improve the validation function --- lib/core.sh | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 3296b38..f7ef9ea 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -322,7 +322,8 @@ function build_image_juju(){ info "Compressing image to ${imagefile}..." sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . - $disable_validation || validate_image "${maindir}" "${imagefile}" + mkdir -p ${maindir}/root_test + $disable_validation || validate_image "${maindir}/root_test" "${imagefile}" sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} @@ -332,34 +333,34 @@ function build_image_juju(){ } function validate_image(){ - local maindir=$1 + local testdir=$1 local imagefile=$2 info "Validating JuJu image..." - mkdir -p ${maindir}/root_test - $TAR -zxpf ${imagefile} -C ${maindir}/root_test - mkdir -p ${maindir}/root_test/run/lock - sed -i -e "s/#Server/Server/" ${maindir}/root_test/etc/pacman.d/mirrorlist - ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -Syy + $TAR -zxpf ${imagefile} -C ${testdir} + mkdir -p ${testdir}/run/lock + sed -i -e "s/#Server/Server/" ${testdir}/etc/pacman.d/mirrorlist + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -Syy - sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test pacman -Qi pacman 1> /dev/null - sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test yaourt -V 1> /dev/null - sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test /opt/proot/proot-$ARCH --help 1> /dev/null - sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test arch-chroot --help 1> /dev/null + # Check most basic executables work + JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r pacman -Qi pacman 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r yaourt -V 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r arch-chroot --help 1> /dev/null - ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S base-devel + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -S base-devel local yaourt_package=tcptraceroute info "Installing ${yaourt_package} package from AUR repo using proot..." - ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test sh --login -c "yaourt --noconfirm -S ${yaourt_package}" - sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test tcptraceroute localhost + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" + JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r tcptraceroute localhost local repo_package=sysstat info "Installing ${repo_package} package from official repo using proot..." - ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S ${repo_package} - ${maindir}/root/opt/proot/proot-$ARCH -R ${maindir}/root_test iostat - ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test iostat + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -S ${repo_package} + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju iostat + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f iostat local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." - ${maindir}/root/opt/proot/proot-$ARCH -S ${maindir}/root_test pacman --noconfirm -S ${repo_package} - sudo ${maindir}/root/usr/bin/arch-chroot ${maindir}/root_test iftop -t -s 5 + JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -S ${repo_package} + JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r iftop -t -s 5 } From 00f0ee3b6a062d25684247b1c8a761a84249854c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 2 May 2015 16:58:42 +0000 Subject: [PATCH 082/326] Issue #71: Use chroot to fallback in root mode --- .travis.yml | 15 +++++++++------ README.md | 4 ++++ lib/core.sh | 20 ++++++++++++++++---- tests/test_core.sh | 31 ++++++++++++++++++++++++------- 4 files changed, 53 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d79584..550c119 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: bash +sudo: required + install: - PATH=$PWD/bin:$PATH - juju -f echo 'Installing juju' @@ -8,13 +10,14 @@ install: - juju -f pacman --noconfirm -S base-devel script: - - SKIP_ROOT_TESTS=1 ./tests/test_all.sh + - ./tests/test_all.sh # Test on installing package from AUR - juju -f yaourt --noconfirm -S tcptraceroute + - sudo $PWD/bin/juju -r tcptraceroute localhost # Test on installing package from official repo - - juju -f pacman --noconfirm -S sysstat - - juju -f iostat -# Test on installing package from official repo with root access (TODO: may not work in ubuntu) - #- juju -f pacman --noconfirm -S iftop - #- sudo bin/juju -r iftop -t -s 5 + - juju -f pacman --noconfirm -S tree + - juju -f tree +# Test on installing package from official repo with root access + - juju -f pacman --noconfirm -S iftop + - sudo bin/juju -r iftop -t -s 5 - yes | juju -d diff --git a/README.md b/README.md index 983fb5a..95ab1cc 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,10 @@ Check out the proot options with: juju -p "--help" +###Automatic fallback to classic chroot### +Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work +on some distros, JuJu automatically tries to fallback to the classic chroot. + ### JuJu as a container ### Although JuJu has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). diff --git a/lib/core.sh b/lib/core.sh index f7ef9ea..0ebbbe0 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -75,9 +75,10 @@ PROOT_LINK=http://static.proot.me/proot-${ARCH} SH=("/bin/sh" "--login") CHROOT=${JUJU_HOME}/usr/bin/arch-chroot +CLASSIC_CHROOT=${JUJU_HOME}/usr/bin/chroot TRUE=/usr/bin/true ID="/usr/bin/id -u" -CHOWN="/usr/bin/chown" +CHOWN="${JUJU_HOME}/usr/bin/chown" ################################# MAIN FUNCTIONS ############################## @@ -164,8 +165,18 @@ function run_juju_as_root(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME}" EXIT QUIT ABRT KILL TERM INT - JUJU_ENV=1 ${CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" - local ret=$? + if ${CHROOT} $JUJU_HOME ${TRUE} &> /dev/null + then + JUJU_ENV=1 ${CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" + local ret=$? + elif ${CLASSIC_CHROOT} $JUJU_HOME ${TRUE} &> /dev/null + then + warn "Warning: The executable arch-chroot does not work, falling back to classic chroot" + JUJU_ENV=1 ${CLASSIC_CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" + local ret=$? + else + die "Error: Chroot does not work" + fi # The ownership of the files in JuJu is assigned to the real user [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} @@ -270,7 +281,8 @@ function build_image_juju(){ info "Installing pacman and its dependencies..." # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # yaourt requires sed - sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts binutils libunistring nano archlinux-keyring sed + # coreutils is needed for chown + sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring nano archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." diff --git a/tests/test_core.sh b/tests/test_core.sh index 0549fff..c374655 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -104,29 +104,46 @@ function test_run_juju_as_root(){ install_mini_juju CHROOT="sudo $CHROOT" + CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" local output=$(run_juju_as_root pwd) - assertEquals "$output" "/" + assertEquals "/" "$output" run_juju_as_root [ -e /run/lock ] - assertEquals $? 0 + assertEquals 0 $? run_juju_as_root [ -e $HOME ] - assertEquals $? 0 + assertEquals 0 $? # test that normal user has ownership of the files created by root run_juju_as_root touch /a_root_file local output=$(run_juju_as_root stat -c '%u' /a_root_file) - assertEquals "$output" "$UID" + assertEquals "$UID" "$output" SH=("sh" "--login" "-c" "type -t type") local output=$(run_juju_as_root) - assertEquals "$output" "builtin" + assertEquals "builtin" "$output" SH=("sh" "--login" "-c" "[ -e /run/lock ]") run_juju_as_root - assertEquals $? 0 + assertEquals 0 $? SH=("sh" "--login" "-c" "[ -e $HOME ]") run_juju_as_root - assertEquals $? 0 + assertEquals 0 $? +} + +function test_run_juju_as_classic_root(){ + [ $SKIP_ROOT_TESTS -eq 1 ] && return + + install_mini_juju + CHROOT="sudo unknowncommand" + CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" + CHOWN="sudo $CHOWN" + + local output=$(run_juju_as_root pwd 2> /dev/null) + assertEquals "/" "$output" + run_juju_as_root [ -e /run/lock ] 2> /dev/null + assertEquals 0 $? + run_juju_as_root [ -e $HOME ] 2> /dev/null + assertEquals 0 $? } function test_run_juju_as_user(){ From 6e6d714127947d9b604d1d966725a87369a2eea6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 5 May 2015 23:26:47 +0000 Subject: [PATCH 083/326] Issue #73: Remove mtab symlink and avoid some error suppressions --- lib/core.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 0ebbbe0..2220436 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -165,11 +165,11 @@ function run_juju_as_root(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME}" EXIT QUIT ABRT KILL TERM INT - if ${CHROOT} $JUJU_HOME ${TRUE} &> /dev/null + if ${CHROOT} $JUJU_HOME ${TRUE} 1> /dev/null then JUJU_ENV=1 ${CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" local ret=$? - elif ${CLASSIC_CHROOT} $JUJU_HOME ${TRUE} &> /dev/null + elif ${CLASSIC_CHROOT} $JUJU_HOME ${TRUE} 1> /dev/null then warn "Warning: The executable arch-chroot does not work, falling back to classic chroot" JUJU_ENV=1 ${CLASSIC_CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" @@ -188,10 +188,10 @@ function run_juju_as_root(){ function _run_proot(){ local proot_args="$1" shift - if ${PROOT_COMPAT} $proot_args ${TRUE} &> /dev/null + if ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null then JUJU_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" - elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} &> /dev/null + elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null then warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" @@ -215,7 +215,7 @@ function _run_juju_with_proot(){ function run_juju_as_fakeroot(){ - local proot_args="$1" + local proot_args="$1 -b /etc/mtab" shift [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." @@ -283,6 +283,7 @@ function build_image_juju(){ # yaourt requires sed # coreutils is needed for chown sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring nano archlinux-keyring sed + sudo rm ${maindir}/root/etc/mtab sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." From 85d8e2ddeb4f1e455cd9579033810e60f00150c2 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 9 May 2015 16:12:51 +0000 Subject: [PATCH 084/326] Issue #73: Ensure to delete mtab in normal user --- README.md | 1 + lib/core.sh | 14 +++++++++++--- tests/test_core.sh | 19 +++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 95ab1cc..6a38f7f 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ of GNU/Linux distributions. The needed executables in the host OS are: - wget or curl - tar - mkdir +- ln - chown (for root access only) The minimum recommended linux kernel is 2.6.0+ diff --git a/lib/core.sh b/lib/core.sh index 2220436..dbe27d6 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -79,6 +79,7 @@ CLASSIC_CHROOT=${JUJU_HOME}/usr/bin/chroot TRUE=/usr/bin/true ID="/usr/bin/id -u" CHOWN="${JUJU_HOME}/usr/bin/chown" +LN="ln" ################################# MAIN FUNCTIONS ############################## @@ -163,7 +164,9 @@ function run_juju_as_root(){ local cmd="mkdir -p ${JUJU_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME}" EXIT QUIT ABRT KILL TERM INT + trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME}; rm -r ${JUJU_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + + [ ! -e ${JUJU_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJU_HOME}/etc/mtab if ${CHROOT} $JUJU_HOME ${TRUE} 1> /dev/null then @@ -181,6 +184,8 @@ function run_juju_as_root(){ # The ownership of the files in JuJu is assigned to the real user [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} + [ -e ${JUJU_HOME}/etc/mtab ] && rm -r ${JUJU_HOME}/etc/mtab + trap - QUIT EXIT ABRT KILL TERM INT return $? } @@ -215,10 +220,12 @@ function _run_juju_with_proot(){ function run_juju_as_fakeroot(){ - local proot_args="$1 -b /etc/mtab" + local proot_args="$1" shift [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." + + [ ! -e ${JUJU_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJU_HOME}/etc/mtab _run_juju_with_proot "-S ${JUJU_HOME} $proot_args" "${@}" } @@ -228,6 +235,8 @@ function run_juju_as_user(){ shift [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." + + [ -e ${JUJU_HOME}/etc/mtab ] && rm -f ${JUJU_HOME}/etc/mtab _run_juju_with_proot "-R ${JUJU_HOME} $proot_args" "${@}" } @@ -283,7 +292,6 @@ function build_image_juju(){ # yaourt requires sed # coreutils is needed for chown sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring nano archlinux-keyring sed - sudo rm ${maindir}/root/etc/mtab sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." diff --git a/tests/test_core.sh b/tests/test_core.sh index c374655..1444445 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -158,6 +158,25 @@ function test_run_juju_as_user(){ assertTrue "[ -e $JUJU_HOME/newdir ]" } +function test_run_juju_as_proot_mtab(){ + install_mini_juju + $(run_juju_as_fakeroot "-k 3.10" "echo") + assertTrue "[ -e $JUJU_HOME/etc/mtab ]" + $(run_juju_as_user "-k 3.10" "echo") + assertTrue "[ ! -e $JUJU_HOME/etc/mtab ]" +} + +function test_run_juju_as_root_mtab(){ + [ $SKIP_ROOT_TESTS -eq 1 ] && return + + install_mini_juju + CHROOT="sudo $CHROOT" + CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" + CHOWN="sudo $CHOWN" + $(run_juju_as_root "echo") + assertTrue "[ ! -e $JUJU_HOME/etc/mtab ]" +} + function test_run_juju_with_quotes(){ install_mini_juju local output=$(run_juju_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') From 1e3f25d5cb509eac7ddbf959ca31a5be361a6ba4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 15 May 2015 19:05:07 +0000 Subject: [PATCH 085/326] Issue #63: Parametrize the environment name --- bin/juju | 27 +++------ lib/core.sh | 125 ++++++++++++++++++++------------------- tests/test_core.sh | 144 ++++++++++++++++++++++----------------------- tests/test_juju.sh | 124 -------------------------------------- 4 files changed, 146 insertions(+), 274 deletions(-) delete mode 100755 tests/test_juju.sh diff --git a/bin/juju b/bin/juju index 8ff792b..1df1997 100755 --- a/bin/juju +++ b/bin/juju @@ -18,15 +18,6 @@ # along with this program. If not, see . # -NAME='JuJu' -CMD='juju' -VERSION='3.6.9' -CODE_NAME='Snake' -DESCRIPTION='The GNU/Linux distribution container for non-root users' -AUTHOR='Filippo Squillace ' -HOMEPAGE='https://github.com/fsquillace/juju' -COPYRIGHT='2012-2014' - source "$(dirname $0)/../lib/core.sh" ################################### @@ -35,7 +26,7 @@ source "$(dirname $0)/../lib/core.sh" usage() { echo -e "$NAME: $DESCRIPTION" - echo -e "Usage: $CMD [options] [command]" + echo -e "Usage: $CMD [options] [--] [command]" echo -e "Options:" echo -e "-i, --setup-from-file Setup the $NAME image in ${JUJU_HOME}" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" @@ -162,30 +153,30 @@ function execute_operation(){ $OPT_VERSION && version && return if $OPT_BUILD_IMAGE; then - build_image_juju $OPT_DISABLE_VALIDATION + build_image_env $OPT_DISABLE_VALIDATION return elif $OPT_DELETE; then - delete_juju + delete_env return fi - if ! is_juju_installed + if ! is_env_installed then if $OPT_SETUP_FROM_FILE; then - setup_from_file_juju $IMAGE_FILE + setup_env_from_file $IMAGE_FILE else - setup_juju + setup_env fi elif $OPT_SETUP_FROM_FILE; then die "Error: The image cannot be installed since $JUJU_HOME is not empty." fi if $OPT_FAKEROOT; then - run_juju_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" + run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" elif $OPT_ROOT; then - run_juju_as_root "${ARGS[@]}" + run_env_as_root "${ARGS[@]}" else - run_juju_as_user "${PROOT_ARGS}" "${ARGS[@]}" + run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" fi } diff --git a/lib/core.sh b/lib/core.sh index dbe27d6..e98a085 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash # -# This file is part of JuJu (https://github.com/fsquillace/juju). -# # Copyright (c) 2012-2015 # # This program is free software; you can redistribute it and/or modify it @@ -29,20 +27,31 @@ source "$(dirname ${BASH_ARGV[0]})/util.sh" ################################# VARIABLES ############################## +NAME='JuJu' +CMD='juju' +VERSION='3.6.9' +CODE_NAME='Snake' +DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' +AUTHOR='Filippo Squillace ' +HOMEPAGE="https://github.com/fsquillace/${CMD}" +COPYRIGHT='2012-2015' + + if [ "$JUJU_ENV" == "1" ] then - die "Error: Nested JuJu environments are not allowed" + die "Error: Nested ${NAME} environments are not allowed" elif [ ! -z $JUJU_ENV ] && [ "$JUJU_ENV" != "0" ] then die "The variable JUJU_ENV is not properly set" fi -[ -z ${JUJU_HOME} ] && JUJU_HOME=~/.juju +[ -z ${JUJU_HOME} ] && JUJU_HOME=~/.${CMD} if [ -z ${JUJU_TEMPDIR} ] || [ ! -d ${JUJU_TEMPDIR} ] then JUJU_TEMPDIR=/tmp fi -JUJU_REPO=https://bitbucket.org/fsquillace/juju-repo/raw/master + +ENV_REPO=https://bitbucket.org/fsquillace/${CMD}-repo/raw/master ORIGIN_WD=$(pwd) WGET="wget --no-check-certificate" @@ -88,7 +97,7 @@ function download(){ die "Error: Both wget and curl commands have failed on downloading $1" } -function is_juju_installed(){ +function is_env_installed(){ [ -d "$JUJU_HOME" ] && [ "$(ls -A $JUJU_HOME)" ] && return 0 return 1 } @@ -105,12 +114,12 @@ function _cleanup_build_directory(){ function _prepare_build_directory(){ trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${maindir}; die \"Error occurred when installing JuJu\"" EXIT QUIT ABRT KILL TERM INT + trap "rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT } -function _setup_juju(){ - is_juju_installed && die "Error: JuJu has been already installed in $JUJU_HOME" +function _setup_env(){ + is_env_installed && die "Error: ${NAME} has been already installed in $JUJU_HOME" mkdir -p "${JUJU_HOME}" imagepath=$1 $TAR -zxpf ${imagepath} -C ${JUJU_HOME} @@ -120,42 +129,38 @@ function _setup_juju(){ info " nano /etc/pacman.d/mirrorlist" info "Remember to refresh the package databases from the server:" info " pacman -Syy" - info "JuJu installed successfully" + info "${NAME} installed successfully" } -function setup_juju(){ -# Setup the JuJu environment - - local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) +function setup_env(){ + local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) _prepare_build_directory - info "Downloading JuJu..." + info "Downloading ${NAME}..." builtin cd ${maindir} - local imagefile=juju-${ARCH}.tar.gz - download ${JUJU_REPO}/${imagefile} + local imagefile=${CMD}-${ARCH}.tar.gz + download ${ENV_REPO}/${imagefile} - info "Installing JuJu..." - _setup_juju ${maindir}/${imagefile} + info "Installing ${NAME}..." + _setup_env ${maindir}/${imagefile} _cleanup_build_directory ${maindir} } -function setup_from_file_juju(){ -# Setup from file the JuJu environment - +function setup_env_from_file(){ local imagefile=$1 - [ ! -e ${imagefile} ] && die "Error: The JuJu image file ${imagefile} does not exist" + [ ! -e ${imagefile} ] && die "Error: The ${NAME} image file ${imagefile} does not exist" - info "Installing JuJu from ${imagefile}..." - _setup_juju ${imagefile} + info "Installing ${NAME} from ${imagefile}..." + _setup_env ${imagefile} builtin cd $ORIGIN_WD } -function run_juju_as_root(){ +function run_env_as_root(){ local uid=$UID [ -z $SUDO_UID ] || uid=$SUDO_UID:$SUDO_GID @@ -181,7 +186,7 @@ function run_juju_as_root(){ die "Error: Chroot does not work" fi - # The ownership of the files in JuJu is assigned to the real user + # The ownership of the files is assigned to the real user [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} [ -e ${JUJU_HOME}/etc/mtab ] && rm -r ${JUJU_HOME}/etc/mtab @@ -201,12 +206,12 @@ function _run_proot(){ warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" else - die "Error: Check if the juju arguments are correct or use the option juju -p \"-k 3.10\"" + die "Error: Check if the ${CMD} arguments are correct or use the option ${CMD} -p \"-k 3.10\"" fi } -function _run_juju_with_proot(){ +function _run_env_with_proot(){ local proot_args="$1" shift @@ -219,46 +224,46 @@ function _run_juju_with_proot(){ } -function run_juju_as_fakeroot(){ +function run_env_as_fakeroot(){ local proot_args="$1" shift [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." [ ! -e ${JUJU_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJU_HOME}/etc/mtab - _run_juju_with_proot "-S ${JUJU_HOME} $proot_args" "${@}" + _run_env_with_proot "-S ${JUJU_HOME} $proot_args" "${@}" } -function run_juju_as_user(){ +function run_env_as_user(){ local proot_args="$1" shift [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." [ -e ${JUJU_HOME}/etc/mtab ] && rm -f ${JUJU_HOME}/etc/mtab - _run_juju_with_proot "-R ${JUJU_HOME} $proot_args" "${@}" + _run_env_with_proot "-R ${JUJU_HOME} $proot_args" "${@}" } -function delete_juju(){ - ! ask "Are you sure to delete JuJu located in ${JUJU_HOME}" "N" && return +function delete_env(){ + ! ask "Are you sure to delete ${NAME} located in ${JUJU_HOME}" "N" && return if mountpoint -q ${JUJU_HOME} then info "There are mounted directories inside ${JUJU_HOME}" if ! umount --force ${JUJU_HOME} then error "Cannot umount directories in ${JUJU_HOME}" - die "Try to delete juju using root permissions" + die "Try to delete ${NAME} using root permissions" fi fi # the CA directories are read only and can be deleted only by changing the mod chmod -R +w ${JUJU_HOME}/etc/ca-certificates if rm -rf ${JUJU_HOME}/* then - info "JuJu deleted in ${JUJU_HOME}" + info "${NAME} deleted in ${JUJU_HOME}" else - error "Error: Cannot delete JuJu in ${JUJU_HOME}" + error "Error: Cannot delete ${NAME} in ${JUJU_HOME}" fi } @@ -271,7 +276,7 @@ function _check_package(){ } -function build_image_juju(){ +function build_image_env(){ # The function must runs on ArchLinux with non-root privileges. [ "$(${ID})" == "0" ] && \ die "You cannot build with root privileges." @@ -283,10 +288,10 @@ function build_image_juju(){ local disable_validation=$1 - local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t juju.XXXXXXXXXX) + local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) sudo mkdir -p ${maindir}/root trap - QUIT EXIT ABRT KILL TERM INT - trap "sudo rm -rf ${maindir}; die \"Error occurred when installing JuJu\"" EXIT QUIT ABRT KILL TERM INT + trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT info "Installing pacman and its dependencies..." # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # yaourt requires sed @@ -326,11 +331,11 @@ function build_image_juju(){ sudo sed -i -e 's/"--asroot"//' ${maindir}/root/opt/yaourt/bin/yaourt sudo cp ${maindir}/root/usr/bin/makepkg ${maindir}/root/opt/yaourt/bin/ sudo sed -i -e 's/EUID\s==\s0/false/' ${maindir}/root/opt/yaourt/bin/makepkg - sudo bash -c "echo 'export PATH=/opt/yaourt/bin:$PATH' > ${maindir}/root/etc/profile.d/juju.sh" - sudo chmod +x ${maindir}/root/etc/profile.d/juju.sh + sudo bash -c "echo 'export PATH=/opt/yaourt/bin:$PATH' > ${maindir}/root/etc/profile.d/${CMD}.sh" + sudo chmod +x ${maindir}/root/etc/profile.d/${CMD}.sh - info "Copying JuJu scripts..." - sudo git clone https://github.com/fsquillace/juju.git ${maindir}/root/opt/juju + info "Copying ${NAME} scripts..." + sudo git clone https://github.com/fsquillace/${CMD}.git ${maindir}/root/opt/${CMD} info "Setting up the pacman keyring (this might take a while!)..." sudo arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" @@ -339,7 +344,7 @@ function build_image_juju(){ mkdir -p ${maindir}/output builtin cd ${maindir}/output - local imagefile="juju-${ARCH}.tar.gz" + local imagefile="${CMD}-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . @@ -356,32 +361,32 @@ function build_image_juju(){ function validate_image(){ local testdir=$1 local imagefile=$2 - info "Validating JuJu image..." + info "Validating ${NAME} image..." $TAR -zxpf ${imagefile} -C ${testdir} mkdir -p ${testdir}/run/lock sed -i -e "s/#Server/Server/" ${testdir}/etc/pacman.d/mirrorlist - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -Syy + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy # Check most basic executables work - JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r pacman -Qi pacman 1> /dev/null - JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r yaourt -V 1> /dev/null - JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r arch-chroot --help 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -S base-devel + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel local yaourt_package=tcptraceroute info "Installing ${yaourt_package} package from AUR repo using proot..." - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" - JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r tcptraceroute localhost + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" + JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost local repo_package=sysstat info "Installing ${repo_package} package from official repo using proot..." - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -S ${repo_package} - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju iostat - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f iostat + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} iostat + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f iostat local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." - JUJU_HOME=${testdir} ${testdir}/opt/juju/bin/juju -f pacman --noconfirm -S ${repo_package} - JUJU_HOME=${testdir} sudo ${testdir}/opt/juju/bin/juju -r iftop -t -s 5 + JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} + JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 } diff --git a/tests/test_core.sh b/tests/test_core.sh index 1444445..ef144a2 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -4,22 +4,22 @@ function oneTimeSetUp(){ [ -z "$SKIP_ROOT_TESTS" ] && SKIP_ROOT_TESTS=0 CURRPWD=$PWD - JUJU_MAIN_HOME=/tmp/jujutesthome - [ -e $JUJU_MAIN_HOME ] || JUJU_HOME=$JUJU_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_juju" + ENV_MAIN_HOME=/tmp/envtesthome + [ -e $ENV_MAIN_HOME ] || JUJU_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env" JUJU_HOME="" } -function install_mini_juju(){ - cp -rfa $JUJU_MAIN_HOME/* $JUJU_HOME +function install_mini_env(){ + cp -rfa $ENV_MAIN_HOME/* $JUJU_HOME } function setUp(){ cd $CURRPWD - JUJU_HOME=$(TMPDIR=/tmp mktemp -d -t jujuhome.XXXXXXXXXX) + JUJU_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) source "$(dirname $0)/../lib/core.sh" - ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t jujuowd.XXXXXXXXXX) + ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX) cd $ORIGIN_WD - JUJU_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t jujutemp.XXXXXXXXXX) + JUJU_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) set +e @@ -38,11 +38,11 @@ function tearDown(){ } -function test_is_juju_installed(){ - is_juju_installed +function test_is_env_installed(){ + is_env_installed assertEquals $? 1 touch $JUJU_HOME/just_file - is_juju_installed + is_env_installed assertEquals $? 0 } @@ -63,7 +63,7 @@ function test_download(){ } -function test_setup_juju(){ +function test_setup_env(){ wget_mock(){ # Proof that the setup is happening # inside $JUJU_TEMPDIR @@ -71,148 +71,148 @@ function test_setup_juju(){ local parent_dir=${PWD%${cwd}} assertEquals "$JUJU_TEMPDIR" "${parent_dir}" touch file - tar -czvf juju-${ARCH}.tar.gz file + tar -czvf ${CMD}-${ARCH}.tar.gz file } WGET=wget_mock - setup_juju &> /dev/null + setup_env &> /dev/null assertTrue "[ -e $JUJU_HOME/file ]" assertTrue "[ -e $JUJU_HOME/run/lock ]" } -function test_setup_from_file_juju(){ +function test_setup_env_from_file(){ touch file - tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null - setup_from_file_juju juju-${ARCH}.tar.gz &> /dev/null + tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null + setup_env_from_file ${CMD}-${ARCH}.tar.gz &> /dev/null assertTrue "[ -e $JUJU_HOME/file ]" assertTrue "[ -e $JUJU_HOME/run/lock ]" - $(setup_from_file_juju noexist.tar.gz 2> /dev/null) + $(setup_env_from_file noexist.tar.gz 2> /dev/null) assertEquals $? 1 } -function test_setup_from_file_juju_with_absolute_path(){ +function test_setup_env_from_file_with_absolute_path(){ touch file - tar -czvf juju-${ARCH}.tar.gz file 1> /dev/null - setup_from_file_juju ${ORIGIN_WD}/juju-${ARCH}.tar.gz &> /dev/null + tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null + setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz &> /dev/null assertTrue "[ -e $JUJU_HOME/file ]" assertTrue "[ -e $JUJU_HOME/run/lock ]" } -function test_run_juju_as_root(){ +function test_run_env_as_root(){ [ $SKIP_ROOT_TESTS -eq 1 ] && return - install_mini_juju + install_mini_env CHROOT="sudo $CHROOT" CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" - local output=$(run_juju_as_root pwd) + local output=$(run_env_as_root pwd) assertEquals "/" "$output" - run_juju_as_root [ -e /run/lock ] + run_env_as_root [ -e /run/lock ] assertEquals 0 $? - run_juju_as_root [ -e $HOME ] + run_env_as_root [ -e $HOME ] assertEquals 0 $? # test that normal user has ownership of the files created by root - run_juju_as_root touch /a_root_file - local output=$(run_juju_as_root stat -c '%u' /a_root_file) + run_env_as_root touch /a_root_file + local output=$(run_env_as_root stat -c '%u' /a_root_file) assertEquals "$UID" "$output" SH=("sh" "--login" "-c" "type -t type") - local output=$(run_juju_as_root) + local output=$(run_env_as_root) assertEquals "builtin" "$output" SH=("sh" "--login" "-c" "[ -e /run/lock ]") - run_juju_as_root + run_env_as_root assertEquals 0 $? SH=("sh" "--login" "-c" "[ -e $HOME ]") - run_juju_as_root + run_env_as_root assertEquals 0 $? } -function test_run_juju_as_classic_root(){ +function test_run_env_as_classic_root(){ [ $SKIP_ROOT_TESTS -eq 1 ] && return - install_mini_juju + install_mini_env CHROOT="sudo unknowncommand" CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" - local output=$(run_juju_as_root pwd 2> /dev/null) + local output=$(run_env_as_root pwd 2> /dev/null) assertEquals "/" "$output" - run_juju_as_root [ -e /run/lock ] 2> /dev/null + run_env_as_root [ -e /run/lock ] 2> /dev/null assertEquals 0 $? - run_juju_as_root [ -e $HOME ] 2> /dev/null + run_env_as_root [ -e $HOME ] 2> /dev/null assertEquals 0 $? } -function test_run_juju_as_user(){ - install_mini_juju - local output=$(run_juju_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') +function test_run_env_as_user(){ + install_mini_env + local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUJU_HOME/newdir2 ]" SH=("/usr/bin/mkdir" "-v" "/newdir") - local output=$(run_juju_as_user "-k 3.10" | awk -F: '{print $1}') + local output=$(run_env_as_user "-k 3.10" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUJU_HOME/newdir ]" } -function test_run_juju_as_proot_mtab(){ - install_mini_juju - $(run_juju_as_fakeroot "-k 3.10" "echo") +function test_run_env_as_proot_mtab(){ + install_mini_env + $(run_env_as_fakeroot "-k 3.10" "echo") assertTrue "[ -e $JUJU_HOME/etc/mtab ]" - $(run_juju_as_user "-k 3.10" "echo") + $(run_env_as_user "-k 3.10" "echo") assertTrue "[ ! -e $JUJU_HOME/etc/mtab ]" } -function test_run_juju_as_root_mtab(){ +function test_run_env_as_root_mtab(){ [ $SKIP_ROOT_TESTS -eq 1 ] && return - install_mini_juju + install_mini_env CHROOT="sudo $CHROOT" CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" - $(run_juju_as_root "echo") + $(run_env_as_root "echo") assertTrue "[ ! -e $JUJU_HOME/etc/mtab ]" } -function test_run_juju_with_quotes(){ - install_mini_juju - local output=$(run_juju_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') +function test_run_env_with_quotes(){ + install_mini_env + local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUJU_HOME/newdir2 ]" } -function test_run_juju_as_user_proot_args(){ - install_mini_juju - run_juju_as_user "--help" "" &> /dev/null +function test_run_env_as_user_proot_args(){ + install_mini_env + run_env_as_user "--help" "" &> /dev/null assertEquals $? 0 mkdir $JUJU_TEMPDIR/newdir touch $JUJU_TEMPDIR/newdir/newfile - run_juju_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null + run_env_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null assertEquals $? 0 - $(_run_juju_with_proot --helps 2> /dev/null) + $(_run_env_with_proot --helps 2> /dev/null) assertEquals $? 1 } -function test_run_juju_with_proot_compat(){ +function test_run_env_with_proot_compat(){ PROOT_COMPAT="/bin/true" - _run_juju_with_proot "" "" &> /dev/null + _run_env_with_proot "" "" &> /dev/null assertEquals $? 0 - $(PROOT_COMPAT="/bin/false" _run_juju_with_proot --helps 2> /dev/null) + $(PROOT_COMPAT="/bin/false" _run_env_with_proot --helps 2> /dev/null) assertEquals $? 1 } -function test_run_juju_with_proot_as_root(){ - install_mini_juju +function test_run_env_with_proot_as_root(){ + install_mini_env - $(ID="/bin/echo 0" run_juju_as_user 2> /dev/null) + $(ID="/bin/echo 0" run_env_as_user 2> /dev/null) assertEquals $? 1 - $(ID="/bin/echo 0" run_juju_as_fakeroot 2> /dev/null) + $(ID="/bin/echo 0" run_env_as_fakeroot 2> /dev/null) assertEquals $? 1 } @@ -230,24 +230,24 @@ function test_run_proot_seccomp(){ assertEquals "$output" "PROOT_NO_SECCOMP=1" } -function test_run_juju_as_fakeroot(){ - install_mini_juju - local output=$(run_juju_as_fakeroot "-k 3.10" "id" | awk '{print $1}') +function test_run_env_as_fakeroot(){ + install_mini_env + local output=$(run_env_as_fakeroot "-k 3.10" "id" | awk '{print $1}') assertEquals "$output" "uid=0(root)" } -function test_delete_juju(){ - install_mini_juju - echo "N" | delete_juju 1> /dev/null - is_juju_installed +function test_delete_env(){ + install_mini_env + echo "N" | delete_env 1> /dev/null + is_env_installed assertEquals $? 0 - echo "Y" | delete_juju 1> /dev/null - is_juju_installed + echo "Y" | delete_env 1> /dev/null + is_env_installed assertEquals $? 1 } -function test_nested_juju(){ - install_mini_juju +function test_nested_env(){ + install_mini_env JUJU_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null assertEquals $? 1 } diff --git a/tests/test_juju.sh b/tests/test_juju.sh deleted file mode 100755 index e16a648..0000000 --- a/tests/test_juju.sh +++ /dev/null @@ -1,124 +0,0 @@ -#!/bin/bash -source $(dirname $0)/../bin/juju -h &> /dev/null - -# Disable the exiterr -set +e - -## Mock functions ## -function usage(){ - echo "usage" -} -function version(){ - echo "version" -} -function build_image_juju(){ - echo "build_image_juju" -} -function delete_juju(){ - echo "delete_juju" -} -function is_juju_installed(){ - return 0 -} -function setup_from_file_juju(){ - echo "setup_from_file_juju $@" -} -function setup_juju(){ - echo "setup_juju" -} -function run_juju_as_fakeroot(){ - local proot_args="$1" - shift - echo "run_juju_as_fakeroot($proot_args,$@)" -} -function run_juju_as_root(){ - echo "run_juju_as_root $@" -} -function run_juju_as_user(){ - local proot_args="$1" - shift - echo "run_juju_as_user($proot_args,$@)" -} - -function wrap_juju(){ - parse_arguments "$@" - check_cli - execute_operation -} - -function test_help(){ - local output=$(wrap_juju -h) - assertEquals $output "usage" - local output=$(wrap_juju --help) - assertEquals $output "usage" -} -function test_version(){ - local output=$(wrap_juju -v) - assertEquals $output "version" - local output=$(wrap_juju --version) - assertEquals $output "version" -} -function test_build_image_juju(){ - local output=$(wrap_juju -b) - assertEquals $output "build_image_juju" - local output=$(wrap_juju --build-image) - assertEquals $output "build_image_juju" -} -function test_delete_juju(){ - local output=$(wrap_juju -d) - assertEquals $output "delete_juju" - local output=$(wrap_juju --delete) - assertEquals $output "delete_juju" -} -function test_run_juju_as_fakeroot(){ - local output=$(wrap_juju -f) - assertEquals $output "run_juju_as_fakeroot(,)" - local output=$(wrap_juju --fakeroot) - assertEquals $output "run_juju_as_fakeroot(,)" - - local output=$(wrap_juju -f -p "-b arg") - assertEquals "${output[@]}" "run_juju_as_fakeroot(-b arg,)" - local output=$(wrap_juju -f -p "-b arg" -- command -kv) - assertEquals "${output[@]}" "run_juju_as_fakeroot(-b arg,command -kv)" - local output=$(wrap_juju -f command --as) - assertEquals "${output[@]}" "run_juju_as_fakeroot(,command --as)" -} -function test_run_juju_as_user(){ - local output=$(wrap_juju) - assertEquals $output "run_juju_as_user(,)" - - local output=$(wrap_juju -p "-b arg") - assertEquals "$output" "run_juju_as_user(-b arg,)" - local output=$(wrap_juju -p "-b arg" -- command -ll) - assertEquals "$output" "run_juju_as_user(-b arg,command -ll)" - local output=$(wrap_juju command -ls) - assertEquals "$output" "run_juju_as_user(,command -ls)" -} -function test_run_juju_as_root(){ - local output=$(wrap_juju -r) - assertEquals $output "run_juju_as_root" - - local output=$(wrap_juju -r command) - assertEquals "${output[@]}" "run_juju_as_root command" -} - -function test_check_cli(){ - $(wrap_juju -b -h 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -n -v 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -d -r 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -h -f 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -v -i fsd 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -f -r 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -p args -v 2> /dev/null) - assertEquals $? 1 - $(wrap_juju -d args 2> /dev/null) - assertEquals $? 1 -} - -source $(dirname $0)/shunit2 From 39b0e941b8f5f4f4298be35d0996c623f3afb5a4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 16 May 2015 13:13:36 +0000 Subject: [PATCH 086/326] Issue #63: Change name to JuJube! --- .travis.yml | 22 +++---- README.md | 135 +++++++++++++++++++++++++------------------ bin/{juju => jujube} | 8 +-- lib/core.sh | 128 ++++++++++++++++++++-------------------- lib/util.sh | 2 +- tests/test_cli.sh | 124 +++++++++++++++++++++++++++++++++++++++ tests/test_core.sh | 58 +++++++++---------- 7 files changed, 311 insertions(+), 166 deletions(-) rename bin/{juju => jujube} (96%) create mode 100755 tests/test_cli.sh diff --git a/.travis.yml b/.travis.yml index 550c119..9554a88 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,20 +4,20 @@ sudo: required install: - PATH=$PWD/bin:$PATH - - juju -f echo 'Installing juju' - - sed -i -e "s/#Server/Server/" ~/.juju/etc/pacman.d/mirrorlist - - juju -f pacman --noconfirm -Syy - - juju -f pacman --noconfirm -S base-devel + - jujube -f echo 'Installing jujube' + - sed -i -e "s/#Server/Server/" ~/.jujube/etc/pacman.d/mirrorlist + - jujube -f pacman --noconfirm -Syy + - jujube -f pacman --noconfirm -S base-devel script: - ./tests/test_all.sh # Test on installing package from AUR - - juju -f yaourt --noconfirm -S tcptraceroute - - sudo $PWD/bin/juju -r tcptraceroute localhost + - jujube -f yaourt --noconfirm -S tcptraceroute + - sudo $PWD/bin/jujube -r tcptraceroute localhost # Test on installing package from official repo - - juju -f pacman --noconfirm -S tree - - juju -f tree + - jujube -f pacman --noconfirm -S tree + - jujube -f tree # Test on installing package from official repo with root access - - juju -f pacman --noconfirm -S iftop - - sudo bin/juju -r iftop -t -s 5 - - yes | juju -d + - jujube -f pacman --noconfirm -S iftop + - sudo bin/jujube -r iftop -t -s 5 + - yes | jujube -d diff --git a/README.md b/README.md index 6a38f7f..1b8072b 100644 --- a/README.md +++ b/README.md @@ -1,123 +1,119 @@ -JuJu +JuJube ==== -**JuJu**: the Arch Linux based distro that runs upon any Linux distros without root access +**JuJube**: the Arch Linux based distro that runs upon any Linux distros without root access -[![Build status](https://api.travis-ci.org/fsquillace/juju.png?branch=master)](https://travis-ci.org/fsquillace/juju) +[![Build status](https://api.travis-ci.org/fsquillace/jujube.png?branch=master)](https://travis-ci.org/fsquillace/jujube) Description ----------- -**JuJu** is a lightweight Arch Linux based distribution that allows to have +**JuJube** is a lightweight Arch Linux based distribution that allows to have an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. -JuJu contains mainly the package managers (called pacman and yaourt) that allows to access +JuJube contains mainly the package managers (called pacman and yaourt) that allows to access to a wide range of packages from the Arch Linux repositories. -The main advantages on using JuJu are: +The main advantages on using JuJube are: - Install packages without root privileges. - Isolated environment in which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). - Available for x86\_64, x86 and ARM architectures but you can build your own image from scratch too! - All Arch Linux lovers can have their favourite distro everywhere! +JuJube follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way). + Quickstart ---------- -There are three different ways you can run JuJu: +There are three different ways you can run JuJube: - As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): -```sh - juju -``` + jujube - As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): -```sh - juju -f -``` + jujube -f -- As root - Allow to have fully root privileges inside JuJu environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): +- As root - Allow to have fully root privileges inside JuJube environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): -```sh - juju -r -``` + jujube -r -If the JuJu image has not been downloaded yet, the script will download -the JuJu image and will place it to the default directory ~/.juju. -You can change the default directory by changing the environment variable *JUJU\_HOME*. +If the JuJube image has not been downloaded yet, the script will download +the JuJube image and will place it to the default directory ~/.jujube. +You can change the default directory by changing the environment variable *JUJUBE\_HOME*. If you are new on Archlinux and you are not familiar with *pacman* package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). Installation ------------ -Just clone the JuJu repo somewhere (for example in ~/juju): +Just clone the JuJube repo somewhere (for example in ~/jujube): - git clone git://github.com/fsquillace/juju ~/juju - export PATH=~/juju/bin:$PATH + git clone git://github.com/fsquillace/jujube ~/jujube + export PATH=~/jujube/bin:$PATH -Alternatively, another installation method would be to directly download the JuJu image and place it to the default directory ~/.juju: +Alternatively, another installation method would be to directly download the JuJube image and place it to the default directory ~/.jujube: ARCH= - mkdir ~/.juju - curl https://bitbucket.org/fsquillace/juju-repo/raw/master/juju-${ARCH}.tar.gz | tar -xz -C ~/.juju - export PATH=~/.juju/opt/juju/bin:$PATH + mkdir ~/.jujube + curl https://dl.dropboxusercontent.com/u/42449030/jujube/jujube-${ARCH}.tar.gz | tar -xz -C ~/.jujube + export PATH=~/.jujube/opt/jujube/bin:$PATH -JuJu can works on GNU/Linux OS with kernel version greater or equal -2.6.0 (JuJu was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. +JuJube can works on GNU/Linux OS with kernel version greater or equal +2.6.0 (JuJube was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. Advanced usage -------------- ### Build image ### -You can build a new JuJu image from scratch by running the following command: +You can build a new JuJube image from scratch by running the following command: - juju -b [-n] + jujube -b [-n] The script will create a directory containing all the essentials -files in order to make JuJu working properly (such as pacman, yaourt, arch-chroot and proot). +files in order to make JuJube working properly (such as pacman, yaourt, arch-chroot and proot). The option `-n` will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. -To change the build directory just use the *JUJU_TEMPDIR* (by default /tmp). +To change the build directory just use the *JUJUBE_TEMPDIR* (by default /tmp). -After creating the image juju-x86\_64.tar.gz you can install it by running: +After creating the image jujube-x86\_64.tar.gz you can install it by running: - juju -i juju-x86_64.tar.gz + jujube -i jujube-x86_64.tar.gz Related wiki page: -- [How to build a JuJu image using QEMU](https://github.com/fsquillace/juju/wiki/How-to-build-a-JuJu-image-using-QEMU) +- [How to build a JuJube image using QEMU](https://github.com/fsquillace/jujube/wiki/How-to-build-a-JuJube-image-using-QEMU) ### Bind directories ### To bind a host directory to a guest location, you can use proot arguments: - juju -p "-b /mnt/mydata:/home/user/mydata" + jujube -p "-b /mnt/mydata:/home/user/mydata" Check out the proot options with: - juju -p "--help" + jujube -p "--help" ###Automatic fallback to classic chroot### Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work -on some distros, JuJu automatically tries to fallback to the classic chroot. +on some distros, JuJube automatically tries to fallback to the classic chroot. -### JuJu as a container ### -Although JuJu has not been designed to be a complete container, it is even possible to +### JuJube as a container ### +Although JuJube has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). -The JuJu containter allows to run services inside the container that can be +The JuJube containter allows to run services inside the container that can be visible from the host OS through the network. The drawbacks of this are that the host OS must use systemd as a service manager, and the container can only be executed using root privileges. -To boot a JuJu container: +To boot a JuJube container: - sudo systemd-nspawn -bD ~/.juju + sudo systemd-nspawn -bD ~/.jujube Related wiki page: -- [How to run juju as a container](https://github.com/fsquillace/juju/wiki/How-to-run-JuJu-as-a-container) +- [How to run jujube as a container](https://github.com/fsquillace/jujube/wiki/How-to-run-JuJube-as-a-container) Dependencies ------------ -JuJu comes with a very short list of dependencies in order to be installed in most +JuJube comes with a very short list of dependencies in order to be installed in most of GNU/Linux distributions. The needed executables in the host OS are: - bash - wget or curl @@ -136,7 +132,7 @@ Troubleshooting ``` Cannot find the gzip binary required for compressing man and info pages. ``` -- **A**: JuJu comes with a very basic number of packages. +- **A**: JuJube comes with a very basic number of packages. In order to install packages using yaourt you may need to install the package group *base-devel* that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): @@ -148,19 +144,19 @@ that contains all the essential packages for compiling source code (such as gcc, - **Q**: Why do I get the error: "FATAL: kernel too old"? - **A**: This is because the executable from the precompiled package cannot properly run if the kernel is old. -JuJu contains two different PRoot binaries, and one of them is highly compatible -with old linux kernel versions. JuJu will detect which PRoot binary need to be +JuJube contains two different PRoot binaries, and one of them is highly compatible +with old linux kernel versions. JuJube will detect which PRoot binary need to be executed but you may need to specify the PRoot *-k* option if the guest rootfs requires a newer kernel version: ``` - juju -p "-k 3.10" + jujube -p "-k 3.10" ``` -In order to check if an executable inside JuJu environment can be compatible +In order to check if an executable inside JuJube environment can be compatible with the kernel of the host OS just use the *file* command, for instance: ``` - file ~/.juju/usr/bin/bash + file ~/.jujube/usr/bin/bash ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped @@ -178,7 +174,7 @@ From the output you can see what is the minimum recommended Linux kernel version - **A**: The ping command uses *suid* permissions that allow to execute the command using root privileges. The fakeroot mode is not able to execute a command set with suid, and you may need to use root privileges. There are other few commands that -have *suid* permission, you can list the commands from your JuJu environment +have *suid* permission, you can list the commands from your JuJube environment with the following command: ``` find /usr/bin -perm +4000 @@ -208,7 +204,7 @@ To quick fix this, you can just install a fonts package: - **A**: In these cases the package installation went smoothly anyway. This should happen every time you install package with root privileges -since JuJu will try to preserve the JuJu environment by assigning ownership +since JuJube will try to preserve the JuJube environment by assigning ownership of the files to the real user. ###No servers configured for repository### @@ -250,8 +246,33 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -## Author +Author +------ Filippo Squillace -## WWW -https://github.com/fsquillace/juju +WWW +--- +https://github.com/fsquillace/jujube + +Last words +--------- +Quote of the [lotus](http://en.wikipedia.org/wiki/Ziziphus_lotus) (a selvatic jujube plant) + +> Per nove infausti dì sul mar pescoso +> i venti rei mi trasportaro. Al fine +> nel decimo sbarcammo in su le rive +> de’ Lotofági, un popolo, a cui cibo +> È d’una pianta il florido germoglio. +> ... +> ... +> Partiro e s’affrontaro a quella gente, +> che, lunge dal voler la vita loro, +> il dolce loto a savorar lor porse. +> chiunque l’esca dilettosa, e nuova +> gustato avea, con le novelle indietro +> non bramava tornar: colà bramava +> starsi, e, mangiando del soave loto, +> la contrada natia sbandir dal petto. + +verse 105-123, Homer, from [Odyssey Book IX](http://it.wikisource.org/wiki/Odissea/Libro_IX) +([en](http://en.wikisource.org/wiki/The_Odyssey_(Butler)/Book_IX)) diff --git a/bin/juju b/bin/jujube similarity index 96% rename from bin/juju rename to bin/jujube index 1df1997..b68ad02 100755 --- a/bin/juju +++ b/bin/jujube @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# This file is part of JuJu (https://github.com/fsquillace/juju). +# This file is part of JuJube (https://github.com/fsquillace/jujube). # # Copyright (c) 2012-2015 # @@ -28,13 +28,13 @@ usage() { echo -e "$NAME: $DESCRIPTION" echo -e "Usage: $CMD [options] [--] [command]" echo -e "Options:" - echo -e "-i, --setup-from-file Setup the $NAME image in ${JUJU_HOME}" + echo -e "-i, --setup-from-file Setup the $NAME image in ${JUJUBE_HOME}" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" echo -e "-p, --proot-args Proot arguments" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" - echo -e "-d, --delete Delete $NAME from ${JUJU_HOME}" + echo -e "-d, --delete Delete $NAME from ${JUJUBE_HOME}" echo -e "-h, --help Show this help message" echo -e "-v, --version Show the $NAME version" } @@ -168,7 +168,7 @@ function execute_operation(){ setup_env fi elif $OPT_SETUP_FROM_FILE; then - die "Error: The image cannot be installed since $JUJU_HOME is not empty." + die "Error: The image cannot be installed since $JUJUBE_HOME is not empty." fi if $OPT_FAKEROOT; then diff --git a/lib/core.sh b/lib/core.sh index e98a085..88973c6 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -27,31 +27,31 @@ source "$(dirname ${BASH_ARGV[0]})/util.sh" ################################# VARIABLES ############################## -NAME='JuJu' -CMD='juju' -VERSION='3.6.9' -CODE_NAME='Snake' +NAME='JuJube' +CMD='jujube' +VERSION='4.7.4' +CODE_NAME='Mairei' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' AUTHOR='Filippo Squillace ' HOMEPAGE="https://github.com/fsquillace/${CMD}" COPYRIGHT='2012-2015' -if [ "$JUJU_ENV" == "1" ] +if [ "$JUJUBE_ENV" == "1" ] then die "Error: Nested ${NAME} environments are not allowed" -elif [ ! -z $JUJU_ENV ] && [ "$JUJU_ENV" != "0" ] +elif [ ! -z $JUJUBE_ENV ] && [ "$JUJUBE_ENV" != "0" ] then - die "The variable JUJU_ENV is not properly set" + die "The variable JUJUBE_ENV is not properly set" fi -[ -z ${JUJU_HOME} ] && JUJU_HOME=~/.${CMD} -if [ -z ${JUJU_TEMPDIR} ] || [ ! -d ${JUJU_TEMPDIR} ] +[ -z ${JUJUBE_HOME} ] && JUJUBE_HOME=~/.${CMD} +if [ -z ${JUJUBE_TEMPDIR} ] || [ ! -d ${JUJUBE_TEMPDIR} ] then - JUJU_TEMPDIR=/tmp + JUJUBE_TEMPDIR=/tmp fi -ENV_REPO=https://bitbucket.org/fsquillace/${CMD}-repo/raw/master +ENV_REPO=https://dl.dropboxusercontent.com/u/42449030/${CMD} ORIGIN_WD=$(pwd) WGET="wget --no-check-certificate" @@ -66,28 +66,28 @@ HOST_ARCH=$(uname -m) if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then ARCH="x86" - LD_LIB="${JUJU_HOME}/lib/ld-linux.so.2" + LD_LIB="${JUJUBE_HOME}/lib/ld-linux.so.2" elif [ $HOST_ARCH == "x86_64" ] then ARCH="x86_64" - LD_LIB="${JUJU_HOME}/lib64/ld-linux-x86-64.so.2" + LD_LIB="${JUJUBE_HOME}/lib64/ld-linux-x86-64.so.2" elif [[ $HOST_ARCH =~ .*(arm).* ]] then ARCH="arm" - LD_LIB="${JUJU_HOME}/lib/ld-linux-armhf.so.3" + LD_LIB="${JUJUBE_HOME}/lib/ld-linux-armhf.so.3" else die "Unknown architecture ${ARCH}" fi -PROOT_COMPAT="${JUJU_HOME}/opt/proot/proot-${ARCH}" +PROOT_COMPAT="${JUJUBE_HOME}/opt/proot/proot-${ARCH}" PROOT_LINK=http://static.proot.me/proot-${ARCH} SH=("/bin/sh" "--login") -CHROOT=${JUJU_HOME}/usr/bin/arch-chroot -CLASSIC_CHROOT=${JUJU_HOME}/usr/bin/chroot +CHROOT=${JUJUBE_HOME}/usr/bin/arch-chroot +CLASSIC_CHROOT=${JUJUBE_HOME}/usr/bin/chroot TRUE=/usr/bin/true ID="/usr/bin/id -u" -CHOWN="${JUJU_HOME}/usr/bin/chown" +CHOWN="${JUJUBE_HOME}/usr/bin/chown" LN="ln" ################################# MAIN FUNCTIONS ############################## @@ -98,7 +98,7 @@ function download(){ } function is_env_installed(){ - [ -d "$JUJU_HOME" ] && [ "$(ls -A $JUJU_HOME)" ] && return 0 + [ -d "$JUJUBE_HOME" ] && [ "$(ls -A $JUJUBE_HOME)" ] && return 0 return 1 } @@ -119,11 +119,11 @@ function _prepare_build_directory(){ function _setup_env(){ - is_env_installed && die "Error: ${NAME} has been already installed in $JUJU_HOME" - mkdir -p "${JUJU_HOME}" + is_env_installed && die "Error: ${NAME} has been already installed in $JUJUBE_HOME" + mkdir -p "${JUJUBE_HOME}" imagepath=$1 - $TAR -zxpf ${imagepath} -C ${JUJU_HOME} - mkdir -p ${JUJU_HOME}/run/lock + $TAR -zxpf ${imagepath} -C ${JUJUBE_HOME} + mkdir -p ${JUJUBE_HOME}/run/lock warn "Warn: The default mirror URL is ${DEFAULT_MIRROR}." warn "To change it:" info " nano /etc/pacman.d/mirrorlist" @@ -134,7 +134,7 @@ function _setup_env(){ function setup_env(){ - local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + local maindir=$(TMPDIR=$JUJUBE_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) _prepare_build_directory info "Downloading ${NAME}..." @@ -166,30 +166,30 @@ function run_env_as_root(){ local main_cmd="${SH[@]}" [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" - local cmd="mkdir -p ${JUJU_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" + local cmd="mkdir -p ${JUJUBE_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME}; rm -r ${JUJU_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJUBE_HOME}; rm -r ${JUJUBE_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT - [ ! -e ${JUJU_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJU_HOME}/etc/mtab + [ ! -e ${JUJUBE_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJUBE_HOME}/etc/mtab - if ${CHROOT} $JUJU_HOME ${TRUE} 1> /dev/null + if ${CHROOT} $JUJUBE_HOME ${TRUE} 1> /dev/null then - JUJU_ENV=1 ${CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" + JUJUBE_ENV=1 ${CHROOT} $JUJUBE_HOME "${SH[@]}" "-c" "${cmd}" local ret=$? - elif ${CLASSIC_CHROOT} $JUJU_HOME ${TRUE} 1> /dev/null + elif ${CLASSIC_CHROOT} $JUJUBE_HOME ${TRUE} 1> /dev/null then warn "Warning: The executable arch-chroot does not work, falling back to classic chroot" - JUJU_ENV=1 ${CLASSIC_CHROOT} $JUJU_HOME "${SH[@]}" "-c" "${cmd}" + JUJUBE_ENV=1 ${CLASSIC_CHROOT} $JUJUBE_HOME "${SH[@]}" "-c" "${cmd}" local ret=$? else die "Error: Chroot does not work" fi # The ownership of the files is assigned to the real user - [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJU_HOME} + [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJUBE_HOME} - [ -e ${JUJU_HOME}/etc/mtab ] && rm -r ${JUJU_HOME}/etc/mtab + [ -e ${JUJUBE_HOME}/etc/mtab ] && rm -r ${JUJUBE_HOME}/etc/mtab trap - QUIT EXIT ABRT KILL TERM INT return $? @@ -200,11 +200,11 @@ function _run_proot(){ shift if ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null then - JUJU_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" + JUJUBE_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null then warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." - JUJU_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" + JUJUBE_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" else die "Error: Check if the ${CMD} arguments are correct or use the option ${CMD} -p \"-k 3.10\"" fi @@ -227,43 +227,43 @@ function _run_env_with_proot(){ function run_env_as_fakeroot(){ local proot_args="$1" shift - [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(_run_proot "-R ${JUJUBE_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - [ ! -e ${JUJU_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJU_HOME}/etc/mtab - _run_env_with_proot "-S ${JUJU_HOME} $proot_args" "${@}" + [ ! -e ${JUJUBE_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJUBE_HOME}/etc/mtab + _run_env_with_proot "-S ${JUJUBE_HOME} $proot_args" "${@}" } function run_env_as_user(){ local proot_args="$1" shift - [ "$(_run_proot "-R ${JUJU_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(_run_proot "-R ${JUJUBE_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - [ -e ${JUJU_HOME}/etc/mtab ] && rm -f ${JUJU_HOME}/etc/mtab - _run_env_with_proot "-R ${JUJU_HOME} $proot_args" "${@}" + [ -e ${JUJUBE_HOME}/etc/mtab ] && rm -f ${JUJUBE_HOME}/etc/mtab + _run_env_with_proot "-R ${JUJUBE_HOME} $proot_args" "${@}" } function delete_env(){ - ! ask "Are you sure to delete ${NAME} located in ${JUJU_HOME}" "N" && return - if mountpoint -q ${JUJU_HOME} + ! ask "Are you sure to delete ${NAME} located in ${JUJUBE_HOME}" "N" && return + if mountpoint -q ${JUJUBE_HOME} then - info "There are mounted directories inside ${JUJU_HOME}" - if ! umount --force ${JUJU_HOME} + info "There are mounted directories inside ${JUJUBE_HOME}" + if ! umount --force ${JUJUBE_HOME} then - error "Cannot umount directories in ${JUJU_HOME}" + error "Cannot umount directories in ${JUJUBE_HOME}" die "Try to delete ${NAME} using root permissions" fi fi # the CA directories are read only and can be deleted only by changing the mod - chmod -R +w ${JUJU_HOME}/etc/ca-certificates - if rm -rf ${JUJU_HOME}/* + chmod -R +w ${JUJUBE_HOME}/etc/ca-certificates + if rm -rf ${JUJUBE_HOME}/* then - info "${NAME} deleted in ${JUJU_HOME}" + info "${NAME} deleted in ${JUJUBE_HOME}" else - error "Error: Cannot delete ${NAME} in ${JUJU_HOME}" + error "Error: Cannot delete ${NAME} in ${JUJUBE_HOME}" fi } @@ -288,7 +288,7 @@ function build_image_env(){ local disable_validation=$1 - local maindir=$(TMPDIR=$JUJU_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + local maindir=$(TMPDIR=$JUJUBE_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) sudo mkdir -p ${maindir}/root trap - QUIT EXIT ABRT KILL TERM INT trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT @@ -365,28 +365,28 @@ function validate_image(){ $TAR -zxpf ${imagefile} -C ${testdir} mkdir -p ${testdir}/run/lock sed -i -e "s/#Server/Server/" ${testdir}/etc/pacman.d/mirrorlist - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy # Check most basic executables work - JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null - JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null - JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null + JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null + JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null + JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel local yaourt_package=tcptraceroute info "Installing ${yaourt_package} package from AUR repo using proot..." - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" - JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" + JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost local repo_package=sysstat info "Installing ${repo_package} package from official repo using proot..." - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} iostat - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f iostat + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} iostat + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f iostat local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." - JUJU_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUJU_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 + JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} + JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 } diff --git a/lib/util.sh b/lib/util.sh index 52e1b24..53b424e 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# This file is part of JuJu (https://github.com/fsquillace/juju) +# This file is part of JuJube (https://github.com/fsquillace/jujube) # # Copyright (c) 2012-2015 # diff --git a/tests/test_cli.sh b/tests/test_cli.sh new file mode 100755 index 0000000..a9e0a13 --- /dev/null +++ b/tests/test_cli.sh @@ -0,0 +1,124 @@ +#!/bin/bash +source $(dirname $0)/../bin/* -h &> /dev/null + +# Disable the exiterr +set +e + +## Mock functions ## +function usage(){ + echo "usage" +} +function version(){ + echo "version" +} +function build_image_env(){ + echo "build_image_env" +} +function delete_env(){ + echo "delete_env" +} +function is_env_installed(){ + return 0 +} +function setup_env_from_file(){ + echo "setup_env_from_file $@" +} +function setup_env(){ + echo "setup_env" +} +function run_env_as_fakeroot(){ + local proot_args="$1" + shift + echo "run_env_as_fakeroot($proot_args,$@)" +} +function run_env_as_root(){ + echo "run_env_as_root $@" +} +function run_env_as_user(){ + local proot_args="$1" + shift + echo "run_env_as_user($proot_args,$@)" +} + +function wrap_env(){ + parse_arguments "$@" + check_cli + execute_operation +} + +function test_help(){ + local output=$(wrap_env -h) + assertEquals $output "usage" + local output=$(wrap_env --help) + assertEquals $output "usage" +} +function test_version(){ + local output=$(wrap_env -v) + assertEquals $output "version" + local output=$(wrap_env --version) + assertEquals $output "version" +} +function test_build_image_env(){ + local output=$(wrap_env -b) + assertEquals $output "build_image_env" + local output=$(wrap_env --build-image) + assertEquals $output "build_image_env" +} +function test_delete_env(){ + local output=$(wrap_env -d) + assertEquals $output "delete_env" + local output=$(wrap_env --delete) + assertEquals $output "delete_env" +} +function test_run_env_as_fakeroot(){ + local output=$(wrap_env -f) + assertEquals $output "run_env_as_fakeroot(,)" + local output=$(wrap_env --fakeroot) + assertEquals $output "run_env_as_fakeroot(,)" + + local output=$(wrap_env -f -p "-b arg") + assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,)" + local output=$(wrap_env -f -p "-b arg" -- command -kv) + assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,command -kv)" + local output=$(wrap_env -f command --as) + assertEquals "${output[@]}" "run_env_as_fakeroot(,command --as)" +} +function test_run_env_as_user(){ + local output=$(wrap_env) + assertEquals $output "run_env_as_user(,)" + + local output=$(wrap_env -p "-b arg") + assertEquals "$output" "run_env_as_user(-b arg,)" + local output=$(wrap_env -p "-b arg" -- command -ll) + assertEquals "$output" "run_env_as_user(-b arg,command -ll)" + local output=$(wrap_env command -ls) + assertEquals "$output" "run_env_as_user(,command -ls)" +} +function test_run_env_as_root(){ + local output=$(wrap_env -r) + assertEquals $output "run_env_as_root" + + local output=$(wrap_env -r command) + assertEquals "${output[@]}" "run_env_as_root command" +} + +function test_check_cli(){ + $(wrap_env -b -h 2> /dev/null) + assertEquals $? 1 + $(wrap_env -n -v 2> /dev/null) + assertEquals $? 1 + $(wrap_env -d -r 2> /dev/null) + assertEquals $? 1 + $(wrap_env -h -f 2> /dev/null) + assertEquals $? 1 + $(wrap_env -v -i fsd 2> /dev/null) + assertEquals $? 1 + $(wrap_env -f -r 2> /dev/null) + assertEquals $? 1 + $(wrap_env -p args -v 2> /dev/null) + assertEquals $? 1 + $(wrap_env -d args 2> /dev/null) + assertEquals $? 1 +} + +source $(dirname $0)/shunit2 diff --git a/tests/test_core.sh b/tests/test_core.sh index ef144a2..ee77816 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -5,35 +5,35 @@ function oneTimeSetUp(){ CURRPWD=$PWD ENV_MAIN_HOME=/tmp/envtesthome - [ -e $ENV_MAIN_HOME ] || JUJU_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env" - JUJU_HOME="" + [ -e $ENV_MAIN_HOME ] || JUJUBE_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env" + JUJUBE_HOME="" } function install_mini_env(){ - cp -rfa $ENV_MAIN_HOME/* $JUJU_HOME + cp -rfa $ENV_MAIN_HOME/* $JUJUBE_HOME } function setUp(){ cd $CURRPWD - JUJU_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) + JUJUBE_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) source "$(dirname $0)/../lib/core.sh" ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX) cd $ORIGIN_WD - JUJU_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) + JUJUBE_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) set +e trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${JUJU_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUJU_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT + trap "rm -rf ${JUJUBE_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUJUBE_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT } function tearDown(){ # the CA directories are read only and can be deleted only by changing the mod - [ -d ${JUJU_HOME}/etc/ca-certificates ] && chmod -R +w ${JUJU_HOME}/etc/ca-certificates - rm -rf $JUJU_HOME + [ -d ${JUJUBE_HOME}/etc/ca-certificates ] && chmod -R +w ${JUJUBE_HOME}/etc/ca-certificates + rm -rf $JUJUBE_HOME rm -rf $ORIGIN_WD - rm -rf $JUJU_TEMPDIR + rm -rf $JUJUBE_TEMPDIR trap - QUIT EXIT ABRT KILL TERM INT } @@ -41,7 +41,7 @@ function tearDown(){ function test_is_env_installed(){ is_env_installed assertEquals $? 1 - touch $JUJU_HOME/just_file + touch $JUJUBE_HOME/just_file is_env_installed assertEquals $? 0 } @@ -66,17 +66,17 @@ function test_download(){ function test_setup_env(){ wget_mock(){ # Proof that the setup is happening - # inside $JUJU_TEMPDIR - local cwd=${PWD#${JUJU_TEMPDIR}} + # inside $JUJUBE_TEMPDIR + local cwd=${PWD#${JUJUBE_TEMPDIR}} local parent_dir=${PWD%${cwd}} - assertEquals "$JUJU_TEMPDIR" "${parent_dir}" + assertEquals "$JUJUBE_TEMPDIR" "${parent_dir}" touch file tar -czvf ${CMD}-${ARCH}.tar.gz file } WGET=wget_mock setup_env &> /dev/null - assertTrue "[ -e $JUJU_HOME/file ]" - assertTrue "[ -e $JUJU_HOME/run/lock ]" + assertTrue "[ -e $JUJUBE_HOME/file ]" + assertTrue "[ -e $JUJUBE_HOME/run/lock ]" } @@ -84,8 +84,8 @@ function test_setup_env_from_file(){ touch file tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null setup_env_from_file ${CMD}-${ARCH}.tar.gz &> /dev/null - assertTrue "[ -e $JUJU_HOME/file ]" - assertTrue "[ -e $JUJU_HOME/run/lock ]" + assertTrue "[ -e $JUJUBE_HOME/file ]" + assertTrue "[ -e $JUJUBE_HOME/run/lock ]" $(setup_env_from_file noexist.tar.gz 2> /dev/null) assertEquals $? 1 @@ -95,8 +95,8 @@ function test_setup_env_from_file_with_absolute_path(){ touch file tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz &> /dev/null - assertTrue "[ -e $JUJU_HOME/file ]" - assertTrue "[ -e $JUJU_HOME/run/lock ]" + assertTrue "[ -e $JUJUBE_HOME/file ]" + assertTrue "[ -e $JUJUBE_HOME/run/lock ]" } function test_run_env_as_root(){ @@ -150,20 +150,20 @@ function test_run_env_as_user(){ install_mini_env local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUJU_HOME/newdir2 ]" + assertTrue "[ -e $JUJUBE_HOME/newdir2 ]" SH=("/usr/bin/mkdir" "-v" "/newdir") local output=$(run_env_as_user "-k 3.10" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUJU_HOME/newdir ]" + assertTrue "[ -e $JUJUBE_HOME/newdir ]" } function test_run_env_as_proot_mtab(){ install_mini_env $(run_env_as_fakeroot "-k 3.10" "echo") - assertTrue "[ -e $JUJU_HOME/etc/mtab ]" + assertTrue "[ -e $JUJUBE_HOME/etc/mtab ]" $(run_env_as_user "-k 3.10" "echo") - assertTrue "[ ! -e $JUJU_HOME/etc/mtab ]" + assertTrue "[ ! -e $JUJUBE_HOME/etc/mtab ]" } function test_run_env_as_root_mtab(){ @@ -174,14 +174,14 @@ function test_run_env_as_root_mtab(){ CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" $(run_env_as_root "echo") - assertTrue "[ ! -e $JUJU_HOME/etc/mtab ]" + assertTrue "[ ! -e $JUJUBE_HOME/etc/mtab ]" } function test_run_env_with_quotes(){ install_mini_env local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUJU_HOME/newdir2 ]" + assertTrue "[ -e $JUJUBE_HOME/newdir2 ]" } function test_run_env_as_user_proot_args(){ @@ -189,9 +189,9 @@ function test_run_env_as_user_proot_args(){ run_env_as_user "--help" "" &> /dev/null assertEquals $? 0 - mkdir $JUJU_TEMPDIR/newdir - touch $JUJU_TEMPDIR/newdir/newfile - run_env_as_user "-b $JUJU_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null + mkdir $JUJUBE_TEMPDIR/newdir + touch $JUJUBE_TEMPDIR/newdir/newfile + run_env_as_user "-b $JUJUBE_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null assertEquals $? 0 $(_run_env_with_proot --helps 2> /dev/null) @@ -248,7 +248,7 @@ function test_delete_env(){ function test_nested_env(){ install_mini_env - JUJU_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null + JUJUBE_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null assertEquals $? 1 } From c7638f0655f6d0bc8b464e33a8e99fc01c6977a8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 23 May 2015 18:51:46 +0000 Subject: [PATCH 087/326] Update the README --- README.md | 163 +++++++++++++++++++++++++++--------------------------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 1b8072b..7ea2d1b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ JuJube -==== -**JuJube**: the Arch Linux based distro that runs upon any Linux distros without root access +====== +The Arch Linux based distro that runs upon any Linux distros without root access [![Build status](https://api.travis-ci.org/fsquillace/jujube.png?branch=master)](https://travis-ci.org/fsquillace/jujube) Description ------------ +=========== **JuJube** is a lightweight Arch Linux based distribution that allows to have an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. @@ -14,6 +14,7 @@ JuJube contains mainly the package managers (called pacman and yaourt) that allo to a wide range of packages from the Arch Linux repositories. The main advantages on using JuJube are: + - Install packages without root privileges. - Isolated environment in which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). @@ -23,20 +24,14 @@ The main advantages on using JuJube are: JuJube follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way). Quickstart ----------- +========== There are three different ways you can run JuJube: -- As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): +- As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): ```jujube``` - jujube +- As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): ```jujube -f``` -- As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): - - jujube -f - -- As root - Allow to have fully root privileges inside JuJube environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): - - jujube -r +- As root - Allow to have fully root privileges inside JuJube environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): ```jujube -r``` If the JuJube image has not been downloaded yet, the script will download the JuJube image and will place it to the default directory ~/.jujube. @@ -46,12 +41,17 @@ If you are new on Archlinux and you are not familiar with *pacman* package manag visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). Installation ------------- +============ +JuJube can works on GNU/Linux OS with kernel version greater or equal +2.6.0 (JuJube was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. + +## Method one (Recommended) ## Just clone the JuJube repo somewhere (for example in ~/jujube): git clone git://github.com/fsquillace/jujube ~/jujube export PATH=~/jujube/bin:$PATH +## Method two ## Alternatively, another installation method would be to directly download the JuJube image and place it to the default directory ~/.jujube: ARCH= @@ -59,19 +59,31 @@ Alternatively, another installation method would be to directly download the JuJ curl https://dl.dropboxusercontent.com/u/42449030/jujube/jujube-${ARCH}.tar.gz | tar -xz -C ~/.jujube export PATH=~/.jujube/opt/jujube/bin:$PATH -JuJube can works on GNU/Linux OS with kernel version greater or equal -2.6.0 (JuJube was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. +Dependencies +============ +JuJube comes with a very short list of dependencies in order to be installed in most +of GNU/Linux distributions. The needed executables in the host OS are: + +- bash +- wget or curl +- tar +- mkdir +- ln +- chown (for root access only) + +The minimum recommended linux kernel is 2.6.0+ Advanced usage --------------- -### Build image ### +============ + +## Build image ## You can build a new JuJube image from scratch by running the following command: jujube -b [-n] The script will create a directory containing all the essentials files in order to make JuJube working properly (such as pacman, yaourt, arch-chroot and proot). -The option `-n` will skip the final validation tests if they are not needed. +The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. To change the build directory just use the *JUJUBE_TEMPDIR* (by default /tmp). @@ -81,9 +93,10 @@ After creating the image jujube-x86\_64.tar.gz you can install it by running: jujube -i jujube-x86_64.tar.gz Related wiki page: + - [How to build a JuJube image using QEMU](https://github.com/fsquillace/jujube/wiki/How-to-build-a-JuJube-image-using-QEMU) -### Bind directories ### +## Bind directories ## To bind a host directory to a guest location, you can use proot arguments: jujube -p "-b /mnt/mydata:/home/user/mydata" @@ -92,11 +105,11 @@ Check out the proot options with: jujube -p "--help" -###Automatic fallback to classic chroot### +##Automatic fallback to classic chroot## Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work on some distros, JuJube automatically tries to fallback to the classic chroot. -### JuJube as a container ### +## JuJube as a container ## Although JuJube has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). The JuJube containter allows to run services inside the container that can be @@ -109,107 +122,92 @@ To boot a JuJube container: sudo systemd-nspawn -bD ~/.jujube Related wiki page: + - [How to run jujube as a container](https://github.com/fsquillace/jujube/wiki/How-to-run-JuJube-as-a-container) -Dependencies ------------- -JuJube comes with a very short list of dependencies in order to be installed in most -of GNU/Linux distributions. The needed executables in the host OS are: -- bash -- wget or curl -- tar -- mkdir -- ln -- chown (for root access only) - -The minimum recommended linux kernel is 2.6.0+ - Troubleshooting ---------------- +=============== -###Cannot use AUR repository### -- **Q**: Why do I get the following error when I try to install a package with yaourt? -``` -Cannot find the gzip binary required for compressing man and info pages. -``` -- **A**: JuJube comes with a very basic number of packages. -In order to install packages using yaourt you may need to install the package group *base-devel* +##Cannot use AUR repository## + +> **Q**: Why do I get the following error when I try to install a package with yaourt? + + Cannot find the gzip binary required for compressing man and info pages. + +> **A**: JuJube comes with a very basic number of packages. +In order to install packages using yaourt you may need to install the package group **base-devel** that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): -``` pacman -S base-devel -``` -###Kernel too old### -- **Q**: Why do I get the error: "FATAL: kernel too old"? -- **A**: This is because the executable from the precompiled package cannot +##Kernel too old## + +> **Q**: Why do I get the error: "FATAL: kernel too old"? + +> **A**: This is because the executable from the precompiled package cannot properly run if the kernel is old. JuJube contains two different PRoot binaries, and one of them is highly compatible with old linux kernel versions. JuJube will detect which PRoot binary need to be executed but you may need to specify the PRoot *-k* option if the guest rootfs requires a newer kernel version: -``` + jujube -p "-k 3.10" -``` In order to check if an executable inside JuJube environment can be compatible with the kernel of the host OS just use the *file* command, for instance: -``` file ~/.jujube/usr/bin/bash ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped -``` From the output you can see what is the minimum recommended Linux kernel version. -###SUID permissions### -- **Q**: Why I do not have permissions for ping? -``` +##SUID permissions## +> **Q**: Why I do not have permissions for ping? + ping www.google.com ping: icmp open socket: Operation not permitted -``` -- **A**: The ping command uses *suid* permissions that allow to execute the command using +> **A**: The ping command uses *suid* permissions that allow to execute the command using root privileges. The fakeroot mode is not able to execute a command set with suid, and you may need to use root privileges. There are other few commands that have *suid* permission, you can list the commands from your JuJube environment with the following command: -``` + find /usr/bin -perm +4000 -``` -###No characters are visible on a graphic application### -- **Q**: Why I do not see any characters in the application I have installed? +##No characters are visible on a graphic application## -- **A**: This is probably because there are no +> **Q**: Why I do not see any characters in the application I have installed? + +> **A**: This is probably because there are no [fonts](https://wiki.archlinux.org/index.php/Font_Configuration) installed in the system. To quick fix this, you can just install a fonts package: -``` - pacman -S gnu-free-fonts -``` -###Differences between filesystem and package ownership### -- **Q**: Why do I get warning when I install a package using root privileges? -``` + pacman -S gnu-free-fonts + +##Differences between filesystem and package ownership## + +> **Q**: Why do I get warning when I install a package using root privileges? + pacman -S systat ... warning: directory ownership differs on /usr/ filesystem: 1000:100 package: 0:0 ... -``` -- **A**: In these cases the package installation went smoothly anyway. +> **A**: In these cases the package installation went smoothly anyway. This should happen every time you install package with root privileges since JuJube will try to preserve the JuJube environment by assigning ownership of the files to the real user. -###No servers configured for repository### -- **Q**: Why I cannot install packages? -``` +##No servers configured for repository## + +> **Q**: Why I cannot install packages? + pacman -S lsof Packages (1): lsof-4.88-2 @@ -220,17 +218,20 @@ of the files to the real user. error: no servers configured for repository: community error: failed to commit transaction (no servers configured for repository) Errors occurred, no packages were upgraded. -``` -- **A**: You need simply to update the mirrorlist file according to your location: -``` +> **A**: You need simply to update the mirrorlist file according to your location: + # Uncomment the repository line according to your location nano /etc/pacman.d/mirrorlist pacman -Syy -``` + +More documentation +================== +There are additional tutorials in the +[JuJube wiki page](https://github.com/fsquillace/jujube/wiki). License -------- +======= Copyright (c) 2012-2015 This program is free software; you can redistribute it and/or modify it @@ -247,15 +248,15 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . Author ------- +====== Filippo Squillace WWW ---- +=== https://github.com/fsquillace/jujube Last words ---------- +========== Quote of the [lotus](http://en.wikipedia.org/wiki/Ziziphus_lotus) (a selvatic jujube plant) > Per nove infausti dì sul mar pescoso From 82cb6caa14749d503dfeac2859fd2a0462b69949 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 25 May 2015 17:43:45 +0000 Subject: [PATCH 088/326] Issue #63: Change name to JuNest! --- .travis.yml | 22 ++++---- README.md | 100 ++++++++++++++++----------------- bin/{jujube => junest} | 8 +-- lib/core.sh | 122 ++++++++++++++++++++--------------------- lib/util.sh | 2 +- tests/test_core.sh | 60 ++++++++++---------- 6 files changed, 157 insertions(+), 157 deletions(-) rename bin/{jujube => junest} (96%) diff --git a/.travis.yml b/.travis.yml index 9554a88..5a5f7f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,20 +4,20 @@ sudo: required install: - PATH=$PWD/bin:$PATH - - jujube -f echo 'Installing jujube' - - sed -i -e "s/#Server/Server/" ~/.jujube/etc/pacman.d/mirrorlist - - jujube -f pacman --noconfirm -Syy - - jujube -f pacman --noconfirm -S base-devel + - junest -f echo 'Installing junest' + - sed -i -e "s/#Server/Server/" ~/.junest/etc/pacman.d/mirrorlist + - junest -f pacman --noconfirm -Syy + - junest -f pacman --noconfirm -S base-devel script: - ./tests/test_all.sh # Test on installing package from AUR - - jujube -f yaourt --noconfirm -S tcptraceroute - - sudo $PWD/bin/jujube -r tcptraceroute localhost + - junest -f yaourt --noconfirm -S tcptraceroute + - sudo $PWD/bin/junest -r tcptraceroute localhost # Test on installing package from official repo - - jujube -f pacman --noconfirm -S tree - - jujube -f tree + - junest -f pacman --noconfirm -S tree + - junest -f tree # Test on installing package from official repo with root access - - jujube -f pacman --noconfirm -S iftop - - sudo bin/jujube -r iftop -t -s 5 - - yes | jujube -d + - junest -f pacman --noconfirm -S iftop + - sudo bin/junest -r iftop -t -s 5 + - yes | junest -d diff --git a/README.md b/README.md index 7ea2d1b..d1cb76e 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -JuJube +JuNest ====== The Arch Linux based distro that runs upon any Linux distros without root access -[![Build status](https://api.travis-ci.org/fsquillace/jujube.png?branch=master)](https://travis-ci.org/fsquillace/jujube) +[![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) Description =========== -**JuJube** is a lightweight Arch Linux based distribution that allows to have +**JuNest** (Jailed User NEST) is a lightweight Arch Linux based distribution that allows to have an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. -JuJube contains mainly the package managers (called pacman and yaourt) that allows to access +JuNest contains mainly the package managers (called pacman and yaourt) that allows to access to a wide range of packages from the Arch Linux repositories. -The main advantages on using JuJube are: +The main advantages on using JuNest are: - Install packages without root privileges. - Isolated environment in which you can install packages without affecting a production system. @@ -21,47 +21,47 @@ The main advantages on using JuJube are: - Available for x86\_64, x86 and ARM architectures but you can build your own image from scratch too! - All Arch Linux lovers can have their favourite distro everywhere! -JuJube follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way). +JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way). Quickstart ========== -There are three different ways you can run JuJube: +There are three different ways you can run JuNest: -- As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): ```jujube``` +- As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): ```junest``` -- As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): ```jujube -f``` +- As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): ```junest -f``` -- As root - Allow to have fully root privileges inside JuJube environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): ```jujube -r``` +- As root - Allow to have fully root privileges inside JuNest environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): ```junest -r``` -If the JuJube image has not been downloaded yet, the script will download -the JuJube image and will place it to the default directory ~/.jujube. -You can change the default directory by changing the environment variable *JUJUBE\_HOME*. +If the JuNest image has not been downloaded yet, the script will download +the JuNest image and will place it to the default directory ~/.junest. +You can change the default directory by changing the environment variable *JUNEST\_HOME*. If you are new on Archlinux and you are not familiar with *pacman* package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). Installation ============ -JuJube can works on GNU/Linux OS with kernel version greater or equal -2.6.0 (JuJube was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. +JuNest can works on GNU/Linux OS with kernel version greater or equal +2.6.0 (JuNest was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. ## Method one (Recommended) ## -Just clone the JuJube repo somewhere (for example in ~/jujube): +Just clone the JuNest repo somewhere (for example in ~/junest): - git clone git://github.com/fsquillace/jujube ~/jujube - export PATH=~/jujube/bin:$PATH + git clone git://github.com/fsquillace/junest ~/junest + export PATH=~/junest/bin:$PATH ## Method two ## -Alternatively, another installation method would be to directly download the JuJube image and place it to the default directory ~/.jujube: +Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory ~/.junest: ARCH= - mkdir ~/.jujube - curl https://dl.dropboxusercontent.com/u/42449030/jujube/jujube-${ARCH}.tar.gz | tar -xz -C ~/.jujube - export PATH=~/.jujube/opt/jujube/bin:$PATH + mkdir ~/.junest + curl https://dl.dropboxusercontent.com/u/42449030/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest + export PATH=~/.junest/opt/junest/bin:$PATH Dependencies ============ -JuJube comes with a very short list of dependencies in order to be installed in most +JuNest comes with a very short list of dependencies in order to be installed in most of GNU/Linux distributions. The needed executables in the host OS are: - bash @@ -77,53 +77,53 @@ Advanced usage ============ ## Build image ## -You can build a new JuJube image from scratch by running the following command: +You can build a new JuNest image from scratch by running the following command: - jujube -b [-n] + junest -b [-n] The script will create a directory containing all the essentials -files in order to make JuJube working properly (such as pacman, yaourt, arch-chroot and proot). +files in order to make JuNest working properly (such as pacman, yaourt, arch-chroot and proot). The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. -To change the build directory just use the *JUJUBE_TEMPDIR* (by default /tmp). +To change the build directory just use the *JUNEST_TEMPDIR* (by default /tmp). -After creating the image jujube-x86\_64.tar.gz you can install it by running: +After creating the image junest-x86\_64.tar.gz you can install it by running: - jujube -i jujube-x86_64.tar.gz + junest -i junest-x86_64.tar.gz Related wiki page: -- [How to build a JuJube image using QEMU](https://github.com/fsquillace/jujube/wiki/How-to-build-a-JuJube-image-using-QEMU) +- [How to build a JuNest image using QEMU](https://github.com/fsquillace/junest/wiki/How-to-build-a-JuNest-image-using-QEMU) ## Bind directories ## To bind a host directory to a guest location, you can use proot arguments: - jujube -p "-b /mnt/mydata:/home/user/mydata" + junest -p "-b /mnt/mydata:/home/user/mydata" Check out the proot options with: - jujube -p "--help" + junest -p "--help" ##Automatic fallback to classic chroot## Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work -on some distros, JuJube automatically tries to fallback to the classic chroot. +on some distros, JuNest automatically tries to fallback to the classic chroot. -## JuJube as a container ## -Although JuJube has not been designed to be a complete container, it is even possible to +## JuNest as a container ## +Although JuNest has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). -The JuJube containter allows to run services inside the container that can be +The JuNest containter allows to run services inside the container that can be visible from the host OS through the network. The drawbacks of this are that the host OS must use systemd as a service manager, and the container can only be executed using root privileges. -To boot a JuJube container: +To boot a JuNest container: - sudo systemd-nspawn -bD ~/.jujube + sudo systemd-nspawn -bD ~/.junest Related wiki page: -- [How to run jujube as a container](https://github.com/fsquillace/jujube/wiki/How-to-run-JuJube-as-a-container) +- [How to run junest as a container](https://github.com/fsquillace/junest/wiki/How-to-run-JuNest-as-a-container) Troubleshooting =============== @@ -134,7 +134,7 @@ Troubleshooting Cannot find the gzip binary required for compressing man and info pages. -> **A**: JuJube comes with a very basic number of packages. +> **A**: JuNest comes with a very basic number of packages. In order to install packages using yaourt you may need to install the package group **base-devel** that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): @@ -146,17 +146,17 @@ that contains all the essential packages for compiling source code (such as gcc, > **A**: This is because the executable from the precompiled package cannot properly run if the kernel is old. -JuJube contains two different PRoot binaries, and one of them is highly compatible -with old linux kernel versions. JuJube will detect which PRoot binary need to be +JuNest contains two different PRoot binaries, and one of them is highly compatible +with old linux kernel versions. JuNest will detect which PRoot binary need to be executed but you may need to specify the PRoot *-k* option if the guest rootfs requires a newer kernel version: - jujube -p "-k 3.10" + junest -p "-k 3.10" -In order to check if an executable inside JuJube environment can be compatible +In order to check if an executable inside JuNest environment can be compatible with the kernel of the host OS just use the *file* command, for instance: - file ~/.jujube/usr/bin/bash + file ~/.junest/usr/bin/bash ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped @@ -172,7 +172,7 @@ From the output you can see what is the minimum recommended Linux kernel version > **A**: The ping command uses *suid* permissions that allow to execute the command using root privileges. The fakeroot mode is not able to execute a command set with suid, and you may need to use root privileges. There are other few commands that -have *suid* permission, you can list the commands from your JuJube environment +have *suid* permission, you can list the commands from your JuNest environment with the following command: find /usr/bin -perm +4000 @@ -201,7 +201,7 @@ To quick fix this, you can just install a fonts package: > **A**: In these cases the package installation went smoothly anyway. This should happen every time you install package with root privileges -since JuJube will try to preserve the JuJube environment by assigning ownership +since JuNest will try to preserve the JuNest environment by assigning ownership of the files to the real user. ##No servers configured for repository## @@ -228,7 +228,7 @@ of the files to the real user. More documentation ================== There are additional tutorials in the -[JuJube wiki page](https://github.com/fsquillace/jujube/wiki). +[JuNest wiki page](https://github.com/fsquillace/junest/wiki). License ======= @@ -253,11 +253,11 @@ Filippo Squillace WWW === -https://github.com/fsquillace/jujube +https://github.com/fsquillace/junest Last words ========== -Quote of the [lotus](http://en.wikipedia.org/wiki/Ziziphus_lotus) (a selvatic jujube plant) +Quote of the [lotus](http://en.wikipedia.org/wiki/Ziziphus_lotus) (a selvatic junest plant) > Per nove infausti dì sul mar pescoso > i venti rei mi trasportaro. Al fine diff --git a/bin/jujube b/bin/junest similarity index 96% rename from bin/jujube rename to bin/junest index b68ad02..abc69bf 100755 --- a/bin/jujube +++ b/bin/junest @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# This file is part of JuJube (https://github.com/fsquillace/jujube). +# This file is part of JuNest (https://github.com/fsquillace/junest). # # Copyright (c) 2012-2015 # @@ -28,13 +28,13 @@ usage() { echo -e "$NAME: $DESCRIPTION" echo -e "Usage: $CMD [options] [--] [command]" echo -e "Options:" - echo -e "-i, --setup-from-file Setup the $NAME image in ${JUJUBE_HOME}" + echo -e "-i, --setup-from-file Setup the $NAME image in ${JUNEST_HOME}" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" echo -e "-p, --proot-args Proot arguments" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" - echo -e "-d, --delete Delete $NAME from ${JUJUBE_HOME}" + echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" echo -e "-h, --help Show this help message" echo -e "-v, --version Show the $NAME version" } @@ -168,7 +168,7 @@ function execute_operation(){ setup_env fi elif $OPT_SETUP_FROM_FILE; then - die "Error: The image cannot be installed since $JUJUBE_HOME is not empty." + die "Error: The image cannot be installed since $JUNEST_HOME is not empty." fi if $OPT_FAKEROOT; then diff --git a/lib/core.sh b/lib/core.sh index 88973c6..1c053a7 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -27,8 +27,8 @@ source "$(dirname ${BASH_ARGV[0]})/util.sh" ################################# VARIABLES ############################## -NAME='JuJube' -CMD='jujube' +NAME='JuNest' +CMD='junest' VERSION='4.7.4' CODE_NAME='Mairei' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' @@ -37,18 +37,18 @@ HOMEPAGE="https://github.com/fsquillace/${CMD}" COPYRIGHT='2012-2015' -if [ "$JUJUBE_ENV" == "1" ] +if [ "$JUNEST_ENV" == "1" ] then die "Error: Nested ${NAME} environments are not allowed" -elif [ ! -z $JUJUBE_ENV ] && [ "$JUJUBE_ENV" != "0" ] +elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] then - die "The variable JUJUBE_ENV is not properly set" + die "The variable JUNEST_ENV is not properly set" fi -[ -z ${JUJUBE_HOME} ] && JUJUBE_HOME=~/.${CMD} -if [ -z ${JUJUBE_TEMPDIR} ] || [ ! -d ${JUJUBE_TEMPDIR} ] +[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} +if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] then - JUJUBE_TEMPDIR=/tmp + JUNEST_TEMPDIR=/tmp fi ENV_REPO=https://dl.dropboxusercontent.com/u/42449030/${CMD} @@ -66,28 +66,28 @@ HOST_ARCH=$(uname -m) if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then ARCH="x86" - LD_LIB="${JUJUBE_HOME}/lib/ld-linux.so.2" + LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2" elif [ $HOST_ARCH == "x86_64" ] then ARCH="x86_64" - LD_LIB="${JUJUBE_HOME}/lib64/ld-linux-x86-64.so.2" + LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2" elif [[ $HOST_ARCH =~ .*(arm).* ]] then ARCH="arm" - LD_LIB="${JUJUBE_HOME}/lib/ld-linux-armhf.so.3" + LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3" else die "Unknown architecture ${ARCH}" fi -PROOT_COMPAT="${JUJUBE_HOME}/opt/proot/proot-${ARCH}" +PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" PROOT_LINK=http://static.proot.me/proot-${ARCH} SH=("/bin/sh" "--login") -CHROOT=${JUJUBE_HOME}/usr/bin/arch-chroot -CLASSIC_CHROOT=${JUJUBE_HOME}/usr/bin/chroot +CHROOT=${JUNEST_HOME}/usr/bin/arch-chroot +CLASSIC_CHROOT=${JUNEST_HOME}/usr/bin/chroot TRUE=/usr/bin/true ID="/usr/bin/id -u" -CHOWN="${JUJUBE_HOME}/usr/bin/chown" +CHOWN="${JUNEST_HOME}/usr/bin/chown" LN="ln" ################################# MAIN FUNCTIONS ############################## @@ -98,7 +98,7 @@ function download(){ } function is_env_installed(){ - [ -d "$JUJUBE_HOME" ] && [ "$(ls -A $JUJUBE_HOME)" ] && return 0 + [ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0 return 1 } @@ -119,11 +119,11 @@ function _prepare_build_directory(){ function _setup_env(){ - is_env_installed && die "Error: ${NAME} has been already installed in $JUJUBE_HOME" - mkdir -p "${JUJUBE_HOME}" + is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME" + mkdir -p "${JUNEST_HOME}" imagepath=$1 - $TAR -zxpf ${imagepath} -C ${JUJUBE_HOME} - mkdir -p ${JUJUBE_HOME}/run/lock + $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} + mkdir -p ${JUNEST_HOME}/run/lock warn "Warn: The default mirror URL is ${DEFAULT_MIRROR}." warn "To change it:" info " nano /etc/pacman.d/mirrorlist" @@ -134,7 +134,7 @@ function _setup_env(){ function setup_env(){ - local maindir=$(TMPDIR=$JUJUBE_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) _prepare_build_directory info "Downloading ${NAME}..." @@ -166,30 +166,30 @@ function run_env_as_root(){ local main_cmd="${SH[@]}" [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" - local cmd="mkdir -p ${JUJUBE_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" + local cmd="mkdir -p ${JUNEST_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUJUBE_HOME}; rm -r ${JUJUBE_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUNEST_HOME}; rm -r ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT - [ ! -e ${JUJUBE_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJUBE_HOME}/etc/mtab + [ ! -e ${JUNEST_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab - if ${CHROOT} $JUJUBE_HOME ${TRUE} 1> /dev/null + if ${CHROOT} $JUNEST_HOME ${TRUE} 1> /dev/null then - JUJUBE_ENV=1 ${CHROOT} $JUJUBE_HOME "${SH[@]}" "-c" "${cmd}" + JUNEST_ENV=1 ${CHROOT} $JUNEST_HOME "${SH[@]}" "-c" "${cmd}" local ret=$? - elif ${CLASSIC_CHROOT} $JUJUBE_HOME ${TRUE} 1> /dev/null + elif ${CLASSIC_CHROOT} $JUNEST_HOME ${TRUE} 1> /dev/null then warn "Warning: The executable arch-chroot does not work, falling back to classic chroot" - JUJUBE_ENV=1 ${CLASSIC_CHROOT} $JUJUBE_HOME "${SH[@]}" "-c" "${cmd}" + JUNEST_ENV=1 ${CLASSIC_CHROOT} $JUNEST_HOME "${SH[@]}" "-c" "${cmd}" local ret=$? else die "Error: Chroot does not work" fi # The ownership of the files is assigned to the real user - [ -z $uid ] || ${CHOWN} -R ${uid} ${JUJUBE_HOME} + [ -z $uid ] || ${CHOWN} -R ${uid} ${JUNEST_HOME} - [ -e ${JUJUBE_HOME}/etc/mtab ] && rm -r ${JUJUBE_HOME}/etc/mtab + [ -e ${JUNEST_HOME}/etc/mtab ] && rm -r ${JUNEST_HOME}/etc/mtab trap - QUIT EXIT ABRT KILL TERM INT return $? @@ -200,11 +200,11 @@ function _run_proot(){ shift if ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null then - JUJUBE_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" + JUNEST_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null then warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." - JUJUBE_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" + JUNEST_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" else die "Error: Check if the ${CMD} arguments are correct or use the option ${CMD} -p \"-k 3.10\"" fi @@ -227,43 +227,43 @@ function _run_env_with_proot(){ function run_env_as_fakeroot(){ local proot_args="$1" shift - [ "$(_run_proot "-R ${JUJUBE_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(_run_proot "-R ${JUNEST_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - [ ! -e ${JUJUBE_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUJUBE_HOME}/etc/mtab - _run_env_with_proot "-S ${JUJUBE_HOME} $proot_args" "${@}" + [ ! -e ${JUNEST_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab + _run_env_with_proot "-S ${JUNEST_HOME} $proot_args" "${@}" } function run_env_as_user(){ local proot_args="$1" shift - [ "$(_run_proot "-R ${JUJUBE_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(_run_proot "-R ${JUNEST_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - [ -e ${JUJUBE_HOME}/etc/mtab ] && rm -f ${JUJUBE_HOME}/etc/mtab - _run_env_with_proot "-R ${JUJUBE_HOME} $proot_args" "${@}" + [ -e ${JUNEST_HOME}/etc/mtab ] && rm -f ${JUNEST_HOME}/etc/mtab + _run_env_with_proot "-R ${JUNEST_HOME} $proot_args" "${@}" } function delete_env(){ - ! ask "Are you sure to delete ${NAME} located in ${JUJUBE_HOME}" "N" && return - if mountpoint -q ${JUJUBE_HOME} + ! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return + if mountpoint -q ${JUNEST_HOME} then - info "There are mounted directories inside ${JUJUBE_HOME}" - if ! umount --force ${JUJUBE_HOME} + info "There are mounted directories inside ${JUNEST_HOME}" + if ! umount --force ${JUNEST_HOME} then - error "Cannot umount directories in ${JUJUBE_HOME}" + error "Cannot umount directories in ${JUNEST_HOME}" die "Try to delete ${NAME} using root permissions" fi fi # the CA directories are read only and can be deleted only by changing the mod - chmod -R +w ${JUJUBE_HOME}/etc/ca-certificates - if rm -rf ${JUJUBE_HOME}/* + chmod -R +w ${JUNEST_HOME}/etc/ca-certificates + if rm -rf ${JUNEST_HOME}/* then - info "${NAME} deleted in ${JUJUBE_HOME}" + info "${NAME} deleted in ${JUNEST_HOME}" else - error "Error: Cannot delete ${NAME} in ${JUJUBE_HOME}" + error "Error: Cannot delete ${NAME} in ${JUNEST_HOME}" fi } @@ -288,7 +288,7 @@ function build_image_env(){ local disable_validation=$1 - local maindir=$(TMPDIR=$JUJUBE_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) sudo mkdir -p ${maindir}/root trap - QUIT EXIT ABRT KILL TERM INT trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT @@ -365,28 +365,28 @@ function validate_image(){ $TAR -zxpf ${imagefile} -C ${testdir} mkdir -p ${testdir}/run/lock sed -i -e "s/#Server/Server/" ${testdir}/etc/pacman.d/mirrorlist - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy # Check most basic executables work - JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null - JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null - JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null + JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null + JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel local yaourt_package=tcptraceroute info "Installing ${yaourt_package} package from AUR repo using proot..." - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" - JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" + JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost local repo_package=sysstat info "Installing ${repo_package} package from official repo using proot..." - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} iostat - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f iostat + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} iostat + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f iostat local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." - JUJUBE_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUJUBE_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} + JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 } diff --git a/lib/util.sh b/lib/util.sh index 53b424e..f65ac26 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# This file is part of JuJube (https://github.com/fsquillace/jujube) +# This file is part of JuNest (https://github.com/fsquillace/junest) # # Copyright (c) 2012-2015 # diff --git a/tests/test_core.sh b/tests/test_core.sh index ee77816..a3ef567 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -5,35 +5,35 @@ function oneTimeSetUp(){ CURRPWD=$PWD ENV_MAIN_HOME=/tmp/envtesthome - [ -e $ENV_MAIN_HOME ] || JUJUBE_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env" - JUJUBE_HOME="" + [ -e $ENV_MAIN_HOME ] || JUNEST_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env" + JUNEST_HOME="" } function install_mini_env(){ - cp -rfa $ENV_MAIN_HOME/* $JUJUBE_HOME + cp -rfa $ENV_MAIN_HOME/* $JUNEST_HOME } function setUp(){ cd $CURRPWD - JUJUBE_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) + JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) source "$(dirname $0)/../lib/core.sh" ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX) cd $ORIGIN_WD - JUJUBE_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) + JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) set +e trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${JUJUBE_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUJUBE_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT + trap "rm -rf ${JUNEST_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT } function tearDown(){ # the CA directories are read only and can be deleted only by changing the mod - [ -d ${JUJUBE_HOME}/etc/ca-certificates ] && chmod -R +w ${JUJUBE_HOME}/etc/ca-certificates - rm -rf $JUJUBE_HOME + [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates + rm -rf $JUNEST_HOME rm -rf $ORIGIN_WD - rm -rf $JUJUBE_TEMPDIR + rm -rf $JUNEST_TEMPDIR trap - QUIT EXIT ABRT KILL TERM INT } @@ -41,7 +41,7 @@ function tearDown(){ function test_is_env_installed(){ is_env_installed assertEquals $? 1 - touch $JUJUBE_HOME/just_file + touch $JUNEST_HOME/just_file is_env_installed assertEquals $? 0 } @@ -66,17 +66,17 @@ function test_download(){ function test_setup_env(){ wget_mock(){ # Proof that the setup is happening - # inside $JUJUBE_TEMPDIR - local cwd=${PWD#${JUJUBE_TEMPDIR}} + # inside $JUNEST_TEMPDIR + local cwd=${PWD#${JUNEST_TEMPDIR}} local parent_dir=${PWD%${cwd}} - assertEquals "$JUJUBE_TEMPDIR" "${parent_dir}" + assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" touch file tar -czvf ${CMD}-${ARCH}.tar.gz file } WGET=wget_mock - setup_env &> /dev/null - assertTrue "[ -e $JUJUBE_HOME/file ]" - assertTrue "[ -e $JUJUBE_HOME/run/lock ]" + setup_env 1> /dev/null + assertTrue "[ -e $JUNEST_HOME/file ]" + assertTrue "[ -e $JUNEST_HOME/run/lock ]" } @@ -84,8 +84,8 @@ function test_setup_env_from_file(){ touch file tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null setup_env_from_file ${CMD}-${ARCH}.tar.gz &> /dev/null - assertTrue "[ -e $JUJUBE_HOME/file ]" - assertTrue "[ -e $JUJUBE_HOME/run/lock ]" + assertTrue "[ -e $JUNEST_HOME/file ]" + assertTrue "[ -e $JUNEST_HOME/run/lock ]" $(setup_env_from_file noexist.tar.gz 2> /dev/null) assertEquals $? 1 @@ -95,8 +95,8 @@ function test_setup_env_from_file_with_absolute_path(){ touch file tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz &> /dev/null - assertTrue "[ -e $JUJUBE_HOME/file ]" - assertTrue "[ -e $JUJUBE_HOME/run/lock ]" + assertTrue "[ -e $JUNEST_HOME/file ]" + assertTrue "[ -e $JUNEST_HOME/run/lock ]" } function test_run_env_as_root(){ @@ -150,20 +150,20 @@ function test_run_env_as_user(){ install_mini_env local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUJUBE_HOME/newdir2 ]" + assertTrue "[ -e $JUNEST_HOME/newdir2 ]" SH=("/usr/bin/mkdir" "-v" "/newdir") local output=$(run_env_as_user "-k 3.10" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUJUBE_HOME/newdir ]" + assertTrue "[ -e $JUNEST_HOME/newdir ]" } function test_run_env_as_proot_mtab(){ install_mini_env $(run_env_as_fakeroot "-k 3.10" "echo") - assertTrue "[ -e $JUJUBE_HOME/etc/mtab ]" + assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" $(run_env_as_user "-k 3.10" "echo") - assertTrue "[ ! -e $JUJUBE_HOME/etc/mtab ]" + assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" } function test_run_env_as_root_mtab(){ @@ -174,14 +174,14 @@ function test_run_env_as_root_mtab(){ CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" $(run_env_as_root "echo") - assertTrue "[ ! -e $JUJUBE_HOME/etc/mtab ]" + assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" } function test_run_env_with_quotes(){ install_mini_env local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUJUBE_HOME/newdir2 ]" + assertTrue "[ -e $JUNEST_HOME/newdir2 ]" } function test_run_env_as_user_proot_args(){ @@ -189,9 +189,9 @@ function test_run_env_as_user_proot_args(){ run_env_as_user "--help" "" &> /dev/null assertEquals $? 0 - mkdir $JUJUBE_TEMPDIR/newdir - touch $JUJUBE_TEMPDIR/newdir/newfile - run_env_as_user "-b $JUJUBE_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null + mkdir $JUNEST_TEMPDIR/newdir + touch $JUNEST_TEMPDIR/newdir/newfile + run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null assertEquals $? 0 $(_run_env_with_proot --helps 2> /dev/null) @@ -248,7 +248,7 @@ function test_delete_env(){ function test_nested_env(){ install_mini_env - JUJUBE_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null + JUNEST_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null assertEquals $? 1 } From 4a7e46d42f618cd2ed67ecd03d2268ae4c87a28a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 25 May 2015 21:00:28 +0000 Subject: [PATCH 089/326] Remove the last word section --- README.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/README.md b/README.md index d1cb76e..11ef105 100644 --- a/README.md +++ b/README.md @@ -254,26 +254,3 @@ Filippo Squillace WWW === https://github.com/fsquillace/junest - -Last words -========== -Quote of the [lotus](http://en.wikipedia.org/wiki/Ziziphus_lotus) (a selvatic junest plant) - -> Per nove infausti dì sul mar pescoso -> i venti rei mi trasportaro. Al fine -> nel decimo sbarcammo in su le rive -> de’ Lotofági, un popolo, a cui cibo -> È d’una pianta il florido germoglio. -> ... -> ... -> Partiro e s’affrontaro a quella gente, -> che, lunge dal voler la vita loro, -> il dolce loto a savorar lor porse. -> chiunque l’esca dilettosa, e nuova -> gustato avea, con le novelle indietro -> non bramava tornar: colà bramava -> starsi, e, mangiando del soave loto, -> la contrada natia sbandir dal petto. - -verse 105-123, Homer, from [Odyssey Book IX](http://it.wikisource.org/wiki/Odissea/Libro_IX) -([en](http://en.wikisource.org/wiki/The_Odyssey_(Butler)/Book_IX)) From 108fe1d45670238e8ab0a5cd121d6b06a15ba079 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 28 May 2015 17:58:00 +0000 Subject: [PATCH 090/326] Improve the validation of the image --- lib/core.sh | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 1c053a7..8a7581d 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -368,16 +368,10 @@ function validate_image(){ JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy # Check most basic executables work - JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null - JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null - - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel - local yaourt_package=tcptraceroute - info "Installing ${yaourt_package} package from AUR repo using proot..." - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt --noconfirm -S ${yaourt_package}" - JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost + JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null + JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null local repo_package=sysstat info "Installing ${repo_package} package from official repo using proot..." @@ -388,5 +382,12 @@ function validate_image(){ local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} sudo ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 + JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 + + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel + local yaourt_package=tcptraceroute + info "Installing ${yaourt_package} package from AUR repo using proot..." + JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt -A --noconfirm -S ${yaourt_package}" + JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost + } From e42cd2fc3720bdfb1b3b5e22630a4882d60d76e8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 3 Jun 2015 21:32:36 +0000 Subject: [PATCH 091/326] Update README --- README.md | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 11ef105..730659b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ JuNest ====== -The Arch Linux based distro that runs upon any Linux distros without root access +The Arch Linux based distro that runs upon any Linux distros without root access. [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) @@ -10,7 +10,7 @@ Description an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. -JuNest contains mainly the package managers (called pacman and yaourt) that allows to access +JuNest contains mainly the package managers (called [pacman](https://wiki.archlinux.org/index.php/Pacman) and [yaourt](https://wiki.archlinux.org/index.php/Yaourt)) that allows to access to a wide range of packages from the Arch Linux repositories. The main advantages on using JuNest are: @@ -27,14 +27,14 @@ Quickstart ========== There are three different ways you can run JuNest: -- As normal user - Allow to make basic operations using [proot](https://wiki.archlinux.org/index.php/Proot): ```junest``` +- As normal user - Allow to make basic operations: ```junest``` -- As fakeroot - Allow to install/remove packages using [proot](https://wiki.archlinux.org/index.php/Proot): ```junest -f``` +- As fakeroot - Allow to install/remove packages: ```junest -f``` -- As root - Allow to have fully root privileges inside JuNest environment using [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) (you need to be root for executing this): ```junest -r``` +- As root - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` If the JuNest image has not been downloaded yet, the script will download -the JuNest image and will place it to the default directory ~/.junest. +the image and will place it to the default directory ~/.junest. You can change the default directory by changing the environment variable *JUNEST\_HOME*. If you are new on Archlinux and you are not familiar with *pacman* package manager @@ -74,7 +74,7 @@ of GNU/Linux distributions. The needed executables in the host OS are: The minimum recommended linux kernel is 2.6.0+ Advanced usage -============ +============== ## Build image ## You can build a new JuNest image from scratch by running the following command: @@ -105,10 +105,6 @@ Check out the proot options with: junest -p "--help" -##Automatic fallback to classic chroot## -Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work -on some distros, JuNest automatically tries to fallback to the classic chroot. - ## JuNest as a container ## Although JuNest has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). @@ -125,6 +121,25 @@ Related wiki page: - [How to run junest as a container](https://github.com/fsquillace/junest/wiki/How-to-run-JuNest-as-a-container) +Internals +========= + +There are two main chroot jail used in JuNest. +The main one is [proot](https://wiki.archlinux.org/index.php/Proot) which +allows unprivileged users to execute programs inside a sandbox and +[arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an +enhanced chroot for privileged users that mounts the primary directories +(i.e. /proc, /sys, /dev and /run) before executing any programs inside +the sandbox. + +##Automatic fallback to classic chroot## +Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work +on some distros, JuNest automatically tries to fallback to the classic chroot. + +##Automatic building of the JuNest images## +The JuNest images are built every week so that you can always get the most +updated package versions. + Troubleshooting =============== From 622cb8858740dd84da2ebc536dde2715b890dee9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 3 Jun 2015 22:09:11 +0000 Subject: [PATCH 092/326] Remove the nano editor Since there is a default URL mirror the nano editor is no longer needed in the image as default. --- lib/core.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 8a7581d..befa043 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -124,9 +124,7 @@ function _setup_env(){ imagepath=$1 $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} mkdir -p ${JUNEST_HOME}/run/lock - warn "Warn: The default mirror URL is ${DEFAULT_MIRROR}." - warn "To change it:" - info " nano /etc/pacman.d/mirrorlist" + info "The default mirror URL is ${DEFAULT_MIRROR}." info "Remember to refresh the package databases from the server:" info " pacman -Syy" info "${NAME} installed successfully" @@ -296,7 +294,7 @@ function build_image_env(){ # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # yaourt requires sed # coreutils is needed for chown - sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring nano archlinux-keyring sed + sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." From eea6d6e150ddea0a6d9d80da3d61618aefaffca1 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 6 Jun 2015 12:33:25 +0000 Subject: [PATCH 093/326] Add badges in README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 730659b..b47d6ca 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ JuNest The Arch Linux based distro that runs upon any Linux distros without root access. [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) +[![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) +[![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) +[![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) Description =========== From 29d76a01a905e189b69c9ead9d77aa06f9e8a31d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 18 Jun 2015 23:30:05 +0000 Subject: [PATCH 094/326] Issue #79: Create the initial functions --- lib/core.sh | 71 ++++++++++++++++++++++++++++++---------------- tests/test_core.sh | 6 ++-- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index befa043..a63aafe 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -51,18 +51,7 @@ then JUNEST_TEMPDIR=/tmp fi -ENV_REPO=https://dl.dropboxusercontent.com/u/42449030/${CMD} -ORIGIN_WD=$(pwd) - -WGET="wget --no-check-certificate" -CURL="curl -L -J -O -k" - -TAR=tar - -DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' - HOST_ARCH=$(uname -m) - if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then ARCH="x86" @@ -79,24 +68,58 @@ else die "Unknown architecture ${ARCH}" fi -PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" PROOT_LINK=http://static.proot.me/proot-${ARCH} +ENV_REPO=https://dl.dropboxusercontent.com/u/42449030/${CMD} +DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' +ORIGIN_WD=$(pwd) + +################################ EXECUTABLES ################################## +# This section contains all the executables needed for JuNest to run properly. +# They are based on a fallback mechanism that tries to use the executable in +# different locations in the host OS. + +# List of executables that are run inside JuNest: SH=("/bin/sh" "--login") +TRUE=true +ID="id -u" + +# List of executables that are run in the host OS: +PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" CHROOT=${JUNEST_HOME}/usr/bin/arch-chroot CLASSIC_CHROOT=${JUNEST_HOME}/usr/bin/chroot -TRUE=/usr/bin/true -ID="/usr/bin/id -u" +WGET="wget --no-check-certificate" +CURL="curl -L -J -O -k" +TAR=tar CHOWN="${JUNEST_HOME}/usr/bin/chown" LN="ln" +MKDIR="mkdir" + +PATH=/usr/bin:/bin:/sbin:$PATH +LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" + +function ln_cmd(){ + ln $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/ln $@ +} + +function rm_cmd(){ + rm $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/rm $@ +} + +function chown_cmd(){ + chown $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chown $@ +} + +function mkdir_cmd(){ + mkdir $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/mkdir $@ +} + +function download_cmd(){ + $WGET $@ || $CURL $@ +} ################################# MAIN FUNCTIONS ############################## -function download(){ - $WGET $1 || $CURL $1 || \ - die "Error: Both wget and curl commands have failed on downloading $1" -} - function is_env_installed(){ [ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0 return 1 @@ -120,10 +143,10 @@ function _prepare_build_directory(){ function _setup_env(){ is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME" - mkdir -p "${JUNEST_HOME}" + mkdir_cmd -p "${JUNEST_HOME}" imagepath=$1 $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} - mkdir -p ${JUNEST_HOME}/run/lock + mkdir_cmd -p ${JUNEST_HOME}/run/lock info "The default mirror URL is ${DEFAULT_MIRROR}." info "Remember to refresh the package databases from the server:" info " pacman -Syy" @@ -138,7 +161,7 @@ function setup_env(){ info "Downloading ${NAME}..." builtin cd ${maindir} local imagefile=${CMD}-${ARCH}.tar.gz - download ${ENV_REPO}/${imagefile} + download_cmd ${ENV_REPO}/${imagefile} info "Installing ${NAME}..." _setup_env ${maindir}/${imagefile} @@ -315,12 +338,12 @@ function build_image_env(){ mkdir -p ${maindir}/packages/{package-query,yaourt} builtin cd ${maindir}/packages/package-query - download https://aur.archlinux.org/packages/pa/package-query/PKGBUILD + download_cmd https://aur.archlinux.org/packages/pa/package-query/PKGBUILD makepkg -sfc sudo pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz builtin cd ${maindir}/packages/yaourt - download https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD + download_cmd https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD makepkg -sfc sudo pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz # Apply patches for yaourt and makepkg diff --git a/tests/test_core.sh b/tests/test_core.sh index a3ef567..b5dd5db 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -50,15 +50,15 @@ function test_is_env_installed(){ function test_download(){ WGET=/bin/true CURL=/bin/false - download + download_cmd assertEquals $? 0 WGET=/bin/false CURL=/bin/true - download + download_cmd assertEquals $? 0 - $(WGET=/bin/false CURL=/bin/false download something 2> /dev/null) + $(WGET=/bin/false CURL=/bin/false download_cmd something 2> /dev/null) assertEquals $? 1 } From 5773c42f041ccad375ae542f27cc58814777494b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 20 Jun 2015 13:09:20 +0000 Subject: [PATCH 095/326] Issue #79: Add tests for ln, rm, chown and mkdir commands --- lib/core.sh | 4 +++ tests/test_core.sh | 71 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index a63aafe..bbf2311 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -98,6 +98,10 @@ MKDIR="mkdir" PATH=/usr/bin:/bin:/sbin:$PATH LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" +# The following functions attempt first to run the executable in the host OS. +# As a last hope they try to run the same executable available in the JuNest +# image. + function ln_cmd(){ ln $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/ln $@ } diff --git a/tests/test_core.sh b/tests/test_core.sh index b5dd5db..a9759d9 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -62,6 +62,77 @@ function test_download(){ assertEquals $? 1 } +function test_ln(){ + install_mini_env + + touch ln_file + ln_cmd -s ln_file new_file + assertEquals $? 0 + assertTrue "[ -e new_file ]" + rm new_file + + touch ln_file + OLDPATH="$PATH" + PATH="" + ln_cmd -s ln_file new_file 2> /dev/null + local ret=$? + PATH="$OLDPATH" + assertEquals $ret 0 + assertTrue "[ -e new_file ]" +} + +function test_rm(){ + install_mini_env + + touch rm_file + rm_cmd rm_file + assertEquals $? 0 + assertTrue "[ ! -e rm_file ]" + + touch rm_file + OLDPATH="$PATH" + PATH="" + rm_cmd rm_file 2> /dev/null + local ret=$? + PATH="$OLDPATH" + assertEquals $ret 0 + assertTrue "[ ! -e rm_file ]" +} + +function test_chown(){ + install_mini_env + + local id=$(id -u) + + touch chown_file + chown_cmd $id chown_file + assertEquals $? 0 + + touch chown_file + OLDPATH="$PATH" + PATH="" + chown_cmd $id chown_file 2> /dev/null + local ret=$? + PATH="$OLDPATH" + assertEquals $ret 0 +} + +function test_mkdir(){ + install_mini_env + + mkdir_cmd -p new_dir/new_dir + assertEquals $? 0 + assertTrue "[ -d new_dir/new_dir ]" + rm -rf new_dir + + OLDPATH="$PATH" + PATH="" + mkdir_cmd -p new_dir/new_dir 2> /dev/null + local ret=$? + PATH="$OLDPATH" + assertEquals $ret 0 + assertTrue "[ -d new_dir/new_dir ]" +} function test_setup_env(){ wget_mock(){ From 6994a6b2e6bb43bd5eb70506a450cc45e0cbef16 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 20 Jun 2015 14:18:53 +0000 Subject: [PATCH 096/326] Issue #79: Apply the new executables --- README.md | 15 +++++++++++---- lib/core.sh | 28 +++++++++++++--------------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index b47d6ca..bb99ccc 100644 --- a/README.md +++ b/README.md @@ -69,11 +69,12 @@ JuNest comes with a very short list of dependencies in order to be installed in of GNU/Linux distributions. The needed executables in the host OS are: - bash -- wget or curl -- tar -- mkdir -- ln - chown (for root access only) +- ln +- mkdir +- rm +- tar +- wget or curl The minimum recommended linux kernel is 2.6.0+ @@ -140,6 +141,12 @@ the sandbox. Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work on some distros, JuNest automatically tries to fallback to the classic chroot. +##Automatic fallback for all the dependent host OS executables## +JuNest attempt first to run the executables in the host OS located in different +positions (/usr/bin, /bin and /sbin). +As a fallback it tries to run the same executable if it is available in the JuNest +image. + ##Automatic building of the JuNest images## The JuNest images are built every week so that you can always get the most updated package versions. diff --git a/lib/core.sh b/lib/core.sh index bbf2311..3d2428f 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -91,9 +91,7 @@ CLASSIC_CHROOT=${JUNEST_HOME}/usr/bin/chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" TAR=tar -CHOWN="${JUNEST_HOME}/usr/bin/chown" -LN="ln" -MKDIR="mkdir" +CHOWN="chown" PATH=/usr/bin:/bin:/sbin:$PATH LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -111,7 +109,7 @@ function rm_cmd(){ } function chown_cmd(){ - chown $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chown $@ + $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chown $@ } function mkdir_cmd(){ @@ -135,13 +133,13 @@ function _cleanup_build_directory(){ local maindir=$1 builtin cd $ORIGIN_WD trap - QUIT EXIT ABRT KILL TERM INT - rm -fr "$maindir" + rm_cmd -fr "$maindir" } function _prepare_build_directory(){ trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT + trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT } @@ -194,9 +192,9 @@ function run_env_as_root(){ local cmd="mkdir -p ${JUNEST_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || ${CHOWN} -R ${uid} ${JUNEST_HOME}; rm -r ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -r ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT - [ ! -e ${JUNEST_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab + [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab if ${CHROOT} $JUNEST_HOME ${TRUE} 1> /dev/null then @@ -212,9 +210,9 @@ function run_env_as_root(){ fi # The ownership of the files is assigned to the real user - [ -z $uid ] || ${CHOWN} -R ${uid} ${JUNEST_HOME} + [ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME} - [ -e ${JUNEST_HOME}/etc/mtab ] && rm -r ${JUNEST_HOME}/etc/mtab + [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -r ${JUNEST_HOME}/etc/mtab trap - QUIT EXIT ABRT KILL TERM INT return $? @@ -255,7 +253,7 @@ function run_env_as_fakeroot(){ [ "$(_run_proot "-R ${JUNEST_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - [ ! -e ${JUNEST_HOME}/etc/mtab ] && $LN -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab + [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab _run_env_with_proot "-S ${JUNEST_HOME} $proot_args" "${@}" } @@ -266,7 +264,7 @@ function run_env_as_user(){ [ "$(_run_proot "-R ${JUNEST_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." - [ -e ${JUNEST_HOME}/etc/mtab ] && rm -f ${JUNEST_HOME}/etc/mtab + [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -f ${JUNEST_HOME}/etc/mtab _run_env_with_proot "-R ${JUNEST_HOME} $proot_args" "${@}" } @@ -284,7 +282,7 @@ function delete_env(){ fi # the CA directories are read only and can be deleted only by changing the mod chmod -R +w ${JUNEST_HOME}/etc/ca-certificates - if rm -rf ${JUNEST_HOME}/* + if rm_cmd -rf ${JUNEST_HOME}/* then info "${NAME} deleted in ${JUNEST_HOME}" else @@ -319,8 +317,8 @@ function build_image_env(){ trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT info "Installing pacman and its dependencies..." # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux + # All the essential executables (ln, mkdir, chown, etc) are in coreutils # yaourt requires sed - # coreutils is needed for chown sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" @@ -356,7 +354,7 @@ function build_image_env(){ sudo sed -i -e 's/"--asroot"//' ${maindir}/root/opt/yaourt/bin/yaourt sudo cp ${maindir}/root/usr/bin/makepkg ${maindir}/root/opt/yaourt/bin/ sudo sed -i -e 's/EUID\s==\s0/false/' ${maindir}/root/opt/yaourt/bin/makepkg - sudo bash -c "echo 'export PATH=/opt/yaourt/bin:$PATH' > ${maindir}/root/etc/profile.d/${CMD}.sh" + sudo bash -c "echo 'export PATH=/opt/yaourt/bin:\$PATH' > ${maindir}/root/etc/profile.d/${CMD}.sh" sudo chmod +x ${maindir}/root/etc/profile.d/${CMD}.sh info "Copying ${NAME} scripts..." From 3dc3a830a2553d1eee27ba4c5e089b499837fd04 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 20 Jun 2015 17:28:43 +0000 Subject: [PATCH 097/326] Issue #74: Create the initial chroot skeleton --- bin/jchroot | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100755 bin/jchroot diff --git a/bin/jchroot b/bin/jchroot new file mode 100755 index 0000000..37f5d3d --- /dev/null +++ b/bin/jchroot @@ -0,0 +1,107 @@ +#!/bin/bash +# +# Copyright (c) 2012-2015 +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU Library General Public License as published +# by the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +set -e + +################################ IMPORTS ################################## +source "$(dirname $0)/../lib/util.sh" + +################################ MAIN FUNCTIONS ########################### + +chroot_add_mount() { + mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}") +} + +chroot_maybe_add_mount() { + local cond=$1; shift + if eval "$cond"; then + chroot_add_mount "$@" + fi +} + +chroot_setup() { + CHROOT_ACTIVE_MOUNTS=() + [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' + trap 'chroot_teardown' EXIT + + #chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind && + chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && + chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && + chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && + chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && + chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && + chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 && + chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid && + mkdir -p "$1/$HOME" && + chroot_add_mount $HOME "$1/$HOME" --bind +} + +chroot_teardown() { + umount "${CHROOT_ACTIVE_MOUNTS[@]}" + unset CHROOT_ACTIVE_MOUNTS +} + +usage() { + cat < Date: Mon, 22 Jun 2015 19:00:37 +0000 Subject: [PATCH 098/326] Issue #74: Substitute arch-chroot to jchroot --- bin/jchroot | 9 ++++++--- bin/junest | 4 +++- lib/core.sh | 9 +++++++-- tests/test_cli.sh | 2 +- tests/test_core.sh | 3 ++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/bin/jchroot b/bin/jchroot index 37f5d3d..83dc10f 100755 --- a/bin/jchroot +++ b/bin/jchroot @@ -16,6 +16,9 @@ # along with this program. If not, see . # +# This script is the simplified and portable version of arch-chroot +# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) + set -e ################################ IMPORTS ################################## @@ -39,14 +42,14 @@ chroot_setup() { [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' trap 'chroot_teardown' EXIT - #chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind && + chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind && chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 && - chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid && + chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,atime,nodev,nosuid && mkdir -p "$1/$HOME" && chroot_add_mount $HOME "$1/$HOME" --bind } @@ -90,7 +93,7 @@ chroot_add_resolv_conf() { chroot_add_mount /etc/resolv.conf "$resolv_conf" --bind } -if [[ -z $1 || $1 = @(-h|--help) ]]; then +if [[ -z $1 || $1 == -h || $1 == --help ]]; then usage exit $(( $# ? 0 : 1 )) fi diff --git a/bin/junest b/bin/junest index abc69bf..28c480f 100755 --- a/bin/junest +++ b/bin/junest @@ -18,7 +18,9 @@ # along with this program. If not, see . # -source "$(dirname $0)/../lib/core.sh" +JUNEST_BASE="$(dirname $0)/.." + +source "${JUNEST_BASE}/lib/core.sh" ################################### ### General functions ### diff --git a/lib/core.sh b/lib/core.sh index 3d2428f..af2989b 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -46,6 +46,7 @@ then fi [ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} +[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] then JUNEST_TEMPDIR=/tmp @@ -86,14 +87,14 @@ ID="id -u" # List of executables that are run in the host OS: PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" -CHROOT=${JUNEST_HOME}/usr/bin/arch-chroot +CHROOT=${JUNEST_BASE}/bin/jchroot CLASSIC_CHROOT=${JUNEST_HOME}/usr/bin/chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" TAR=tar CHOWN="chown" -PATH=/usr/bin:/bin:/sbin:$PATH +PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" # The following functions attempt first to run the executable in the host OS. @@ -120,6 +121,10 @@ function download_cmd(){ $WGET $@ || $CURL $@ } +function chroot_cmd(){ + $CHROOT $@ || chroot $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot $@ +} + ################################# MAIN FUNCTIONS ############################## function is_env_installed(){ diff --git a/tests/test_cli.sh b/tests/test_cli.sh index a9e0a13..bcf2f0c 100755 --- a/tests/test_cli.sh +++ b/tests/test_cli.sh @@ -1,5 +1,5 @@ #!/bin/bash -source $(dirname $0)/../bin/* -h &> /dev/null +source $(dirname $0)/../bin/junest -h &> /dev/null # Disable the exiterr set +e diff --git a/tests/test_core.sh b/tests/test_core.sh index a9759d9..84ed818 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -16,7 +16,8 @@ function install_mini_env(){ function setUp(){ cd $CURRPWD JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) - source "$(dirname $0)/../lib/core.sh" + JUNEST_BASE="$CURRPWD/$(dirname $0)/.." + source "${JUNEST_BASE}/lib/core.sh" ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX) cd $ORIGIN_WD JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) From f15dc54b3899deebee3a5198d78529fdf19f5c72 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 22 Jun 2015 21:20:21 +0000 Subject: [PATCH 099/326] Issue #74: Apply chroot_cmd function --- bin/jchroot | 2 ++ lib/core.sh | 20 ++++---------------- tests/test_core.sh | 17 +++++++++++++++++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/bin/jchroot b/bin/jchroot index 83dc10f..2ed810f 100755 --- a/bin/jchroot +++ b/bin/jchroot @@ -52,6 +52,8 @@ chroot_setup() { chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,atime,nodev,nosuid && mkdir -p "$1/$HOME" && chroot_add_mount $HOME "$1/$HOME" --bind + + mkdir -p "$1/run/lock" } chroot_teardown() { diff --git a/lib/core.sh b/lib/core.sh index af2989b..e2295c1 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -88,7 +88,7 @@ ID="id -u" # List of executables that are run in the host OS: PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" CHROOT=${JUNEST_BASE}/bin/jchroot -CLASSIC_CHROOT=${JUNEST_HOME}/usr/bin/chroot +CLASSIC_CHROOT="chroot" WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" TAR=tar @@ -122,7 +122,7 @@ function download_cmd(){ } function chroot_cmd(){ - $CHROOT $@ || chroot $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot $@ + $CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@" } ################################# MAIN FUNCTIONS ############################## @@ -187,32 +187,20 @@ function setup_env_from_file(){ builtin cd $ORIGIN_WD } - function run_env_as_root(){ local uid=$UID [ -z $SUDO_UID ] || uid=$SUDO_UID:$SUDO_GID local main_cmd="${SH[@]}" [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" - local cmd="mkdir -p ${JUNEST_HOME}/${HOME} && mkdir -p /run/lock && ${main_cmd}" trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -r ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab - if ${CHROOT} $JUNEST_HOME ${TRUE} 1> /dev/null - then - JUNEST_ENV=1 ${CHROOT} $JUNEST_HOME "${SH[@]}" "-c" "${cmd}" - local ret=$? - elif ${CLASSIC_CHROOT} $JUNEST_HOME ${TRUE} 1> /dev/null - then - warn "Warning: The executable arch-chroot does not work, falling back to classic chroot" - JUNEST_ENV=1 ${CLASSIC_CHROOT} $JUNEST_HOME "${SH[@]}" "-c" "${cmd}" - local ret=$? - else - die "Error: Chroot does not work" - fi + JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" + local ret=$? # The ownership of the files is assigned to the real user [ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME} diff --git a/tests/test_core.sh b/tests/test_core.sh index 84ed818..7c3e45f 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -218,6 +218,23 @@ function test_run_env_as_classic_root(){ assertEquals 0 $? } +function test_run_env_as_junest_root(){ + [ $SKIP_ROOT_TESTS -eq 1 ] && return + + install_mini_env + CHROOT="sudo unknowncommand" + CLASSIC_CHROOT="sudo unknowncommand" + LD_EXEC="sudo $LD_EXEC" + CHOWN="sudo $CHOWN" + + local output=$(run_env_as_root pwd 2> /dev/null) + assertEquals "/" "$output" + run_env_as_root [ -e /run/lock ] 2> /dev/null + assertEquals 0 $? + run_env_as_root [ -e $HOME ] 2> /dev/null + assertEquals 0 $? +} + function test_run_env_as_user(){ install_mini_env local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') From be3f771cee75e932aafd0e9ff5cf0debe24c199c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 22 Jun 2015 21:59:18 +0000 Subject: [PATCH 100/326] Issue #74: Update doc and remove arch-install-scripts from JuNest image --- README.md | 10 ++++++---- lib/core.sh | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index bb99ccc..1181ea1 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ You can build a new JuNest image from scratch by running the following command: junest -b [-n] The script will create a directory containing all the essentials -files in order to make JuNest working properly (such as pacman, yaourt, arch-chroot and proot). +files in order to make JuNest working properly (such as pacman, yaourt and proot). The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. @@ -132,18 +132,20 @@ Internals There are two main chroot jail used in JuNest. The main one is [proot](https://wiki.archlinux.org/index.php/Proot) which allows unprivileged users to execute programs inside a sandbox and +jchroot, a small and portable version of [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an enhanced chroot for privileged users that mounts the primary directories (i.e. /proc, /sys, /dev and /run) before executing any programs inside the sandbox. ##Automatic fallback to classic chroot## -Since the [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) may not work -on some distros, JuNest automatically tries to fallback to the classic chroot. +If jchroot fails for some reasons in the host system (i.e. it is not able to +mount one of the directories), +JuNest automatically tries to fallback to the classic chroot. ##Automatic fallback for all the dependent host OS executables## JuNest attempt first to run the executables in the host OS located in different -positions (/usr/bin, /bin and /sbin). +positions (/usr/bin, /bin, /usr/sbin and /sbin). As a fallback it tries to run the same executable if it is available in the JuNest image. diff --git a/lib/core.sh b/lib/core.sh index e2295c1..50fce21 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -312,7 +312,7 @@ function build_image_env(){ # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils # yaourt requires sed - sudo pacstrap -G -M -d ${maindir}/root pacman arch-install-scripts coreutils binutils libunistring archlinux-keyring sed + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils binutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." @@ -387,7 +387,6 @@ function validate_image(){ JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r arch-chroot --help 1> /dev/null local repo_package=sysstat info "Installing ${repo_package} package from official repo using proot..." From 8425b09fce3516ba2bc85225b2a329b58929bfe6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 22 Jun 2015 23:51:16 +0000 Subject: [PATCH 101/326] Issue #89: Remove the true executable --- lib/core.sh | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 50fce21..218c74d 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -82,7 +82,7 @@ ORIGIN_WD=$(pwd) # List of executables that are run inside JuNest: SH=("/bin/sh" "--login") -TRUE=true +TRUE="true" ID="id -u" # List of executables that are run in the host OS: @@ -117,6 +117,11 @@ function mkdir_cmd(){ mkdir $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/mkdir $@ } +function proot_cmd(){ + ${PROOT_COMPAT} "${@}" || PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} "${@}" || \ + die "Error: Check if the ${CMD} arguments are correct or use the option ${CMD} -p \"-k 3.10\"" +} + function download_cmd(){ $WGET $@ || $CURL $@ } @@ -214,16 +219,7 @@ function run_env_as_root(){ function _run_proot(){ local proot_args="$1" shift - if ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null - then - JUNEST_ENV=1 ${PROOT_COMPAT} $proot_args "${@}" - elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args ${TRUE} 1> /dev/null - then - warn "Proot error: Trying to execute proot with PROOT_NO_SECCOMP=1..." - JUNEST_ENV=1 PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} $proot_args "${@}" - else - die "Error: Check if the ${CMD} arguments are correct or use the option ${CMD} -p \"-k 3.10\"" - fi + JUNEST_ENV=1 proot_cmd $proot_args "${@}" } From 5e19ac138ec98e2f26c9b18f1fecb1201f0b48a9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Jun 2015 00:05:13 +0000 Subject: [PATCH 102/326] Issue #89: Adjust the tests --- lib/core.sh | 1 - tests/test_core.sh | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 218c74d..d6c4fd5 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -82,7 +82,6 @@ ORIGIN_WD=$(pwd) # List of executables that are run inside JuNest: SH=("/bin/sh" "--login") -TRUE="true" ID="id -u" # List of executables that are run in the host OS: diff --git a/tests/test_core.sh b/tests/test_core.sh index 7c3e45f..1d0984c 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -306,16 +306,15 @@ function test_run_env_with_proot_as_root(){ } function test_run_proot_seccomp(){ - TRUE="" PROOT_COMPAT=env - local output=$(_run_proot | grep "^PROOT_NO_SECCOMP") + local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") assertEquals "$output" "" envv(){ env | grep "^PROOT_NO_SECCOMP" } PROOT_COMPAT=envv - local output=$(_run_proot 2> /dev/null | grep "^PROOT_NO_SECCOMP") + local output=$(proot_cmd 2> /dev/null | grep "^PROOT_NO_SECCOMP") assertEquals "$output" "PROOT_NO_SECCOMP=1" } From a5346f8154fd56ebe94ada8f9de690c881d5c81a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Jun 2015 16:03:06 +0000 Subject: [PATCH 103/326] Issue #89: Remove the _run_proot function --- lib/core.sh | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index d6c4fd5..8097941 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -215,22 +215,16 @@ function run_env_as_root(){ return $? } -function _run_proot(){ - local proot_args="$1" - shift - JUNEST_ENV=1 proot_cmd $proot_args "${@}" -} - - function _run_env_with_proot(){ + local proot_args="$1" shift if [ "$1" != "" ] then - _run_proot "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + JUNEST_ENV=1 proot_cmd ${proot_args} "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else - _run_proot "${proot_args}" "${SH[@]}" + JUNEST_ENV=1 proot_cmd ${proot_args} "${SH[@]}" fi } @@ -238,7 +232,7 @@ function _run_env_with_proot(){ function run_env_as_fakeroot(){ local proot_args="$1" shift - [ "$(_run_proot "-R ${JUNEST_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(proot_cmd -R ${JUNEST_HOME} $proot_args ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab @@ -249,7 +243,7 @@ function run_env_as_fakeroot(){ function run_env_as_user(){ local proot_args="$1" shift - [ "$(_run_proot "-R ${JUNEST_HOME} $proot_args" ${ID} 2> /dev/null )" == "0" ] && \ + [ "$(proot_cmd -R ${JUNEST_HOME} $proot_args ${ID} 2> /dev/null )" == "0" ] && \ die "You cannot access with root privileges. Use --root option instead." [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -f ${JUNEST_HOME}/etc/mtab From 21f3b6ebdad0f203a8f80489cf983e62b4a1dbeb Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Jun 2015 21:44:49 +0000 Subject: [PATCH 104/326] Issue #89: Remove id executable --- lib/core.sh | 13 +++++++------ tests/test_core.sh | 6 ++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 8097941..ee713b3 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -82,7 +82,6 @@ ORIGIN_WD=$(pwd) # List of executables that are run inside JuNest: SH=("/bin/sh" "--login") -ID="id -u" # List of executables that are run in the host OS: PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" @@ -230,10 +229,11 @@ function _run_env_with_proot(){ function run_env_as_fakeroot(){ + (( EUID == 0 )) && \ + die "You cannot access with root privileges. Use --root option instead." + local proot_args="$1" shift - [ "$(proot_cmd -R ${JUNEST_HOME} $proot_args ${ID} 2> /dev/null )" == "0" ] && \ - die "You cannot access with root privileges. Use --root option instead." [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab _run_env_with_proot "-S ${JUNEST_HOME} $proot_args" "${@}" @@ -241,10 +241,11 @@ function run_env_as_fakeroot(){ function run_env_as_user(){ + (( EUID == 0 )) && \ + die "You cannot access with root privileges. Use --root option instead." + local proot_args="$1" shift - [ "$(proot_cmd -R ${JUNEST_HOME} $proot_args ${ID} 2> /dev/null )" == "0" ] && \ - die "You cannot access with root privileges. Use --root option instead." [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -f ${JUNEST_HOME}/etc/mtab _run_env_with_proot "-R ${JUNEST_HOME} $proot_args" "${@}" @@ -283,7 +284,7 @@ function _check_package(){ function build_image_env(){ # The function must runs on ArchLinux with non-root privileges. - [ "$(${ID})" == "0" ] && \ + (( EUID == 0 )) && \ die "You cannot build with root privileges." _check_package arch-install-scripts diff --git a/tests/test_core.sh b/tests/test_core.sh index 1d0984c..1f40693 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -297,11 +297,13 @@ function test_run_env_with_proot_compat(){ } function test_run_env_with_proot_as_root(){ + [ $SKIP_ROOT_TESTS -eq 1 ] && return + install_mini_env - $(ID="/bin/echo 0" run_env_as_user 2> /dev/null) + $(sudo run_env_as_user 2> /dev/null) assertEquals $? 1 - $(ID="/bin/echo 0" run_env_as_fakeroot 2> /dev/null) + $(sudo run_env_as_fakeroot 2> /dev/null) assertEquals $? 1 } From e3a0726a19a08f9b25edec052d5dfa264a282e57 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 23 Jun 2015 22:23:47 +0000 Subject: [PATCH 105/326] Remove binutils from the image --- lib/core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index ee713b3..06ac5fa 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -302,7 +302,7 @@ function build_image_env(){ # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils # yaourt requires sed - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils binutils libunistring archlinux-keyring sed + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" info "Generating the locales..." From 2cae586c346059b8de3c097755b6ef605eecffc2 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 24 Jun 2015 18:33:02 +0000 Subject: [PATCH 106/326] Use SUDO_USER instead of SUDO_UID --- lib/core.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 06ac5fa..dacc020 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -192,7 +192,8 @@ function setup_env_from_file(){ function run_env_as_root(){ local uid=$UID - [ -z $SUDO_UID ] || uid=$SUDO_UID:$SUDO_GID + # 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 "$@")" From 98a1ef5bf0290568054c6072ba186bde45fd991e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 22 Jun 2015 23:30:35 +0000 Subject: [PATCH 107/326] Issue #88: Copy qemu static and all proot compat binaries --- lib/core.sh | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index dacc020..3cd1daa 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -52,6 +52,7 @@ then JUNEST_TEMPDIR=/tmp fi +ARCH_LIST=('x86_64' 'x86' 'arm') HOST_ARCH=$(uname -m) if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then @@ -69,8 +70,9 @@ else die "Unknown architecture ${ARCH}" fi -PROOT_LINK=http://static.proot.me/proot-${ARCH} -ENV_REPO=https://dl.dropboxusercontent.com/u/42449030/${CMD} +PROOT_LINK=http://static.proot.me/ +MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030 +ENV_REPO=${MAIN_REPO}/${CMD} DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) @@ -313,11 +315,24 @@ function build_image_env(){ sudo arch-chroot ${maindir}/root locale-gen sudo bash -c "echo 'LANG = \"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" - info "Installing compatibility binary proot" + info "Installing compatibility binaries proot" sudo mkdir -p ${maindir}/root/opt/proot builtin cd ${maindir}/root/opt/proot - sudo $CURL $PROOT_LINK - sudo chmod +x proot-$ARCH + for arch in ${ARCH_LIST[@]} + do + sudo $CURL $PROOT_LINK/proot-$arch + sudo chmod +x proot-$arch + done + + info "Installing qemu static binaries" + sudo mkdir -p ${maindir}/root/opt/qemu + builtin cd ${maindir}/root/opt/qemu + NEW_ARCH_LIST=( "${ARCH_LIST[@]/$ARCH}" ) + for arch in ${NEW_ARCH_LIST[@]} + do + sudo $CURL ${MAIN_REPO}/qemu/$ARCH/qemu-$ARCH-static-$arch + sudo chmod +x qemu-$ARCH-static-$arch + done # AUR packages requires non-root user to be compiled. proot fakes the user to 10 info "Compiling and installing yaourt..." From 45814d65a5d810dd7a2ef8ec96199c7dd514d94c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 28 Jun 2015 12:30:22 +0000 Subject: [PATCH 108/326] Refactor the chroot script --- lib/core.sh | 12 ++---------- tests/test_core.sh | 6 +++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 3cd1daa..0a1d645 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -200,21 +200,13 @@ function run_env_as_root(){ local main_cmd="${SH[@]}" [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" + # With chown the ownership of the files is assigned to the real user trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -r ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -f ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" - local ret=$? - - # The ownership of the files is assigned to the real user - [ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME} - - [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -r ${JUNEST_HOME}/etc/mtab - - trap - QUIT EXIT ABRT KILL TERM INT - return $? } function _run_env_with_proot(){ diff --git a/tests/test_core.sh b/tests/test_core.sh index 1f40693..baf17dd 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -188,6 +188,8 @@ function test_run_env_as_root(){ # test that normal user has ownership of the files created by root run_env_as_root touch /a_root_file + # This ensure that the trap will be executed + kill -TERM $$ local output=$(run_env_as_root stat -c '%u' /a_root_file) assertEquals "$UID" "$output" @@ -214,8 +216,6 @@ function test_run_env_as_classic_root(){ assertEquals "/" "$output" run_env_as_root [ -e /run/lock ] 2> /dev/null assertEquals 0 $? - run_env_as_root [ -e $HOME ] 2> /dev/null - assertEquals 0 $? } function test_run_env_as_junest_root(){ @@ -232,7 +232,7 @@ function test_run_env_as_junest_root(){ run_env_as_root [ -e /run/lock ] 2> /dev/null assertEquals 0 $? run_env_as_root [ -e $HOME ] 2> /dev/null - assertEquals 0 $? + assertEquals 1 $? } function test_run_env_as_user(){ From 8475d8eb4173136c2b01d965e83d65be67d9299e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 29 Jun 2015 13:20:54 +0000 Subject: [PATCH 109/326] Fix the build of x86 image --- lib/core.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 0a1d645..cd3a8a0 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -312,6 +312,7 @@ function build_image_env(){ builtin cd ${maindir}/root/opt/proot for arch in ${ARCH_LIST[@]} do + info "Downloading $PROOT_LINK/proot-$arch ..." sudo $CURL $PROOT_LINK/proot-$arch sudo chmod +x proot-$arch done @@ -319,11 +320,14 @@ function build_image_env(){ info "Installing qemu static binaries" sudo mkdir -p ${maindir}/root/opt/qemu builtin cd ${maindir}/root/opt/qemu - NEW_ARCH_LIST=( "${ARCH_LIST[@]/$ARCH}" ) - for arch in ${NEW_ARCH_LIST[@]} + for arch in ${ARCH_LIST[@]} do - sudo $CURL ${MAIN_REPO}/qemu/$ARCH/qemu-$ARCH-static-$arch - sudo chmod +x qemu-$ARCH-static-$arch + if [ "$arch" != "$ARCH" ] + then + info "Downloading qemu-$ARCH-static-$arch ..." + sudo $CURL ${MAIN_REPO}/qemu/$ARCH/qemu-$ARCH-static-$arch + sudo chmod +x qemu-$ARCH-static-$arch + fi done # AUR packages requires non-root user to be compiled. proot fakes the user to 10 From 0cf7c624ec816cb50c4c77e497aa6534738865e4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 25 Jun 2015 18:49:41 +0000 Subject: [PATCH 110/326] Issue #91: Add the architecture option --- README.md | 13 ++++++++++ bin/junest | 17 ++++++++----- lib/core.sh | 41 +++++++++++++++++++++---------- lib/util.sh | 6 +++++ tests/test_cli.sh | 36 +++++++++++++++++---------- tests/test_core.sh | 61 +++++++++++++++++++++++++++++----------------- tests/test_util.sh | 9 +++++++ 7 files changed, 129 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 1181ea1..e145c22 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ The main advantages on using JuNest are: - Isolated environment in which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). - Available for x86\_64, x86 and ARM architectures but you can build your own image from scratch too! +- Run on a different architecture from the host OS via QEMU - All Arch Linux lovers can have their favourite distro everywhere! JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way). @@ -101,6 +102,13 @@ Related wiki page: - [How to build a JuNest image using QEMU](https://github.com/fsquillace/junest/wiki/How-to-build-a-JuNest-image-using-QEMU) +## Run JuNest using a different architecture via QEMU ## +The following command will download the ARM JuNest image and will run QEMU in +case the host OS runs on either x86\_64 or x86 architectures: + + $> JUNEST_HOME=~/.junest-arm junest -a arm -- uname -m + armv7l + ## Bind directories ## To bind a host directory to a guest location, you can use proot arguments: @@ -153,6 +161,11 @@ image. The JuNest images are built every week so that you can always get the most updated package versions. +##Static QEMU binaries## +There are static QEMU binaries included in JuNest image that allows to run JuNest +in a different architecture from the host system. They are located in `/opt/qemu` +directory. + Troubleshooting =============== diff --git a/bin/junest b/bin/junest index 28c480f..707dcd8 100755 --- a/bin/junest +++ b/bin/junest @@ -34,6 +34,8 @@ usage() { echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" echo -e "-p, --proot-args Proot arguments" + echo -e "-a, --arch $NAME architecture to use (x86_64, x86, arm)." + echo -e " Defaults to the host architecture ($ARCH)" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" @@ -92,12 +94,12 @@ check_cli(){ then die "You must access to $NAME with either fakeroot or root permissions" fi - if $OPT_PROOT_ARGS + if $OPT_PROOT_ARGS || $OPT_ARCH then - if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION then - die "Invalid syntax: Proot args are not allowed with the other options" + die "Invalid syntax: Proot and arch args are not allowed with the other options" fi fi if [ "$ARGS" != "" ] @@ -120,6 +122,8 @@ function parse_arguments(){ OPT_ROOT=false OPT_PROOT_ARGS=false PROOT_ARGS="" + OPT_ARCH=false + ARCH_ARG="" OPT_BUILD_IMAGE=false OPT_DISABLE_VALIDATION=false OPT_DELETE=false @@ -132,6 +136,7 @@ function parse_arguments(){ -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; -r|--root) OPT_ROOT=true ; shift ;; -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; + -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; @@ -167,18 +172,18 @@ function execute_operation(){ if $OPT_SETUP_FROM_FILE; then setup_env_from_file $IMAGE_FILE else - setup_env + setup_env $ARCH_ARG fi elif $OPT_SETUP_FROM_FILE; then die "Error: The image cannot be installed since $JUNEST_HOME is not empty." fi if $OPT_FAKEROOT; then - run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" + run_env_as_fakeroot "${ARCH_ARG}" "${PROOT_ARGS}" "${ARGS[@]}" elif $OPT_ROOT; then run_env_as_root "${ARGS[@]}" else - run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" + run_env_as_user "${ARCH_ARG}" "${PROOT_ARGS}" "${ARGS[@]}" fi } diff --git a/lib/core.sh b/lib/core.sh index cd3a8a0..9cafbb3 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -167,12 +167,17 @@ function _setup_env(){ function setup_env(){ + local arch=$ARCH + [ -z $1 ] || arch="$1" + contains_element $arch "${ARCH_LIST[@]}" || \ + die "The architecture is not one of: ${ARCH_LIST[@]}" + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) _prepare_build_directory info "Downloading ${NAME}..." builtin cd ${maindir} - local imagefile=${CMD}-${ARCH}.tar.gz + local imagefile=${CMD}-${arch}.tar.gz download_cmd ${ENV_REPO}/${imagefile} info "Installing ${NAME}..." @@ -210,7 +215,6 @@ function run_env_as_root(){ } function _run_env_with_proot(){ - local proot_args="$1" shift @@ -222,28 +226,39 @@ function _run_env_with_proot(){ fi } +function _run_env_with_qemu(){ + local proot_args="$2" + if [ "$1" != "" ] && [ "$1" != "$ARCH" ] + then + local qemu_bin="/tmp/qemu-$1-static-$ARCH-$RANDOM" + trap - QUIT EXIT ABRT KILL TERM INT + trap "[ -e ${qemu_bin} ] && rm_cmd -f ${qemu_bin}" EXIT QUIT ABRT KILL TERM INT + + contains_element $1 "${ARCH_LIST[@]}" || \ + die "The architecture is not one of: ${ARCH_LIST[@]}" + [ -e "${JUNEST_HOME}/opt/qemu/qemu-$1-static-$ARCH" ] || \ + die "The JuNest image in ${JUNEST_HOME} is not an $1 architecture" + warn "Emulating $NAME via QEMU..." + [ -e ${qemu_bin} ] || \ + ln_cmd -s ${JUNEST_HOME}/opt/qemu/qemu-$1-static-$ARCH ${qemu_bin} + proot_args="-q ${qemu_bin} $2" + fi + shift 2 + _run_env_with_proot "$proot_args" "${@}" +} function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die "You cannot access with root privileges. Use --root option instead." - - local proot_args="$1" - shift - [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab - _run_env_with_proot "-S ${JUNEST_HOME} $proot_args" "${@}" + _run_env_with_qemu "$1" "-S ${JUNEST_HOME} $2" "${@:3}" } - function run_env_as_user(){ (( EUID == 0 )) && \ die "You cannot access with root privileges. Use --root option instead." - - local proot_args="$1" - shift - [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -f ${JUNEST_HOME}/etc/mtab - _run_env_with_proot "-R ${JUNEST_HOME} $proot_args" "${@}" + _run_env_with_qemu "$1" "-R ${JUNEST_HOME} $2" "${@:3}" } diff --git a/lib/util.sh b/lib/util.sh index f65ac26..7f45102 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -85,3 +85,9 @@ function insert_quotes_on_spaces(){ done echo $C } + +contains_element () { + local e + for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done + return 1 +} diff --git a/tests/test_cli.sh b/tests/test_cli.sh index bcf2f0c..f653d5b 100755 --- a/tests/test_cli.sh +++ b/tests/test_cli.sh @@ -27,17 +27,21 @@ function setup_env(){ echo "setup_env" } function run_env_as_fakeroot(){ - local proot_args="$1" + local arch_arg="$1" + local proot_args="$2" shift - echo "run_env_as_fakeroot($proot_args,$@)" + shift + echo "run_env_as_fakeroot($arch_arg,$proot_args,$@)" } function run_env_as_root(){ echo "run_env_as_root $@" } function run_env_as_user(){ - local proot_args="$1" + local arch_arg="$1" + local proot_args="$2" shift - echo "run_env_as_user($proot_args,$@)" + shift + echo "run_env_as_user($arch_arg,$proot_args,$@)" } function wrap_env(){ @@ -72,27 +76,31 @@ function test_delete_env(){ } function test_run_env_as_fakeroot(){ local output=$(wrap_env -f) - assertEquals $output "run_env_as_fakeroot(,)" + assertEquals $output "run_env_as_fakeroot(,,)" local output=$(wrap_env --fakeroot) - assertEquals $output "run_env_as_fakeroot(,)" + assertEquals $output "run_env_as_fakeroot(,,)" local output=$(wrap_env -f -p "-b arg") - assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,)" + assertEquals "${output[@]}" "run_env_as_fakeroot(,-b arg,)" local output=$(wrap_env -f -p "-b arg" -- command -kv) - assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,command -kv)" + assertEquals "${output[@]}" "run_env_as_fakeroot(,-b arg,command -kv)" local output=$(wrap_env -f command --as) - assertEquals "${output[@]}" "run_env_as_fakeroot(,command --as)" + assertEquals "${output[@]}" "run_env_as_fakeroot(,,command --as)" + local output=$(wrap_env -a "myarch" -f command --as) + assertEquals "${output[@]}" "run_env_as_fakeroot(myarch,,command --as)" } function test_run_env_as_user(){ local output=$(wrap_env) - assertEquals $output "run_env_as_user(,)" + assertEquals $output "run_env_as_user(,,)" local output=$(wrap_env -p "-b arg") - assertEquals "$output" "run_env_as_user(-b arg,)" + assertEquals "$output" "run_env_as_user(,-b arg,)" local output=$(wrap_env -p "-b arg" -- command -ll) - assertEquals "$output" "run_env_as_user(-b arg,command -ll)" + assertEquals "$output" "run_env_as_user(,-b arg,command -ll)" local output=$(wrap_env command -ls) - assertEquals "$output" "run_env_as_user(,command -ls)" + assertEquals "$output" "run_env_as_user(,,command -ls)" + local output=$(wrap_env -a "myarch" -- command -ls) + assertEquals "$output" "run_env_as_user(myarch,,command -ls)" } function test_run_env_as_root(){ local output=$(wrap_env -r) @@ -117,6 +125,8 @@ function test_check_cli(){ assertEquals $? 1 $(wrap_env -p args -v 2> /dev/null) assertEquals $? 1 + $(wrap_env -a arch -v 2> /dev/null) + assertEquals $? 1 $(wrap_env -d args 2> /dev/null) assertEquals $? 1 } diff --git a/tests/test_core.sh b/tests/test_core.sh index baf17dd..cafaa72 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -149,6 +149,9 @@ function test_setup_env(){ setup_env 1> /dev/null assertTrue "[ -e $JUNEST_HOME/file ]" assertTrue "[ -e $JUNEST_HOME/run/lock ]" + + $(setup_env "noarch" 2> /dev/null) + assertEquals 1 $? } @@ -237,21 +240,28 @@ function test_run_env_as_junest_root(){ function test_run_env_as_user(){ install_mini_env - local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') + local output=$(run_env_as_user "" "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" SH=("/usr/bin/mkdir" "-v" "/newdir") - local output=$(run_env_as_user "-k 3.10" | awk -F: '{print $1}') + local output=$(run_env_as_user "" "-k 3.10" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUNEST_HOME/newdir ]" + + $(run_env_as_user "noarch" "-k 3.10" "mycommand" 2> /dev/null) + assertEquals 1 $? + + local different_arch=(${ARCH_LIST[@]/$ARCH}) + $(run_env_as_user "${different_arch[0]}" "-k 3.10" "mycommand" 2> /dev/null) + assertEquals 1 $? } function test_run_env_as_proot_mtab(){ install_mini_env - $(run_env_as_fakeroot "-k 3.10" "echo") + $(run_env_as_fakeroot "" "-k 3.10" "echo") assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" - $(run_env_as_user "-k 3.10" "echo") + $(run_env_as_user "" "-k 3.10" "echo") assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" } @@ -268,32 +278,32 @@ function test_run_env_as_root_mtab(){ function test_run_env_with_quotes(){ install_mini_env - local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') - assertEquals "$output" "/usr/bin/mkdir" + local output=$(run_env_as_user "" "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') + assertEquals "/usr/bin/mkdir" "$output" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" } function test_run_env_as_user_proot_args(){ install_mini_env - run_env_as_user "--help" "" &> /dev/null - assertEquals $? 0 + run_env_as_user "" "--help" "" &> /dev/null + assertEquals 0 $? mkdir $JUNEST_TEMPDIR/newdir touch $JUNEST_TEMPDIR/newdir/newfile - run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null - assertEquals $? 0 + run_env_as_user "" "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null + assertEquals 0 $? $(_run_env_with_proot --helps 2> /dev/null) - assertEquals $? 1 + assertEquals 1 $? } function test_run_env_with_proot_compat(){ PROOT_COMPAT="/bin/true" _run_env_with_proot "" "" &> /dev/null - assertEquals $? 0 + assertEquals 0 $? $(PROOT_COMPAT="/bin/false" _run_env_with_proot --helps 2> /dev/null) - assertEquals $? 1 + assertEquals 1 $? } function test_run_env_with_proot_as_root(){ @@ -302,44 +312,51 @@ function test_run_env_with_proot_as_root(){ install_mini_env $(sudo run_env_as_user 2> /dev/null) - assertEquals $? 1 + assertEquals 1 $? $(sudo run_env_as_fakeroot 2> /dev/null) - assertEquals $? 1 + assertEquals 1 $? } function test_run_proot_seccomp(){ PROOT_COMPAT=env local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") - assertEquals "$output" "" + assertEquals "" "$output" envv(){ env | grep "^PROOT_NO_SECCOMP" } PROOT_COMPAT=envv local output=$(proot_cmd 2> /dev/null | grep "^PROOT_NO_SECCOMP") - assertEquals "$output" "PROOT_NO_SECCOMP=1" + assertEquals "PROOT_NO_SECCOMP=1" "$output" } function test_run_env_as_fakeroot(){ install_mini_env - local output=$(run_env_as_fakeroot "-k 3.10" "id" | awk '{print $1}') - assertEquals "$output" "uid=0(root)" + local output=$(run_env_as_fakeroot "" "-k 3.10" "id" | awk '{print $1}') + assertEquals "uid=0(root)" "$output" + + $(run_env_as_fakeroot "noarch" "-k 3.10" "mycommand" 2> /dev/null) + assertEquals 1 $? + + local different_arch=(${ARCH_LIST[@]/$ARCH}) + $(run_env_as_fakeroot "${different_arch[0]}" "-k 3.10" "mycommand" 2> /dev/null) + assertEquals 1 $? } function test_delete_env(){ install_mini_env echo "N" | delete_env 1> /dev/null is_env_installed - assertEquals $? 0 + assertEquals 0 $? echo "Y" | delete_env 1> /dev/null is_env_installed - assertEquals $? 1 + assertEquals 1 $? } function test_nested_env(){ install_mini_env JUNEST_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null - assertEquals $? 1 + assertEquals 1 $? } source $(dirname $0)/shunit2 diff --git a/tests/test_util.sh b/tests/test_util.sh index c10a095..80fd660 100755 --- a/tests/test_util.sh +++ b/tests/test_util.sh @@ -60,4 +60,13 @@ function test_insert_quotes_on_spaces(){ assertEquals "this is \"a test\"" "$actual" } +function test_contains_element(){ + array=("something to search for" "a string" "test2000") + contains_element "a string" "${array[@]}" + assertEquals "$?" "0" + + contains_element "blabla" "${array[@]}" + assertEquals "$?" "1" +} + source $(dirname $0)/shunit2 From d27f790562ded8985eb24d8223e1d55ae0deed57 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 29 Jun 2015 21:56:47 +0000 Subject: [PATCH 111/326] Issue #95: Document the uname executable --- README.md | 1 + lib/core.sh | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e145c22..ba473a1 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ of GNU/Linux distributions. The needed executables in the host OS are: - mkdir - rm - tar +- uname - wget or curl The minimum recommended linux kernel is 2.6.0+ diff --git a/lib/core.sh b/lib/core.sh index 9cafbb3..954b93a 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -52,8 +52,16 @@ then JUNEST_TEMPDIR=/tmp fi +# The update of the variable PATH ensures that the executables are +# found on different locations +PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH + +# The executable uname is essential in order to get the architecture +# of the host system, so a fallback mechanism cannot be used for it. +UNAME=uname + ARCH_LIST=('x86_64' 'x86' 'arm') -HOST_ARCH=$(uname -m) +HOST_ARCH=$($UNAME -m) if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then ARCH="x86" @@ -94,7 +102,6 @@ CURL="curl -L -J -O -k" TAR=tar CHOWN="chown" -PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" # The following functions attempt first to run the executable in the host OS. From b7ad8457714aa68d6314d6439590fd5b14cb63c6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 4 Jul 2015 23:46:27 +0000 Subject: [PATCH 112/326] Issue #93: Add JuNest metadata --- lib/core.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index 954b93a..a9576a8 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -329,6 +329,10 @@ function build_image_env(){ sudo arch-chroot ${maindir}/root locale-gen sudo bash -c "echo 'LANG = \"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" + info "Generating the metadata info..." + sudo mkdir ${maindir}/root/etc/${CMD} + sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info" + info "Installing compatibility binaries proot" sudo mkdir -p ${maindir}/root/opt/proot builtin cd ${maindir}/root/opt/proot From 438eeafb634386802cb2e7edec1f3ab59e887d5c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 5 Jul 2015 11:46:35 +0000 Subject: [PATCH 113/326] Issue #93: Add test for chroot --- lib/core.sh | 4 ++++ tests/test_core.sh | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/core.sh b/lib/core.sh index a9576a8..a9055a7 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -205,6 +205,10 @@ function setup_env_from_file(){ } function run_env_as_root(){ + source ${JUNEST_HOME}/etc/junest/info + [ "$JUNEST_ARCH" != "$ARCH" ] && \ + die "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" + local uid=$UID # SUDO_USER is more reliable compared to SUDO_UID [ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID diff --git a/tests/test_core.sh b/tests/test_core.sh index cafaa72..b2ef4fc 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -207,6 +207,15 @@ function test_run_env_as_root(){ assertEquals 0 $? } +function test_run_env_as_root_different_arch(){ + [ $SKIP_ROOT_TESTS -eq 1 ] && return + + install_mini_env + echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + $(run_env_as_root pwd 2> /dev/null) + assertEquals 1 $? +} + function test_run_env_as_classic_root(){ [ $SKIP_ROOT_TESTS -eq 1 ] && return From e2b14e9bff0849d207cb973e578f5522c32fbbd5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 5 Jul 2015 14:20:07 +0000 Subject: [PATCH 114/326] Issue #93: Improve help and add test for proot access --- bin/junest | 25 ++++++++++++++++++------- lib/core.sh | 31 +++++++++++++++---------------- tests/test_cli.sh | 38 +++++++++++++++++--------------------- tests/test_core.sh | 30 ++++++++---------------------- 4 files changed, 58 insertions(+), 66 deletions(-) diff --git a/bin/junest b/bin/junest index 707dcd8..d24ab4a 100755 --- a/bin/junest +++ b/bin/junest @@ -29,16 +29,23 @@ source "${JUNEST_BASE}/lib/core.sh" usage() { echo -e "$NAME: $DESCRIPTION" echo -e "Usage: $CMD [options] [--] [command]" - echo -e "Options:" + echo + echo -e "Setup options:" echo -e "-i, --setup-from-file Setup the $NAME image in ${JUNEST_HOME}" + echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)." + echo -e " Defaults to the host architecture ($ARCH)" + echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" + echo + echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" - echo -e "-p, --proot-args Proot arguments" - echo -e "-a, --arch $NAME architecture to use (x86_64, x86, arm)." - echo -e " Defaults to the host architecture ($ARCH)" + echo -e "-p, --proot-args Proot arguments" + echo + echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" - echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" + echo + echo -e "General options:" echo -e "-h, --help Show this help message" echo -e "-v, --version Show the $NAME version" } @@ -173,17 +180,21 @@ function execute_operation(){ setup_env_from_file $IMAGE_FILE else setup_env $ARCH_ARG + unset ARCH_ARG fi elif $OPT_SETUP_FROM_FILE; then die "Error: The image cannot be installed since $JUNEST_HOME is not empty." fi + [ -z "${ARCH_ARG}" ] || \ + die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" + if $OPT_FAKEROOT; then - run_env_as_fakeroot "${ARCH_ARG}" "${PROOT_ARGS}" "${ARGS[@]}" + run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" elif $OPT_ROOT; then run_env_as_root "${ARGS[@]}" else - run_env_as_user "${ARCH_ARG}" "${PROOT_ARGS}" "${ARGS[@]}" + run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" fi } diff --git a/lib/core.sh b/lib/core.sh index a9055a7..e21b3e1 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -238,23 +238,22 @@ function _run_env_with_proot(){ } function _run_env_with_qemu(){ - local proot_args="$2" - if [ "$1" != "" ] && [ "$1" != "$ARCH" ] - then - local qemu_bin="/tmp/qemu-$1-static-$ARCH-$RANDOM" - trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -e ${qemu_bin} ] && rm_cmd -f ${qemu_bin}" EXIT QUIT ABRT KILL TERM INT + local proot_args="$1" + source ${JUNEST_HOME}/etc/junest/info + + if [ "$JUNEST_ARCH" != "$ARCH" ] + then + local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH" + local qemu_symlink="/tmp/${qemu_bin}-$RANDOM" + trap - QUIT EXIT ABRT KILL TERM INT + trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT - contains_element $1 "${ARCH_LIST[@]}" || \ - die "The architecture is not one of: ${ARCH_LIST[@]}" - [ -e "${JUNEST_HOME}/opt/qemu/qemu-$1-static-$ARCH" ] || \ - die "The JuNest image in ${JUNEST_HOME} is not an $1 architecture" warn "Emulating $NAME via QEMU..." - [ -e ${qemu_bin} ] || \ - ln_cmd -s ${JUNEST_HOME}/opt/qemu/qemu-$1-static-$ARCH ${qemu_bin} - proot_args="-q ${qemu_bin} $2" + [ -e ${qemu_symlink} ] || \ + ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink} + proot_args="-q ${qemu_symlink} $proot_args" fi - shift 2 + shift _run_env_with_proot "$proot_args" "${@}" } @@ -262,14 +261,14 @@ function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die "You cannot access with root privileges. Use --root option instead." [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab - _run_env_with_qemu "$1" "-S ${JUNEST_HOME} $2" "${@:3}" + _run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" } function run_env_as_user(){ (( EUID == 0 )) && \ die "You cannot access with root privileges. Use --root option instead." [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -f ${JUNEST_HOME}/etc/mtab - _run_env_with_qemu "$1" "-R ${JUNEST_HOME} $2" "${@:3}" + _run_env_with_qemu "-R ${JUNEST_HOME} $1" "${@:2}" } diff --git a/tests/test_cli.sh b/tests/test_cli.sh index f653d5b..a0ddf58 100755 --- a/tests/test_cli.sh +++ b/tests/test_cli.sh @@ -27,21 +27,17 @@ function setup_env(){ echo "setup_env" } function run_env_as_fakeroot(){ - local arch_arg="$1" - local proot_args="$2" + local proot_args="$1" shift - shift - echo "run_env_as_fakeroot($arch_arg,$proot_args,$@)" + echo "run_env_as_fakeroot($proot_args,$@)" } function run_env_as_root(){ echo "run_env_as_root $@" } function run_env_as_user(){ - local arch_arg="$1" - local proot_args="$2" + local proot_args="$1" shift - shift - echo "run_env_as_user($arch_arg,$proot_args,$@)" + echo "run_env_as_user($proot_args,$@)" } function wrap_env(){ @@ -76,31 +72,31 @@ function test_delete_env(){ } function test_run_env_as_fakeroot(){ local output=$(wrap_env -f) - assertEquals $output "run_env_as_fakeroot(,,)" + assertEquals $output "run_env_as_fakeroot(,)" local output=$(wrap_env --fakeroot) - assertEquals $output "run_env_as_fakeroot(,,)" + assertEquals $output "run_env_as_fakeroot(,)" local output=$(wrap_env -f -p "-b arg") - assertEquals "${output[@]}" "run_env_as_fakeroot(,-b arg,)" + assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,)" local output=$(wrap_env -f -p "-b arg" -- command -kv) - assertEquals "${output[@]}" "run_env_as_fakeroot(,-b arg,command -kv)" + assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,command -kv)" local output=$(wrap_env -f command --as) - assertEquals "${output[@]}" "run_env_as_fakeroot(,,command --as)" - local output=$(wrap_env -a "myarch" -f command --as) - assertEquals "${output[@]}" "run_env_as_fakeroot(myarch,,command --as)" + assertEquals "${output[@]}" "run_env_as_fakeroot(,command --as)" + $(wrap_env -a "myarch" -f command --as 2> /dev/null) + assertEquals 1 $? } function test_run_env_as_user(){ local output=$(wrap_env) - assertEquals $output "run_env_as_user(,,)" + assertEquals $output "run_env_as_user(,)" local output=$(wrap_env -p "-b arg") - assertEquals "$output" "run_env_as_user(,-b arg,)" + assertEquals "$output" "run_env_as_user(-b arg,)" local output=$(wrap_env -p "-b arg" -- command -ll) - assertEquals "$output" "run_env_as_user(,-b arg,command -ll)" + assertEquals "$output" "run_env_as_user(-b arg,command -ll)" local output=$(wrap_env command -ls) - assertEquals "$output" "run_env_as_user(,,command -ls)" - local output=$(wrap_env -a "myarch" -- command -ls) - assertEquals "$output" "run_env_as_user(myarch,,command -ls)" + assertEquals "$output" "run_env_as_user(,command -ls)" + $(wrap_env -a "myarch" -- command -ls 2> /dev/null) + assertEquals 1 $? } function test_run_env_as_root(){ local output=$(wrap_env -r) diff --git a/tests/test_core.sh b/tests/test_core.sh index b2ef4fc..38d7b41 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -249,28 +249,21 @@ function test_run_env_as_junest_root(){ function test_run_env_as_user(){ install_mini_env - local output=$(run_env_as_user "" "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') + local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" SH=("/usr/bin/mkdir" "-v" "/newdir") - local output=$(run_env_as_user "" "-k 3.10" | awk -F: '{print $1}') + local output=$(run_env_as_user "-k 3.10" | awk -F: '{print $1}') assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUNEST_HOME/newdir ]" - - $(run_env_as_user "noarch" "-k 3.10" "mycommand" 2> /dev/null) - assertEquals 1 $? - - local different_arch=(${ARCH_LIST[@]/$ARCH}) - $(run_env_as_user "${different_arch[0]}" "-k 3.10" "mycommand" 2> /dev/null) - assertEquals 1 $? } function test_run_env_as_proot_mtab(){ install_mini_env - $(run_env_as_fakeroot "" "-k 3.10" "echo") + $(run_env_as_fakeroot "-k 3.10" "echo") assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" - $(run_env_as_user "" "-k 3.10" "echo") + $(run_env_as_user "-k 3.10" "echo") assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" } @@ -287,19 +280,19 @@ function test_run_env_as_root_mtab(){ function test_run_env_with_quotes(){ install_mini_env - local output=$(run_env_as_user "" "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') + local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') assertEquals "/usr/bin/mkdir" "$output" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" } function test_run_env_as_user_proot_args(){ install_mini_env - run_env_as_user "" "--help" "" &> /dev/null + run_env_as_user "--help" "" &> /dev/null assertEquals 0 $? mkdir $JUNEST_TEMPDIR/newdir touch $JUNEST_TEMPDIR/newdir/newfile - run_env_as_user "" "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null + run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null assertEquals 0 $? $(_run_env_with_proot --helps 2> /dev/null) @@ -341,15 +334,8 @@ function test_run_proot_seccomp(){ function test_run_env_as_fakeroot(){ install_mini_env - local output=$(run_env_as_fakeroot "" "-k 3.10" "id" | awk '{print $1}') + local output=$(run_env_as_fakeroot "-k 3.10" "id" | awk '{print $1}') assertEquals "uid=0(root)" "$output" - - $(run_env_as_fakeroot "noarch" "-k 3.10" "mycommand" 2> /dev/null) - assertEquals 1 $? - - local different_arch=(${ARCH_LIST[@]/$ARCH}) - $(run_env_as_fakeroot "${different_arch[0]}" "-k 3.10" "mycommand" 2> /dev/null) - assertEquals 1 $? } function test_delete_env(){ From 7f3919700af25cb4d14cee4f89f2512beac39c70 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 4 Jul 2015 18:53:27 +0000 Subject: [PATCH 115/326] Issue #96: Add the check option --- .travis.yml | 17 +++-------------- bin/junest | 30 +++++++++++++++++++++++------- lib/core.sh | 47 ++++++++++++++++++++++++++--------------------- tests/test_cli.sh | 11 +++++++++++ 4 files changed, 63 insertions(+), 42 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5a5f7f7..d3273b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,20 +4,9 @@ sudo: required install: - PATH=$PWD/bin:$PATH - - junest -f echo 'Installing junest' - - sed -i -e "s/#Server/Server/" ~/.junest/etc/pacman.d/mirrorlist - - junest -f pacman --noconfirm -Syy - - junest -f pacman --noconfirm -S base-devel + - junest --fakeroot echo 'Installing junest' script: - ./tests/test_all.sh -# Test on installing package from AUR - - junest -f yaourt --noconfirm -S tcptraceroute - - sudo $PWD/bin/junest -r tcptraceroute localhost -# Test on installing package from official repo - - junest -f pacman --noconfirm -S tree - - junest -f tree -# Test on installing package from official repo with root access - - junest -f pacman --noconfirm -S iftop - - sudo bin/junest -r iftop -t -s 5 - - yes | junest -d + - junest --check ./bin/junest + - yes | junest --delete diff --git a/bin/junest b/bin/junest index d24ab4a..d00167e 100755 --- a/bin/junest +++ b/bin/junest @@ -44,6 +44,8 @@ usage() { echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" + echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}" + echo -e " using ${CMD}_script. This will alterate the environment." echo echo -e "General options:" echo -e "-h, --help Show this help message" @@ -60,15 +62,23 @@ check_cli(){ if $OPT_BUILD_IMAGE then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT + $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK then die "The build image option must be used exclusively" fi fi + if $OPT_CHECK + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_BUILD_IMAGE + then + die "The validation image option must be used exclusively" + fi + fi if $OPT_DISABLE_VALIDATION then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT + $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK then die "The disable validation option must be used with the build image option only" fi @@ -76,7 +86,7 @@ check_cli(){ if $OPT_DELETE then if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK then die "The $NAME delete option must be used exclusively" fi @@ -84,7 +94,7 @@ check_cli(){ if $OPT_HELP then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK then die "The $NAME help option must be used exclusively" fi @@ -92,7 +102,7 @@ check_cli(){ if $OPT_VERSION then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK then die "The $NAME version option must be used exclusively" fi @@ -104,7 +114,7 @@ check_cli(){ if $OPT_PROOT_ARGS || $OPT_ARCH then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ - $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION + $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK then die "Invalid syntax: Proot and arch args are not allowed with the other options" fi @@ -112,7 +122,7 @@ check_cli(){ if [ "$ARGS" != "" ] then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_VERSION || $OPT_DISABLE_VALIDATION + $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK then die "No arguments are needed. For the CLI syntax run: $CMD --help" fi @@ -133,6 +143,8 @@ function parse_arguments(){ ARCH_ARG="" OPT_BUILD_IMAGE=false OPT_DISABLE_VALIDATION=false + OPT_CHECK=false + CHECK_ARG="" OPT_DELETE=false OPT_HELP=false OPT_VERSION=false @@ -146,6 +158,7 @@ function parse_arguments(){ -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; + -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -v|--version) OPT_VERSION=true ; shift ;; @@ -172,6 +185,9 @@ function execute_operation(){ elif $OPT_DELETE; then delete_env return + elif $OPT_CHECK; then + check_env "${JUNEST_HOME}" "${CHECK_ARG}" + return fi if ! is_env_installed diff --git a/lib/core.sh b/lib/core.sh index e21b3e1..97c81f8 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -395,8 +395,12 @@ function build_image_env(){ info "Compressing image to ${imagefile}..." sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . - mkdir -p ${maindir}/root_test - $disable_validation || validate_image "${maindir}/root_test" "${imagefile}" + if ! $disable_validation + then + mkdir -p ${maindir}/root_test + $TAR -zxpf ${imagefile} -C "${maindir}/root_test" + check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" + fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} @@ -405,35 +409,36 @@ function build_image_env(){ sudo rm -fr "$maindir" } -function validate_image(){ +function check_env(){ local testdir=$1 - local imagefile=$2 - info "Validating ${NAME} image..." - $TAR -zxpf ${imagefile} -C ${testdir} - mkdir -p ${testdir}/run/lock - sed -i -e "s/#Server/Server/" ${testdir}/etc/pacman.d/mirrorlist - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -Syy + local cmd=$2 + info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." + echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy # Check most basic executables work - JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r yaourt -V 1> /dev/null - JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} sudo -E ${cmd} -r yaourt -V 1> /dev/null + JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null - local repo_package=sysstat + local repo_package=tree info "Installing ${repo_package} package from official repo using proot..." - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} iostat - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f iostat + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} + JUNEST_HOME=${testdir} ${cmd} tree + JUNEST_HOME=${testdir} ${cmd} -f tree local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r iftop -t -s 5 + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} + JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f pacman --noconfirm -S base-devel + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel local yaourt_package=tcptraceroute info "Installing ${yaourt_package} package from AUR repo using proot..." - JUNEST_HOME=${testdir} ${testdir}/opt/${CMD}/bin/${CMD} -f sh --login -c "yaourt -A --noconfirm -S ${yaourt_package}" - JUNEST_HOME=${testdir} sudo -E ${testdir}/opt/${CMD}/bin/${CMD} -r tcptraceroute localhost + JUNEST_HOME=${testdir} ${cmd} -f -- yaourt -A --noconfirm -S ${yaourt_package} + JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost + + info "Removing the previous packages..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop } diff --git a/tests/test_cli.sh b/tests/test_cli.sh index a0ddf58..f78c487 100755 --- a/tests/test_cli.sh +++ b/tests/test_cli.sh @@ -14,6 +14,9 @@ function version(){ function build_image_env(){ echo "build_image_env" } +function check_env(){ + echo "check_env" +} function delete_env(){ echo "delete_env" } @@ -64,6 +67,12 @@ function test_build_image_env(){ local output=$(wrap_env --build-image) assertEquals $output "build_image_env" } +function test_check_env(){ + local output=$(wrap_env -c) + assertEquals $output "check_env" + local output=$(wrap_env --check) + assertEquals $output "check_env" +} function test_delete_env(){ local output=$(wrap_env -d) assertEquals $output "delete_env" @@ -109,6 +118,8 @@ function test_run_env_as_root(){ function test_check_cli(){ $(wrap_env -b -h 2> /dev/null) assertEquals $? 1 + $(wrap_env -b -c 2> /dev/null) + assertEquals $? 1 $(wrap_env -n -v 2> /dev/null) assertEquals $? 1 $(wrap_env -d -r 2> /dev/null) From 6b357245c3796e786204c027ee22b35a5ea53825 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Jul 2015 12:21:47 +0000 Subject: [PATCH 116/326] Issue #94: Add tests for arch option --- .travis.yml | 7 +++- bin/junest | 15 ++++++-- lib/core.sh | 20 +++++++---- tests/test_cli.sh | 87 ++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 107 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3273b8..570a311 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,14 @@ sudo: required install: - PATH=$PWD/bin:$PATH - - junest --fakeroot echo 'Installing junest' + - junest -- echo "Installing JuNest (\$(uname -m))" + - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" + # TODO: Remember to enable x86 tests when fixed + #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" script: - ./tests/test_all.sh - junest --check ./bin/junest - yes | junest --delete + - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests + - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/bin/junest b/bin/junest index d00167e..18a3de8 100755 --- a/bin/junest +++ b/bin/junest @@ -46,6 +46,7 @@ usage() { echo -e "-n, --disable-validation Disable the $NAME image validation" echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}" echo -e " using ${CMD}_script. This will alterate the environment." + echo -e "-s, --skip-root-tests Skip the root tests during the validation process." echo echo -e "General options:" echo -e "-h, --help Show this help message" @@ -67,6 +68,14 @@ check_cli(){ die "The build image option must be used exclusively" fi fi + if $OPT_SKIP_ROOT_TEST + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT + then + die "The skip root tests option must be used with either build image or check options" + fi + fi if $OPT_CHECK then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ @@ -145,6 +154,7 @@ function parse_arguments(){ OPT_DISABLE_VALIDATION=false OPT_CHECK=false CHECK_ARG="" + OPT_SKIP_ROOT_TEST=false OPT_DELETE=false OPT_HELP=false OPT_VERSION=false @@ -159,6 +169,7 @@ function parse_arguments(){ -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; + -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -v|--version) OPT_VERSION=true ; shift ;; @@ -180,13 +191,13 @@ function execute_operation(){ $OPT_VERSION && version && return if $OPT_BUILD_IMAGE; then - build_image_env $OPT_DISABLE_VALIDATION + build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST return elif $OPT_DELETE; then delete_env return elif $OPT_CHECK; then - check_env "${JUNEST_HOME}" "${CHECK_ARG}" + check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST return fi diff --git a/lib/core.sh b/lib/core.sh index 97c81f8..836dd3e 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -313,6 +313,7 @@ function build_image_env(){ _check_package git local disable_validation=$1 + local skip_root_tests=$2 local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) sudo mkdir -p ${maindir}/root @@ -399,7 +400,7 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" + check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} @@ -412,14 +413,21 @@ function build_image_env(){ function check_env(){ local testdir=$1 local cmd=$2 + local skip_root_tests=$3 info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy # Check most basic executables work - JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} sudo -E ${cmd} -r yaourt -V 1> /dev/null - JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yaourt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- yaourt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- yaourt -V 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null local repo_package=tree info "Installing ${repo_package} package from official repo using proot..." @@ -430,13 +438,13 @@ function check_env(){ local repo_package=iftop info "Installing ${repo_package} package from official repo using root..." JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel local yaourt_package=tcptraceroute info "Installing ${yaourt_package} package from AUR repo using proot..." JUNEST_HOME=${testdir} ${cmd} -f -- yaourt -A --noconfirm -S ${yaourt_package} - JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost info "Removing the previous packages..." JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop diff --git a/tests/test_cli.sh b/tests/test_cli.sh index f78c487..46d38d1 100755 --- a/tests/test_cli.sh +++ b/tests/test_cli.sh @@ -4,6 +4,12 @@ source $(dirname $0)/../bin/junest -h &> /dev/null # Disable the exiterr set +e +function setUp(){ + function is_env_installed(){ + return 0 + } +} + ## Mock functions ## function usage(){ echo "usage" @@ -12,22 +18,24 @@ function version(){ echo "version" } function build_image_env(){ - echo "build_image_env" + local disable_validation=$1 + local skip_root_tests=$2 + echo "build_image_env($disable_validation,$skip_root_tests)" } function check_env(){ - echo "check_env" + local env_home=$1 + local cmd_script=$2 + local skip_root_tests=$3 + echo "check_env($env_home,$cmd_script,$skip_root_tests)" } function delete_env(){ echo "delete_env" } -function is_env_installed(){ - return 0 -} function setup_env_from_file(){ - echo "setup_env_from_file $@" + echo "setup_env_from_file($1)" } function setup_env(){ - echo "setup_env" + echo "setup_env($1)" } function run_env_as_fakeroot(){ local proot_args="$1" @@ -63,15 +71,27 @@ function test_version(){ } function test_build_image_env(){ local output=$(wrap_env -b) - assertEquals $output "build_image_env" + assertEquals $output "build_image_env(false,false)" local output=$(wrap_env --build-image) - assertEquals $output "build_image_env" + assertEquals $output "build_image_env(false,false)" + local output=$(wrap_env -b -s) + assertEquals $output "build_image_env(false,true)" + local output=$(wrap_env -b -n) + assertEquals $output "build_image_env(true,false)" + local output=$(wrap_env -b -n -s) + assertEquals $output "build_image_env(true,true)" + local output=$(wrap_env --build-image --disable-validation --skip-root-tests) + assertEquals $output "build_image_env(true,true)" } function test_check_env(){ - local output=$(wrap_env -c) - assertEquals $output "check_env" - local output=$(wrap_env --check) - assertEquals $output "check_env" + local output=$(wrap_env -c myscript) + assertEquals $output "check_env(${JUNEST_HOME},myscript,false)" + local output=$(wrap_env --check myscript) + assertEquals $output "check_env(${JUNEST_HOME},myscript,false)" + local output=$(wrap_env -c myscript -s) + assertEquals $output "check_env(${JUNEST_HOME},myscript,true)" + local output=$(wrap_env --check myscript --skip-root-tests) + assertEquals $output "check_env(${JUNEST_HOME},myscript,true)" } function test_delete_env(){ local output=$(wrap_env -d) @@ -79,6 +99,45 @@ function test_delete_env(){ local output=$(wrap_env --delete) assertEquals $output "delete_env" } +#function test_setup_env_from_file(){ + #local output=$(wrap_env -i myimage) + #assertEquals $output "setup_env_from_file(myimage)" + #local output=$(wrap_env --setup-from-file myimage) + #assertEquals $output "setup_env_from_file(myimage)" +#} +function test_setup_env_from_file(){ + is_env_installed(){ + return 1 + } + local output=$(wrap_env -i myimage) + assertEquals "$output" "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" + local output=$(wrap_env --setup-from-file myimage) + assertEquals "$output" "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" + + is_env_installed(){ + return 0 + } + $(wrap_env -i myimage 2> /dev/null) + assertEquals 1 $? +} + +function test_setup_env(){ + is_env_installed(){ + return 1 + } + local output=$(wrap_env -a arm) + assertEquals "$output" "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" + local output=$(wrap_env --arch arm) + assertEquals "$output" "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" + local output=$(wrap_env) + assertEquals "$output" "$(echo -e "setup_env()\nrun_env_as_user(,)")" + + is_env_installed(){ + return 0 + } + $(wrap_env -a arm 2> /dev/null) + assertEquals 1 $? +} function test_run_env_as_fakeroot(){ local output=$(wrap_env -f) assertEquals $output "run_env_as_fakeroot(,)" @@ -120,6 +179,8 @@ function test_check_cli(){ assertEquals $? 1 $(wrap_env -b -c 2> /dev/null) assertEquals $? 1 + $(wrap_env -d -s 2> /dev/null) + assertEquals $? 1 $(wrap_env -n -v 2> /dev/null) assertEquals $? 1 $(wrap_env -d -r 2> /dev/null) From f3c043ee15bc92723403e298cd2df38b19a254b6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 4 Aug 2015 15:17:42 +0000 Subject: [PATCH 117/326] Issue #102: Update README for installing JuNest via AUR --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ba473a1..8a23b6a 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,12 @@ Just clone the JuNest repo somewhere (for example in ~/junest): git clone git://github.com/fsquillace/junest ~/junest export PATH=~/junest/bin:$PATH +### Installation using AUR (Arch Linux only) ### +If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/): + + yaourt -S junest-git + export PATH=/opt/junest/bin:$PATH + ## Method two ## Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory ~/.junest: From e0a9ee3b268821a2cd0d6a603c4ff5014eb339d0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 7 Aug 2015 12:48:08 +0000 Subject: [PATCH 118/326] Change URLs for the AUR repository system --- lib/core.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 836dd3e..605be23 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -365,12 +365,12 @@ function build_image_env(){ mkdir -p ${maindir}/packages/{package-query,yaourt} builtin cd ${maindir}/packages/package-query - download_cmd https://aur.archlinux.org/packages/pa/package-query/PKGBUILD + $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=package-query" makepkg -sfc sudo pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz builtin cd ${maindir}/packages/yaourt - download_cmd https://aur.archlinux.org/packages/ya/yaourt/PKGBUILD + $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=yaourt" makepkg -sfc sudo pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz # Apply patches for yaourt and makepkg From 6365d52f5009386731141e45ff304331f43654ce Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 7 Aug 2015 15:29:58 +0000 Subject: [PATCH 119/326] Issue #104: Use junest-git package in the image --- lib/core.sh | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 605be23..3f6db46 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -301,6 +301,17 @@ function _check_package(){ fi } +function _install_from_aur(){ + local maindir=$1 + local pkgname=$2 + local installname=$3 + mkdir -p ${maindir}/packages/${pkgname} + builtin cd ${maindir}/packages/${pkgname} + $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" + [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" + makepkg -sfc + sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz +} function build_image_env(){ # The function must runs on ArchLinux with non-root privileges. @@ -362,17 +373,9 @@ function build_image_env(){ # AUR packages requires non-root user to be compiled. proot fakes the user to 10 info "Compiling and installing yaourt..." - mkdir -p ${maindir}/packages/{package-query,yaourt} + _install_from_aur ${maindir} "package-query" - builtin cd ${maindir}/packages/package-query - $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=package-query" - makepkg -sfc - sudo pacman --noconfirm --root ${maindir}/root -U package-query*.pkg.tar.xz - - builtin cd ${maindir}/packages/yaourt - $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=yaourt" - makepkg -sfc - sudo pacman --noconfirm --root ${maindir}/root -U yaourt*.pkg.tar.xz + _install_from_aur ${maindir} "yaourt" # Apply patches for yaourt and makepkg sudo mkdir -p ${maindir}/root/opt/yaourt/bin/ sudo cp ${maindir}/root/usr/bin/yaourt ${maindir}/root/opt/yaourt/bin/ @@ -382,8 +385,10 @@ function build_image_env(){ sudo bash -c "echo 'export PATH=/opt/yaourt/bin:\$PATH' > ${maindir}/root/etc/profile.d/${CMD}.sh" sudo chmod +x ${maindir}/root/etc/profile.d/${CMD}.sh - info "Copying ${NAME} scripts..." - sudo git clone https://github.com/fsquillace/${CMD}.git ${maindir}/root/opt/${CMD} + info "Install ${NAME} script..." + sudo pacman --noconfirm --root ${maindir}/root -S git + _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + sudo pacman --noconfirm --root ${maindir}/root -Rsn git info "Setting up the pacman keyring (this might take a while!)..." sudo arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" From cfa512755fe296764a9bd7caa72670231e7c8569 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 29 Aug 2015 18:30:59 +0000 Subject: [PATCH 120/326] Update contacts in docs --- README.md | 2 +- lib/core.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a23b6a..7bb703f 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ along with this program. If not, see . Author ====== -Filippo Squillace +Filippo Squillace WWW === diff --git a/lib/core.sh b/lib/core.sh index 3f6db46..afce54c 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -32,7 +32,7 @@ CMD='junest' VERSION='4.7.4' CODE_NAME='Mairei' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' -AUTHOR='Filippo Squillace ' +AUTHOR='Filippo Squillace ' HOMEPAGE="https://github.com/fsquillace/${CMD}" COPYRIGHT='2012-2015' From 2cfb81daaa07d97834cfeeb6b779c913865f36d8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 14 Oct 2015 22:34:25 +0000 Subject: [PATCH 121/326] Issue #113: Fix fallback for proot command --- lib/core.sh | 17 +++++++++++++---- tests/test_core.sh | 12 +++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index afce54c..0b299c4 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -125,8 +125,17 @@ function mkdir_cmd(){ } function proot_cmd(){ - ${PROOT_COMPAT} "${@}" || PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} "${@}" || \ - die "Error: Check if the ${CMD} arguments are correct or use the option ${CMD} -p \"-k 3.10\"" + local proot_args="$1" + shift + if ${PROOT_COMPAT} ${proot_args} "${SH[@]}" "-c" ":" + then + ${PROOT_COMPAT} ${proot_args} "${@}" + elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${proot_args} "${SH[@]}" "-c" ":" + then + PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${proot_args} "${@}" + else + die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" + fi } function download_cmd(){ @@ -231,9 +240,9 @@ function _run_env_with_proot(){ if [ "$1" != "" ] then - JUNEST_ENV=1 proot_cmd ${proot_args} "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else - JUNEST_ENV=1 proot_cmd ${proot_args} "${SH[@]}" + JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" fi } diff --git a/tests/test_core.sh b/tests/test_core.sh index 38d7b41..d2a6aea 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -253,10 +253,9 @@ function test_run_env_as_user(){ assertEquals "$output" "/usr/bin/mkdir" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" - SH=("/usr/bin/mkdir" "-v" "/newdir") - local output=$(run_env_as_user "-k 3.10" | awk -F: '{print $1}') - assertEquals "$output" "/usr/bin/mkdir" - assertTrue "[ -e $JUNEST_HOME/newdir ]" + SH=("/usr/bin/echo") + local output=$(run_env_as_user "-k 3.10") + assertEquals "-c :" "$output" } function test_run_env_as_proot_mtab(){ @@ -329,7 +328,10 @@ function test_run_proot_seccomp(){ } PROOT_COMPAT=envv local output=$(proot_cmd 2> /dev/null | grep "^PROOT_NO_SECCOMP") - assertEquals "PROOT_NO_SECCOMP=1" "$output" + # The variable PROOT_NO_SECCOMP will be produced + # twice due to the fallback mechanism + assertEquals "PROOT_NO_SECCOMP=1 +PROOT_NO_SECCOMP=1" "$output" } function test_run_env_as_fakeroot(){ From 88992cc5039cd01a16769820100ad2b7b9d934a6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 15 Oct 2015 20:22:00 +0000 Subject: [PATCH 122/326] Small fix in the proot seccomp test --- tests/test_core.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_core.sh b/tests/test_core.sh index d2a6aea..bc23b88 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -319,7 +319,10 @@ function test_run_env_with_proot_as_root(){ } function test_run_proot_seccomp(){ - PROOT_COMPAT=env + envv(){ + env + } + PROOT_COMPAT=envv local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") assertEquals "" "$output" @@ -327,7 +330,7 @@ function test_run_proot_seccomp(){ env | grep "^PROOT_NO_SECCOMP" } PROOT_COMPAT=envv - local output=$(proot_cmd 2> /dev/null | grep "^PROOT_NO_SECCOMP") + local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") # The variable PROOT_NO_SECCOMP will be produced # twice due to the fallback mechanism assertEquals "PROOT_NO_SECCOMP=1 From 1aa7a3ddbd63f8cf5698cd769bd4d2f0053de786 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 16 Oct 2015 09:28:10 +0000 Subject: [PATCH 123/326] Issue #114: Add umask on build image script --- lib/core.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index 0b299c4..dc71700 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -323,7 +323,9 @@ function _install_from_aur(){ } function build_image_env(){ -# The function must runs on ArchLinux with non-root privileges. + umask 022 + + # The function must runs on ArchLinux with non-root privileges. (( EUID == 0 )) && \ die "You cannot build with root privileges." From dbc6f7ad1245230017b9bbbf966b681f5895635a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 17 Oct 2015 23:18:03 +0000 Subject: [PATCH 124/326] Issue #116: Kill gpg-agent during build of image Use jchroot instead of arch-chroot since it is more reliable on all architectures. --- lib/core.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index dc71700..7d96498 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -348,11 +348,16 @@ function build_image_env(){ sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" + info "Install ${NAME} script..." + sudo pacman --noconfirm --root ${maindir}/root -S git + _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + sudo pacman --noconfirm --root ${maindir}/root -Rsn git + info "Generating the locales..." # sed command is required for locale-gen sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo arch-chroot ${maindir}/root locale-gen + sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen sudo bash -c "echo 'LANG = \"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" info "Generating the metadata info..." @@ -396,13 +401,9 @@ function build_image_env(){ sudo bash -c "echo 'export PATH=/opt/yaourt/bin:\$PATH' > ${maindir}/root/etc/profile.d/${CMD}.sh" sudo chmod +x ${maindir}/root/etc/profile.d/${CMD}.sh - info "Install ${NAME} script..." - sudo pacman --noconfirm --root ${maindir}/root -S git - _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" - sudo pacman --noconfirm --root ${maindir}/root -Rsn git - info "Setting up the pacman keyring (this might take a while!)..." - sudo arch-chroot ${maindir}/root bash -c "pacman-key --init; pacman-key --populate archlinux" + sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ + "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" sudo rm ${maindir}/root/var/cache/pacman/pkg/* From fd28e511fc463f846e70e8951ef4c603137649b7 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 19 Oct 2015 18:42:24 +0000 Subject: [PATCH 125/326] Update README with junest-builder reference --- README.md | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7bb703f..4ee9007 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,11 @@ After creating the image junest-x86\_64.tar.gz you can install it by running: junest -i junest-x86_64.tar.gz +For more details, you can also take a look at +[junest-builder](https://github.com/fsquillace/junest-builder) +that contains the script and systemd service used for the automatic building +of the JuNest image. + Related wiki page: - [How to build a JuNest image using QEMU](https://github.com/fsquillace/junest/wiki/How-to-build-a-JuNest-image-using-QEMU) @@ -183,8 +188,8 @@ Troubleshooting Cannot find the gzip binary required for compressing man and info pages. > **A**: JuNest comes with a very basic number of packages. -In order to install packages using yaourt you may need to install the package group **base-devel** -that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): +> In order to install packages using yaourt you may need to install the package group **base-devel** +> that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): pacman -S base-devel @@ -193,23 +198,21 @@ that contains all the essential packages for compiling source code (such as gcc, > **Q**: Why do I get the error: "FATAL: kernel too old"? > **A**: This is because the executable from the precompiled package cannot -properly run if the kernel is old. -JuNest contains two different PRoot binaries, and one of them is highly compatible -with old linux kernel versions. JuNest will detect which PRoot binary need to be -executed but you may need to specify the PRoot *-k* option if the guest rootfs -requires a newer kernel version: +> properly run if the kernel is old. +> You may need to specify the PRoot *-k* option if the guest rootfs +> requires a newer kernel version: junest -p "-k 3.10" -In order to check if an executable inside JuNest environment can be compatible -with the kernel of the host OS just use the *file* command, for instance: +> In order to check if an executable inside JuNest environment can be compatible +> with the kernel of the host OS just use the *file* command, for instance: file ~/.junest/usr/bin/bash ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped -From the output you can see what is the minimum recommended Linux kernel version. +> From the output you can see what is the minimum recommended Linux kernel version. ##SUID permissions## > **Q**: Why I do not have permissions for ping? @@ -218,10 +221,10 @@ From the output you can see what is the minimum recommended Linux kernel version ping: icmp open socket: Operation not permitted > **A**: The ping command uses *suid* permissions that allow to execute the command using -root privileges. The fakeroot mode is not able to execute a command set with suid, -and you may need to use root privileges. There are other few commands that -have *suid* permission, you can list the commands from your JuNest environment -with the following command: +> root privileges. The fakeroot mode is not able to execute a command set with suid, +> and you may need to use root privileges. There are other few commands that +> have *suid* permission, you can list the commands from your JuNest environment +> with the following command: find /usr/bin -perm +4000 @@ -230,10 +233,10 @@ with the following command: > **Q**: Why I do not see any characters in the application I have installed? > **A**: This is probably because there are no -[fonts](https://wiki.archlinux.org/index.php/Font_Configuration) installed in -the system. +> [fonts](https://wiki.archlinux.org/index.php/Font_Configuration) installed in +> the system. -To quick fix this, you can just install a fonts package: +> To quick fix this, you can just install a fonts package: pacman -S gnu-free-fonts @@ -248,9 +251,9 @@ To quick fix this, you can just install a fonts package: ... > **A**: In these cases the package installation went smoothly anyway. -This should happen every time you install package with root privileges -since JuNest will try to preserve the JuNest environment by assigning ownership -of the files to the real user. +> This should happen every time you install package with root privileges +> since JuNest will try to preserve the JuNest environment by assigning ownership +> of the files to the real user. ##No servers configured for repository## From 90510f8da9304c7c939699e03bb26a8041381581 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 20 Oct 2015 23:15:25 +0000 Subject: [PATCH 126/326] Add OpenHub badge and TOC in README --- README.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4ee9007..9c50a98 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,22 @@ JuNest ====== The Arch Linux based distro that runs upon any Linux distros without root access. -[![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) -[![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) -[![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) -[![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) +|Project Status|Donation|Communication| +|:------------:|:------:|:-----------:| +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) | + +**Table of Contents** +- [Description](#description) +- [Quickstart](#quickstart) +- [Installation](#installation) +- [Dependencies](#dependencies) +- [Advanced usage](#advanced-usage) +- [Internals](#internals) +- [Troubleshooting](#troubleshooting) +- [More documentation](#more documentation) +- [License](#license) +- [Author](#author) +- [WWW](#www) Description =========== From 55029662765f8422519447880bab2b34c3a405ae Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 23 Oct 2015 22:21:25 +0000 Subject: [PATCH 127/326] Update the version to 5.6.7 (Nitida) --- README.md | 6 ++++-- lib/core.sh | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9c50a98..0c6505d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The Arch Linux based distro that runs upon any Linux distros without root access |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) | +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) @@ -141,7 +141,8 @@ Check out the proot options with: junest -p "--help" -## JuNest as a container ## +## Systemd integration ## + Although JuNest has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). The JuNest containter allows to run services inside the container that can be @@ -156,6 +157,7 @@ To boot a JuNest container: Related wiki page: - [How to run junest as a container](https://github.com/fsquillace/junest/wiki/How-to-run-JuNest-as-a-container) +- [How to run services using Systemd](https://github.com/fsquillace/junest/wiki/How-to-run-services-using-Systemd) Internals ========= diff --git a/lib/core.sh b/lib/core.sh index 7d96498..bb95c80 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -29,8 +29,8 @@ source "$(dirname ${BASH_ARGV[0]})/util.sh" NAME='JuNest' CMD='junest' -VERSION='4.7.4' -CODE_NAME='Mairei' +VERSION='5.6.7' +CODE_NAME='Nitida' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' AUTHOR='Filippo Squillace ' HOMEPAGE="https://github.com/fsquillace/${CMD}" From 336652ccf6fa7366110dec11d0deb843fcc21f0a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 30 Oct 2015 21:37:14 +0000 Subject: [PATCH 128/326] Add gratipay badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c6505d..0725d65 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The Arch Linux based distro that runs upon any Linux distros without root access |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) From c6bb53e2cc4118c59ba2394209fa5089d09cf2ad Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 1 Dec 2015 19:52:11 +0000 Subject: [PATCH 129/326] Issue #128: Fix the /etc/locale.conf file --- lib/core.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core.sh b/lib/core.sh index bb95c80..b85c1fa 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -358,7 +358,7 @@ function build_image_env(){ sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen - sudo bash -c "echo 'LANG = \"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" + sudo bash -c "echo 'LANG=\"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" info "Generating the metadata info..." sudo mkdir ${maindir}/root/etc/${CMD} From 6116585fb89973a56cbbe15606c0e9131148c765 Mon Sep 17 00:00:00 2001 From: Adam Basfop Cavendish Date: Mon, 14 Dec 2015 01:14:45 +0800 Subject: [PATCH 130/326] Add a message for showing proot arguments help --- bin/junest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/junest b/bin/junest index 18a3de8..ae494d8 100755 --- a/bin/junest +++ b/bin/junest @@ -39,7 +39,7 @@ usage() { echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" - echo -e "-p, --proot-args Proot arguments" + echo -e "-p, --proot-args Proot arguments (use `junest -p \"--help\"` to check out the proot options)" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" From 36212d3cbff777fd3fc1bbe855df531dc2692697 Mon Sep 17 00:00:00 2001 From: builder Date: Fri, 25 Dec 2015 15:26:54 +0000 Subject: [PATCH 131/326] Issue #127: Do not let proot mount the mtab file This change prevents inconsistency problems when the JuNest environment is run simultaneously in fakeroot and normal user. The mtab file is never mount by proot but, instead, it is symlinked to /proc/self/mounts. --- lib/core.sh | 21 +++++++++++++++++++-- tests/test_core.sh | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index b85c1fa..250917d 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -229,6 +229,8 @@ function run_env_as_root(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -f ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + # The mtab file should already be available in the image. + # This following instruction will be deleted [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" @@ -269,6 +271,8 @@ function _run_env_with_qemu(){ function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die "You cannot access with root privileges. Use --root option instead." + # The mtab file should already be available in the image. + # This following instruction will be deleted [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab _run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" } @@ -276,10 +280,23 @@ function run_env_as_fakeroot(){ function run_env_as_user(){ (( EUID == 0 )) && \ die "You cannot access with root privileges. Use --root option instead." - [ -e ${JUNEST_HOME}/etc/mtab ] && rm_cmd -f ${JUNEST_HOME}/etc/mtab - _run_env_with_qemu "-R ${JUNEST_HOME} $1" "${@:2}" + # The mtab file should already be available in the image. + # This following instruction will be deleted + [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab + _run_env_with_qemu "$(_provide_bindings_as_user) -r ${JUNEST_HOME} $1" "${@:2}" } +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. + local existing_bindings="" + 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" + do + [ -e "$bind" ] && existing_bindings="-b $bind $existing_bindings" + done + echo $existing_bindings +} function delete_env(){ ! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return diff --git a/tests/test_core.sh b/tests/test_core.sh index bc23b88..d73a613 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -263,7 +263,7 @@ function test_run_env_as_proot_mtab(){ $(run_env_as_fakeroot "-k 3.10" "echo") assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" $(run_env_as_user "-k 3.10" "echo") - assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" + assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" } function test_run_env_as_root_mtab(){ From c10c8713bbee99f1fd9c1c25a2fb7945ff2b6a6d Mon Sep 17 00:00:00 2001 From: builder Date: Sat, 26 Dec 2015 13:31:24 +0000 Subject: [PATCH 132/326] Fix proot arguments help --- bin/junest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/junest b/bin/junest index ae494d8..d889d5e 100755 --- a/bin/junest +++ b/bin/junest @@ -39,7 +39,7 @@ usage() { echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" - echo -e "-p, --proot-args Proot arguments (use `junest -p \"--help\"` to check out the proot options)" + echo -e "-p, --proot-args Proot arguments (use 'junest -p \"--help\"' to check out the proot options)" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" From 846b47ff3aff11a6f283c0af8e70228639d517a3 Mon Sep 17 00:00:00 2001 From: builder Date: Sat, 26 Dec 2015 15:56:07 +0000 Subject: [PATCH 133/326] Small fix in usage function --- bin/junest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/junest b/bin/junest index d889d5e..c978dc5 100755 --- a/bin/junest +++ b/bin/junest @@ -39,7 +39,7 @@ usage() { echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" - echo -e "-p, --proot-args Proot arguments (use 'junest -p \"--help\"' to check out the proot options)" + echo -e "-p, --proot-args Proot arguments (use '$CMD -p \"--help\"' to check out the proot options)" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" From 0ecd1b297b47acb5b41ad8d06b03db1842a480cc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 30 Jan 2016 12:03:46 +0000 Subject: [PATCH 134/326] Add CONTRIBUTING.md file --- CONTRIBUTING.md | 179 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..fee979e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,179 @@ +# Contributing to JuNest # + +First off, thanks for taking the time to contribute! + +The following is a set of guidelines for contributing to JuNest. +These are just guidelines, not rules, use your best judgment and +feel free to propose changes to this document in a pull request. + +**Table of Contents** + +- [How Can I Contribute?](#how-can-i-contribute) + - [Reporting Bugs](#reporting-bugs) + - [Suggesting Enhancements](#suggesting-enhancements) + - [Your First Code Contribution](#your-first-code-contribution) + +- [Styleguides](#styleguides) + - [Git Commit Messages](#git-commit-messages) + - [Documentation Styleguide](#documentation-styleguide) + - [Shell Styleguide](#shell-styleguide) + +## How Can I Contribute? ## + +### Reporting Bugs ### + +This section guides you through submitting a bug report for JuNest. + +#### Before submitting a bug report #### + +You might be able to find the cause of the problem and fix things yourself. + +- **Check the [troubleshooting section](https://github.com/fsquillace/junest#troubleshooting)** +- **Check if you can reproduce the problem with the latest version of JuNest** +- **Check for [existing open/closed issues](https://github.com/fsquillace/junest/issues?utf8=%E2%9C%93&q=is%3Aissue)** + - If the bug has already been suggested, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Bug Report? #### + +Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/) in the [JuNest issues page](https://github.com/fsquillace/junest/issues). +Explain the problem and include additional details to help maintainers reproduce the problem: + +* **Use a clear and descriptive title** for the issue to identify the problem. +* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started JuNest, e.g. which command exactly you used in the terminal. When listing steps, **don't just say what you did, but explain how you did it**. For example. +* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. +* **Explain which behavior you expected to see instead and why.** +* **Put the bug label to the issue.** + +Include details about your configuration and environment: + +* **Which version of JuNest are you using?** +* **What's the name and version of the OS you're using**? +* **Are you running JuNest in a virtual machine?** If so, which VM software are you using and which operating systems and versions are used for the host and the guest? +* **Which packages do you have installed?** You can get that list by running `pacman -Qq`. + +#### Template For Submitting Bug Reports #### + + [Short description of problem here] + + **Reproduction Steps:** + + 1. [First Step] + 2. [Second Step] + 3. [Other Steps...] + + **Expected behavior:** + + [Describe expected behavior here] + + **Observed behavior:** + + [Describe observed behavior here] + + **JuNest version:** [Enter JuNest version here] + **OS and version:** [Enter OS name and version here] + + **Installed packages:** + + [List of installed packages here] + + **Additional information:** + + * Problem started happening recently, didn't happen in an older version of JuNest: [Yes/No] + * Problem can be reliably reproduced, doesn't happen randomly: [Yes/No] + +### Suggesting Enhancements ### + +This section guides you through submitting an enhancement suggestion for JuNest, including completely new features and minor improvements to existing functionality. + +#### Before Submitting An Enhancement Suggestion #### + +* **Check if you're using the latest version of JuNest** +- **Check for [existing open/closed issues](https://github.com/fsquillace/junest/issues?utf8=%E2%9C%93&q=is%3Aissue)** + - If enhancement has already been suggested, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Enhancement Suggestion? #### + +Enhancement suggestions are tracked as [GitHub issues](https://guides.github.com/features/issues/) in the [JuNest issues page](https://github.com/fsquillace/junest/issues). + +Create an issue on that repository and provide the following information: + +* **Use a clear and descriptive title** for the issue to identify the suggestion. +* **Provide a step-by-step description of the suggested enhancement** in as many details as possible. +* **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use in those examples, as [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). +* **Describe the current behavior** and **explain which behavior you expected to see instead** and why. +* **Specify which version of JuNest you're using.** +* **Specify the name and version of the OS you're using.** +* **Put the enanchement label to the issue.** + +#### Template For Submitting Enhancement Suggestions #### + + [Short description of suggestion] + + **Steps which explain the enhancement** + + 1. [First Step] + 2. [Second Step] + 3. [Other Steps...] + + **Current and suggested behavior** + + [Describe current and suggested behavior here] + + **Why would the enhancement be useful to most users** + + [Explain why the enhancement would be useful to most users] + + [List some other text editors or applications where this enhancement exists] + + **JuNest Version:** [Enter JuNest version here] + **OS and Version:** [Enter OS name and version here] + +### Your First Code Contribution ### + +All JuNest issues are tracked as [GitHub issues](https://guides.github.com/features/issues/) in the [JuNest issues page](https://github.com/fsquillace/junest/issues). + +#### Pull Requests #### + +* Follow the [Shell styleguide](#shell-styleguide). +* Document new code based on the + [Documentation Styleguide](#documentation-styleguide). +* End files with a newline. +* Follow the [Git commit messages](#git-commit-messages). +* Send a [GitHub Pull Request to JuNest](https://github.com/fsquillace/junest/compare/dev...) with a clear list of what you've done (read more about [pull requests](http://help.github.com/pull-requests/)). +* Put **dev as the base branch** and NOT the master one. + +## Styleguides ## + +### Git Commit Messages ### + +* Use the present tense ("Add feature" not "Added feature") +* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") +* Limit the first line to 72 characters or less +* Reference issues and pull requests liberally +* When only changing documentation, include `[ci skip]` in the commit description +* Consider starting the commit message with an applicable emoji: + * :art: `:art:` when improving the format/structure of the code + * :racehorse: `:racehorse:` when improving performance + * :non-potable_water: `:non-potable_water:` when plugging memory leaks + * :memo: `:memo:` when writing docs + * :penguin: `:penguin:` when fixing something on Linux + * :apple: `:apple:` when fixing something on Mac OS + * :checkered_flag: `:checkered_flag:` when fixing something on Windows + * :bug: `:bug:` when fixing a bug + * :fire: `:fire:` when removing code or files + * :green_heart: `:green_heart:` when fixing the CI build + * :white_check_mark: `:white_check_mark:` when adding tests + * :lock: `:lock:` when dealing with security + * :arrow_up: `:arrow_up:` when upgrading dependencies + * :arrow_down: `:arrow_down:` when downgrading dependencies + * :shirt: `:shirt:` when removing linter warnings + +### Documentation Styleguide ### + +* Use [Markdown](https://daringfireball.net/projects/markdown). + +### Shell Styleguide ### + +* Use [google shell styleguide](https://google.github.io/styleguide/shell.xml) + From d36093b0f5a39ba83930ee42f5464b355a045f8c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 30 Jan 2016 12:04:22 +0000 Subject: [PATCH 135/326] Change the name of proot variable --- lib/core.sh | 10 +++++----- tests/test_core.sh | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 250917d..bf13710 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -94,7 +94,7 @@ ORIGIN_WD=$(pwd) SH=("/bin/sh" "--login") # List of executables that are run in the host OS: -PROOT_COMPAT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" +PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" CHROOT=${JUNEST_BASE}/bin/jchroot CLASSIC_CHROOT="chroot" WGET="wget --no-check-certificate" @@ -127,12 +127,12 @@ function mkdir_cmd(){ function proot_cmd(){ local proot_args="$1" shift - if ${PROOT_COMPAT} ${proot_args} "${SH[@]}" "-c" ":" + if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" then - ${PROOT_COMPAT} ${proot_args} "${@}" - elif PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${proot_args} "${SH[@]}" "-c" ":" + ${PROOT} ${proot_args} "${@}" + elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" then - PROOT_NO_SECCOMP=1 ${PROOT_COMPAT} ${proot_args} "${@}" + PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" fi diff --git a/tests/test_core.sh b/tests/test_core.sh index d73a613..bd57032 100755 --- a/tests/test_core.sh +++ b/tests/test_core.sh @@ -299,11 +299,11 @@ function test_run_env_as_user_proot_args(){ } function test_run_env_with_proot_compat(){ - PROOT_COMPAT="/bin/true" + PROOT="/bin/true" _run_env_with_proot "" "" &> /dev/null assertEquals 0 $? - $(PROOT_COMPAT="/bin/false" _run_env_with_proot --helps 2> /dev/null) + $(PROOT="/bin/false" _run_env_with_proot --helps 2> /dev/null) assertEquals 1 $? } @@ -322,14 +322,14 @@ function test_run_proot_seccomp(){ envv(){ env } - PROOT_COMPAT=envv + PROOT=envv local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") assertEquals "" "$output" envv(){ env | grep "^PROOT_NO_SECCOMP" } - PROOT_COMPAT=envv + PROOT=envv local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") # The variable PROOT_NO_SECCOMP will be produced # twice due to the fallback mechanism From ea3af255cf674d47a9ce2aba8a79e43d4a1f3f52 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 26 Feb 2016 23:21:52 +0000 Subject: [PATCH 136/326] Issue #138: pkgfile documentation --- README.md | 148 ++++++++++++++++++++++++++++------------------------ bin/jchroot | 4 +- bin/junest | 2 +- lib/core.sh | 4 +- lib/util.sh | 2 +- 5 files changed, 88 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 0725d65..8f7a22e 100644 --- a/README.md +++ b/README.md @@ -204,75 +204,13 @@ Troubleshooting > In order to install packages using yaourt you may need to install the package group **base-devel** > that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): - pacman -S base-devel - -##Kernel too old## - -> **Q**: Why do I get the error: "FATAL: kernel too old"? - -> **A**: This is because the executable from the precompiled package cannot -> properly run if the kernel is old. -> You may need to specify the PRoot *-k* option if the guest rootfs -> requires a newer kernel version: - - junest -p "-k 3.10" - -> In order to check if an executable inside JuNest environment can be compatible -> with the kernel of the host OS just use the *file* command, for instance: - - file ~/.junest/usr/bin/bash - ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked - (uses shared libs), for GNU/Linux 2.6.32, - BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped - -> From the output you can see what is the minimum recommended Linux kernel version. - -##SUID permissions## -> **Q**: Why I do not have permissions for ping? - - ping www.google.com - ping: icmp open socket: Operation not permitted - -> **A**: The ping command uses *suid* permissions that allow to execute the command using -> root privileges. The fakeroot mode is not able to execute a command set with suid, -> and you may need to use root privileges. There are other few commands that -> have *suid* permission, you can list the commands from your JuNest environment -> with the following command: - - find /usr/bin -perm +4000 - -##No characters are visible on a graphic application## - -> **Q**: Why I do not see any characters in the application I have installed? - -> **A**: This is probably because there are no -> [fonts](https://wiki.archlinux.org/index.php/Font_Configuration) installed in -> the system. - -> To quick fix this, you can just install a fonts package: - - pacman -S gnu-free-fonts - -##Differences between filesystem and package ownership## - -> **Q**: Why do I get warning when I install a package using root privileges? - - pacman -S systat - ... - warning: directory ownership differs on /usr/ - filesystem: 1000:100 package: 0:0 - ... - -> **A**: In these cases the package installation went smoothly anyway. -> This should happen every time you install package with root privileges -> since JuNest will try to preserve the JuNest environment by assigning ownership -> of the files to the real user. + #> pacman -S base-devel ##No servers configured for repository## > **Q**: Why I cannot install packages? - pacman -S lsof + #> pacman -S lsof Packages (1): lsof-4.88-2 Total Download Size: 0.09 MiB @@ -286,8 +224,84 @@ Troubleshooting > **A**: You need simply to update the mirrorlist file according to your location: # Uncomment the repository line according to your location - nano /etc/pacman.d/mirrorlist - pacman -Syy + #> nano /etc/pacman.d/mirrorlist + #> pacman -Syy + +## Locate the package for a given file ## + +> **Q**: How do I find which package a certain file belongs to? + +> **A**: JuNest is a really small distro, therefore you frequently need to find +> the package name for a certain file. `pkgfile` is an extremely useful package +> that allows you to detect the package of a given file. +> For instance, if you want to find the package name for the command `getopt`: + + #> pacman -S pkgfile + #> pkgfile --update + $> pkgfile getop + core/util-linux + +##Kernel too old## + +> **Q**: Why do I get the error: "FATAL: kernel too old"? + +> **A**: This is because the executable from the precompiled package cannot +> properly run if the kernel is old. +> You may need to specify the PRoot *-k* option if the guest rootfs +> requires a newer kernel version: + + $> junest -p "-k 3.10" + +> In order to check if an executable inside JuNest environment can be compatible +> with the kernel of the host OS just use the *file* command, for instance: + + $> file ~/.junest/usr/bin/bash + ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked + (uses shared libs), for GNU/Linux 2.6.32, + BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped + +> From the output you can see what is the minimum recommended Linux kernel version. + +##SUID permissions## +> **Q**: Why I do not have permissions for ping? + + $> ping www.google.com + ping: icmp open socket: Operation not permitted + +> **A**: The ping command uses *suid* permissions that allow to execute the command using +> root privileges. The fakeroot mode is not able to execute a command set with suid, +> and you may need to use root privileges. There are other few commands that +> have *suid* permission, you can list the commands from your JuNest environment +> with the following command: + + $> find /usr/bin -perm +4000 + +##No characters are visible on a graphic application## + +> **Q**: Why I do not see any characters in the application I have installed? + +> **A**: This is probably because there are no +> [fonts](https://wiki.archlinux.org/index.php/Font_Configuration) installed in +> the system. + +> To quick fix this, you can just install a fonts package: + + #> pacman -S gnu-free-fonts + +##Differences between filesystem and package ownership## + +> **Q**: Why do I get warning when I install a package using root privileges? + + #> pacman -S systat + ... + warning: directory ownership differs on /usr/ + filesystem: 1000:100 package: 0:0 + ... + +> **A**: In these cases the package installation went smoothly anyway. +> This should happen every time you install package with root privileges +> since JuNest will try to preserve the JuNest environment by assigning ownership +> of the files to the real user. More documentation ================== @@ -296,7 +310,7 @@ There are additional tutorials in the License ======= -Copyright (c) 2012-2015 +Copyright (c) 2012-2016 This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published diff --git a/bin/jchroot b/bin/jchroot index 2ed810f..98f8680 100755 --- a/bin/jchroot +++ b/bin/jchroot @@ -1,6 +1,8 @@ #!/bin/bash # -# Copyright (c) 2012-2015 +# This file is part of JuNest (https://github.com/fsquillace/junest) +# +# Copyright (c) 2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published diff --git a/bin/junest b/bin/junest index c978dc5..9ac3736 100755 --- a/bin/junest +++ b/bin/junest @@ -2,7 +2,7 @@ # # This file is part of JuNest (https://github.com/fsquillace/junest). # -# Copyright (c) 2012-2015 +# Copyright (c) 2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published diff --git a/lib/core.sh b/lib/core.sh index bf13710..4cd08f0 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# Copyright (c) 2012-2015 +# Copyright (c) 2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published @@ -34,7 +34,7 @@ CODE_NAME='Nitida' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' AUTHOR='Filippo Squillace ' HOMEPAGE="https://github.com/fsquillace/${CMD}" -COPYRIGHT='2012-2015' +COPYRIGHT='2012-2016' if [ "$JUNEST_ENV" == "1" ] diff --git a/lib/util.sh b/lib/util.sh index 7f45102..6865c16 100644 --- a/lib/util.sh +++ b/lib/util.sh @@ -2,7 +2,7 @@ # # This file is part of JuNest (https://github.com/fsquillace/junest) # -# Copyright (c) 2012-2015 +# Copyright (c) 2015 # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published From b7f10dc55b7632ff15a632e9c8679dd568516bee Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 11 May 2016 22:40:12 +0100 Subject: [PATCH 137/326] :memo: Update CONTRIBUTING.md and change unit tests file names --- .travis.yml | 2 +- CONTRIBUTING.md | 91 ++++++++++++++++++++++++++-- tests/shunit2 | 59 ++++++++++++------ tests/{test_cli.sh => test-cli.sh} | 0 tests/{test_core.sh => test-core.sh} | 0 tests/{test_util.sh => test-util.sh} | 0 tests/{test_all.sh => unit-tests.sh} | 3 +- 7 files changed, 128 insertions(+), 27 deletions(-) mode change 100755 => 100644 tests/shunit2 rename tests/{test_cli.sh => test-cli.sh} (100%) rename tests/{test_core.sh => test-core.sh} (100%) rename tests/{test_util.sh => test-util.sh} (100%) rename tests/{test_all.sh => unit-tests.sh} (51%) diff --git a/.travis.yml b/.travis.yml index 570a311..3eb7b32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" script: - - ./tests/test_all.sh + - ./tests/unit-tests.sh - junest --check ./bin/junest - yes | junest --delete - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fee979e..c5b62fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,5 @@ -# Contributing to JuNest # +Contributing to JuNest +===================== First off, thanks for taking the time to contribute! @@ -18,6 +19,8 @@ feel free to propose changes to this document in a pull request. - [Documentation Styleguide](#documentation-styleguide) - [Shell Styleguide](#shell-styleguide) +- [Versioning](#versioning) + ## How Can I Contribute? ## ### Reporting Bugs ### @@ -135,6 +138,10 @@ All JuNest issues are tracked as [GitHub issues](https://guides.github.com/featu #### Pull Requests #### +* Fork the repo and create your feature branch from ***dev***. +* If you make significant changes, please add tests too. + Get familiar with [shunit](https://github.com/kward/shunit2). +* If you've changed APIs, please update the documentation * Follow the [Shell styleguide](#shell-styleguide). * Document new code based on the [Documentation Styleguide](#documentation-styleguide). @@ -143,15 +150,23 @@ All JuNest issues are tracked as [GitHub issues](https://guides.github.com/featu * Send a [GitHub Pull Request to JuNest](https://github.com/fsquillace/junest/compare/dev...) with a clear list of what you've done (read more about [pull requests](http://help.github.com/pull-requests/)). * Put **dev as the base branch** and NOT the master one. +#### Unit Tests #### +To run unit tests: +```sh +./tests/unit-tests.sh +``` + +#### Integration Tests #### +Generally, there is no need to run integration tests locally +since [Travis](https://travis-ci.org/fsquillace/junest) will run as +soon as the pull request gets created. + ## Styleguides ## ### Git Commit Messages ### -* Use the present tense ("Add feature" not "Added feature") -* Use the imperative mood ("Move cursor to..." not "Moves cursor to...") -* Limit the first line to 72 characters or less +* Follow the [seven rules](http://chris.beams.io/posts/git-commit/#seven-rules) of a great Git commit message * Reference issues and pull requests liberally -* When only changing documentation, include `[ci skip]` in the commit description * Consider starting the commit message with an applicable emoji: * :art: `:art:` when improving the format/structure of the code * :racehorse: `:racehorse:` when improving performance @@ -168,6 +183,7 @@ All JuNest issues are tracked as [GitHub issues](https://guides.github.com/featu * :arrow_up: `:arrow_up:` when upgrading dependencies * :arrow_down: `:arrow_down:` when downgrading dependencies * :shirt: `:shirt:` when removing linter warnings + * :package: `:package:` when bumping the version ### Documentation Styleguide ### @@ -177,3 +193,68 @@ All JuNest issues are tracked as [GitHub issues](https://guides.github.com/featu * Use [google shell styleguide](https://google.github.io/styleguide/shell.xml) +#### Function documentation #### +For function documentation follows the example below: + + ####################################### + # Cleanup files from the backup dir. + # + # Globals: + # VAR1 (RO,bool) : `my_func` access to VAR1. + # VAR2 (WO) : `my_func` change the value of VAR2. + # VAR3 (RW) : `my_func` read and write to VAR3. + # Arguments: + # arg1 ($1,int) : Directory to cleanup. + # arg2 ($2-) : Command to execute for the cleanup. + # Returns: + # 0 : Cleanup completed successfully. + # 101 : Backup directory is not readable. + # $NOT_DIR_ERROR : Backup directory is not a directory. + # Output: + # None + ####################################### + my_func() { + local arg1=$1 + shift + local arg2=$@ + ... + } + +The documentation is divided by a description of the function, a `Globals`, +`Arguments`, `Returns` and `Output` sections. If a section does not need details +use the word `None` inside of it. + +`Globals` section provides all global variables that interact with the function. + +`Arguments` section provides the list of arguments to pass to the function. Use +the parenthesis to indicate the position of the arguments: + +- `$1` : Argument is in position one. +- `$2-` : Argument takes all args from position two up to the end. +- `$@` : Argument takes all args. +- `$3?` : Argument is optional. + +Variables defined in `Globals` and `Arguments` sections can have the following +types: + +- `int` : Integer variable. +- `str` : String variable (default). +- `bool` : Bool variable. + +`Returns` section contains the exit status of the function. + +`Output` section describe the string printed to stdout. + +## Versioning ## + +* JuNest uses the following [semantic versioning](http://semver.org/) + +### Public API ### + +The public API refers to the following parts of JuNest system: + +- JuNest script CLI + +Any potential code change that cause backwards incompatible changes to the +public API requires the major version to be incremented. + diff --git a/tests/shunit2 b/tests/shunit2 old mode 100755 new mode 100644 index 8862ffd..d6e7503 --- a/tests/shunit2 +++ b/tests/shunit2 @@ -1,5 +1,5 @@ #! /bin/sh -# $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ +# $Id$ # vim:et:ft=sh:sts=2:sw=2 # # Copyright 2008 Kate Ward. All Rights Reserved. @@ -15,20 +15,31 @@ # return if shunit already loaded [ -n "${SHUNIT_VERSION:-}" ] && exit 0 +SHUNIT_VERSION='2.1.7pre' -SHUNIT_VERSION='2.1.6' - +# return values that scripts can use SHUNIT_TRUE=0 SHUNIT_FALSE=1 SHUNIT_ERROR=2 -# enable strict mode by default -SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} - +# logging functions _shunit_warn() { echo "shunit2:WARN $@" >&2; } _shunit_error() { echo "shunit2:ERROR $@" >&2; } _shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } +# determine some reasonable command defaults +__SHUNIT_UNAME_S=`uname -s` +case "${__SHUNIT_UNAME_S}" in + BSD) __SHUNIT_EXPR_CMD='gexpr' ;; + *) __SHUNIT_EXPR_CMD='expr' ;; +esac + +# commands a user can override if needed +SHUNIT_EXPR_CMD=${SHUNIT_EXPR_CMD:-${__SHUNIT_EXPR_CMD}} + +# enable strict mode by default +SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} + # specific shell checks if [ -n "${ZSH_VERSION:-}" ]; then setopt |grep "^shwordsplit$" >/dev/null @@ -51,19 +62,24 @@ __SHUNIT_MODE_STANDALONE='standalone' __SHUNIT_PARENT=${SHUNIT_PARENT:-$0} # set the constants readonly -shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` -echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ - shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` -for shunit_constant_ in ${shunit_constants_}; do - shunit_ro_opts_='' - case ${ZSH_VERSION:-} in - '') ;; # this isn't zsh - [123].*) ;; # early versions (1.x, 2.x, 3.x) - *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally - esac - readonly ${shunit_ro_opts_} ${shunit_constant_} +__shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` +echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ + __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` +for __shunit_const in ${__shunit_constants}; do + if [ -z "${ZSH_VERSION:-}" ]; then + readonly ${__shunit_const} + else + case ${ZSH_VERSION} in + [123].*) readonly ${__shunit_const} ;; + *) readonly -g ${__shunit_const} # declare readonly constants globally + esac + fi done -unset shunit_constant_ shunit_constants_ shunit_ro_opts_ +unset __shunit_const __shunit_constants + +# +# internal variables +# # variables __shunit_lineno='' # line number of executed test @@ -88,6 +104,9 @@ __shunit_assertsSkipped=0 # macros _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' +#----------------------------------------------------------------------------- +# private functions + #----------------------------------------------------------------------------- # assert functions # @@ -313,8 +332,8 @@ _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' assertTrue() { ${_SHUNIT_LINENO_} - if [ $# -gt 2 ]; then - _shunit_error "assertTrue() takes one two arguments; $# given" + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertTrue() takes one or two arguments; $# given" return ${SHUNIT_ERROR} fi _shunit_shouldSkip && return ${SHUNIT_TRUE} diff --git a/tests/test_cli.sh b/tests/test-cli.sh similarity index 100% rename from tests/test_cli.sh rename to tests/test-cli.sh diff --git a/tests/test_core.sh b/tests/test-core.sh similarity index 100% rename from tests/test_core.sh rename to tests/test-core.sh diff --git a/tests/test_util.sh b/tests/test-util.sh similarity index 100% rename from tests/test_util.sh rename to tests/test-util.sh diff --git a/tests/test_all.sh b/tests/unit-tests.sh similarity index 51% rename from tests/test_all.sh rename to tests/unit-tests.sh index 48f9262..acf1bba 100755 --- a/tests/test_all.sh +++ b/tests/unit-tests.sh @@ -1,5 +1,6 @@ +#!/bin/bash tests_succeded=true -for tst in $(ls $(dirname $0)/test_* | grep -v $(basename $0)) +for tst in $(ls $(dirname $0)/test* | grep -v $(basename $0)) do $tst || tests_succeded=false done From ce3fefeab553568117883eada58a820cb82cd251 Mon Sep 17 00:00:00 2001 From: fsquillace Date: Thu, 26 May 2016 12:04:10 +0100 Subject: [PATCH 138/326] Issue #141: :art: Refactor code --- LICENSE | 11 ++- VERSION | 1 + bin/jchroot | 24 +----- bin/junest | 35 +++----- lib/core.sh | 175 +++++++++++++++++++++++++++++---------- lib/util.sh | 93 --------------------- lib/utils.sh | 195 ++++++++++++++++++++++++++++++++++++++++++++ tests/test-cli.sh | 193 +++++++++++++++++++------------------------ tests/test-core.sh | 151 +++++++++++++++------------------- tests/test-util.sh | 72 ---------------- tests/test-utils.sh | 97 ++++++++++++++++++++++ tests/utils.sh | 32 ++++++++ 12 files changed, 631 insertions(+), 448 deletions(-) create mode 100644 VERSION delete mode 100644 lib/util.sh create mode 100644 lib/utils.sh delete mode 100755 tests/test-util.sh create mode 100755 tests/test-utils.sh create mode 100644 tests/utils.sh diff --git a/LICENSE b/LICENSE index 6b156fe..610ce97 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ -GNU GENERAL PUBLIC LICENSE + + + GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. @@ -631,8 +633,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} + JuNest: The Arch Linux based distro that runs upon any Linux distros without root access + Copyright (C) 2014 Filippo Squillace This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -652,7 +654,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - {project} Copyright (C) {year} {fullname} + JuNest Copyright (C) 2014 Filippo Squillace This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -673,3 +675,4 @@ the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..b3ae5c7 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +5.6.7 diff --git a/bin/jchroot b/bin/jchroot index 98f8680..8eaa8d4 100755 --- a/bin/jchroot +++ b/bin/jchroot @@ -1,30 +1,14 @@ #!/bin/bash # -# This file is part of JuNest (https://github.com/fsquillace/junest) -# -# Copyright (c) 2015 -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - # This script is the simplified and portable version of arch-chroot # (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) +# set -e -################################ IMPORTS ################################## -source "$(dirname $0)/../lib/util.sh" +JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" + +source "${JUNEST_BASE}/lib/utils.sh" ################################ MAIN FUNCTIONS ########################### diff --git a/bin/junest b/bin/junest index 9ac3736..b081e71 100755 --- a/bin/junest +++ b/bin/junest @@ -2,24 +2,10 @@ # # This file is part of JuNest (https://github.com/fsquillace/junest). # -# Copyright (c) 2015 -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -JUNEST_BASE="$(dirname $0)/.." +JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" +source "${JUNEST_BASE}/lib/utils.sh" source "${JUNEST_BASE}/lib/core.sh" ################################### @@ -27,7 +13,8 @@ source "${JUNEST_BASE}/lib/core.sh" ################################### usage() { - echo -e "$NAME: $DESCRIPTION" + echo -e "$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION" + echo echo -e "Usage: $CMD [options] [--] [command]" echo echo -e "Setup options:" @@ -54,9 +41,7 @@ usage() { } version() { - echo -e "$NAME $VERSION ($CODE_NAME): $DESCRIPTION" - echo -e "Copyright (c) $COPYRIGHT $AUTHOR" - echo -e "Homepage: $HOMEPAGE" + echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" } check_cli(){ @@ -225,7 +210,11 @@ function execute_operation(){ fi } -parse_arguments "$@" -check_cli -execute_operation +function cli() { + parse_arguments "$@" + check_cli + execute_operation +} + +cli "$@" # vim: set ts=4 sw=4 noet: diff --git a/lib/core.sh b/lib/core.sh index 4cd08f0..451d4ca 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -1,41 +1,17 @@ #!/usr/bin/env bash # -# Copyright (c) 2015 +# This module contains all core functionalities for JuNest. # -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. +# Dependencies: +# - lib/utils.sh # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# - -# References: -# https://wiki.archlinux.org/index.php/PKGBUILD -# https://wiki.archlinux.org/index.php/Creating_Packages +# vim: ft=sh set -e -################################ IMPORTS ################################# -source "$(dirname ${BASH_ARGV[0]})/util.sh" - -################################# VARIABLES ############################## - NAME='JuNest' CMD='junest' -VERSION='5.6.7' -CODE_NAME='Nitida' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' -AUTHOR='Filippo Squillace ' -HOMEPAGE="https://github.com/fsquillace/${CMD}" -COPYRIGHT='2012-2016' - if [ "$JUNEST_ENV" == "1" ] then @@ -101,6 +77,7 @@ WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" TAR=tar CHOWN="chown" +LN=ln LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -109,7 +86,7 @@ LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" # image. function ln_cmd(){ - ln $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/ln $@ + $LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@ } function rm_cmd(){ @@ -148,6 +125,24 @@ function chroot_cmd(){ ################################# MAIN FUNCTIONS ############################## +NOT_AVAILABLE_ARCH=102 +NOT_EXISTING_FILE=103 +ARCHITECTURE_MISMATCH=104 +ROOT_ACCESS_ERROR=105 + +####################################### +# Check if the JuNest system is installed in JUNEST_HOME. +# +# Globals: +# JUNEST_HOME (RO) : Contains the JuNest home directory. +# Arguments: +# None +# Returns: +# 0 : If JuNest is installed +# 1 : If JuNest is not installed +# Output: +# None +####################################### function is_env_installed(){ [ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0 return 1 @@ -155,8 +150,8 @@ function is_env_installed(){ function _cleanup_build_directory(){ -# $1: maindir (optional) - str: build directory to get rid local maindir=$1 + check_not_null "$maindir" builtin cd $ORIGIN_WD trap - QUIT EXIT ABRT KILL TERM INT rm_cmd -fr "$maindir" @@ -164,15 +159,20 @@ function _cleanup_build_directory(){ function _prepare_build_directory(){ + local maindir=$1 + check_not_null "$maindir" trap - QUIT EXIT ABRT KILL TERM INT trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT } function _setup_env(){ + local imagepath=$1 + check_not_null "$imagepath" + is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME" + mkdir_cmd -p "${JUNEST_HOME}" - imagepath=$1 $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} mkdir_cmd -p ${JUNEST_HOME}/run/lock info "The default mirror URL is ${DEFAULT_MIRROR}." @@ -182,14 +182,33 @@ function _setup_env(){ } +####################################### +# Setup JuNest. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs +# to be installed. +# ARCH (RO) : The host architecture. +# JUNEST_TEMPDIR (RO) : The JuNest temporary directory for building +# the JuNest system from the image. +# ENV_REPO (RO) : URL of the site containing JuNest images. +# NAME (RO) : The JuNest name. +# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. +# Arguments: +# arch ($1?) : The JuNest architecture image to download. +# Defaults to the host architecture +# Returns: +# $NOT_AVAILABLE_ARCH : If the architecture is not one of the available ones. +# Output: +# None +####################################### function setup_env(){ - local arch=$ARCH - [ -z $1 ] || arch="$1" + local arch=${1:-$ARCH} contains_element $arch "${ARCH_LIST[@]}" || \ - die "The architecture is not one of: ${ARCH_LIST[@]}" + die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}" local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) - _prepare_build_directory + _prepare_build_directory $maindir info "Downloading ${NAME}..." builtin cd ${maindir} @@ -202,21 +221,51 @@ function setup_env(){ _cleanup_build_directory ${maindir} } - +####################################### +# Setup JuNest from file. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs +# to be installed. +# NAME (RO) : The JuNest name. +# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. +# Arguments: +# imagefile ($1) : The JuNest image file. +# Returns: +# $NOT_EXISTING_FILE : If the image file does not exist. +# Output: +# None +####################################### function setup_env_from_file(){ local imagefile=$1 - [ ! -e ${imagefile} ] && die "Error: The ${NAME} image file ${imagefile} does not exist" + check_not_null "$imagefile" + [ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist" info "Installing ${NAME} from ${imagefile}..." _setup_env ${imagefile} - - builtin cd $ORIGIN_WD } +####################################### +# Run JuNest as real root. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# 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. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### function run_env_as_root(){ source ${JUNEST_HOME}/etc/junest/info [ "$JUNEST_ARCH" != "$ARCH" ] && \ - die "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" + die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" local uid=$UID # SUDO_USER is more reliable compared to SUDO_UID @@ -268,18 +317,48 @@ function _run_env_with_qemu(){ _run_env_with_proot "$proot_args" "${@}" } +####################################### +# Run JuNest as fakeroot. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# EUID (RO) : The user ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ROOT_ACCESS_ERROR : If the user is the real root. +# Output: +# - : The command output. +####################################### function run_env_as_fakeroot(){ (( EUID == 0 )) && \ - die "You cannot access with root privileges. Use --root option instead." + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." # The mtab file should already be available in the image. # This following instruction will be deleted [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab _run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" } +####################################### +# Run JuNest as normal user. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# EUID (RO) : The user ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ROOT_ACCESS_ERROR : If the user is the real root. +# Output: +# - : The command output. +####################################### function run_env_as_user(){ (( EUID == 0 )) && \ - die "You cannot access with root privileges. Use --root option instead." + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." # The mtab file should already be available in the image. # This following instruction will be deleted [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab @@ -298,6 +377,18 @@ function _provide_bindings_as_user(){ echo $existing_bindings } +####################################### +# Remove an existing JuNest system. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory to remove. +# Arguments: +# None +# Returns: +# None +# Output: +# None +####################################### function delete_env(){ ! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return if mountpoint -q ${JUNEST_HOME} diff --git a/lib/util.sh b/lib/util.sh deleted file mode 100644 index 6865c16..0000000 --- a/lib/util.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env bash -# -# This file is part of JuNest (https://github.com/fsquillace/junest) -# -# Copyright (c) 2015 -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU Library General Public License as published -# by the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -function echoerr(){ - echo "$@" 1>&2 -} -function die(){ -# $@: msg (mandatory) - str: Message to print - error $@ - exit 1 -} -function error(){ -# $@: msg (mandatory) - str: Message to print - echoerr -e "\033[1;31m$@\033[0m" -} -function warn(){ -# $@: msg (mandatory) - str: Message to print - echoerr -e "\033[1;33m$@\033[0m" -} -function info(){ -# $@: msg (mandatory) - str: Message to print - echo -e "\033[1;37m$@\033[0m" -} - -function ask(){ - # $1: question string - # $2: default value - can be either Y, y, N, n (by default Y) - - local default="Y" - [ -z $2 ] || default=$(echo "$2" | tr '[:lower:]' '[:upper:]') - - local other="n" - [ "$default" == "N" ] && other="y" - - local prompt="$1 (${default}/${other})> " - - local res="none" - while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ]; - do - read -p "$prompt" res - res=$(echo "$res" | tr '[:lower:]' '[:upper:]') - done - - [ "$res" == "" ] && res="$default" - - if [ "$res" == "Y" ] - then - return 0 - else - return 1 - fi - -} - -function insert_quotes_on_spaces(){ -# It inserts quotes between arguments. -# Useful to preserve quotes on command -# to be used inside sh -c/bash -c - C='' - whitespace="[[:space:]]" - for i in "$@" - do - if [[ $i =~ $whitespace ]] - then - C="$C \"$i\"" - else - C="$C $i" - fi - done - echo $C -} - -contains_element () { - local e - for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done - return 1 -} diff --git a/lib/utils.sh b/lib/utils.sh new file mode 100644 index 0000000..840fbe9 --- /dev/null +++ b/lib/utils.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bash + +NULL_EXCEPTION=11 +WRONG_ANSWER=33 + +####################################### +# Check if the argument is null. +# +# Globals: +# None +# Arguments: +# argument ($1) : Argument to check. +# Returns: +# 0 : If argument is not null. +# NULL_EXCEPTION : If argument is null. +# Output: +# None +####################################### +function check_not_null() { + [ -z "$1" ] && { error "Error: null argument $1"; return $NULL_EXCEPTION; } + return 0 +} + +####################################### +# Redirect message to stderr. +# +# Globals: +# None +# Arguments: +# msg ($@): Message to print. +# Returns: +# None +# Output: +# Message printed to stderr. +####################################### +function echoerr() { + echo "$@" 1>&2; +} + +####################################### +# Print an error message to stderr and exit program. +# +# Globals: +# None +# Arguments: +# msg ($@) : Message to print. +# Returns: +# 1 : The unique exit status printed. +# Output: +# Message printed to stderr. +####################################### +function die() { + error $@ + exit 1 +} + +####################################### +# Print an error message to stderr and exit program with a given status. +# +# Globals: +# None +# Arguments: +# status ($1) : The exit status to use. +# msg ($2-) : Message to print. +# Returns: +# $? : The $status exit status. +# Output: +# Message printed to stderr. +####################################### +function die_on_status() { + status=$1 + shift + error $@ + exit $status +} + +####################################### +# Print an error message to stderr. +# +# Globals: +# None +# Arguments: +# msg ($@): Message to print. +# Returns: +# None +# Output: +# Message printed to stderr. +####################################### +function error() { + echoerr -e "\033[1;31m$@\033[0m" +} + +####################################### +# Print a warn message to stderr. +# +# Globals: +# None +# Arguments: +# msg ($@): Message to print. +# Returns: +# None +# Output: +# Message printed to stderr. +####################################### +function warn() { + # $@: msg (mandatory) - str: Message to print + echoerr -e "\033[1;33m$@\033[0m" +} + +####################################### +# Print an info message to stdout. +# +# Globals: +# None +# Arguments: +# msg ($@): Message to print. +# Returns: +# None +# Output: +# Message printed to stdout. +####################################### +function info(){ + echo -e "\033[1;36m$@\033[0m" +} + +####################################### +# Ask a question and wait to receive an answer from stdin. +# It returns $default_answer if no answer has be received from stdin. +# +# Globals: +# None +# Arguments: +# question ($1) : The question to ask. +# default_answer ($2) : Possible values: 'Y', 'y', 'N', 'n' (default: 'Y') +# Returns: +# 0 : If user replied with either 'Y' or 'y'. +# 1 : If user replied with either 'N' or 'n'. +# WRONG_ANSWER : If `default_answer` is not one of the possible values. +# Output: +# Print the question to ask. +####################################### +function ask(){ + local question=$1 + local default_answer=$2 + check_not_null $question + + if [ ! -z "$default_answer" ] + then + local answers="Y y N n" + [[ "$answers" =~ "$default_answer" ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; } + fi + + local default="Y" + [ -z "$default_answer" ] || default=$(echo "$default_answer" | tr '[:lower:]' '[:upper:]') + + local other="n" + [ "$default" == "N" ] && other="y" + + local prompt=$(info "$question (${default}/${other})> ") + + local res="none" + while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ]; + do + read -p "$prompt" res + res=$(echo "$res" | tr '[:lower:]' '[:upper:]') + done + + [ "$res" == "" ] && res="$default" + + [ "$res" == "Y" ] +} + +function insert_quotes_on_spaces(){ +# It inserts quotes between arguments. +# Useful to preserve quotes on command +# to be used inside sh -c/bash -c + C='' + whitespace="[[:space:]]" + for i in "$@" + do + if [[ $i =~ $whitespace ]] + then + C="$C \"$i\"" + else + C="$C $i" + fi + done + echo $C +} + +contains_element () { + local e + for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done + return 1 +} diff --git a/tests/test-cli.sh b/tests/test-cli.sh index 46d38d1..c7795dc 100755 --- a/tests/test-cli.sh +++ b/tests/test-cli.sh @@ -1,9 +1,15 @@ #!/bin/bash +source "$(dirname $0)/utils.sh" + source $(dirname $0)/../bin/junest -h &> /dev/null # Disable the exiterr set +e +function oneTimeSetUp(){ + setUpUnitTests +} + function setUp(){ function is_env_installed(){ return 0 @@ -51,152 +57,125 @@ function run_env_as_user(){ echo "run_env_as_user($proot_args,$@)" } -function wrap_env(){ - parse_arguments "$@" - check_cli - execute_operation -} - function test_help(){ - local output=$(wrap_env -h) - assertEquals $output "usage" - local output=$(wrap_env --help) - assertEquals $output "usage" + assertCommandSuccess cli -h + assertEquals "usage" "$(cat $STDOUTF)" + assertCommandSuccess cli --help + assertEquals "usage" "$(cat $STDOUTF)" } function test_version(){ - local output=$(wrap_env -v) - assertEquals $output "version" - local output=$(wrap_env --version) - assertEquals $output "version" + assertCommandSuccess cli -v + assertEquals "version" "$(cat $STDOUTF)" + assertCommandSuccess cli --version + assertEquals "version" "$(cat $STDOUTF)" } function test_build_image_env(){ - local output=$(wrap_env -b) - assertEquals $output "build_image_env(false,false)" - local output=$(wrap_env --build-image) - assertEquals $output "build_image_env(false,false)" - local output=$(wrap_env -b -s) - assertEquals $output "build_image_env(false,true)" - local output=$(wrap_env -b -n) - assertEquals $output "build_image_env(true,false)" - local output=$(wrap_env -b -n -s) - assertEquals $output "build_image_env(true,true)" - local output=$(wrap_env --build-image --disable-validation --skip-root-tests) - assertEquals $output "build_image_env(true,true)" + assertCommandSuccess cli -b + assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli --build-image + assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli -b -s + assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)" + assertCommandSuccess cli -b -n + assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli -b -n -s + assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" + assertCommandSuccess cli --build-image --disable-validation --skip-root-tests + assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" } function test_check_env(){ - local output=$(wrap_env -c myscript) - assertEquals $output "check_env(${JUNEST_HOME},myscript,false)" - local output=$(wrap_env --check myscript) - assertEquals $output "check_env(${JUNEST_HOME},myscript,false)" - local output=$(wrap_env -c myscript -s) - assertEquals $output "check_env(${JUNEST_HOME},myscript,true)" - local output=$(wrap_env --check myscript --skip-root-tests) - assertEquals $output "check_env(${JUNEST_HOME},myscript,true)" + assertCommandSuccess cli -c myscript + assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli --check myscript + assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli -c myscript -s + assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" + assertCommandSuccess cli --check myscript --skip-root-tests + assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" } function test_delete_env(){ - local output=$(wrap_env -d) - assertEquals $output "delete_env" - local output=$(wrap_env --delete) - assertEquals $output "delete_env" + assertCommandSuccess cli -d + assertEquals "delete_env" "$(cat $STDOUTF)" + assertCommandSuccess cli --delete + assertEquals "delete_env" "$(cat $STDOUTF)" } -#function test_setup_env_from_file(){ - #local output=$(wrap_env -i myimage) - #assertEquals $output "setup_env_from_file(myimage)" - #local output=$(wrap_env --setup-from-file myimage) - #assertEquals $output "setup_env_from_file(myimage)" -#} function test_setup_env_from_file(){ is_env_installed(){ return 1 } - local output=$(wrap_env -i myimage) - assertEquals "$output" "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" - local output=$(wrap_env --setup-from-file myimage) - assertEquals "$output" "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" + assertCommandSuccess cli -i myimage + assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess cli --setup-from-file myimage + assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - $(wrap_env -i myimage 2> /dev/null) - assertEquals 1 $? + assertCommandFail cli -i myimage } function test_setup_env(){ is_env_installed(){ return 1 } - local output=$(wrap_env -a arm) - assertEquals "$output" "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" - local output=$(wrap_env --arch arm) - assertEquals "$output" "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" - local output=$(wrap_env) - assertEquals "$output" "$(echo -e "setup_env()\nrun_env_as_user(,)")" + assertCommandSuccess cli -a arm + assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess cli --arch arm + assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess cli + assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - $(wrap_env -a arm 2> /dev/null) - assertEquals 1 $? + assertCommandFail cli -a arm } function test_run_env_as_fakeroot(){ - local output=$(wrap_env -f) - assertEquals $output "run_env_as_fakeroot(,)" - local output=$(wrap_env --fakeroot) - assertEquals $output "run_env_as_fakeroot(,)" + assertCommandSuccess cli -f + assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" + assertCommandSuccess cli --fakeroot + assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - local output=$(wrap_env -f -p "-b arg") - assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,)" - local output=$(wrap_env -f -p "-b arg" -- command -kv) - assertEquals "${output[@]}" "run_env_as_fakeroot(-b arg,command -kv)" - local output=$(wrap_env -f command --as) - assertEquals "${output[@]}" "run_env_as_fakeroot(,command --as)" - $(wrap_env -a "myarch" -f command --as 2> /dev/null) - assertEquals 1 $? + assertCommandSuccess cli -f -p "-b arg" + assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess cli -f -p "-b arg" -- command -kv + assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess cli -f command --as + assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" + assertCommandFail cli -a "myarch" -f command --as } function test_run_env_as_user(){ - local output=$(wrap_env) - assertEquals $output "run_env_as_user(,)" + assertCommandSuccess cli + assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)" - local output=$(wrap_env -p "-b arg") - assertEquals "$output" "run_env_as_user(-b arg,)" - local output=$(wrap_env -p "-b arg" -- command -ll) - assertEquals "$output" "run_env_as_user(-b arg,command -ll)" - local output=$(wrap_env command -ls) - assertEquals "$output" "run_env_as_user(,command -ls)" - $(wrap_env -a "myarch" -- command -ls 2> /dev/null) - assertEquals 1 $? + assertCommandSuccess cli -p "-b arg" + assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess cli -p "-b arg" -- command -ll + assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)" + assertCommandSuccess cli command -ls + assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" + + assertCommandFail cli -a "myarch" -- command -ls } function test_run_env_as_root(){ - local output=$(wrap_env -r) - assertEquals $output "run_env_as_root" - - local output=$(wrap_env -r command) - assertEquals "${output[@]}" "run_env_as_root command" + assertCommandSuccess cli -r + assertEquals "run_env_as_root " "$(cat $STDOUTF)" + assertCommandSuccess cli -r command + assertEquals "run_env_as_root command" "$(cat $STDOUTF)" } function test_check_cli(){ - $(wrap_env -b -h 2> /dev/null) - assertEquals $? 1 - $(wrap_env -b -c 2> /dev/null) - assertEquals $? 1 - $(wrap_env -d -s 2> /dev/null) - assertEquals $? 1 - $(wrap_env -n -v 2> /dev/null) - assertEquals $? 1 - $(wrap_env -d -r 2> /dev/null) - assertEquals $? 1 - $(wrap_env -h -f 2> /dev/null) - assertEquals $? 1 - $(wrap_env -v -i fsd 2> /dev/null) - assertEquals $? 1 - $(wrap_env -f -r 2> /dev/null) - assertEquals $? 1 - $(wrap_env -p args -v 2> /dev/null) - assertEquals $? 1 - $(wrap_env -a arch -v 2> /dev/null) - assertEquals $? 1 - $(wrap_env -d args 2> /dev/null) - assertEquals $? 1 + assertCommandFail cli -b -h + assertCommandFail cli -b -c + assertCommandFail cli -d -s + assertCommandFail cli -n -v + assertCommandFail cli -d -r + assertCommandFail cli -h -f + assertCommandFail cli -v -i fsd + assertCommandFail cli -f -r + assertCommandFail cli -p args -v + assertCommandFail cli -a arch -v + assertCommandFail cli -d args } source $(dirname $0)/shunit2 diff --git a/tests/test-core.sh b/tests/test-core.sh index bd57032..2724eee 100755 --- a/tests/test-core.sh +++ b/tests/test-core.sh @@ -1,12 +1,17 @@ #!/bin/bash +source "$(dirname $0)/utils.sh" + +# Disable the exiterr +set +e function oneTimeSetUp(){ [ -z "$SKIP_ROOT_TESTS" ] && SKIP_ROOT_TESTS=0 CURRPWD=$PWD - ENV_MAIN_HOME=/tmp/envtesthome - [ -e $ENV_MAIN_HOME ] || JUNEST_HOME=$ENV_MAIN_HOME bash --rcfile "$(dirname $0)/../lib/core.sh" -ic "setup_env" + ENV_MAIN_HOME=/tmp/junest-test-home + [ -e $ENV_MAIN_HOME ] || JUNEST_HOME=$ENV_MAIN_HOME bash -ic "source $CURRPWD/$(dirname $0)/../lib/utils.sh; source $CURRPWD/$(dirname $0)/../lib/core.sh; setup_env" JUNEST_HOME="" + setUpUnitTests } function install_mini_env(){ @@ -17,6 +22,7 @@ function setUp(){ cd $CURRPWD JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) JUNEST_BASE="$CURRPWD/$(dirname $0)/.." + source "${JUNEST_BASE}/lib/utils.sh" source "${JUNEST_BASE}/lib/core.sh" ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX) cd $ORIGIN_WD @@ -40,42 +46,36 @@ function tearDown(){ function test_is_env_installed(){ - is_env_installed - assertEquals $? 1 + assertCommandFail is_env_installed touch $JUNEST_HOME/just_file - is_env_installed - assertEquals $? 0 + assertCommandSuccess is_env_installed } function test_download(){ WGET=/bin/true CURL=/bin/false - download_cmd - assertEquals $? 0 + assertCommandSuccess download_cmd WGET=/bin/false CURL=/bin/true - download_cmd - assertEquals $? 0 + assertCommandSuccess download_cmd - $(WGET=/bin/false CURL=/bin/false download_cmd something 2> /dev/null) - assertEquals $? 1 + WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd } function test_ln(){ install_mini_env touch ln_file - ln_cmd -s ln_file new_file - assertEquals $? 0 + assertCommandSuccess ln_cmd -s ln_file new_file assertTrue "[ -e new_file ]" rm new_file touch ln_file OLDPATH="$PATH" PATH="" - ln_cmd -s ln_file new_file 2> /dev/null + $(ln_cmd -s ln_file new_file 2> /dev/null) local ret=$? PATH="$OLDPATH" assertEquals $ret 0 @@ -86,8 +86,7 @@ function test_rm(){ install_mini_env touch rm_file - rm_cmd rm_file - assertEquals $? 0 + assertCommandSuccess rm_cmd rm_file assertTrue "[ ! -e rm_file ]" touch rm_file @@ -106,8 +105,7 @@ function test_chown(){ local id=$(id -u) touch chown_file - chown_cmd $id chown_file - assertEquals $? 0 + assertCommandSuccess chown_cmd $id chown_file touch chown_file OLDPATH="$PATH" @@ -121,8 +119,7 @@ function test_chown(){ function test_mkdir(){ install_mini_env - mkdir_cmd -p new_dir/new_dir - assertEquals $? 0 + assertCommandSuccess mkdir_cmd -p new_dir/new_dir assertTrue "[ -d new_dir/new_dir ]" rm -rf new_dir @@ -150,8 +147,7 @@ function test_setup_env(){ assertTrue "[ -e $JUNEST_HOME/file ]" assertTrue "[ -e $JUNEST_HOME/run/lock ]" - $(setup_env "noarch" 2> /dev/null) - assertEquals 1 $? + assertCommandFailOnStatus 102 setup_env "noarch" } @@ -162,8 +158,7 @@ function test_setup_env_from_file(){ assertTrue "[ -e $JUNEST_HOME/file ]" assertTrue "[ -e $JUNEST_HOME/run/lock ]" - $(setup_env_from_file noexist.tar.gz 2> /dev/null) - assertEquals $? 1 + assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz } function test_setup_env_from_file_with_absolute_path(){ @@ -182,29 +177,23 @@ function test_run_env_as_root(){ CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" - local output=$(run_env_as_root pwd) - assertEquals "/" "$output" - run_env_as_root [ -e /run/lock ] - assertEquals 0 $? - run_env_as_root [ -e $HOME ] - assertEquals 0 $? + assertCommandSuccess run_env_as_root pwd + assertEquals "/" "$(cat $STDOUTF)" + assertCommandSuccess run_env_as_root [ -e /run/lock ] + assertCommandSuccess run_env_as_root [ -e $HOME ] # test that normal user has ownership of the files created by root - run_env_as_root touch /a_root_file - # This ensure that the trap will be executed - kill -TERM $$ - local output=$(run_env_as_root stat -c '%u' /a_root_file) - assertEquals "$UID" "$output" + assertCommandSuccess run_env_as_root touch /a_root_file + assertCommandSuccess run_env_as_root stat -c '%u' /a_root_file + assertEquals "$UID" "$(cat $STDOUTF)" SH=("sh" "--login" "-c" "type -t type") - local output=$(run_env_as_root) - assertEquals "builtin" "$output" + assertCommandSuccess run_env_as_root + assertEquals "builtin" "$(cat $STDOUTF)" SH=("sh" "--login" "-c" "[ -e /run/lock ]") - run_env_as_root - assertEquals 0 $? + assertCommandSuccess run_env_as_root SH=("sh" "--login" "-c" "[ -e $HOME ]") - run_env_as_root - assertEquals 0 $? + assertCommandSuccess run_env_as_root } function test_run_env_as_root_different_arch(){ @@ -212,8 +201,7 @@ function test_run_env_as_root_different_arch(){ install_mini_env echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info - $(run_env_as_root pwd 2> /dev/null) - assertEquals 1 $? + assertCommandFailOnStatus 104 run_env_as_root pwd } function test_run_env_as_classic_root(){ @@ -224,10 +212,9 @@ function test_run_env_as_classic_root(){ CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" - local output=$(run_env_as_root pwd 2> /dev/null) - assertEquals "/" "$output" - run_env_as_root [ -e /run/lock ] 2> /dev/null - assertEquals 0 $? + assertCommandSuccess run_env_as_root pwd + assertEquals "/" "$(cat $STDOUTF)" + assertCommandSuccess run_env_as_root [ -e /run/lock ] } function test_run_env_as_junest_root(){ @@ -239,30 +226,28 @@ function test_run_env_as_junest_root(){ LD_EXEC="sudo $LD_EXEC" CHOWN="sudo $CHOWN" - local output=$(run_env_as_root pwd 2> /dev/null) - assertEquals "/" "$output" - run_env_as_root [ -e /run/lock ] 2> /dev/null - assertEquals 0 $? - run_env_as_root [ -e $HOME ] 2> /dev/null - assertEquals 1 $? + assertCommandSuccess run_env_as_root pwd + assertEquals "/" "$(cat $STDOUTF)" + assertCommandSuccess run_env_as_root [ -e /run/lock ] + assertCommandFail run_env_as_root [ -e $HOME ] } function test_run_env_as_user(){ install_mini_env - local output=$(run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" | awk -F: '{print $1}') - assertEquals "$output" "/usr/bin/mkdir" + assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "/usr/bin/mkdir" "$(cat $STDOUTF| awk -F: '{print $1}')" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" SH=("/usr/bin/echo") - local output=$(run_env_as_user "-k 3.10") - assertEquals "-c :" "$output" + assertCommandSuccess run_env_as_user "-k 3.10" + assertEquals "-c :" "$(cat $STDOUTF)" } function test_run_env_as_proot_mtab(){ install_mini_env - $(run_env_as_fakeroot "-k 3.10" "echo") + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "echo" assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" - $(run_env_as_user "-k 3.10" "echo") + assertCommandSuccess run_env_as_user "-k 3.10" "echo" assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" } @@ -273,38 +258,33 @@ function test_run_env_as_root_mtab(){ CHROOT="sudo $CHROOT" CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" CHOWN="sudo $CHOWN" - $(run_env_as_root "echo") + assertCommandSuccess run_env_as_root "echo" assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" } function test_run_env_with_quotes(){ install_mini_env - local output=$(run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" | awk -F: '{print $1}') - assertEquals "/usr/bin/mkdir" "$output" + assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + assertEquals "/usr/bin/mkdir" "$(cat $STDOUTF| awk -F: '{print $1}')" assertTrue "[ -e $JUNEST_HOME/newdir2 ]" } function test_run_env_as_user_proot_args(){ install_mini_env - run_env_as_user "--help" "" &> /dev/null - assertEquals 0 $? + assertCommandSuccess run_env_as_user "--help" "" mkdir $JUNEST_TEMPDIR/newdir touch $JUNEST_TEMPDIR/newdir/newfile - run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" &> /dev/null - assertEquals 0 $? + assertCommandSuccess run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" - $(_run_env_with_proot --helps 2> /dev/null) - assertEquals 1 $? + assertCommandFail _run_env_with_proot --helps } function test_run_env_with_proot_compat(){ PROOT="/bin/true" - _run_env_with_proot "" "" &> /dev/null - assertEquals 0 $? + assertCommandSuccess _run_env_with_proot "" "" - $(PROOT="/bin/false" _run_env_with_proot --helps 2> /dev/null) - assertEquals 1 $? + PROOT="/bin/false" assertCommandFail _run_env_with_proot --helps } function test_run_env_with_proot_as_root(){ @@ -312,10 +292,8 @@ function test_run_env_with_proot_as_root(){ install_mini_env - $(sudo run_env_as_user 2> /dev/null) - assertEquals 1 $? - $(sudo run_env_as_fakeroot 2> /dev/null) - assertEquals 1 $? + assertCommandFail sudo run_env_as_user + assertCommandFail sudo run_env_as_fakeroot } function test_run_proot_seccomp(){ @@ -323,39 +301,38 @@ function test_run_proot_seccomp(){ env } PROOT=envv - local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") - assertEquals "" "$output" + assertCommandSuccess proot_cmd cmd + assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" envv(){ env | grep "^PROOT_NO_SECCOMP" } PROOT=envv local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") + assertCommandSuccess proot_cmd cmd # The variable PROOT_NO_SECCOMP will be produced # twice due to the fallback mechanism assertEquals "PROOT_NO_SECCOMP=1 -PROOT_NO_SECCOMP=1" "$output" +PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" } function test_run_env_as_fakeroot(){ install_mini_env - local output=$(run_env_as_fakeroot "-k 3.10" "id" | awk '{print $1}') - assertEquals "uid=0(root)" "$output" + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "id" + assertEquals "uid=0(root)" "$(cat $STDOUTF | awk '{print $1}')" } function test_delete_env(){ install_mini_env echo "N" | delete_env 1> /dev/null - is_env_installed - assertEquals 0 $? + assertCommandSuccess is_env_installed echo "Y" | delete_env 1> /dev/null - is_env_installed - assertEquals 1 $? + assertCommandFail is_env_installed } function test_nested_env(){ install_mini_env - JUNEST_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null + JUNEST_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/utils.sh; source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null assertEquals 1 $? } diff --git a/tests/test-util.sh b/tests/test-util.sh deleted file mode 100755 index 80fd660..0000000 --- a/tests/test-util.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash -source "$(dirname $0)/../lib/util.sh" - -# Disable the exiterr -set +e - -function test_echoerr(){ - local actual=$(echoerr "Test" 2>&1) - assertEquals "$actual" "Test" -} - -function test_error(){ - local actual=$(error "Test" 2>&1) - local expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$actual" "$expected" -} - -function test_warn(){ - local actual=$(warn "Test" 2>&1) - local expected=$(echo -e "\033[1;33mTest\033[0m") - assertEquals "$actual" "$expected" -} - -function test_info(){ - local actual=$(info "Test") - local expected=$(echo -e "\033[1;37mTest\033[0m") - assertEquals "$actual" "$expected" -} - -function test_die(){ - local actual=$(die "Test" 2>&1) - local expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$actual" "$expected" - $(die Dying 2> /dev/null) - assertEquals $? 1 -} - -function test_ask(){ - echo "Y" | ask "Test" &> /dev/null - assertEquals $? 0 - echo "y" | ask "Test" &> /dev/null - assertEquals $? 0 - echo "N" | ask "Test" &> /dev/null - assertEquals $? 1 - echo "n" | ask "Test" &> /dev/null - assertEquals $? 1 - echo -e "\n" | ask "Test" &> /dev/null - assertEquals $? 0 - echo -e "\n" | ask "Test" "N" &> /dev/null - assertEquals $? 1 - echo -e "asdf\n\n" | ask "Test" "N" &> /dev/null - assertEquals $? 1 -} - -function test_insert_quotes_on_spaces(){ - local actual=$(insert_quotes_on_spaces this is "a test") - assertEquals "this is \"a test\"" "$actual" - - local actual=$(insert_quotes_on_spaces this is 'a test') - assertEquals "this is \"a test\"" "$actual" -} - -function test_contains_element(){ - array=("something to search for" "a string" "test2000") - contains_element "a string" "${array[@]}" - assertEquals "$?" "0" - - contains_element "blabla" "${array[@]}" - assertEquals "$?" "1" -} - -source $(dirname $0)/shunit2 diff --git a/tests/test-utils.sh b/tests/test-utils.sh new file mode 100755 index 0000000..437ae5a --- /dev/null +++ b/tests/test-utils.sh @@ -0,0 +1,97 @@ +#!/bin/bash +source "$(dirname $0)/utils.sh" + +unset HOME +export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX) + +source "$(dirname $0)/../lib/utils.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function test_check_not_null(){ + assertCommandFailOnStatus 11 check_not_null "" "" + assertCommandSuccess check_not_null "bla" "" +} + +function test_echoerr(){ + assertCommandSuccess echoerr "Test" + assertEquals "Test" "$(cat $STDERRF)" +} + +function test_error(){ + assertCommandSuccess error "Test" + local expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" +} + +function test_warn(){ + assertCommandSuccess warn "Test" + local expected=$(echo -e "\033[1;33mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" +} + +function test_info(){ + assertCommandSuccess info "Test" + local expected=$(echo -e "\033[1;36mTest\033[0m") + assertEquals "$expected" "$(cat $STDOUTF)" +} + +function test_die(){ + assertCommandFail die "Test" + local expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" +} + +function test_die_on_status(){ + assertCommandFailOnStatus 222 die_on_status 222 "Test" + local expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" +} + +function test_ask_null_question(){ + assertCommandFailOnStatus 11 ask "" "Y" +} + +function test_ask(){ + echo "Y" | ask "Test" &> /dev/null + assertEquals 0 $? + echo "y" | ask "Test" &> /dev/null + assertEquals 0 $? + echo "N" | ask "Test" &> /dev/null + assertEquals 1 $? + echo "n" | ask "Test" &> /dev/null + assertEquals 1 $? + echo -e "\n" | ask "Test" &> /dev/null + assertEquals 0 $? + echo -e "\n" | ask "Test" "N" &> /dev/null + assertEquals 1 $? + echo -e "asdf\n\n" | ask "Test" "N" &> /dev/null + assertEquals 1 $? +} + +function test_ask_wrong_default_answer() { + echo "Y" | ask "Test" G &> /dev/null + assertEquals 33 $? +} + +function test_insert_quotes_on_spaces(){ + assertCommandSuccess insert_quotes_on_spaces this is "a test" + assertEquals "this is \"a test\"" "$(cat $STDOUTF)" + + assertCommandSuccess insert_quotes_on_spaces this is 'a test' + assertEquals "this is \"a test\"" "$(cat $STDOUTF)" +} + +function test_contains_element(){ + array=("something to search for" "a string" "test2000") + assertCommandSuccess contains_element "a string" "${array[@]}" + + assertCommandFailOnStatus 1 contains_element "blabla" "${array[@]}" +} + +source $(dirname $0)/shunit2 diff --git a/tests/utils.sh b/tests/utils.sh new file mode 100644 index 0000000..b12420e --- /dev/null +++ b/tests/utils.sh @@ -0,0 +1,32 @@ + +function setUpUnitTests(){ + OUTPUT_DIR="${SHUNIT_TMPDIR}/output" + mkdir "${OUTPUT_DIR}" + STDOUTF="${OUTPUT_DIR}/stdout" + STDERRF="${OUTPUT_DIR}/stderr" +} + +function assertCommandSuccess(){ + $(set -e + "$@" > $STDOUTF 2> $STDERRF + ) + assertTrue "The command $1 did not return 0 exit status" $? +} + +function assertCommandFail(){ + $(set -e + "$@" > $STDOUTF 2> $STDERRF + ) + assertFalse "The command $1 returned 0 exit status" $? +} + +# $1: expected exit status +# $2-: The command under test +function assertCommandFailOnStatus(){ + local status=$1 + shift + $(set -e + "$@" > $STDOUTF 2> $STDERRF + ) + assertEquals $status $? +} From 19f4848a9d8f0ba4c539bad050c4813f0933f2f5 Mon Sep 17 00:00:00 2001 From: fsquillace Date: Thu, 26 May 2016 20:24:59 +0100 Subject: [PATCH 139/326] :art: Substitute tab chars with whitespace --- bin/junest | 148 ++++++++++++++++++++++++++--------------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/bin/junest b/bin/junest index b081e71..530a759 100755 --- a/bin/junest +++ b/bin/junest @@ -16,7 +16,7 @@ usage() { echo -e "$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION" echo echo -e "Usage: $CMD [options] [--] [command]" - echo + echo echo -e "Setup options:" echo -e "-i, --setup-from-file Setup the $NAME image in ${JUNEST_HOME}" echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)." @@ -127,87 +127,87 @@ check_cli(){ function parse_arguments(){ - OPT_SETUP_FROM_FILE=false - IMAGE_FILE="" - OPT_FAKEROOT=false - OPT_ROOT=false - OPT_PROOT_ARGS=false - PROOT_ARGS="" - OPT_ARCH=false - ARCH_ARG="" - OPT_BUILD_IMAGE=false - OPT_DISABLE_VALIDATION=false - OPT_CHECK=false - CHECK_ARG="" - OPT_SKIP_ROOT_TEST=false - OPT_DELETE=false - OPT_HELP=false - OPT_VERSION=false - for opt in "$@" - do - case "$1" in - -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; - -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -r|--root) OPT_ROOT=true ; shift ;; - -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; - -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; - -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; - -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; - -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; - -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; - -d|--delete) OPT_DELETE=true ; shift ;; - -h|--help) OPT_HELP=true ; shift ;; - -v|--version) OPT_VERSION=true ; shift ;; - --) shift ; break ;; - -*) die "Invalid option $1" ;; - *) break ;; - esac - done + OPT_SETUP_FROM_FILE=false + IMAGE_FILE="" + OPT_FAKEROOT=false + OPT_ROOT=false + OPT_PROOT_ARGS=false + PROOT_ARGS="" + OPT_ARCH=false + ARCH_ARG="" + OPT_BUILD_IMAGE=false + OPT_DISABLE_VALIDATION=false + OPT_CHECK=false + CHECK_ARG="" + OPT_SKIP_ROOT_TEST=false + OPT_DELETE=false + OPT_HELP=false + OPT_VERSION=false + for opt in "$@" + do + case "$1" in + -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; + -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; + -r|--root) OPT_ROOT=true ; shift ;; + -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; + -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; + -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; + -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; + -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; + -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; + -d|--delete) OPT_DELETE=true ; shift ;; + -h|--help) OPT_HELP=true ; shift ;; + -v|--version) OPT_VERSION=true ; shift ;; + --) shift ; break ;; + -*) die "Invalid option $1" ;; + *) break ;; + esac + done - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done } function execute_operation(){ - $OPT_HELP && usage && return - $OPT_VERSION && version && return + $OPT_HELP && usage && return + $OPT_VERSION && version && return - if $OPT_BUILD_IMAGE; then - build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST - return - elif $OPT_DELETE; then - delete_env - return - elif $OPT_CHECK; then - check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST - return - fi + if $OPT_BUILD_IMAGE; then + build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST + return + elif $OPT_DELETE; then + delete_env + return + elif $OPT_CHECK; then + check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST + return + fi - if ! is_env_installed - then - if $OPT_SETUP_FROM_FILE; then - setup_env_from_file $IMAGE_FILE - else - setup_env $ARCH_ARG - unset ARCH_ARG - fi - elif $OPT_SETUP_FROM_FILE; then - die "Error: The image cannot be installed since $JUNEST_HOME is not empty." - fi + if ! is_env_installed + then + if $OPT_SETUP_FROM_FILE; then + setup_env_from_file $IMAGE_FILE + else + setup_env $ARCH_ARG + unset ARCH_ARG + fi + elif $OPT_SETUP_FROM_FILE; then + die "Error: The image cannot be installed since $JUNEST_HOME is not empty." + fi - [ -z "${ARCH_ARG}" ] || \ - die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" + [ -z "${ARCH_ARG}" ] || \ + die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" - if $OPT_FAKEROOT; then - run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" - elif $OPT_ROOT; then - run_env_as_root "${ARGS[@]}" - else - run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" - fi + if $OPT_FAKEROOT; then + run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" + elif $OPT_ROOT; then + run_env_as_root "${ARGS[@]}" + else + run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" + fi } function cli() { From 3102ff1d8a59aebf903e826cd56f31d800668683 Mon Sep 17 00:00:00 2001 From: fsquillace Date: Fri, 27 May 2016 21:43:20 +0100 Subject: [PATCH 140/326] :art: Refactor core.sh code --- lib/core.sh | 50 +++-- tests/test-core.sh | 448 +++++++++++++++++++++------------------------ 2 files changed, 242 insertions(+), 256 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 451d4ca..15219fe 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -13,12 +13,19 @@ NAME='JuNest' CMD='junest' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' +NOT_AVAILABLE_ARCH=102 +NOT_EXISTING_FILE=103 +ARCHITECTURE_MISMATCH=104 +ROOT_ACCESS_ERROR=105 +NESTED_ENVIRONMENT=106 +VARIABLE_NOT_SET=107 + if [ "$JUNEST_ENV" == "1" ] then - die "Error: Nested ${NAME} environments are not allowed" + die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] then - die "The variable JUNEST_ENV is not properly set" + die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" fi [ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} @@ -78,6 +85,8 @@ CURL="curl -L -J -O -k" TAR=tar CHOWN="chown" LN=ln +RM=rm +MKDIR=mkdir LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -90,15 +99,15 @@ function ln_cmd(){ } function rm_cmd(){ - rm $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/rm $@ + $RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@ } function chown_cmd(){ - $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/chown $@ + $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@ } function mkdir_cmd(){ - mkdir $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/mkdir $@ + $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ } function proot_cmd(){ @@ -125,11 +134,6 @@ function chroot_cmd(){ ################################# MAIN FUNCTIONS ############################## -NOT_AVAILABLE_ARCH=102 -NOT_EXISTING_FILE=103 -ARCHITECTURE_MISMATCH=104 -ROOT_ACCESS_ERROR=105 - ####################################### # Check if the JuNest system is installed in JUNEST_HOME. # @@ -276,7 +280,7 @@ function run_env_as_root(){ # With chown the ownership of the files is assigned to the real user trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME}; rm_cmd -f ${JUNEST_HOME}/etc/mtab" EXIT QUIT ABRT KILL TERM INT + trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT # The mtab file should already be available in the image. # This following instruction will be deleted @@ -362,19 +366,35 @@ function run_env_as_user(){ # The mtab file should already be available in the image. # This following instruction will be deleted [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab - _run_env_with_qemu "$(_provide_bindings_as_user) -r ${JUNEST_HOME} $1" "${@:2}" + + _provide_bindings_as_user + local bindings="$RESULT" + unset RESULT + _run_env_with_qemu "$bindings -r ${JUNEST_HOME} $1" "${@:2}" } +####################################### +# Provide the proot binding options for the normal user. +# +# Globals: +# HOME (RO) : The home directory. +# RESULT (WO) : Contains the binding options. +# Arguments: +# None +# Returns: +# None +# Output: +# 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. - local existing_bindings="" + 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" do - [ -e "$bind" ] && existing_bindings="-b $bind $existing_bindings" + [ -e "$bind" ] && RESULT="-b $bind $RESULT" done - echo $existing_bindings } ####################################### diff --git a/tests/test-core.sh b/tests/test-core.sh index 2724eee..a83237f 100755 --- a/tests/test-core.sh +++ b/tests/test-core.sh @@ -6,32 +6,27 @@ set +e function oneTimeSetUp(){ [ -z "$SKIP_ROOT_TESTS" ] && SKIP_ROOT_TESTS=0 - - CURRPWD=$PWD - ENV_MAIN_HOME=/tmp/junest-test-home - [ -e $ENV_MAIN_HOME ] || JUNEST_HOME=$ENV_MAIN_HOME bash -ic "source $CURRPWD/$(dirname $0)/../lib/utils.sh; source $CURRPWD/$(dirname $0)/../lib/core.sh; setup_env" - JUNEST_HOME="" setUpUnitTests } -function install_mini_env(){ - cp -rfa $ENV_MAIN_HOME/* $JUNEST_HOME -} - function setUp(){ - cd $CURRPWD - JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t envhome.XXXXXXXXXX) - JUNEST_BASE="$CURRPWD/$(dirname $0)/.." - source "${JUNEST_BASE}/lib/utils.sh" - source "${JUNEST_BASE}/lib/core.sh" - ORIGIN_WD=$(TMPDIR=/tmp mktemp -d -t envowd.XXXXXXXXXX) - cd $ORIGIN_WD - JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t envtemp.XXXXXXXXXX) + JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) + mkdir -p ${JUNEST_HOME}/etc/junest + echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info + mkdir -p ${JUNEST_HOME}/etc/ca-certificates + JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t junest-temp.XXXXXXXXXX) + source "$(dirname $0)/../lib/utils.sh" + source "$(dirname $0)/../lib/core.sh" set +e trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${JUNEST_HOME}; rm -rf ${ORIGIN_WD}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT + trap "rm -rf ${JUNEST_HOME}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT + + ld_exec() { + echo "ld_exec $@" + } + LD_EXEC=ld_exec } @@ -39,18 +34,20 @@ function tearDown(){ # the CA directories are read only and can be deleted only by changing the mod [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates rm -rf $JUNEST_HOME - rm -rf $ORIGIN_WD rm -rf $JUNEST_TEMPDIR trap - QUIT EXIT ABRT KILL TERM INT } -function test_is_env_installed(){ - assertCommandFail is_env_installed - touch $JUNEST_HOME/just_file - assertCommandSuccess is_env_installed -} +function test_ln(){ + LN=echo assertCommandSuccess ln_cmd -s ln_file new_file + assertEquals "-s ln_file new_file" "$(cat $STDOUTF)" + LN=false assertCommandSuccess ln_cmd -s ln_file new_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)" + + LN=false LD_EXEC=false assertCommandFail ln_cmd +} function test_download(){ WGET=/bin/true @@ -64,236 +61,55 @@ function test_download(){ WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd } -function test_ln(){ - install_mini_env - - touch ln_file - assertCommandSuccess ln_cmd -s ln_file new_file - assertTrue "[ -e new_file ]" - rm new_file - - touch ln_file - OLDPATH="$PATH" - PATH="" - $(ln_cmd -s ln_file new_file 2> /dev/null) - local ret=$? - PATH="$OLDPATH" - assertEquals $ret 0 - assertTrue "[ -e new_file ]" -} - function test_rm(){ - install_mini_env + RM=echo assertCommandSuccess rm_cmd rm_file + assertEquals "rm_file" "$(cat $STDOUTF)" - touch rm_file - assertCommandSuccess rm_cmd rm_file - assertTrue "[ ! -e rm_file ]" + RM=false assertCommandSuccess rm_cmd rm_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)" - touch rm_file - OLDPATH="$PATH" - PATH="" - rm_cmd rm_file 2> /dev/null - local ret=$? - PATH="$OLDPATH" - assertEquals $ret 0 - assertTrue "[ ! -e rm_file ]" + RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file } function test_chown(){ - install_mini_env - local id=$(id -u) - touch chown_file - assertCommandSuccess chown_cmd $id chown_file + CHOWN=echo assertCommandSuccess chown_cmd $id chown_file + assertEquals "$id chown_file" "$(cat $STDOUTF)" - touch chown_file - OLDPATH="$PATH" - PATH="" - chown_cmd $id chown_file 2> /dev/null - local ret=$? - PATH="$OLDPATH" - assertEquals $ret 0 + CHOWN=false assertCommandSuccess chown_cmd $id chown_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)" + + CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file } function test_mkdir(){ - install_mini_env + MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir + assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)" - assertCommandSuccess mkdir_cmd -p new_dir/new_dir - assertTrue "[ -d new_dir/new_dir ]" - rm -rf new_dir + MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)" - OLDPATH="$PATH" - PATH="" - mkdir_cmd -p new_dir/new_dir 2> /dev/null - local ret=$? - PATH="$OLDPATH" - assertEquals $ret 0 - assertTrue "[ -d new_dir/new_dir ]" + MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir } -function test_setup_env(){ - wget_mock(){ - # Proof that the setup is happening - # inside $JUNEST_TEMPDIR - local cwd=${PWD#${JUNEST_TEMPDIR}} - local parent_dir=${PWD%${cwd}} - assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" - touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file - } - WGET=wget_mock - setup_env 1> /dev/null - assertTrue "[ -e $JUNEST_HOME/file ]" - assertTrue "[ -e $JUNEST_HOME/run/lock ]" +function test_chroot(){ + CHROOT=echo assertCommandSuccess chroot_cmd root + assertEquals "root" "$(cat $STDOUTF)" - assertCommandFailOnStatus 102 setup_env "noarch" + CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root + assertEquals "root" "$(cat $STDOUTF)" + + CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)" + + CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } +function test_proot_cmd_compat(){ + PROOT="/bin/true" assertCommandSuccess proot_cmd "" "" -function test_setup_env_from_file(){ - touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null - setup_env_from_file ${CMD}-${ARCH}.tar.gz &> /dev/null - assertTrue "[ -e $JUNEST_HOME/file ]" - assertTrue "[ -e $JUNEST_HOME/run/lock ]" - - assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz -} - -function test_setup_env_from_file_with_absolute_path(){ - touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null - setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz &> /dev/null - assertTrue "[ -e $JUNEST_HOME/file ]" - assertTrue "[ -e $JUNEST_HOME/run/lock ]" -} - -function test_run_env_as_root(){ - [ $SKIP_ROOT_TESTS -eq 1 ] && return - - install_mini_env - CHROOT="sudo $CHROOT" - CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" - CHOWN="sudo $CHOWN" - - assertCommandSuccess run_env_as_root pwd - assertEquals "/" "$(cat $STDOUTF)" - assertCommandSuccess run_env_as_root [ -e /run/lock ] - assertCommandSuccess run_env_as_root [ -e $HOME ] - - # test that normal user has ownership of the files created by root - assertCommandSuccess run_env_as_root touch /a_root_file - assertCommandSuccess run_env_as_root stat -c '%u' /a_root_file - assertEquals "$UID" "$(cat $STDOUTF)" - - SH=("sh" "--login" "-c" "type -t type") - assertCommandSuccess run_env_as_root - assertEquals "builtin" "$(cat $STDOUTF)" - SH=("sh" "--login" "-c" "[ -e /run/lock ]") - assertCommandSuccess run_env_as_root - SH=("sh" "--login" "-c" "[ -e $HOME ]") - assertCommandSuccess run_env_as_root -} - -function test_run_env_as_root_different_arch(){ - [ $SKIP_ROOT_TESTS -eq 1 ] && return - - install_mini_env - echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info - assertCommandFailOnStatus 104 run_env_as_root pwd -} - -function test_run_env_as_classic_root(){ - [ $SKIP_ROOT_TESTS -eq 1 ] && return - - install_mini_env - CHROOT="sudo unknowncommand" - CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" - CHOWN="sudo $CHOWN" - - assertCommandSuccess run_env_as_root pwd - assertEquals "/" "$(cat $STDOUTF)" - assertCommandSuccess run_env_as_root [ -e /run/lock ] -} - -function test_run_env_as_junest_root(){ - [ $SKIP_ROOT_TESTS -eq 1 ] && return - - install_mini_env - CHROOT="sudo unknowncommand" - CLASSIC_CHROOT="sudo unknowncommand" - LD_EXEC="sudo $LD_EXEC" - CHOWN="sudo $CHOWN" - - assertCommandSuccess run_env_as_root pwd - assertEquals "/" "$(cat $STDOUTF)" - assertCommandSuccess run_env_as_root [ -e /run/lock ] - assertCommandFail run_env_as_root [ -e $HOME ] -} - -function test_run_env_as_user(){ - install_mini_env - assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "/usr/bin/mkdir" "$(cat $STDOUTF| awk -F: '{print $1}')" - assertTrue "[ -e $JUNEST_HOME/newdir2 ]" - - SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_user "-k 3.10" - assertEquals "-c :" "$(cat $STDOUTF)" -} - -function test_run_env_as_proot_mtab(){ - install_mini_env - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "echo" - assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" - assertCommandSuccess run_env_as_user "-k 3.10" "echo" - assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" -} - -function test_run_env_as_root_mtab(){ - [ $SKIP_ROOT_TESTS -eq 1 ] && return - - install_mini_env - CHROOT="sudo $CHROOT" - CLASSIC_CHROOT="sudo $CLASSIC_CHROOT" - CHOWN="sudo $CHOWN" - assertCommandSuccess run_env_as_root "echo" - assertTrue "[ ! -e $JUNEST_HOME/etc/mtab ]" -} - -function test_run_env_with_quotes(){ - install_mini_env - assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" - assertEquals "/usr/bin/mkdir" "$(cat $STDOUTF| awk -F: '{print $1}')" - assertTrue "[ -e $JUNEST_HOME/newdir2 ]" -} - -function test_run_env_as_user_proot_args(){ - install_mini_env - assertCommandSuccess run_env_as_user "--help" "" - - mkdir $JUNEST_TEMPDIR/newdir - touch $JUNEST_TEMPDIR/newdir/newfile - assertCommandSuccess run_env_as_user "-b $JUNEST_TEMPDIR/newdir:/newdir -k 3.10" "ls" "-l" "/newdir/newfile" - - assertCommandFail _run_env_with_proot --helps -} - -function test_run_env_with_proot_compat(){ - PROOT="/bin/true" - assertCommandSuccess _run_env_with_proot "" "" - - PROOT="/bin/false" assertCommandFail _run_env_with_proot --helps -} - -function test_run_env_with_proot_as_root(){ - [ $SKIP_ROOT_TESTS -eq 1 ] && return - - install_mini_env - - assertCommandFail sudo run_env_as_user - assertCommandFail sudo run_env_as_fakeroot + PROOT="/bin/false" assertCommandFail proot_cmd --helps } function test_run_proot_seccomp(){ @@ -316,14 +132,146 @@ function test_run_proot_seccomp(){ PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" } +function test_is_env_installed(){ + rm -rf $JUNEST_HOME/* + assertCommandFail is_env_installed + touch $JUNEST_HOME/just_file + assertCommandSuccess is_env_installed +} + +function test_setup_env(){ + rm -rf $JUNEST_HOME/* + wget_mock(){ + # Proof that the setup is happening + # inside $JUNEST_TEMPDIR + local cwd=${PWD#${JUNEST_TEMPDIR}} + local parent_dir=${PWD%${cwd}} + assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" + touch file + tar -czvf ${CMD}-${ARCH}.tar.gz file + } + WGET=wget_mock + setup_env 1> /dev/null + assertTrue "[ -e $JUNEST_HOME/file ]" + assertTrue "[ -e $JUNEST_HOME/run/lock ]" + + assertCommandFailOnStatus 102 setup_env "noarch" +} + + +function test_setup_env_from_file(){ + rm -rf $JUNEST_HOME/* + touch file + tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null + assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz + assertTrue "[ -e $JUNEST_HOME/file ]" +} + +function test_setup_env_from_file_not_existing_file(){ + assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz +} + +function test_setup_env_from_file_with_absolute_path(){ + rm -rf $JUNEST_HOME/* + touch file + tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null + assertCommandSuccess setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz + assertTrue "[ -e $JUNEST_HOME/file ]" +} + +function test_run_env_as_root_different_arch(){ + echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + assertCommandFailOnStatus 104 run_env_as_root pwd +} + +function _test_run_env_as_root() { + chroot_cmd() { + [ "$JUNEST_ENV" != "1" ] && return 1 + echo $@ + } + + assertCommandSuccess run_env_as_root $@ + assertEquals "/proc/self/mounts" "$(readlink ${JUNEST_HOME}/etc/mtab)" +} + +function test_run_env_as_root_cmd(){ + _test_run_env_as_root pwd + assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +} + +function test_run_env_as_classic_root_no_cmd(){ + _test_run_env_as_root + assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +} + +#function test_run_env_with_proot_as_root(){ + #[ $SKIP_ROOT_TESTS -eq 1 ] && return + + #sudo run_env_as_user + #sudo run_env_as_fakeroot +#} + +function test_run_env_as_user(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + _provide_bindings_as_user + assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + SH=("/usr/bin/echo") + assertCommandSuccess run_env_as_user "-k 3.10" + _provide_bindings_as_user + assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" +} + function test_run_env_as_fakeroot(){ - install_mini_env - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "id" - assertEquals "uid=0(root)" "$(cat $STDOUTF | awk '{print $1}')" + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "-S ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + SH=("/usr/bin/echo") + assertCommandSuccess run_env_as_fakeroot "-k 3.10" + assertEquals "-S ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" +} + +function test_run_env_as_proot_mtab(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "echo" + assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" + assertCommandSuccess run_env_as_user "-k 3.10" "echo" + assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" +} + +function test_run_env_with_quotes(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + _provide_bindings_as_user + assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" +} + +function test_run_env_with_proot_args(){ + proot_cmd() { + [ "$JUNEST_ENV" != "1" ] && return 1 + echo $@ + } + + assertCommandSuccess _run_env_with_proot --help + assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)" + + assertCommandSuccess _run_env_with_proot --help mycommand + assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)" + + assertCommandFail _run_env_with_proot } function test_delete_env(){ - install_mini_env echo "N" | delete_env 1> /dev/null assertCommandSuccess is_env_installed echo "Y" | delete_env 1> /dev/null @@ -331,9 +279,27 @@ function test_delete_env(){ } function test_nested_env(){ - install_mini_env - JUNEST_ENV=1 bash -ic "source $CURRPWD/$(dirname $0)/../lib/utils.sh; source $CURRPWD/$(dirname $0)/../lib/core.sh" &> /dev/null - assertEquals 1 $? + JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -ic "source $PWD/$(dirname $0)/../lib/utils.sh; source $PWD/$(dirname $0)/../lib/core.sh" +} + +function test_nested_env_not_set_variable(){ + JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -ic "source $PWD/$(dirname $0)/../lib/utils.sh; source $PWD/$(dirname $0)/../lib/core.sh" +} + +function test_qemu() { + echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info + rm_cmd() { + echo $@ + } + ln_cmd() { + echo $@ + } + _run_env_with_proot() { + echo $@ + } + + RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" + assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" } source $(dirname $0)/shunit2 From 1f66d810cdf4ae771c8b6bcde26d5f6047296183 Mon Sep 17 00:00:00 2001 From: fsquillace Date: Fri, 27 May 2016 22:31:49 +0100 Subject: [PATCH 141/326] Remove check for mtab file and lock directory --- lib/core.sh | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index 15219fe..7012391 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -178,7 +178,6 @@ function _setup_env(){ mkdir_cmd -p "${JUNEST_HOME}" $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} - mkdir_cmd -p ${JUNEST_HOME}/run/lock info "The default mirror URL is ${DEFAULT_MIRROR}." info "Remember to refresh the package databases from the server:" info " pacman -Syy" @@ -282,10 +281,6 @@ function run_env_as_root(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT - # The mtab file should already be available in the image. - # This following instruction will be deleted - [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab - JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" } @@ -339,9 +334,7 @@ function _run_env_with_qemu(){ function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - # The mtab file should already be available in the image. - # This following instruction will be deleted - [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab + _run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" } @@ -363,9 +356,6 @@ function run_env_as_fakeroot(){ function run_env_as_user(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - # The mtab file should already be available in the image. - # This following instruction will be deleted - [ ! -e ${JUNEST_HOME}/etc/mtab ] && ln_cmd -s /proc/self/mounts ${JUNEST_HOME}/etc/mtab _provide_bindings_as_user local bindings="$RESULT" @@ -475,6 +465,7 @@ function build_image_env(){ # yaourt requires sed sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" + mkdir -p ${maindir}/root/run/lock info "Install ${NAME} script..." sudo pacman --noconfirm --root ${maindir}/root -S git From 195d8d00694d2861bc1d00ed9e43a9da3a1aee0b Mon Sep 17 00:00:00 2001 From: fsquillace Date: Fri, 27 May 2016 22:57:53 +0100 Subject: [PATCH 142/326] Update travis --- .travis.yml | 27 +++++++++++++++++---------- tests/integ-tests/install-bash.sh | 13 +++++++++++++ tests/test-core.sh | 19 ------------------- 3 files changed, 30 insertions(+), 29 deletions(-) create mode 100755 tests/integ-tests/install-bash.sh diff --git a/.travis.yml b/.travis.yml index 3eb7b32..0ec0f3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,16 +2,23 @@ language: bash sudo: required +env: + - TRAVIS_BASH_VERSION="4.1" + +before_install: + - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" + install: - - PATH=$PWD/bin:$PATH - - junest -- echo "Installing JuNest (\$(uname -m))" - - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" - # TODO: Remember to enable x86 tests when fixed - #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" + - PATH=$PWD/bin:$PATH + - junest -- echo "Installing JuNest (\$(uname -m))" + - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" + # TODO: Remember to enable x86 tests when fixed + #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" script: - - ./tests/unit-tests.sh - - junest --check ./bin/junest - - yes | junest --delete - - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests - - yes | JUNEST_HOME=~/.junest-arm junest --delete + - bash --version + - ./tests/unit-tests.sh + - junest --check ./bin/junest + - yes | junest --delete + - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests + - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/tests/integ-tests/install-bash.sh b/tests/integ-tests/install-bash.sh new file mode 100755 index 0000000..575c9c5 --- /dev/null +++ b/tests/integ-tests/install-bash.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -ex + +VERSION=$1 + +cd /tmp +wget http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz + +tar -zxf bash-$VERSION.tar.gz +cd /tmp/bash-$VERSION* +./configure +make +sudo make install diff --git a/tests/test-core.sh b/tests/test-core.sh index a83237f..ae64776 100755 --- a/tests/test-core.sh +++ b/tests/test-core.sh @@ -153,7 +153,6 @@ function test_setup_env(){ WGET=wget_mock setup_env 1> /dev/null assertTrue "[ -e $JUNEST_HOME/file ]" - assertTrue "[ -e $JUNEST_HOME/run/lock ]" assertCommandFailOnStatus 102 setup_env "noarch" } @@ -191,7 +190,6 @@ function _test_run_env_as_root() { } assertCommandSuccess run_env_as_root $@ - assertEquals "/proc/self/mounts" "$(readlink ${JUNEST_HOME}/etc/mtab)" } function test_run_env_as_root_cmd(){ @@ -204,13 +202,6 @@ function test_run_env_as_classic_root_no_cmd(){ assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } -#function test_run_env_with_proot_as_root(){ - #[ $SKIP_ROOT_TESTS -eq 1 ] && return - - #sudo run_env_as_user - #sudo run_env_as_fakeroot -#} - function test_run_env_as_user(){ _run_env_with_qemu() { echo $@ @@ -237,16 +228,6 @@ function test_run_env_as_fakeroot(){ assertEquals "-S ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" } -function test_run_env_as_proot_mtab(){ - _run_env_with_qemu() { - echo $@ - } - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "echo" - assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" - assertCommandSuccess run_env_as_user "-k 3.10" "echo" - assertTrue "[ -e $JUNEST_HOME/etc/mtab ]" -} - function test_run_env_with_quotes(){ _run_env_with_qemu() { echo $@ From 374cb2e42e3b9cea219f8366c04f66788174b12c Mon Sep 17 00:00:00 2001 From: fsquillace Date: Sat, 28 May 2016 23:20:20 +0100 Subject: [PATCH 143/326] Move the unit tests to a specific folder --- tests/{ => unit-tests}/shunit2 | 0 tests/{ => unit-tests}/test-cli.sh | 2 +- tests/{ => unit-tests}/test-core.sh | 22 ++++++++++++++-------- tests/{ => unit-tests}/test-utils.sh | 2 +- tests/{ => unit-tests}/unit-tests.sh | 0 tests/{ => unit-tests}/utils.sh | 0 6 files changed, 16 insertions(+), 10 deletions(-) rename tests/{ => unit-tests}/shunit2 (100%) rename tests/{ => unit-tests}/test-cli.sh (99%) rename tests/{ => unit-tests}/test-core.sh (93%) rename tests/{ => unit-tests}/test-utils.sh (98%) rename tests/{ => unit-tests}/unit-tests.sh (100%) rename tests/{ => unit-tests}/utils.sh (100%) diff --git a/tests/shunit2 b/tests/unit-tests/shunit2 similarity index 100% rename from tests/shunit2 rename to tests/unit-tests/shunit2 diff --git a/tests/test-cli.sh b/tests/unit-tests/test-cli.sh similarity index 99% rename from tests/test-cli.sh rename to tests/unit-tests/test-cli.sh index c7795dc..5dd2513 100755 --- a/tests/test-cli.sh +++ b/tests/unit-tests/test-cli.sh @@ -1,7 +1,7 @@ #!/bin/bash source "$(dirname $0)/utils.sh" -source $(dirname $0)/../bin/junest -h &> /dev/null +source $(dirname $0)/../../bin/junest -h &> /dev/null # Disable the exiterr set +e diff --git a/tests/test-core.sh b/tests/unit-tests/test-core.sh similarity index 93% rename from tests/test-core.sh rename to tests/unit-tests/test-core.sh index ae64776..46072e1 100755 --- a/tests/test-core.sh +++ b/tests/unit-tests/test-core.sh @@ -1,22 +1,27 @@ #!/bin/bash -source "$(dirname $0)/utils.sh" + +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) + +source "$JUNEST_ROOT/tests/unit-tests/utils.sh" # Disable the exiterr set +e function oneTimeSetUp(){ - [ -z "$SKIP_ROOT_TESTS" ] && SKIP_ROOT_TESTS=0 + SKIP_ROOT_TESTS=${SKIP_ROOT_TESTS:-0} setUpUnitTests } function setUp(){ + ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) + cd $ORIGIN_CWD JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) mkdir -p ${JUNEST_HOME}/etc/junest echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info mkdir -p ${JUNEST_HOME}/etc/ca-certificates JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t junest-temp.XXXXXXXXXX) - source "$(dirname $0)/../lib/utils.sh" - source "$(dirname $0)/../lib/core.sh" + source "$JUNEST_ROOT/lib/utils.sh" + source "$JUNEST_ROOT/lib/core.sh" set +e @@ -35,6 +40,7 @@ function tearDown(){ [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates rm -rf $JUNEST_HOME rm -rf $JUNEST_TEMPDIR + rm -rf $ORIGIN_CWD trap - QUIT EXIT ABRT KILL TERM INT } @@ -112,7 +118,7 @@ function test_proot_cmd_compat(){ PROOT="/bin/false" assertCommandFail proot_cmd --helps } -function test_run_proot_seccomp(){ +function test_proot_cmd_seccomp(){ envv(){ env } @@ -260,11 +266,11 @@ function test_delete_env(){ } function test_nested_env(){ - JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -ic "source $PWD/$(dirname $0)/../lib/utils.sh; source $PWD/$(dirname $0)/../lib/core.sh" + JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -ic "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" } function test_nested_env_not_set_variable(){ - JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -ic "source $PWD/$(dirname $0)/../lib/utils.sh; source $PWD/$(dirname $0)/../lib/core.sh" + JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -ic "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" } function test_qemu() { @@ -283,4 +289,4 @@ function test_qemu() { assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" } -source $(dirname $0)/shunit2 +source $JUNEST_ROOT/tests/unit-tests/shunit2 diff --git a/tests/test-utils.sh b/tests/unit-tests/test-utils.sh similarity index 98% rename from tests/test-utils.sh rename to tests/unit-tests/test-utils.sh index 437ae5a..5816d11 100755 --- a/tests/test-utils.sh +++ b/tests/unit-tests/test-utils.sh @@ -4,7 +4,7 @@ source "$(dirname $0)/utils.sh" unset HOME export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX) -source "$(dirname $0)/../lib/utils.sh" +source "$(dirname $0)/../../lib/utils.sh" # Disable the exiterr set +e diff --git a/tests/unit-tests.sh b/tests/unit-tests/unit-tests.sh similarity index 100% rename from tests/unit-tests.sh rename to tests/unit-tests/unit-tests.sh diff --git a/tests/utils.sh b/tests/unit-tests/utils.sh similarity index 100% rename from tests/utils.sh rename to tests/unit-tests/utils.sh From c114590ea9d48ad7b3777564022dea315d0488fa Mon Sep 17 00:00:00 2001 From: fsquillace Date: Sun, 29 May 2016 00:03:57 +0100 Subject: [PATCH 144/326] :memo: Update README for installation process and change the bash version --- .travis.yml | 4 ++-- README.md | 34 +++++++++++++--------------------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0ec0f3c..e43ddc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: bash sudo: required env: - - TRAVIS_BASH_VERSION="4.1" + - TRAVIS_BASH_VERSION="4.0" before_install: - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" @@ -17,7 +17,7 @@ install: script: - bash --version - - ./tests/unit-tests.sh + - ./tests/unit-tests/unit-tests.sh - junest --check ./bin/junest - yes | junest --delete - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests diff --git a/README.md b/README.md index 8f7a22e..ef21b49 100644 --- a/README.md +++ b/README.md @@ -58,14 +58,22 @@ visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rose Installation ============ -JuNest can works on GNU/Linux OS with kernel version greater or equal -2.6.0 (JuNest was not tested on kernel versions older than this) on 64 bit, 32 bit and ARM architectures. + +## Dependencies ## +JuNest comes with a very short list of dependencies in order to be installed in most +of GNU/Linux distributions. +Before installing JuNest be sure that all dependencies are properly installed in your system: + +- [bash (>=4.0)](https://www.gnu.org/software/bash/) +- [GNU coreutils](https://www.gnu.org/software/coreutils/) + +The minimum recommended Linux kernel is 2.6.0+ on x86 32 and 64 bit and ARM architectures. ## Method one (Recommended) ## -Just clone the JuNest repo somewhere (for example in ~/junest): +Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): - git clone git://github.com/fsquillace/junest ~/junest - export PATH=~/junest/bin:$PATH + git clone git://github.com/fsquillace/junest ~/.local/share/junest + export PATH=~/.local/share/junest/bin:$PATH ### Installation using AUR (Arch Linux only) ### If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/): @@ -81,22 +89,6 @@ Alternatively, another installation method would be to directly download the JuN curl https://dl.dropboxusercontent.com/u/42449030/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest export PATH=~/.junest/opt/junest/bin:$PATH -Dependencies -============ -JuNest comes with a very short list of dependencies in order to be installed in most -of GNU/Linux distributions. The needed executables in the host OS are: - -- bash -- chown (for root access only) -- ln -- mkdir -- rm -- tar -- uname -- wget or curl - -The minimum recommended linux kernel is 2.6.0+ - Advanced usage ============== From 709ceda12fefd3a2787be91fa5dc68f2e02b3bcf Mon Sep 17 00:00:00 2001 From: fsquillace Date: Tue, 31 May 2016 18:22:03 +0100 Subject: [PATCH 145/326] :memo: Add logo and refactor README.md --- README.md | 56 +++++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index ef21b49..c7764fe 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,13 @@ JuNest ====== The Arch Linux based distro that runs upon any Linux distros without root access. +

+ JuNest +

+ |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| | [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | @@ -14,10 +21,9 @@ The Arch Linux based distro that runs upon any Linux distros without root access - [Advanced usage](#advanced-usage) - [Internals](#internals) - [Troubleshooting](#troubleshooting) -- [More documentation](#more documentation) -- [License](#license) +- [More documentation](#more-documentation) +- [Contributing](#contributing) - [Author](#author) -- [WWW](#www) Description =========== @@ -163,22 +169,22 @@ enhanced chroot for privileged users that mounts the primary directories (i.e. /proc, /sys, /dev and /run) before executing any programs inside the sandbox. -##Automatic fallback to classic chroot## +## Automatic fallback to classic chroot ## If jchroot fails for some reasons in the host system (i.e. it is not able to mount one of the directories), JuNest automatically tries to fallback to the classic chroot. -##Automatic fallback for all the dependent host OS executables## +## Automatic fallback for all the dependent host OS executables ## JuNest attempt first to run the executables in the host OS located in different positions (/usr/bin, /bin, /usr/sbin and /sbin). As a fallback it tries to run the same executable if it is available in the JuNest image. -##Automatic building of the JuNest images## +## Automatic building of the JuNest images ## The JuNest images are built every week so that you can always get the most updated package versions. -##Static QEMU binaries## +## Static QEMU binaries ## There are static QEMU binaries included in JuNest image that allows to run JuNest in a different architecture from the host system. They are located in `/opt/qemu` directory. @@ -186,7 +192,7 @@ directory. Troubleshooting =============== -##Cannot use AUR repository## +## Cannot use AUR repository ## > **Q**: Why do I get the following error when I try to install a package with yaourt? @@ -198,7 +204,7 @@ Troubleshooting #> pacman -S base-devel -##No servers configured for repository## +## No servers configured for repository ## > **Q**: Why I cannot install packages? @@ -233,7 +239,7 @@ Troubleshooting $> pkgfile getop core/util-linux -##Kernel too old## +## Kernel too old ## > **Q**: Why do I get the error: "FATAL: kernel too old"? @@ -254,7 +260,7 @@ Troubleshooting > From the output you can see what is the minimum recommended Linux kernel version. -##SUID permissions## +## SUID permissions ## > **Q**: Why I do not have permissions for ping? $> ping www.google.com @@ -268,7 +274,7 @@ Troubleshooting $> find /usr/bin -perm +4000 -##No characters are visible on a graphic application## +## No characters are visible on a graphic application ## > **Q**: Why I do not see any characters in the application I have installed? @@ -280,7 +286,7 @@ Troubleshooting #> pacman -S gnu-free-fonts -##Differences between filesystem and package ownership## +## Differences between filesystem and package ownership ## > **Q**: Why do I get warning when I install a package using root privileges? @@ -300,27 +306,15 @@ More documentation There are additional tutorials in the [JuNest wiki page](https://github.com/fsquillace/junest/wiki). -License -======= -Copyright (c) 2012-2016 +Contributing +============ +You could help improving JuNest in the following ways: -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU Library General Public License as published -by the Free Software Foundation; either version 2, or (at your option) -any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . +- [Reporting Bugs](CONTRIBUTING.md#reporting-bugs) +- [Suggesting Enhancements](CONTRIBUTING.md#suggesting-enhancements) +- [Writing Code](CONTRIBUTING.md#your-first-code-contribution) Author ====== Filippo Squillace -WWW -=== -https://github.com/fsquillace/junest From 147798117bb3541f66ba53b98580bf18d11c3e20 Mon Sep 17 00:00:00 2001 From: fsquillace Date: Tue, 31 May 2016 20:27:27 +0100 Subject: [PATCH 146/326] :memo: Fix path to unit tests --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 #### From 846bcc9c1f8c781bcd94b97523d8604cc601c1ce Mon Sep 17 00:00:00 2001 From: fsquillace Date: Wed, 1 Jun 2016 23:36:40 +0100 Subject: [PATCH 147/326] Issue #81: Use getent to build the passwd and group files --- lib/core.sh | 56 ++++++++++++++++++++++++++++++--- tests/unit-tests/test-core.sh | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 5 deletions(-) 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 $@ From 55a4ffd78a28627a7d65a33f247907f64f523377 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 7 Jun 2016 23:24:49 +0100 Subject: [PATCH 148/326] 5.6.8 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b3ae5c7..349e9d0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.7 +5.6.8 From 56a5f48b32b5b88e53924d13dfec61d7be19e83f Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 9 Jun 2016 21:12:46 +0100 Subject: [PATCH 149/326] Use the new junest-git package --- README.md | 11 +++++----- lib/core.sh | 61 +++++++++++------------------------------------------ 2 files changed, 18 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index c7764fe..da14441 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,8 @@ Description an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. -JuNest contains mainly the package managers (called [pacman](https://wiki.archlinux.org/index.php/Pacman) and [yaourt](https://wiki.archlinux.org/index.php/Yaourt)) that allows to access +JuNest contains mainly the package managers (called [pacman](https://wiki.archlinux.org/index.php/Pacman) +and a simple wrapper of [yaourt](https://wiki.archlinux.org/index.php/Yaourt) called yogurt) that allows to access to a wide range of packages from the Arch Linux repositories. The main advantages on using JuNest are: @@ -84,7 +85,7 @@ Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): ### Installation using AUR (Arch Linux only) ### If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/): - yaourt -S junest-git + yogurt -S junest-git export PATH=/opt/junest/bin:$PATH ## Method two ## @@ -104,7 +105,7 @@ You can build a new JuNest image from scratch by running the following command: junest -b [-n] The script will create a directory containing all the essentials -files in order to make JuNest working properly (such as pacman, yaourt and proot). +files in order to make JuNest working properly (such as pacman, yogurt and proot). The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. @@ -194,12 +195,12 @@ Troubleshooting ## Cannot use AUR repository ## -> **Q**: Why do I get the following error when I try to install a package with yaourt? +> **Q**: Why do I get the following error when I try to install a package with yogurt? Cannot find the gzip binary required for compressing man and info pages. > **A**: JuNest comes with a very basic number of packages. -> In order to install packages using yaourt you may need to install the package group **base-devel** +> In order to install packages using yogurt you may need to install the package group **base-devel** > that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): #> pacman -S base-devel diff --git a/lib/core.sh b/lib/core.sh index dbb81d2..dc29c34 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -61,7 +61,6 @@ else die "Unknown architecture ${ARCH}" fi -PROOT_LINK=http://static.proot.me/ MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030 ENV_REPO=${MAIN_REPO}/${CMD} DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' @@ -511,7 +510,12 @@ function build_image_env(){ # yaourt requires sed sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" - mkdir -p ${maindir}/root/run/lock + sudo mkdir -p ${maindir}/root/run/lock + + # AUR packages requires non-root user to be compiled. proot fakes the user to 10 + info "Compiling and installing yaourt..." + _install_from_aur ${maindir} "package-query" + _install_from_aur ${maindir} "yaourt" info "Install ${NAME} script..." sudo pacman --noconfirm --root ${maindir}/root -S git @@ -525,47 +529,6 @@ function build_image_env(){ sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen sudo bash -c "echo 'LANG=\"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" - info "Generating the metadata info..." - sudo mkdir ${maindir}/root/etc/${CMD} - sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info" - - info "Installing compatibility binaries proot" - sudo mkdir -p ${maindir}/root/opt/proot - builtin cd ${maindir}/root/opt/proot - for arch in ${ARCH_LIST[@]} - do - info "Downloading $PROOT_LINK/proot-$arch ..." - sudo $CURL $PROOT_LINK/proot-$arch - sudo chmod +x proot-$arch - done - - info "Installing qemu static binaries" - sudo mkdir -p ${maindir}/root/opt/qemu - builtin cd ${maindir}/root/opt/qemu - for arch in ${ARCH_LIST[@]} - do - if [ "$arch" != "$ARCH" ] - then - info "Downloading qemu-$ARCH-static-$arch ..." - sudo $CURL ${MAIN_REPO}/qemu/$ARCH/qemu-$ARCH-static-$arch - sudo chmod +x qemu-$ARCH-static-$arch - fi - done - - # AUR packages requires non-root user to be compiled. proot fakes the user to 10 - info "Compiling and installing yaourt..." - _install_from_aur ${maindir} "package-query" - - _install_from_aur ${maindir} "yaourt" - # Apply patches for yaourt and makepkg - sudo mkdir -p ${maindir}/root/opt/yaourt/bin/ - sudo cp ${maindir}/root/usr/bin/yaourt ${maindir}/root/opt/yaourt/bin/ - sudo sed -i -e 's/"--asroot"//' ${maindir}/root/opt/yaourt/bin/yaourt - sudo cp ${maindir}/root/usr/bin/makepkg ${maindir}/root/opt/yaourt/bin/ - sudo sed -i -e 's/EUID\s==\s0/false/' ${maindir}/root/opt/yaourt/bin/makepkg - sudo bash -c "echo 'export PATH=/opt/yaourt/bin:\$PATH' > ${maindir}/root/etc/profile.d/${CMD}.sh" - sudo chmod +x ${maindir}/root/etc/profile.d/${CMD}.sh - info "Setting up the pacman keyring (this might take a while!)..." sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" @@ -604,9 +567,9 @@ function check_env(){ $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yaourt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- yaourt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- yaourt -V 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null @@ -623,9 +586,9 @@ function check_env(){ $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel - local yaourt_package=tcptraceroute - info "Installing ${yaourt_package} package from AUR repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f -- yaourt -A --noconfirm -S ${yaourt_package} + local aur_package=tcptraceroute + info "Installing ${aur_package} package from AUR repo using proot..." + JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package} $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost info "Removing the previous packages..." From 6d4e5f7404da996f0f80c45c588d52eae90e9575 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 9 Jun 2016 22:14:52 +0100 Subject: [PATCH 150/326] 5.6.9 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 349e9d0..1502747 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.8 +5.6.9 From 6568430add5e98187a34e0eefa8a45cdbb8b7bbc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 27 Nov 2016 12:49:09 +0000 Subject: [PATCH 151/326] Mitigate user missing from getent enumeration Sometimes `getent passwd` does not give the user information. This change tries to at least get the current user via `getent passwd $USER` since it uses a more reliable and faster system call (getpwnam(3)). Reference: https://github.com/Orochimarufan/junest/commit/be748493a362575273a016d79035b19b28371eea --- lib/core.sh | 8 +++++++- tests/unit-tests/test-core.sh | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/core.sh b/lib/core.sh index dc29c34..75e405c 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -420,11 +420,17 @@ function _provide_bindings_as_user(){ # None ####################################### function _build_passwd_and_group(){ - if ! getent_cmd passwd > ${JUNEST_HOME}/etc/junest/passwd + # Enumeration of users/groups is disabled/limited depending on how nsswitch.conf + # is configured. + # Try to at least get the current user via `getent passwd $USER` since it uses + # a more reliable and faster system call (getpwnam(3)). + if ! getent_cmd passwd > ${JUNEST_HOME}/etc/junest/passwd || \ + ! getent_cmd passwd ${USER} >> ${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." diff --git a/tests/unit-tests/test-core.sh b/tests/unit-tests/test-core.sh index a009510..1483d26 100755 --- a/tests/unit-tests/test-core.sh +++ b/tests/unit-tests/test-core.sh @@ -265,7 +265,7 @@ function test_build_passwd_and_group(){ echo $@ } GETENT=getent_cmd_mock assertCommandSuccess _build_passwd_and_group - assertEquals "passwd" "$(cat $JUNEST_HOME/etc/junest/passwd)" + assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/junest/passwd)" assertEquals "group" "$(cat $JUNEST_HOME/etc/junest/group)" } @@ -325,11 +325,11 @@ function test_delete_env(){ } function test_nested_env(){ - JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -ic "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" + JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" } function test_nested_env_not_set_variable(){ - JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -ic "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" + JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" } function test_qemu() { From d07b06b39d52c22a6cd436450cd600b88448384e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 21 Jan 2017 16:56:47 +0000 Subject: [PATCH 152/326] Substitute bindings with explicit copy of files --- bin/junest | 2 +- lib/core.sh | 72 ++++++++++++++++++++++++++--------- tests/unit-tests/test-core.sh | 60 ++++++++++++++--------------- 3 files changed, 84 insertions(+), 50 deletions(-) diff --git a/bin/junest b/bin/junest index 530a759..69d8f85 100755 --- a/bin/junest +++ b/bin/junest @@ -26,7 +26,7 @@ usage() { echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" echo -e "-r, --root Run $NAME with root privileges" - echo -e "-p, --proot-args Proot arguments (use '$CMD -p \"--help\"' to check out the proot options)" + echo -e "-p, --proot-args Proot arguments (use $CMD -p \"--help\" to check out the proot options)" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" diff --git a/lib/core.sh b/lib/core.sh index 75e405c..d4f1c65 100644 --- a/lib/core.sh +++ b/lib/core.sh @@ -58,7 +58,7 @@ then ARCH="arm" LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3" else - die "Unknown architecture ${ARCH}" + die "Unknown architecture ${HOST_ARCH}" fi MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030 @@ -344,7 +344,15 @@ function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - _run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" + _copy_common_files + + _provide_common_bindings + local bindings=${RESULT} + unset RESULT + + # An alternative is via -S option: + #_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" + _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}" } ####################################### @@ -366,15 +374,27 @@ 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" + # Files to bind are visible in `proot --help`. + # This function excludes /etc/mtab file so that + # it will not give conflicts with the related + # symlink in the Arch Linux image. + _copy_common_files + _copy_file /etc/hosts.equiv + _copy_file /etc/netgroup + _copy_file /etc/networks + # No need for localtime as it is setup during the image build + #_copy_file /etc/localtime + _copy_passwd_and_group + + _provide_common_bindings + local bindings=${RESULT} unset RESULT - _run_env_with_qemu "$bindings -r ${JUNEST_HOME} $1" "${@:2}" + + _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}" } ####################################### -# Provide the proot binding options for the normal user. +# Provide the proot common binding options for both normal user and fakeroot. # 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. @@ -389,10 +409,10 @@ function run_env_as_user(){ # Output: # None ####################################### -function _provide_bindings_as_user(){ +function _provide_common_bindings(){ RESULT="" 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" + for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" do if [[ $bind =~ $re ]] then @@ -401,6 +421,7 @@ function _provide_bindings_as_user(){ [ -e "$bind" ] && RESULT="-b $bind $RESULT" fi done + return 0 } ####################################### @@ -419,23 +440,38 @@ function _provide_bindings_as_user(){ # Output: # None ####################################### -function _build_passwd_and_group(){ +function _copy_passwd_and_group(){ # Enumeration of users/groups is disabled/limited depending on how nsswitch.conf # is configured. # Try to at least get the current user via `getent passwd $USER` since it uses # a more reliable and faster system call (getpwnam(3)). - if ! getent_cmd passwd > ${JUNEST_HOME}/etc/junest/passwd || \ - ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/junest/passwd + if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \ + ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd then warn "getent command failed or does not exist. Binding directly from /etc/passwd." - cp_cmd /etc/passwd ${JUNEST_HOME}/etc/junest/passwd + _copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd fi - if ! getent_cmd group > ${JUNEST_HOME}/etc/junest/group + if ! getent_cmd group > ${JUNEST_HOME}/etc/group then warn "getent command failed or does not exist. Binding directly from /etc/group." - cp_cmd /etc/group ${JUNEST_HOME}/etc/junest/group + _copy_file /etc/group ${JUNEST_HOME}/etc/group fi + return 0 +} + +function _copy_file() { + local file="${1}" + [[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file" + return 0 +} + +function _copy_common_files() { + _copy_file /etc/host.conf + _copy_file /etc/hosts + _copy_file /etc/nsswitch.conf + _copy_file /etc/resolv.conf + return 0 } ####################################### @@ -471,7 +507,6 @@ function delete_env(){ fi } - function _check_package(){ if ! pacman -Qq $1 > /dev/null then @@ -514,7 +549,8 @@ function build_image_env(){ # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils # yaourt requires sed - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed + # localedef (called by locale-gen) requires gzip + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" sudo mkdir -p ${maindir}/root/run/lock @@ -533,7 +569,7 @@ function build_image_env(){ sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen - sudo bash -c "echo 'LANG=\"en_US.UTF-8\"' >> ${maindir}/root/etc/locale.conf" + sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" info "Setting up the pacman keyring (this might take a while!)..." sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ diff --git a/tests/unit-tests/test-core.sh b/tests/unit-tests/test-core.sh index 1483d26..78e5009 100755 --- a/tests/unit-tests/test-core.sh +++ b/tests/unit-tests/test-core.sh @@ -233,52 +233,46 @@ function test_run_env_as_user(){ echo $@ } assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" - _provide_bindings_as_user - assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_user "-k 3.10" - _provide_bindings_as_user - assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" -} + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -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 $? -} + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" -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" + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" + + [[ -e /etc/passwd ]] assertEquals 0 $? - echo "$RESULT" | grep -q "$JUNEST_HOME/etc/junest/group" + [[ -e /etc/group ]] assertEquals 0 $? + } -function test_build_passwd_and_group(){ +function test_copy_passwd_and_group(){ getent_cmd_mock() { echo $@ } - GETENT=getent_cmd_mock assertCommandSuccess _build_passwd_and_group - assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/junest/passwd)" - assertEquals "group" "$(cat $JUNEST_HOME/etc/junest/group)" + GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group + assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)" + assertEquals "group" "$(cat $JUNEST_HOME/etc/group)" } -function test_build_passwd_and_group_fallback(){ +function test_copy_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)" + CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group + assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/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_copy_passwd_and_group_failure(){ + CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group } function test_run_env_as_fakeroot(){ @@ -286,11 +280,16 @@ function test_run_env_as_fakeroot(){ echo $@ } assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-S ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_fakeroot "-k 3.10" - assertEquals "-S ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" } function test_run_env_with_quotes(){ @@ -298,8 +297,7 @@ function test_run_env_with_quotes(){ echo $@ } assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" - _provide_bindings_as_user - assertEquals "${RESULT}-r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" } function test_run_env_with_proot_args(){ From 978ab8d408041e7e775380eddc54cd8f41e09903 Mon Sep 17 00:00:00 2001 From: Christian Friesicke Date: Sat, 11 Mar 2017 17:33:22 +0100 Subject: [PATCH 153/326] :memo: Recommend kernel version 2.6.32 Reasoning: the pre-compiled binaries that are downloaded by JuNest during installation as well as binaries that are available from the Arch repositories are compiled for Linux kernel 2.6.32. Therefore, with kernel version 2.6.32 on the host OS no warnings, errors, or unexpected crashes due to kernel version incompatibilities should be expected. The recommended kernel version is now mentioned in the "Dependencies" section of the README. In the "Troubleshooting" section about "Kernel too old", more specific information about the problem and the workaround using PRoot -k option is added. Resolves: #172 --- README.md | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index da14441..2eea0a0 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,12 @@ Before installing JuNest be sure that all dependencies are properly installed in - [bash (>=4.0)](https://www.gnu.org/software/bash/) - [GNU coreutils](https://www.gnu.org/software/coreutils/) -The minimum recommended Linux kernel is 2.6.0+ on x86 32 and 64 bit and ARM architectures. +The minimum recommended Linux kernel of the host OS is 2.6.32 on x86 (32-bit +and 64 bit) and ARM architectures. It is still possible to run JuNest on lower +2.6.x host OS kernels but errors may appear, and some applications may +crash. For further information, read the [Troubleshooting](#troubleshooting) +section below. + ## Method one (Recommended) ## Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): @@ -244,22 +249,32 @@ Troubleshooting > **Q**: Why do I get the error: "FATAL: kernel too old"? -> **A**: This is because the executable from the precompiled package cannot -> properly run if the kernel is old. -> You may need to specify the PRoot *-k* option if the guest rootfs -> requires a newer kernel version: +> **A**: This is because the binaries from the precompiled package are +> compiled for Linux kernel 2.6.32. When JuNest is started without further +> options, it tries to run a shell from the JuNest chroot. The system sees that +> the host OS kernel is too old and refuses to start the shell. + +> The solution is to present a higher "fake" kernel version to the JuNest +> chroot. PRoot offers the *-k* option for this, and JuNest passes this option +> on to PRoot when *-p* is prepended. For example, to fake a kernel version of +> 3.10, issue the following command: $> junest -p "-k 3.10" -> In order to check if an executable inside JuNest environment can be compatible -> with the kernel of the host OS just use the *file* command, for instance: +> As Arch Linux ships binaries for kernel version 2.6.32, the above error is +> not unique to the precompiled package from JuNest. It will also appear when +> trying to run binaries that were later installed in the JuNest chroot with +> the `pacman` command. + +> In order to check if an executable inside JuNest chroot is compatible with +> the kernel of the host OS just use the `file` command, for instance: $> file ~/.junest/usr/bin/bash ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=ec37e49e7188ff4030052783e61b859113e18ca6, stripped -> From the output you can see what is the minimum recommended Linux kernel version. +> The output shows the minimum recommended Linux kernel version. ## SUID permissions ## > **Q**: Why I do not have permissions for ping? From bee9e2df54d2003b73a2274ab887eb079731cc16 Mon Sep 17 00:00:00 2001 From: Christian Friesicke Date: Sat, 11 Mar 2017 17:45:54 +0100 Subject: [PATCH 154/326] :memo: Add Q&A entry about private futex warning Since this problem can be pin-pointed to kernel versions that are older than 2.6.22, a Q&A entry separate from the more general "Kernel too old" problem may be justified. This Q&A entry discusses the origin of the problem, some of the symptoms (no symptoms for "simple" programs like vim, but warnings and crashes for others), and concludes with a remark about possible (but complicated) workarounds. --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 2eea0a0..98f0c9e 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,34 @@ Troubleshooting > The output shows the minimum recommended Linux kernel version. +## Kernel doesn't support private futexes ## + +> **Q**: Why do I get the warning: "kompat: this kernel doesn't support private +> futexes and PRoot can't emulate them."? + +> **A**: This happens on older host OS kernels when the trick of showing a fake +> kernel version to the JuNest chroot is applied (see above: +> [Kernel too old](#kernel-too-old)). + +> The consequence of showing a fake kernel version to the JuNest chroot is that +> in the background, PRoot needs to translate requests from applications in the +> chroot to the old kernel of the host OS. Some of the newer kernel +> functionality can be emulated, but private futexes cannot be translated. + +> Private Futexes were introduced in Linux kernel 2.6.22. Therefore, the above +> problem likely appears on old Linux systems, for example RHEL5 systems, which +> are based on Linux kernel 2.6.18. Many of the core tools like `which`, `man`, +> or `vim` run without problems while others, especially XOrg-based programs, +> are more likely to show the warning. These are also more likely to crash +> unexpectedly. + +> Currently, there is no (easy) workaround for this. In order to be fully +> compatible with kernels below 2.6.22, both the precompiled package from +> JuNest and all software that is installed later needs to be compiled for this +> kernel. Most likely this can only be achieved by building the needed software +> packages from source, which kind of contradicts JuNest's distro-in-a-distro +> philosophy. + ## SUID permissions ## > **Q**: Why I do not have permissions for ping? From ddc7ede70a7dbb9b7daac092f1b4b19aaccf9d54 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 11 Mar 2017 17:57:34 +0000 Subject: [PATCH 155/326] Issue #174: :art: Change structure of core modules This change separate different parts of the code into several categories: `chroot`, `proot`, `build`, `common`, `setup`. This should simplify the maintenance of the code and will help introducing the user namespace module in a easier way. --- .travis.yml | 3 +- bin/junest | 14 +- lib/core.sh | 639 ---------------------------- lib/core/build.sh | 140 ++++++ lib/core/chroot.sh | 45 ++ lib/core/common.sh | 226 ++++++++++ lib/core/proot.sh | 109 +++++ lib/core/setup.sh | 157 +++++++ lib/{ => utils}/utils.sh | 0 tests/checkstyle/checkstyle.sh | 21 + tests/unit-tests/test-chroot.sh | 52 +++ tests/unit-tests/test-cli.sh | 4 +- tests/unit-tests/test-common.sh | 171 ++++++++ tests/unit-tests/test-core.sh | 349 --------------- tests/unit-tests/test-proot.sh | 114 +++++ tests/unit-tests/test-setup.sh | 81 ++++ tests/unit-tests/test-utils.sh | 6 +- tests/unit-tests/utils.sh | 32 -- tests/{unit-tests => utils}/shunit2 | 0 tests/utils/utils.sh | 57 +++ 20 files changed, 1189 insertions(+), 1031 deletions(-) delete mode 100644 lib/core.sh create mode 100644 lib/core/build.sh create mode 100644 lib/core/chroot.sh create mode 100644 lib/core/common.sh create mode 100644 lib/core/proot.sh create mode 100644 lib/core/setup.sh rename lib/{ => utils}/utils.sh (100%) create mode 100755 tests/checkstyle/checkstyle.sh create mode 100755 tests/unit-tests/test-chroot.sh create mode 100755 tests/unit-tests/test-common.sh delete mode 100755 tests/unit-tests/test-core.sh create mode 100755 tests/unit-tests/test-proot.sh create mode 100755 tests/unit-tests/test-setup.sh delete mode 100644 tests/unit-tests/utils.sh rename tests/{unit-tests => utils}/shunit2 (100%) create mode 100644 tests/utils/utils.sh diff --git a/.travis.yml b/.travis.yml index e43ddc3..a1b6078 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,8 @@ install: script: - bash --version - - ./tests/unit-tests/unit-tests.sh + - bash ./tests/unit-tests/unit-tests.sh + - bash ./tests/checkstyle/checkstyle.sh - junest --check ./bin/junest - yes | junest --delete - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests diff --git a/bin/junest b/bin/junest index 69d8f85..836c19b 100755 --- a/bin/junest +++ b/bin/junest @@ -5,8 +5,12 @@ JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" -source "${JUNEST_BASE}/lib/utils.sh" -source "${JUNEST_BASE}/lib/core.sh" +source "${JUNEST_BASE}/lib/utils/utils.sh" +source "${JUNEST_BASE}/lib/core/common.sh" +source "${JUNEST_BASE}/lib/core/build.sh" +source "${JUNEST_BASE}/lib/core/setup.sh" +source "${JUNEST_BASE}/lib/core/proot.sh" +source "${JUNEST_BASE}/lib/core/chroot.sh" ################################### ### General functions ### @@ -19,7 +23,7 @@ usage() { echo echo -e "Setup options:" echo -e "-i, --setup-from-file Setup the $NAME image in ${JUNEST_HOME}" - echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)." + echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)" echo -e " Defaults to the host architecture ($ARCH)" echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" echo @@ -32,8 +36,8 @@ usage() { echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}" - echo -e " using ${CMD}_script. This will alterate the environment." - echo -e "-s, --skip-root-tests Skip the root tests during the validation process." + echo -e " using ${CMD}_script. This will alterate the environment" + echo -e "-s, --skip-root-tests Skip the root tests during the validation process" echo echo -e "General options:" echo -e "-h, --help Show this help message" diff --git a/lib/core.sh b/lib/core.sh deleted file mode 100644 index d4f1c65..0000000 --- a/lib/core.sh +++ /dev/null @@ -1,639 +0,0 @@ -#!/usr/bin/env bash -# -# This module contains all core functionalities for JuNest. -# -# Dependencies: -# - lib/utils.sh -# -# vim: ft=sh - -set -e - -NAME='JuNest' -CMD='junest' -DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' - -NOT_AVAILABLE_ARCH=102 -NOT_EXISTING_FILE=103 -ARCHITECTURE_MISMATCH=104 -ROOT_ACCESS_ERROR=105 -NESTED_ENVIRONMENT=106 -VARIABLE_NOT_SET=107 - -if [ "$JUNEST_ENV" == "1" ] -then - die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" -elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] -then - die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" -fi - -[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} -[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest -if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] -then - JUNEST_TEMPDIR=/tmp -fi - -# The update of the variable PATH ensures that the executables are -# found on different locations -PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH - -# The executable uname is essential in order to get the architecture -# of the host system, so a fallback mechanism cannot be used for it. -UNAME=uname - -ARCH_LIST=('x86_64' 'x86' 'arm') -HOST_ARCH=$($UNAME -m) -if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] -then - ARCH="x86" - LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2" -elif [ $HOST_ARCH == "x86_64" ] -then - ARCH="x86_64" - LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2" -elif [[ $HOST_ARCH =~ .*(arm).* ]] -then - ARCH="arm" - LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3" -else - die "Unknown architecture ${HOST_ARCH}" -fi - -MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030 -ENV_REPO=${MAIN_REPO}/${CMD} -DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' - -ORIGIN_WD=$(pwd) - -################################ EXECUTABLES ################################## -# This section contains all the executables needed for JuNest to run properly. -# They are based on a fallback mechanism that tries to use the executable in -# different locations in the host OS. - -# List of executables that are run inside JuNest: -SH=("/bin/sh" "--login") - -# List of executables that are run in the host OS: -PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" -CHROOT=${JUNEST_BASE}/bin/jchroot -CLASSIC_CHROOT="chroot" -WGET="wget --no-check-certificate" -CURL="curl -L -J -O -k" -TAR=tar -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" - -# The following functions attempt first to run the executable in the host OS. -# As a last hope they try to run the same executable available in the JuNest -# image. - -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 $@ -} - -function chown_cmd(){ - $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@ -} - -function mkdir_cmd(){ - $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ -} - -function proot_cmd(){ - local proot_args="$1" - shift - if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" - then - ${PROOT} ${proot_args} "${@}" - elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" - then - PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" - else - die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" - fi -} - -function download_cmd(){ - $WGET $@ || $CURL $@ -} - -function chroot_cmd(){ - $CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@" -} - -################################# MAIN FUNCTIONS ############################## - -####################################### -# Check if the JuNest system is installed in JUNEST_HOME. -# -# Globals: -# JUNEST_HOME (RO) : Contains the JuNest home directory. -# Arguments: -# None -# Returns: -# 0 : If JuNest is installed -# 1 : If JuNest is not installed -# Output: -# None -####################################### -function is_env_installed(){ - [ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0 - return 1 -} - - -function _cleanup_build_directory(){ - local maindir=$1 - check_not_null "$maindir" - builtin cd $ORIGIN_WD - trap - QUIT EXIT ABRT KILL TERM INT - rm_cmd -fr "$maindir" -} - - -function _prepare_build_directory(){ - local maindir=$1 - check_not_null "$maindir" - trap - QUIT EXIT ABRT KILL TERM INT - trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT -} - - -function _setup_env(){ - local imagepath=$1 - check_not_null "$imagepath" - - is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME" - - mkdir_cmd -p "${JUNEST_HOME}" - $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} - info "The default mirror URL is ${DEFAULT_MIRROR}." - info "Remember to refresh the package databases from the server:" - info " pacman -Syy" - info "${NAME} installed successfully" -} - - -####################################### -# Setup JuNest. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs -# to be installed. -# ARCH (RO) : The host architecture. -# JUNEST_TEMPDIR (RO) : The JuNest temporary directory for building -# the JuNest system from the image. -# ENV_REPO (RO) : URL of the site containing JuNest images. -# NAME (RO) : The JuNest name. -# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. -# Arguments: -# arch ($1?) : The JuNest architecture image to download. -# Defaults to the host architecture -# Returns: -# $NOT_AVAILABLE_ARCH : If the architecture is not one of the available ones. -# Output: -# None -####################################### -function setup_env(){ - local arch=${1:-$ARCH} - contains_element $arch "${ARCH_LIST[@]}" || \ - die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}" - - local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) - _prepare_build_directory $maindir - - info "Downloading ${NAME}..." - builtin cd ${maindir} - local imagefile=${CMD}-${arch}.tar.gz - download_cmd ${ENV_REPO}/${imagefile} - - info "Installing ${NAME}..." - _setup_env ${maindir}/${imagefile} - - _cleanup_build_directory ${maindir} -} - -####################################### -# Setup JuNest from file. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs -# to be installed. -# NAME (RO) : The JuNest name. -# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. -# Arguments: -# imagefile ($1) : The JuNest image file. -# Returns: -# $NOT_EXISTING_FILE : If the image file does not exist. -# Output: -# None -####################################### -function setup_env_from_file(){ - local imagefile=$1 - check_not_null "$imagefile" - [ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist" - - info "Installing ${NAME} from ${imagefile}..." - _setup_env ${imagefile} -} - -####################################### -# Run JuNest as real root. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# 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. -# Arguments: -# cmd ($@?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Output: -# - : The command output. -####################################### -function run_env_as_root(){ - source ${JUNEST_HOME}/etc/junest/info - [ "$JUNEST_ARCH" != "$ARCH" ] && \ - die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" - - local uid=$UID - # 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 "$@")" - - # With chown the ownership of the files is assigned to the real user - trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT - - JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" -} - -function _run_env_with_proot(){ - local proot_args="$1" - shift - - if [ "$1" != "" ] - then - JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" - else - JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" - fi -} - -function _run_env_with_qemu(){ - local proot_args="$1" - source ${JUNEST_HOME}/etc/junest/info - - if [ "$JUNEST_ARCH" != "$ARCH" ] - then - local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH" - local qemu_symlink="/tmp/${qemu_bin}-$RANDOM" - trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT - - warn "Emulating $NAME via QEMU..." - [ -e ${qemu_symlink} ] || \ - ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink} - proot_args="-q ${qemu_symlink} $proot_args" - fi - shift - _run_env_with_proot "$proot_args" "${@}" -} - -####################################### -# Run JuNest as fakeroot. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# EUID (RO) : The user ID. -# SH (RO) : Contains the default command to run in JuNest. -# Arguments: -# cmd ($@?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# $ROOT_ACCESS_ERROR : If the user is the real root. -# Output: -# - : The command output. -####################################### -function run_env_as_fakeroot(){ - (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - - _copy_common_files - - _provide_common_bindings - local bindings=${RESULT} - unset RESULT - - # An alternative is via -S option: - #_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" - _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}" -} - -####################################### -# Run JuNest as normal user. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# EUID (RO) : The user ID. -# SH (RO) : Contains the default command to run in JuNest. -# Arguments: -# cmd ($@?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# $ROOT_ACCESS_ERROR : If the user is the real root. -# Output: -# - : The command output. -####################################### -function run_env_as_user(){ - (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - - # Files to bind are visible in `proot --help`. - # This function excludes /etc/mtab file so that - # it will not give conflicts with the related - # symlink in the Arch Linux image. - _copy_common_files - _copy_file /etc/hosts.equiv - _copy_file /etc/netgroup - _copy_file /etc/networks - # No need for localtime as it is setup during the image build - #_copy_file /etc/localtime - _copy_passwd_and_group - - _provide_common_bindings - local bindings=${RESULT} - unset RESULT - - _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}" -} - -####################################### -# Provide the proot common binding options for both normal user and fakeroot. -# 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. -# RESULT (WO) : Contains the binding options. -# Arguments: -# None -# Returns: -# None -# Output: -# None -####################################### -function _provide_common_bindings(){ - RESULT="" - local re='(.*):.*' - for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" - do - if [[ $bind =~ $re ]] - then - [ -e "${BASH_REMATCH[1]}" ] && RESULT="-b $bind $RESULT" - else - [ -e "$bind" ] && RESULT="-b $bind $RESULT" - fi - done - return 0 -} - -####################################### -# 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 _copy_passwd_and_group(){ - # Enumeration of users/groups is disabled/limited depending on how nsswitch.conf - # is configured. - # Try to at least get the current user via `getent passwd $USER` since it uses - # a more reliable and faster system call (getpwnam(3)). - if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \ - ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd - then - warn "getent command failed or does not exist. Binding directly from /etc/passwd." - _copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd - fi - - if ! getent_cmd group > ${JUNEST_HOME}/etc/group - then - warn "getent command failed or does not exist. Binding directly from /etc/group." - _copy_file /etc/group ${JUNEST_HOME}/etc/group - fi - return 0 -} - -function _copy_file() { - local file="${1}" - [[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file" - return 0 -} - -function _copy_common_files() { - _copy_file /etc/host.conf - _copy_file /etc/hosts - _copy_file /etc/nsswitch.conf - _copy_file /etc/resolv.conf - return 0 -} - -####################################### -# Remove an existing JuNest system. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory to remove. -# Arguments: -# None -# Returns: -# None -# Output: -# None -####################################### -function delete_env(){ - ! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return - if mountpoint -q ${JUNEST_HOME} - then - info "There are mounted directories inside ${JUNEST_HOME}" - if ! umount --force ${JUNEST_HOME} - then - error "Cannot umount directories in ${JUNEST_HOME}" - die "Try to delete ${NAME} using root permissions" - fi - fi - # the CA directories are read only and can be deleted only by changing the mod - chmod -R +w ${JUNEST_HOME}/etc/ca-certificates - if rm_cmd -rf ${JUNEST_HOME}/* - then - info "${NAME} deleted in ${JUNEST_HOME}" - else - error "Error: Cannot delete ${NAME} in ${JUNEST_HOME}" - fi -} - -function _check_package(){ - if ! pacman -Qq $1 > /dev/null - then - die "Package $1 must be installed" - fi -} - -function _install_from_aur(){ - local maindir=$1 - local pkgname=$2 - local installname=$3 - mkdir -p ${maindir}/packages/${pkgname} - builtin cd ${maindir}/packages/${pkgname} - $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" - [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" - makepkg -sfc - sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz -} - -function build_image_env(){ - umask 022 - - # The function must runs on ArchLinux with non-root privileges. - (( EUID == 0 )) && \ - die "You cannot build with root privileges." - - _check_package arch-install-scripts - _check_package gcc - _check_package package-query - _check_package git - - local disable_validation=$1 - local skip_root_tests=$2 - - local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) - sudo mkdir -p ${maindir}/root - trap - QUIT EXIT ABRT KILL TERM INT - trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT - info "Installing pacman and its dependencies..." - # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux - # All the essential executables (ln, mkdir, chown, etc) are in coreutils - # yaourt requires sed - # localedef (called by locale-gen) requires gzip - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip - sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" - sudo mkdir -p ${maindir}/root/run/lock - - # AUR packages requires non-root user to be compiled. proot fakes the user to 10 - info "Compiling and installing yaourt..." - _install_from_aur ${maindir} "package-query" - _install_from_aur ${maindir} "yaourt" - - info "Install ${NAME} script..." - sudo pacman --noconfirm --root ${maindir}/root -S git - _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" - sudo pacman --noconfirm --root ${maindir}/root -Rsn git - - info "Generating the locales..." - # sed command is required for locale-gen - sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime - sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen - sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" - - info "Setting up the pacman keyring (this might take a while!)..." - sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ - "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" - - sudo rm ${maindir}/root/var/cache/pacman/pkg/* - - mkdir -p ${maindir}/output - builtin cd ${maindir}/output - local imagefile="${CMD}-${ARCH}.tar.gz" - info "Compressing image to ${imagefile}..." - sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . - - if ! $disable_validation - then - mkdir -p ${maindir}/root_test - $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests - fi - - sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} - - builtin cd ${ORIGIN_WD} - trap - QUIT EXIT ABRT KILL TERM INT - sudo rm -fr "$maindir" -} - -function check_env(){ - local testdir=$1 - local cmd=$2 - local skip_root_tests=$3 - info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." - echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy - - # Check most basic executables work - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null - - local repo_package=tree - info "Installing ${repo_package} package from official repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} ${cmd} tree - JUNEST_HOME=${testdir} ${cmd} -f tree - - local repo_package=iftop - info "Installing ${repo_package} package from official repo using root..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 - - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel - local aur_package=tcptraceroute - info "Installing ${aur_package} package from AUR repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package} - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost - - info "Removing the previous packages..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop - -} diff --git a/lib/core/build.sh b/lib/core/build.sh new file mode 100644 index 0000000..017ccad --- /dev/null +++ b/lib/core/build.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +# +# This module contains all build functionalities for JuNest. +# +# Dependencies: +# - lib/utils/utils.sh +# - lib/core/common.sh +# +# vim: ft=sh + +function _check_package(){ + if ! pacman -Qq $1 > /dev/null + then + die "Package $1 must be installed" + fi +} + +function _install_from_aur(){ + local maindir=$1 + local pkgname=$2 + local installname=$3 + mkdir -p ${maindir}/packages/${pkgname} + builtin cd ${maindir}/packages/${pkgname} + $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" + [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" + makepkg -sfc + sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz +} + +function build_image_env(){ + umask 022 + + # The function must runs on ArchLinux with non-root privileges. + (( EUID == 0 )) && \ + die "You cannot build with root privileges." + + _check_package arch-install-scripts + _check_package gcc + _check_package package-query + _check_package git + + local disable_validation=$1 + local skip_root_tests=$2 + + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + sudo mkdir -p ${maindir}/root + trap - QUIT EXIT ABRT KILL TERM INT + trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT + info "Installing pacman and its dependencies..." + # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux + # All the essential executables (ln, mkdir, chown, etc) are in coreutils + # yaourt requires sed + # localedef (called by locale-gen) requires gzip + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip + sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" + sudo mkdir -p ${maindir}/root/run/lock + + # AUR packages requires non-root user to be compiled. proot fakes the user to 10 + info "Compiling and installing yaourt..." + _install_from_aur ${maindir} "package-query" + _install_from_aur ${maindir} "yaourt" + + info "Install ${NAME} script..." + sudo pacman --noconfirm --root ${maindir}/root -S git + _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + sudo pacman --noconfirm --root ${maindir}/root -Rsn git + + info "Generating the locales..." + # sed command is required for locale-gen + sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime + sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" + sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen + sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" + + info "Setting up the pacman keyring (this might take a while!)..." + sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ + "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" + + sudo rm ${maindir}/root/var/cache/pacman/pkg/* + + mkdir -p ${maindir}/output + builtin cd ${maindir}/output + local imagefile="${CMD}-${ARCH}.tar.gz" + info "Compressing image to ${imagefile}..." + sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . + + if ! $disable_validation + then + mkdir -p ${maindir}/root_test + $TAR -zxpf ${imagefile} -C "${maindir}/root_test" + check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests + fi + + sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} + + builtin cd ${ORIGIN_WD} + trap - QUIT EXIT ABRT KILL TERM INT + sudo rm -fr "$maindir" +} + +function check_env(){ + local testdir=$1 + local cmd=$2 + local skip_root_tests=$3 + info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." + echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy + + # Check most basic executables work + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null + + local repo_package=tree + info "Installing ${repo_package} package from official repo using proot..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} + JUNEST_HOME=${testdir} ${cmd} tree + JUNEST_HOME=${testdir} ${cmd} -f tree + + local repo_package=iftop + info "Installing ${repo_package} package from official repo using root..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 + + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel + local aur_package=tcptraceroute + info "Installing ${aur_package} package from AUR repo using proot..." + JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package} + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost + + info "Removing the previous packages..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop + +} diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh new file mode 100644 index 0000000..ff8465d --- /dev/null +++ b/lib/core/chroot.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# This module contains all chroot functionalities for JuNest. +# +# Dependencies: +# - lib/utils/utils.sh +# - lib/core/common.sh +# +# vim: ft=sh + +####################################### +# Run JuNest as real root. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# 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. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### +function run_env_as_root(){ + source ${JUNEST_HOME}/etc/junest/info + [ "$JUNEST_ARCH" != "$ARCH" ] && \ + die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" + + local uid=$UID + # 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 "$@")" + + # With chown the ownership of the files is assigned to the real user + trap - QUIT EXIT ABRT KILL TERM INT + trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT + + JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" +} diff --git a/lib/core/common.sh b/lib/core/common.sh new file mode 100644 index 0000000..f477444 --- /dev/null +++ b/lib/core/common.sh @@ -0,0 +1,226 @@ +#!/usr/bin/env bash +# +# This module contains all common functionalities for JuNest. +# +# Dependencies: +# - lib/utils/utils.sh +# +# vim: ft=sh + +set -e + +NAME='JuNest' +CMD='junest' +DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' + +NOT_AVAILABLE_ARCH=102 +NOT_EXISTING_FILE=103 +ARCHITECTURE_MISMATCH=104 +ROOT_ACCESS_ERROR=105 +NESTED_ENVIRONMENT=106 +VARIABLE_NOT_SET=107 + +if [ "$JUNEST_ENV" == "1" ] +then + die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" +elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] +then + die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" +fi + +[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} +[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest +if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] +then + JUNEST_TEMPDIR=/tmp +fi + +# The update of the variable PATH ensures that the executables are +# found on different locations +PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH + +# The executable uname is essential in order to get the architecture +# of the host system, so a fallback mechanism cannot be used for it. +UNAME=uname + +ARCH_LIST=('x86_64' 'x86' 'arm') +HOST_ARCH=$($UNAME -m) +if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] +then + ARCH="x86" + LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2" +elif [ $HOST_ARCH == "x86_64" ] +then + ARCH="x86_64" + LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2" +elif [[ $HOST_ARCH =~ .*(arm).* ]] +then + ARCH="arm" + LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3" +else + die "Unknown architecture ${HOST_ARCH}" +fi + +MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030 +ENV_REPO=${MAIN_REPO}/${CMD} +DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' + +ORIGIN_WD=$(pwd) + +################## EXECUTABLES ################ + +# This section contains all the executables needed for JuNest to run properly. +# They are based on a fallback mechanism that tries to use the executable in +# different locations in the host OS. + +# List of executables that are run inside JuNest: +SH=("/bin/sh" "--login") + +# List of executables that are run in the host OS: +PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" +CHROOT=${JUNEST_BASE}/bin/jchroot +CLASSIC_CHROOT="chroot" +WGET="wget --no-check-certificate" +CURL="curl -L -J -O -k" +TAR=tar +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" + +# The following functions attempt first to run the executable in the host OS. +# As a last hope they try to run the same executable available in the JuNest +# image. + +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 $@ +} + +function chown_cmd(){ + $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@ +} + +function mkdir_cmd(){ + $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ +} + +function proot_cmd(){ + local proot_args="$1" + shift + if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" + then + ${PROOT} ${proot_args} "${@}" + elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" + then + PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" + else + die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" + fi +} + +function download_cmd(){ + $WGET $@ || $CURL $@ +} + +function chroot_cmd(){ + $CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@" +} + +############## COMMON FUNCTIONS ############### + +####################################### +# Provide the proot common binding options for both normal user and fakeroot. +# 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. +# RESULT (WO) : Contains the binding options. +# Arguments: +# None +# Returns: +# None +# Output: +# None +####################################### +function _provide_common_bindings(){ + RESULT="" + local re='(.*):.*' + for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" + do + if [[ $bind =~ $re ]] + then + [ -e "${BASH_REMATCH[1]}" ] && RESULT="-b $bind $RESULT" + else + [ -e "$bind" ] && RESULT="-b $bind $RESULT" + fi + done + return 0 +} + +####################################### +# 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 _copy_passwd_and_group(){ + # Enumeration of users/groups is disabled/limited depending on how nsswitch.conf + # is configured. + # Try to at least get the current user via `getent passwd $USER` since it uses + # a more reliable and faster system call (getpwnam(3)). + if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \ + ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd + then + warn "getent command failed or does not exist. Binding directly from /etc/passwd." + _copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd + fi + + if ! getent_cmd group > ${JUNEST_HOME}/etc/group + then + warn "getent command failed or does not exist. Binding directly from /etc/group." + _copy_file /etc/group ${JUNEST_HOME}/etc/group + fi + return 0 +} + +function _copy_file() { + local file="${1}" + [[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file" + return 0 +} + +function _copy_common_files() { + _copy_file /etc/host.conf + _copy_file /etc/hosts + _copy_file /etc/nsswitch.conf + _copy_file /etc/resolv.conf + return 0 +} diff --git a/lib/core/proot.sh b/lib/core/proot.sh new file mode 100644 index 0000000..39d901c --- /dev/null +++ b/lib/core/proot.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# +# This module contains all proot functionalities for JuNest. +# +# Dependencies: +# - lib/utils/utils.sh +# - lib/core/common.sh +# +# vim: ft=sh + +function _run_env_with_proot(){ + local proot_args="$1" + shift + + if [ "$1" != "" ] + then + JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + else + JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" + fi +} + +function _run_env_with_qemu(){ + local proot_args="$1" + source ${JUNEST_HOME}/etc/junest/info + + if [ "$JUNEST_ARCH" != "$ARCH" ] + then + local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH" + local qemu_symlink="/tmp/${qemu_bin}-$RANDOM" + trap - QUIT EXIT ABRT KILL TERM INT + trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT + + warn "Emulating $NAME via QEMU..." + [ -e ${qemu_symlink} ] || \ + ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink} + proot_args="-q ${qemu_symlink} $proot_args" + fi + shift + _run_env_with_proot "$proot_args" "${@}" +} + +####################################### +# Run JuNest as fakeroot. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# EUID (RO) : The user ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ROOT_ACCESS_ERROR : If the user is the real root. +# Output: +# - : The command output. +####################################### +function run_env_as_fakeroot(){ + (( EUID == 0 )) && \ + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + + _copy_common_files + + _provide_common_bindings + local bindings=${RESULT} + unset RESULT + + # An alternative is via -S option: + #_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" + _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}" +} + +####################################### +# Run JuNest as normal user. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# EUID (RO) : The user ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ROOT_ACCESS_ERROR : If the user is the real root. +# Output: +# - : The command output. +####################################### +function run_env_as_user(){ + (( EUID == 0 )) && \ + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + + # Files to bind are visible in `proot --help`. + # This function excludes /etc/mtab file so that + # it will not give conflicts with the related + # symlink in the Arch Linux image. + _copy_common_files + _copy_file /etc/hosts.equiv + _copy_file /etc/netgroup + _copy_file /etc/networks + # No need for localtime as it is setup during the image build + #_copy_file /etc/localtime + _copy_passwd_and_group + + _provide_common_bindings + local bindings=${RESULT} + unset RESULT + + _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}" +} diff --git a/lib/core/setup.sh b/lib/core/setup.sh new file mode 100644 index 0000000..f55780b --- /dev/null +++ b/lib/core/setup.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash +# +# This module contains all setup functionalities for JuNest. +# +# Dependencies: +# - lib/utils/utils.sh +# - lib/core/common.sh +# +# vim: ft=sh + +####################################### +# Check if the JuNest system is installed in JUNEST_HOME. +# +# Globals: +# JUNEST_HOME (RO) : Contains the JuNest home directory. +# Arguments: +# None +# Returns: +# 0 : If JuNest is installed +# 1 : If JuNest is not installed +# Output: +# None +####################################### +function is_env_installed(){ + [ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0 + return 1 +} + + +function _cleanup_build_directory(){ + local maindir=$1 + check_not_null "$maindir" + builtin cd $ORIGIN_WD + trap - QUIT EXIT ABRT KILL TERM INT + rm_cmd -fr "$maindir" +} + + +function _prepare_build_directory(){ + local maindir=$1 + check_not_null "$maindir" + trap - QUIT EXIT ABRT KILL TERM INT + trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT +} + + +function _setup_env(){ + local imagepath=$1 + check_not_null "$imagepath" + + is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME" + + mkdir_cmd -p "${JUNEST_HOME}" + $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} + info "The default mirror URL is ${DEFAULT_MIRROR}." + info "Remember to refresh the package databases from the server:" + info " pacman -Syy" + info "${NAME} installed successfully" +} + + +####################################### +# Setup JuNest. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs +# to be installed. +# ARCH (RO) : The host architecture. +# JUNEST_TEMPDIR (RO) : The JuNest temporary directory for building +# the JuNest system from the image. +# ENV_REPO (RO) : URL of the site containing JuNest images. +# NAME (RO) : The JuNest name. +# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. +# Arguments: +# arch ($1?) : The JuNest architecture image to download. +# Defaults to the host architecture +# Returns: +# $NOT_AVAILABLE_ARCH : If the architecture is not one of the available ones. +# Output: +# None +####################################### +function setup_env(){ + local arch=${1:-$ARCH} + contains_element $arch "${ARCH_LIST[@]}" || \ + die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}" + + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + _prepare_build_directory $maindir + + info "Downloading ${NAME}..." + builtin cd ${maindir} + local imagefile=${CMD}-${arch}.tar.gz + download_cmd ${ENV_REPO}/${imagefile} + + info "Installing ${NAME}..." + _setup_env ${maindir}/${imagefile} + + _cleanup_build_directory ${maindir} +} + +####################################### +# Setup JuNest from file. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs +# to be installed. +# NAME (RO) : The JuNest name. +# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. +# Arguments: +# imagefile ($1) : The JuNest image file. +# Returns: +# $NOT_EXISTING_FILE : If the image file does not exist. +# Output: +# None +####################################### +function setup_env_from_file(){ + local imagefile=$1 + check_not_null "$imagefile" + [ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist" + + info "Installing ${NAME} from ${imagefile}..." + _setup_env ${imagefile} +} + +####################################### +# Remove an existing JuNest system. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory to remove. +# Arguments: +# None +# Returns: +# None +# Output: +# None +####################################### +function delete_env(){ + ! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return + if mountpoint -q ${JUNEST_HOME} + then + info "There are mounted directories inside ${JUNEST_HOME}" + if ! umount --force ${JUNEST_HOME} + then + error "Cannot umount directories in ${JUNEST_HOME}" + die "Try to delete ${NAME} using root permissions" + fi + fi + # the CA directories are read only and can be deleted only by changing the mod + chmod -R +w ${JUNEST_HOME}/etc/ca-certificates + if rm_cmd -rf ${JUNEST_HOME}/* + then + info "${NAME} deleted in ${JUNEST_HOME}" + else + error "Error: Cannot delete ${NAME} in ${JUNEST_HOME}" + fi +} + diff --git a/lib/utils.sh b/lib/utils/utils.sh similarity index 100% rename from lib/utils.sh rename to lib/utils/utils.sh diff --git a/tests/checkstyle/checkstyle.sh b/tests/checkstyle/checkstyle.sh new file mode 100755 index 0000000..27cb82a --- /dev/null +++ b/tests/checkstyle/checkstyle.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +source "$(dirname $0)/../utils/utils.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function test_check_no_tabs(){ + assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../bin/* + assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat $STDERRF)" + assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../lib/* + assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat $STDERRF)" +} + +source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh new file mode 100755 index 0000000..04b22a7 --- /dev/null +++ b/tests/unit-tests/test-chroot.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) + +source "$JUNEST_ROOT/tests/utils/utils.sh" + +source "$JUNEST_ROOT/lib/utils/utils.sh" +source "$JUNEST_ROOT/lib/core/common.sh" +source "$JUNEST_ROOT/lib/core/chroot.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + cwdSetUp + junestSetUp +} + +function tearDown(){ + junestTearDown + cwdTearDown +} + +function test_run_env_as_root_different_arch(){ + echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + assertCommandFailOnStatus 104 run_env_as_root pwd +} + +function _test_run_env_as_root() { + chroot_cmd() { + [ "$JUNEST_ENV" != "1" ] && return 1 + echo $@ + } + + assertCommandSuccess run_env_as_root $@ +} + +function test_run_env_as_root_cmd(){ + _test_run_env_as_root pwd + assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +} + +function test_run_env_as_classic_root_no_cmd(){ + _test_run_env_as_root + assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +} + +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-cli.sh b/tests/unit-tests/test-cli.sh index 5dd2513..db23eea 100755 --- a/tests/unit-tests/test-cli.sh +++ b/tests/unit-tests/test-cli.sh @@ -1,5 +1,5 @@ #!/bin/bash -source "$(dirname $0)/utils.sh" +source "$(dirname $0)/../utils/utils.sh" source $(dirname $0)/../../bin/junest -h &> /dev/null @@ -178,4 +178,4 @@ function test_check_cli(){ assertCommandFail cli -d args } -source $(dirname $0)/shunit2 +source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh new file mode 100755 index 0000000..ad871f5 --- /dev/null +++ b/tests/unit-tests/test-common.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) + +source "$JUNEST_ROOT/tests/utils/utils.sh" + +source "$JUNEST_ROOT/lib/utils/utils.sh" +source "$JUNEST_ROOT/lib/core/common.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests + junestSetUp +} + +function oneTimeTearDown(){ + junestTearDown +} + +function setUp(){ + ld_exec() { + echo "ld_exec $@" + } + LD_EXEC=ld_exec +} + +function test_ln(){ + LN=echo assertCommandSuccess ln_cmd -s ln_file new_file + assertEquals "-s ln_file new_file" "$(cat $STDOUTF)" + + LN=false assertCommandSuccess ln_cmd -s ln_file new_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)" + + 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 + assertCommandSuccess download_cmd + + WGET=/bin/false + CURL=/bin/true + assertCommandSuccess download_cmd + + WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd +} + +function test_rm(){ + RM=echo assertCommandSuccess rm_cmd rm_file + assertEquals "rm_file" "$(cat $STDOUTF)" + + RM=false assertCommandSuccess rm_cmd rm_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)" + + RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file +} + +function test_chown(){ + local id=$(id -u) + + CHOWN=echo assertCommandSuccess chown_cmd $id chown_file + assertEquals "$id chown_file" "$(cat $STDOUTF)" + + CHOWN=false assertCommandSuccess chown_cmd $id chown_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)" + + CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file +} + +function test_mkdir(){ + MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir + assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)" + + MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)" + + MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir +} + +function test_chroot(){ + CHROOT=echo assertCommandSuccess chroot_cmd root + assertEquals "root" "$(cat $STDOUTF)" + + CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root + assertEquals "root" "$(cat $STDOUTF)" + + CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)" + + CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root +} + +function test_proot_cmd_compat(){ + PROOT="/bin/true" assertCommandSuccess proot_cmd "" "" + + PROOT="/bin/false" assertCommandFail proot_cmd --helps +} + +function test_proot_cmd_seccomp(){ + envv(){ + env + } + PROOT=envv + assertCommandSuccess proot_cmd cmd + assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" + + envv(){ + env | grep "^PROOT_NO_SECCOMP" + } + PROOT=envv + local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") + assertCommandSuccess proot_cmd cmd + # The variable PROOT_NO_SECCOMP will be produced + # twice due to the fallback mechanism + assertEquals "PROOT_NO_SECCOMP=1 +PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" +} + +function test_copy_passwd_and_group(){ + getent_cmd_mock() { + echo $@ + } + GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group + assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)" + assertEquals "group" "$(cat $JUNEST_HOME/etc/group)" +} + +function test_copy_passwd_and_group_fallback(){ + cp_cmd_mock() { + echo $@ + } + CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group + assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" +} + +function test_copy_passwd_and_group_failure(){ + CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group +} + +function test_nested_env(){ + JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" +} + +function test_nested_env_not_set_variable(){ + JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" +} + +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-core.sh b/tests/unit-tests/test-core.sh deleted file mode 100755 index 78e5009..0000000 --- a/tests/unit-tests/test-core.sh +++ /dev/null @@ -1,349 +0,0 @@ -#!/bin/bash - -JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) - -source "$JUNEST_ROOT/tests/unit-tests/utils.sh" - -# Disable the exiterr -set +e - -function oneTimeSetUp(){ - SKIP_ROOT_TESTS=${SKIP_ROOT_TESTS:-0} - setUpUnitTests -} - -function setUp(){ - ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) - cd $ORIGIN_CWD - JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) - mkdir -p ${JUNEST_HOME}/etc/junest - echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info - mkdir -p ${JUNEST_HOME}/etc/ca-certificates - JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t junest-temp.XXXXXXXXXX) - source "$JUNEST_ROOT/lib/utils.sh" - source "$JUNEST_ROOT/lib/core.sh" - - set +e - - trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${JUNEST_HOME}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT - - ld_exec() { - echo "ld_exec $@" - } - LD_EXEC=ld_exec -} - - -function tearDown(){ - # the CA directories are read only and can be deleted only by changing the mod - [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates - rm -rf $JUNEST_HOME - rm -rf $JUNEST_TEMPDIR - rm -rf $ORIGIN_CWD - trap - QUIT EXIT ABRT KILL TERM INT -} - - -function test_ln(){ - LN=echo assertCommandSuccess ln_cmd -s ln_file new_file - assertEquals "-s ln_file new_file" "$(cat $STDOUTF)" - - LN=false assertCommandSuccess ln_cmd -s ln_file new_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)" - - 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 - assertCommandSuccess download_cmd - - WGET=/bin/false - CURL=/bin/true - assertCommandSuccess download_cmd - - WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd -} - -function test_rm(){ - RM=echo assertCommandSuccess rm_cmd rm_file - assertEquals "rm_file" "$(cat $STDOUTF)" - - RM=false assertCommandSuccess rm_cmd rm_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)" - - RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file -} - -function test_chown(){ - local id=$(id -u) - - CHOWN=echo assertCommandSuccess chown_cmd $id chown_file - assertEquals "$id chown_file" "$(cat $STDOUTF)" - - CHOWN=false assertCommandSuccess chown_cmd $id chown_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)" - - CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file -} - -function test_mkdir(){ - MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir - assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)" - - MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)" - - MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir -} - -function test_chroot(){ - CHROOT=echo assertCommandSuccess chroot_cmd root - assertEquals "root" "$(cat $STDOUTF)" - - CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root - assertEquals "root" "$(cat $STDOUTF)" - - CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root - assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)" - - CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root -} - -function test_proot_cmd_compat(){ - PROOT="/bin/true" assertCommandSuccess proot_cmd "" "" - - PROOT="/bin/false" assertCommandFail proot_cmd --helps -} - -function test_proot_cmd_seccomp(){ - envv(){ - env - } - PROOT=envv - assertCommandSuccess proot_cmd cmd - assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" - - envv(){ - env | grep "^PROOT_NO_SECCOMP" - } - PROOT=envv - local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") - assertCommandSuccess proot_cmd cmd - # The variable PROOT_NO_SECCOMP will be produced - # twice due to the fallback mechanism - assertEquals "PROOT_NO_SECCOMP=1 -PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" -} - -function test_is_env_installed(){ - rm -rf $JUNEST_HOME/* - assertCommandFail is_env_installed - touch $JUNEST_HOME/just_file - assertCommandSuccess is_env_installed -} - -function test_setup_env(){ - rm -rf $JUNEST_HOME/* - wget_mock(){ - # Proof that the setup is happening - # inside $JUNEST_TEMPDIR - local cwd=${PWD#${JUNEST_TEMPDIR}} - local parent_dir=${PWD%${cwd}} - assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" - touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file - } - WGET=wget_mock - setup_env 1> /dev/null - assertTrue "[ -e $JUNEST_HOME/file ]" - - assertCommandFailOnStatus 102 setup_env "noarch" -} - - -function test_setup_env_from_file(){ - rm -rf $JUNEST_HOME/* - touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null - assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz - assertTrue "[ -e $JUNEST_HOME/file ]" -} - -function test_setup_env_from_file_not_existing_file(){ - assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz -} - -function test_setup_env_from_file_with_absolute_path(){ - rm -rf $JUNEST_HOME/* - touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null - assertCommandSuccess setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz - assertTrue "[ -e $JUNEST_HOME/file ]" -} - -function test_run_env_as_root_different_arch(){ - echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info - assertCommandFailOnStatus 104 run_env_as_root pwd -} - -function _test_run_env_as_root() { - chroot_cmd() { - [ "$JUNEST_ENV" != "1" ] && return 1 - echo $@ - } - - assertCommandSuccess run_env_as_root $@ -} - -function test_run_env_as_root_cmd(){ - _test_run_env_as_root pwd - assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" -} - -function test_run_env_as_classic_root_no_cmd(){ - _test_run_env_as_root - assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" -} - -function test_run_env_as_user(){ - _run_env_with_qemu() { - echo $@ - } - assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" - - SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_user "-k 3.10" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" - - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" - - [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" - [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" - - [[ -e /etc/passwd ]] - assertEquals 0 $? - [[ -e /etc/group ]] - assertEquals 0 $? - -} - -function test_copy_passwd_and_group(){ - getent_cmd_mock() { - echo $@ - } - GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group - assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)" - assertEquals "group" "$(cat $JUNEST_HOME/etc/group)" -} - -function test_copy_passwd_and_group_fallback(){ - cp_cmd_mock() { - echo $@ - } - CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group - assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" -} - -function test_copy_passwd_and_group_failure(){ - CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group -} - -function test_run_env_as_fakeroot(){ - _run_env_with_qemu() { - echo $@ - } - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" - - SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_fakeroot "-k 3.10" - assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" - - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" -} - -function test_run_env_with_quotes(){ - _run_env_with_qemu() { - echo $@ - } - assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" - assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" -} - -function test_run_env_with_proot_args(){ - proot_cmd() { - [ "$JUNEST_ENV" != "1" ] && return 1 - echo $@ - } - - assertCommandSuccess _run_env_with_proot --help - assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)" - - assertCommandSuccess _run_env_with_proot --help mycommand - assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)" - - assertCommandFail _run_env_with_proot -} - -function test_delete_env(){ - echo "N" | delete_env 1> /dev/null - assertCommandSuccess is_env_installed - echo "Y" | delete_env 1> /dev/null - assertCommandFail is_env_installed -} - -function test_nested_env(){ - JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" -} - -function test_nested_env_not_set_variable(){ - JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh" -} - -function test_qemu() { - echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info - rm_cmd() { - echo $@ - } - ln_cmd() { - echo $@ - } - _run_env_with_proot() { - echo $@ - } - - RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" - assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" -} - -source $JUNEST_ROOT/tests/unit-tests/shunit2 diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh new file mode 100755 index 0000000..fdc83b2 --- /dev/null +++ b/tests/unit-tests/test-proot.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) + +source "$JUNEST_ROOT/tests/utils/utils.sh" + +source "$JUNEST_ROOT/lib/utils/utils.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + cwdSetUp + junestSetUp + + # Attempt to source the files under test to revert variable + # overrides (i.e. SH variable) + source "$JUNEST_ROOT/lib/core/common.sh" + source "$JUNEST_ROOT/lib/core/proot.sh" + set +e +} + +function tearDown(){ + junestTearDown + cwdTearDown +} + +function test_run_env_as_user(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + SH=("/usr/bin/echo") + assertCommandSuccess run_env_as_user "-k 3.10" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" + + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" + + [[ -e /etc/passwd ]] + assertEquals 0 $? + [[ -e /etc/group ]] + assertEquals 0 $? + +} + +function test_run_env_as_fakeroot(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + SH=("/usr/bin/echo") + assertCommandSuccess run_env_as_fakeroot "-k 3.10" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" +} + +function test_run_env_with_quotes(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" +} + +function test_run_env_with_proot_args(){ + proot_cmd() { + [ "$JUNEST_ENV" != "1" ] && return 1 + echo $@ + } + + assertCommandSuccess _run_env_with_proot --help + assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)" + + assertCommandSuccess _run_env_with_proot --help mycommand + assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)" + + assertCommandFail _run_env_with_proot +} + +function test_qemu() { + echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info + rm_cmd() { + echo $@ + } + ln_cmd() { + echo $@ + } + _run_env_with_proot() { + echo $@ + } + + RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" + assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" +} + +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-setup.sh b/tests/unit-tests/test-setup.sh new file mode 100755 index 0000000..a15dbca --- /dev/null +++ b/tests/unit-tests/test-setup.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) + +source "$JUNEST_ROOT/tests/utils/utils.sh" + +source "$JUNEST_ROOT/lib/utils/utils.sh" +source "$JUNEST_ROOT/lib/core/common.sh" +source "$JUNEST_ROOT/lib/core/setup.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + cwdSetUp + junestSetUp +} + +function tearDown(){ + junestTearDown + cwdTearDown +} + +function test_is_env_installed(){ + rm -rf $JUNEST_HOME/* + assertCommandFail is_env_installed + touch $JUNEST_HOME/just_file + assertCommandSuccess is_env_installed +} + +function test_setup_env(){ + rm -rf $JUNEST_HOME/* + wget_mock(){ + # Proof that the setup is happening + # inside $JUNEST_TEMPDIR + local cwd=${PWD#${JUNEST_TEMPDIR}} + local parent_dir=${PWD%${cwd}} + assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" + touch file + tar -czvf ${CMD}-${ARCH}.tar.gz file + } + WGET=wget_mock + setup_env 1> /dev/null + assertTrue "[ -e $JUNEST_HOME/file ]" + + assertCommandFailOnStatus 102 setup_env "noarch" +} + + +function test_setup_env_from_file(){ + rm -rf $JUNEST_HOME/* + touch file + tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null + assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz + assertTrue "[ -e $JUNEST_HOME/file ]" +} + +function test_setup_env_from_file_not_existing_file(){ + assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz +} + +function test_setup_env_from_file_with_absolute_path(){ + rm -rf $JUNEST_HOME/* + touch file + tar -czf ${CMD}-${ARCH}.tar.gz file + assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz + assertTrue "[ -e $JUNEST_HOME/file ]" +} + +function test_delete_env(){ + echo "N" | delete_env 1> /dev/null + assertCommandSuccess is_env_installed + echo "Y" | delete_env 1> /dev/null + assertCommandFail is_env_installed +} + +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-utils.sh b/tests/unit-tests/test-utils.sh index 5816d11..8a5a127 100755 --- a/tests/unit-tests/test-utils.sh +++ b/tests/unit-tests/test-utils.sh @@ -1,10 +1,10 @@ #!/bin/bash -source "$(dirname $0)/utils.sh" +source "$(dirname $0)/../utils/utils.sh" unset HOME export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX) -source "$(dirname $0)/../../lib/utils.sh" +source "$(dirname $0)/../../lib/utils/utils.sh" # Disable the exiterr set +e @@ -94,4 +94,4 @@ function test_contains_element(){ assertCommandFailOnStatus 1 contains_element "blabla" "${array[@]}" } -source $(dirname $0)/shunit2 +source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/utils.sh b/tests/unit-tests/utils.sh deleted file mode 100644 index b12420e..0000000 --- a/tests/unit-tests/utils.sh +++ /dev/null @@ -1,32 +0,0 @@ - -function setUpUnitTests(){ - OUTPUT_DIR="${SHUNIT_TMPDIR}/output" - mkdir "${OUTPUT_DIR}" - STDOUTF="${OUTPUT_DIR}/stdout" - STDERRF="${OUTPUT_DIR}/stderr" -} - -function assertCommandSuccess(){ - $(set -e - "$@" > $STDOUTF 2> $STDERRF - ) - assertTrue "The command $1 did not return 0 exit status" $? -} - -function assertCommandFail(){ - $(set -e - "$@" > $STDOUTF 2> $STDERRF - ) - assertFalse "The command $1 returned 0 exit status" $? -} - -# $1: expected exit status -# $2-: The command under test -function assertCommandFailOnStatus(){ - local status=$1 - shift - $(set -e - "$@" > $STDOUTF 2> $STDERRF - ) - assertEquals $status $? -} diff --git a/tests/unit-tests/shunit2 b/tests/utils/shunit2 similarity index 100% rename from tests/unit-tests/shunit2 rename to tests/utils/shunit2 diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh new file mode 100644 index 0000000..b96000c --- /dev/null +++ b/tests/utils/utils.sh @@ -0,0 +1,57 @@ +function cwdSetUp(){ + ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) + cd $ORIGIN_CWD +} + +function cwdTearDown(){ + rm -rf $ORIGIN_CWD +} + +function junestSetUp(){ + JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) + mkdir -p ${JUNEST_HOME}/etc/junest + echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info + mkdir -p ${JUNEST_HOME}/etc/ca-certificates + trap - QUIT EXIT ABRT KILL TERM INT + trap "rm -rf ${JUNEST_HOME}" EXIT QUIT ABRT KILL TERM INT +} + +function junestTearDown(){ + # the CA directories are read only and can be deleted only by changing the mod + [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates + rm -rf $JUNEST_HOME + trap - QUIT EXIT ABRT KILL TERM INT + unset JUNEST_HOME +} + +function setUpUnitTests(){ + OUTPUT_DIR="${SHUNIT_TMPDIR}/output" + mkdir "${OUTPUT_DIR}" + STDOUTF="${OUTPUT_DIR}/stdout" + STDERRF="${OUTPUT_DIR}/stderr" +} + +function assertCommandSuccess(){ + $(set -e + "$@" > $STDOUTF 2> $STDERRF + ) + assertTrue "The command $1 did not return 0 exit status" $? +} + +function assertCommandFail(){ + $(set -e + "$@" > $STDOUTF 2> $STDERRF + ) + assertFalse "The command $1 returned 0 exit status" $? +} + +# $1: expected exit status +# $2-: The command under test +function assertCommandFailOnStatus(){ + local status=$1 + shift + $(set -e + "$@" > $STDOUTF 2> $STDERRF + ) + assertEquals $status $? +} From adcfe7c8dcf1e7f0423f5e511c5cea9c57f291da Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 16 Mar 2017 19:40:54 +0000 Subject: [PATCH 156/326] Move to S3 service for hosting the JuNest images Dropbox Public folder became private: https://www.dropbox.com/help/16 --- lib/core/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index f477444..6b777bf 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -61,7 +61,7 @@ else die "Unknown architecture ${HOST_ARCH}" fi -MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030 +MAIN_REPO=https://s3-eu-west-1.amazonaws.com ENV_REPO=${MAIN_REPO}/${CMD} DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' From b3a41d1d52dd39d14a786f5588c6ccc26bffa26c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 16 Mar 2017 21:34:03 +0000 Subject: [PATCH 157/326] 5.6.10 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1502747..4794f16 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.9 +5.6.10 From 72640b3ca3aa2cd1b34047c0f5b526727c2060f6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Mar 2017 14:53:48 +0000 Subject: [PATCH 158/326] Create the proper S3 bucket for JuNest --- lib/core/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index 6b777bf..d317933 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -61,7 +61,7 @@ else die "Unknown architecture ${HOST_ARCH}" fi -MAIN_REPO=https://s3-eu-west-1.amazonaws.com +MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' From 7a6ef3f0f9d8d0db9ad0a57f66f8dc7d53b443f8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Mar 2017 15:34:35 +0000 Subject: [PATCH 159/326] 5.6.11 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4794f16..723bfc6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.10 +5.6.11 From 2ed75c854524ff0d431f5dd2ad27694cacdfbb44 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Mar 2017 15:55:03 +0000 Subject: [PATCH 160/326] :bug: Fix jchroot according to refactor --- bin/jchroot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/jchroot b/bin/jchroot index 8eaa8d4..fe43661 100755 --- a/bin/jchroot +++ b/bin/jchroot @@ -8,7 +8,7 @@ set -e JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" -source "${JUNEST_BASE}/lib/utils.sh" +source "${JUNEST_BASE}/lib/utils/utils.sh" ################################ MAIN FUNCTIONS ########################### From f85c62274f2b12adb1aade06f3c3eef445b48cc7 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Mar 2017 15:56:14 +0000 Subject: [PATCH 161/326] 5.6.12 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 723bfc6..b8a773e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.11 +5.6.12 From 0ec35a408800a9f1a858d983d3c1ab3024682c26 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 14 Mar 2017 23:43:52 +0000 Subject: [PATCH 162/326] Issue #174: Add namespace module and check for user namespace --- bin/junest | 43 ++++++++++++++++++-------- lib/core/common.sh | 7 +++++ lib/core/namespace.sh | 47 +++++++++++++++++++++++++++++ tests/unit-tests/test-cli.sh | 43 +++++++++++++++++++++++--- tests/unit-tests/test-common.sh | 10 +++++++ tests/unit-tests/test-namespace.sh | 48 ++++++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 17 deletions(-) create mode 100644 lib/core/namespace.sh create mode 100755 tests/unit-tests/test-namespace.sh diff --git a/bin/junest b/bin/junest index 836c19b..5e2e6bf 100755 --- a/bin/junest +++ b/bin/junest @@ -7,10 +7,13 @@ JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" source "${JUNEST_BASE}/lib/utils/utils.sh" source "${JUNEST_BASE}/lib/core/common.sh" + source "${JUNEST_BASE}/lib/core/build.sh" -source "${JUNEST_BASE}/lib/core/setup.sh" -source "${JUNEST_BASE}/lib/core/proot.sh" source "${JUNEST_BASE}/lib/core/chroot.sh" +source "${JUNEST_BASE}/lib/core/namespace.sh" +source "${JUNEST_BASE}/lib/core/proot.sh" +source "${JUNEST_BASE}/lib/core/setup.sh" + ################################### ### General functions ### @@ -29,8 +32,11 @@ usage() { echo echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" - echo -e "-r, --root Run $NAME with root privileges" - echo -e "-p, --proot-args Proot arguments (use $CMD -p \"--help\" to check out the proot options)" + echo -e "-r, --root Run $NAME with root privileges via jchroot" + echo -e "-p, --backend-args Arguments for backend program (PRoot or jchroot)" + echo -e " ($CMD -p \"--help\" to check out the PRoot options" + echo -e " $CMD -u -p \"--help\" to check out the jchroot options)" + echo -e "-u, --user-namespace Use Linux User Namespace instead of PRoot" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" @@ -109,7 +115,7 @@ check_cli(){ then die "You must access to $NAME with either fakeroot or root permissions" fi - if $OPT_PROOT_ARGS || $OPT_ARCH + if $OPT_BACKEND_ARGS || $OPT_ARCH then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK @@ -135,8 +141,9 @@ function parse_arguments(){ IMAGE_FILE="" OPT_FAKEROOT=false OPT_ROOT=false - OPT_PROOT_ARGS=false - PROOT_ARGS="" + OPT_USER_NAMESPACE=false + OPT_BACKEND_ARGS=false + BACKEND_ARGS="" OPT_ARCH=false ARCH_ARG="" OPT_BUILD_IMAGE=false @@ -153,7 +160,8 @@ function parse_arguments(){ -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; -r|--root) OPT_ROOT=true ; shift ;; - -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; + -u|--user-namespace) OPT_USER_NAMESPACE=true ; shift ;; + -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; @@ -205,13 +213,22 @@ function execute_operation(){ [ -z "${ARCH_ARG}" ] || \ die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" - if $OPT_FAKEROOT; then - run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" - elif $OPT_ROOT; then - run_env_as_root "${ARGS[@]}" + if $OPT_USER_NAMESPACE; then + if $OPT_FAKEROOT; then + run_env_as_fakeroot_with_namespace "${BACKEND_ARGS}" "${ARGS[@]}" + else + run_env_as_user_with_namespace "${BACKEND_ARGS}" "${ARGS[@]}" + fi else - run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" + if $OPT_FAKEROOT; then + run_env_as_fakeroot "${BACKEND_ARGS}" "${ARGS[@]}" + elif $OPT_ROOT; then + run_env_as_root "${ARGS[@]}" + else + run_env_as_user "${BACKEND_ARGS}" "${ARGS[@]}" + fi fi + } function cli() { diff --git a/lib/core/common.sh b/lib/core/common.sh index d317933..1ceb092 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -19,6 +19,7 @@ ARCHITECTURE_MISMATCH=104 ROOT_ACCESS_ERROR=105 NESTED_ENVIRONMENT=106 VARIABLE_NOT_SET=107 +NO_CONFIG_FOUND=108 if [ "$JUNEST_ENV" == "1" ] then @@ -89,6 +90,8 @@ RM=rm MKDIR=mkdir GETENT=getent CP=cp +# Used for checking user namespace in config.gz file +ZGREP=zgrep LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -120,6 +123,10 @@ function mkdir_cmd(){ $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ } +function zgrep_cmd(){ + $ZGREP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$ZGREP $@ +} + function proot_cmd(){ local proot_args="$1" shift diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh new file mode 100644 index 0000000..ee26d6c --- /dev/null +++ b/lib/core/namespace.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# +# This module contains all namespace functionalities for JuNest. +# +# http://man7.org/linux/man-pages/man7/namespaces.7.html +# http://man7.org/linux/man-pages/man2/unshare.2.html +# +# Dependencies: +# - lib/utils/utils.sh +# - lib/core/common.sh +# +# vim: ft=sh + +CONFIG_PROC_FILE="/proc/config.gz" +CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" + +function _is_user_namespace_enabled() { + local config_file="" + if [[ -e $CONFIG_PROC_FILE ]] + then + config_file=$CONFIG_PROC_FILE + elif [[ -e $CONFIG_BOOT_FILE ]] + then + config_file=$CONFIG_BOOT_FILE + else + return $NOT_EXISTING_FILE + fi + + if ! zgrep_cmd "CONFIG_USER_NS=y" $config_file + then + return $NO_CONFIG_FOUND + fi +} + +function run_env_as_user_with_namespace() { + set +e + _is_user_namespace_enabled + case $? in + $NOT_EXISTING_FILE) warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;; + $NO_CONFIG_FOUND) warn "User namespace is not enabled or Kernel too old. Proceeding anyway..." ;; + esac + set -e +} + +function run_env_as_fakeroot_with_namespace() { + die_on_status 1 "Not implemented yet" +} diff --git a/tests/unit-tests/test-cli.sh b/tests/unit-tests/test-cli.sh index db23eea..efe55b5 100755 --- a/tests/unit-tests/test-cli.sh +++ b/tests/unit-tests/test-cli.sh @@ -44,17 +44,27 @@ function setup_env(){ echo "setup_env($1)" } function run_env_as_fakeroot(){ - local proot_args="$1" + local backend_args="$1" shift - echo "run_env_as_fakeroot($proot_args,$@)" + echo "run_env_as_fakeroot($backend_args,$@)" } function run_env_as_root(){ echo "run_env_as_root $@" } function run_env_as_user(){ - local proot_args="$1" + local backend_args="$1" shift - echo "run_env_as_user($proot_args,$@)" + echo "run_env_as_user($backend_args,$@)" +} +function run_env_as_fakeroot_with_namespace(){ + local backend_args="$1" + shift + echo "run_env_as_fakeroot_with_namespace($backend_args,$@)" +} +function run_env_as_user_with_namespace(){ + local backend_args="$1" + shift + echo "run_env_as_user_with_namespace($backend_args,$@)" } function test_help(){ @@ -164,6 +174,31 @@ function test_run_env_as_root(){ assertEquals "run_env_as_root command" "$(cat $STDOUTF)" } +function test_run_env_as_fakeroot_with_namespace(){ + assertCommandSuccess cli -u -f + assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" + assertCommandSuccess cli --user-namespace --fakeroot + assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" + + assertCommandSuccess cli -u -f -p "-b arg" + assertEquals "run_env_as_fakeroot_with_namespace(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess cli -u -f -p "-b arg" -- command -kv + assertEquals "run_env_as_fakeroot_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess cli -u -f command --as + assertEquals "run_env_as_fakeroot_with_namespace(,command --as)" "$(cat $STDOUTF)" +} +function test_run_env_as_user_with_namespace(){ + assertCommandSuccess cli -u + assertEquals "run_env_as_user_with_namespace(,)" "$(cat $STDOUTF)" + + assertCommandSuccess cli -u -p "-b arg" + assertEquals "run_env_as_user_with_namespace(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess cli -u -p "-b arg" -- command -ll + assertEquals "run_env_as_user_with_namespace(-b arg,command -ll)" "$(cat $STDOUTF)" + assertCommandSuccess cli -u command -ls + assertEquals "run_env_as_user_with_namespace(,command -ls)" "$(cat $STDOUTF)" +} + function test_check_cli(){ assertCommandFail cli -b -h assertCommandFail cli -b -c diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index ad871f5..3cbed72 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -100,6 +100,16 @@ function test_mkdir(){ MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir } +function test_zgrep(){ + ZGREP=echo assertCommandSuccess zgrep_cmd new_file + assertEquals "new_file" "$(cat $STDOUTF)" + + ZGREP=false assertCommandSuccess zgrep_cmd new_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false new_file" "$(cat $STDOUTF)" + + ZGREP=false LD_EXEC=false assertCommandFail zgrep_cmd new_file +} + function test_chroot(){ CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh new file mode 100755 index 0000000..deb90d2 --- /dev/null +++ b/tests/unit-tests/test-namespace.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) + +source "$JUNEST_ROOT/tests/utils/utils.sh" + +source "$JUNEST_ROOT/lib/utils/utils.sh" +source "$JUNEST_ROOT/lib/core/common.sh" +source "$JUNEST_ROOT/lib/core/namespace.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + cwdSetUp +} + +function tearDown(){ + cwdTearDown +} + +function test_is_user_namespace_enabled_no_config_file(){ + CONFIG_PROC_FILE="blah" + CONFIG_BOOT_FILE="blah" + assertCommandFailOnStatus $NOT_EXISTING_FILE _is_user_namespace_enabled +} + +function test_is_user_namespace_enabled_no_config(){ + touch config + gzip config + CONFIG_PROC_FILE="config.gz" + CONFIG_BOOT_FILE="blah" + assertCommandFailOnStatus $NO_CONFIG_FOUND _is_user_namespace_enabled +} + +function test_is_user_namespace_enabled_with_config(){ + echo "CONFIG_USER_NS=y" > config + gzip config + CONFIG_PROC_FILE="config.gz" + CONFIG_BOOT_FILE="blah" + assertCommandSuccess _is_user_namespace_enabled +} + +source $JUNEST_ROOT/tests/utils/shunit2 From 426b708d2d39df8e5597e752993ab9e0c0e158c7 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 15 Mar 2017 22:22:12 +0000 Subject: [PATCH 163/326] Issue #174: Rename common functions and define skeleton for namespace functions --- lib/core/common.sh | 31 ++++++++++++++++----------- lib/core/namespace.sh | 38 +++++++++++++++++++++++++++++---- lib/core/proot.sh | 18 ++++++++-------- tests/unit-tests/test-common.sh | 26 +++++++++++++++------- 4 files changed, 79 insertions(+), 34 deletions(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index 1ceb092..87b5812 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -79,8 +79,8 @@ SH=("/bin/sh" "--login") # List of executables that are run in the host OS: PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" -CHROOT=${JUNEST_BASE}/bin/jchroot -CLASSIC_CHROOT="chroot" +JCHROOT=${JUNEST_BASE}/bin/jchroot +CLASSIC_CHROOT=chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" TAR=tar @@ -92,6 +92,7 @@ GETENT=getent CP=cp # Used for checking user namespace in config.gz file ZGREP=zgrep +UNSHARE=unshare LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -127,6 +128,10 @@ function zgrep_cmd(){ $ZGREP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$ZGREP $@ } +function unshare_cmd(){ + $UNSHARE $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE $@ +} + function proot_cmd(){ local proot_args="$1" shift @@ -146,7 +151,7 @@ function download_cmd(){ } function chroot_cmd(){ - $CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@" + $JCHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" } ############## COMMON FUNCTIONS ############### @@ -167,7 +172,7 @@ function chroot_cmd(){ # Output: # None ####################################### -function _provide_common_bindings(){ +function provide_common_bindings(){ RESULT="" local re='(.*):.*' for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" @@ -198,7 +203,7 @@ function _provide_common_bindings(){ # Output: # None ####################################### -function _copy_passwd_and_group(){ +function copy_passwd_and_group(){ # Enumeration of users/groups is disabled/limited depending on how nsswitch.conf # is configured. # Try to at least get the current user via `getent passwd $USER` since it uses @@ -207,27 +212,27 @@ function _copy_passwd_and_group(){ ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd then warn "getent command failed or does not exist. Binding directly from /etc/passwd." - _copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd + copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd fi if ! getent_cmd group > ${JUNEST_HOME}/etc/group then warn "getent command failed or does not exist. Binding directly from /etc/group." - _copy_file /etc/group ${JUNEST_HOME}/etc/group + copy_file /etc/group ${JUNEST_HOME}/etc/group fi return 0 } -function _copy_file() { +function copy_file() { local file="${1}" [[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file" return 0 } -function _copy_common_files() { - _copy_file /etc/host.conf - _copy_file /etc/hosts - _copy_file /etc/nsswitch.conf - _copy_file /etc/resolv.conf +function copy_common_files() { + copy_file /etc/host.conf + copy_file /etc/hosts + copy_file /etc/nsswitch.conf + copy_file /etc/resolv.conf return 0 } diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index ee26d6c..dddf521 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -32,16 +32,46 @@ function _is_user_namespace_enabled() { fi } -function run_env_as_user_with_namespace() { +function _check_user_namespace() { set +e _is_user_namespace_enabled case $? in $NOT_EXISTING_FILE) warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;; - $NO_CONFIG_FOUND) warn "User namespace is not enabled or Kernel too old. Proceeding anyway..." ;; + $NO_CONFIG_FOUND) warn "User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway..." ;; esac set -e } -function run_env_as_fakeroot_with_namespace() { - die_on_status 1 "Not implemented yet" +function run_env_as_user_with_namespace() { + local backend_args="$1" + shift + _check_user_namespace + + copy_common_files + copy_file /etc/hosts.equiv + copy_file /etc/netgroup + copy_file /etc/networks + # No need for localtime as it is setup during the image build + #copy_file /etc/localtime + copy_passwd_and_group + + provide_common_bindings + local bindings=${RESULT} + unset RESULT + + unshare_cmd --mount --user --map-root-user $JCHROOT $bindings $backend_args "$JUNEST_HOME" +} + +function run_env_as_fakeroot_with_namespace() { + local backend_args="$1" + shift + _check_user_namespace + + copy_common_files + + provide_common_bindings + local bindings=${RESULT} + unset RESULT + + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $JCHROOT $bindings $backend_args "$JUNEST_HOME" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index 39d901c..3460f18 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -59,9 +59,9 @@ function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - _copy_common_files + copy_common_files - _provide_common_bindings + provide_common_bindings local bindings=${RESULT} unset RESULT @@ -93,15 +93,15 @@ function run_env_as_user(){ # This function excludes /etc/mtab file so that # it will not give conflicts with the related # symlink in the Arch Linux image. - _copy_common_files - _copy_file /etc/hosts.equiv - _copy_file /etc/netgroup - _copy_file /etc/networks + copy_common_files + copy_file /etc/hosts.equiv + copy_file /etc/netgroup + copy_file /etc/networks # No need for localtime as it is setup during the image build - #_copy_file /etc/localtime - _copy_passwd_and_group + #copy_file /etc/localtime + copy_passwd_and_group - _provide_common_bindings + provide_common_bindings local bindings=${RESULT} unset RESULT diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index 3cbed72..33beefa 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -110,17 +110,27 @@ function test_zgrep(){ ZGREP=false LD_EXEC=false assertCommandFail zgrep_cmd new_file } +function test_unshare(){ + UNSHARE=echo assertCommandSuccess unshare_cmd new_program + assertEquals "new_program" "$(cat $STDOUTF)" + + UNSHARE=false assertCommandSuccess unshare_cmd new_program + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false new_program" "$(cat $STDOUTF)" + + UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program +} + function test_chroot(){ - CHROOT=echo assertCommandSuccess chroot_cmd root + JCHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root + JCHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root - assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)" + JCHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)" - CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root + JCHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } function test_proot_cmd_compat(){ @@ -153,7 +163,7 @@ function test_copy_passwd_and_group(){ getent_cmd_mock() { echo $@ } - GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group + GETENT=getent_cmd_mock assertCommandSuccess copy_passwd_and_group assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)" assertEquals "group" "$(cat $JUNEST_HOME/etc/group)" } @@ -162,12 +172,12 @@ function test_copy_passwd_and_group_fallback(){ cp_cmd_mock() { echo $@ } - CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group + CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess copy_passwd_and_group assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" } function test_copy_passwd_and_group_failure(){ - CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group + CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 copy_passwd_and_group } function test_nested_env(){ From 0f7fd33c53e7fd20b07ae37be1fb3b26c152d2c3 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 17 Mar 2017 17:49:00 +0000 Subject: [PATCH 164/326] Issue #174: Add new program GRoot and change version option for JuNest! This replaces jchroot because GRoot can be also used in a user namespace environment. --- README.md | 4 +- bin/groot | 180 ++++++++++++++++++ bin/jchroot | 98 ---------- bin/junest | 20 +- lib/core/build.sh | 4 +- lib/core/common.sh | 9 +- lib/core/namespace.sh | 14 +- lib/utils/utils.sh | 14 ++ tests/unit-tests/test-common.sh | 20 +- tests/unit-tests/test-groot.sh | 137 +++++++++++++ .../{test-cli.sh => test-junest.sh} | 115 +++++------ tests/unit-tests/test-utils.sh | 22 +++ tests/utils/utils.sh | 5 +- 13 files changed, 458 insertions(+), 184 deletions(-) create mode 100755 bin/groot delete mode 100755 bin/jchroot create mode 100755 tests/unit-tests/test-groot.sh rename tests/unit-tests/{test-cli.sh => test-junest.sh} (66%) diff --git a/README.md b/README.md index 98f0c9e..e747c4e 100644 --- a/README.md +++ b/README.md @@ -169,14 +169,14 @@ Internals There are two main chroot jail used in JuNest. The main one is [proot](https://wiki.archlinux.org/index.php/Proot) which allows unprivileged users to execute programs inside a sandbox and -jchroot, a small and portable version of +GRoot, a small and portable version of [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an enhanced chroot for privileged users that mounts the primary directories (i.e. /proc, /sys, /dev and /run) before executing any programs inside the sandbox. ## Automatic fallback to classic chroot ## -If jchroot fails for some reasons in the host system (i.e. it is not able to +If GRoot fails for some reasons in the host system (i.e. it is not able to mount one of the directories), JuNest automatically tries to fallback to the classic chroot. diff --git a/bin/groot b/bin/groot new file mode 100755 index 0000000..1d6e26b --- /dev/null +++ b/bin/groot @@ -0,0 +1,180 @@ +#!/bin/bash +# +# This script is the simplified and portable version of arch-chroot +# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) +# + +set -e + +# JUNEST_BASE can be overridden for testing purposes. +# There is no need for doing it for normal usage. +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}" +NAME='GRoot' +CMD='groot' +DESCRIPTION="I am $NAME!" +CHROOTCMD=${CHROOTCMD:-chroot} +SHELL="/bin/sh" +MOUNT=mount +UMOUNT=umount +MOUNTPOINT=mountpoint +MKDIR=mkdir +TOUCH=touch + +NOT_EXISTING_FILE=103 +NOT_ABSOLUTE_PATH=111 +NO_ROOT_PRIVILEGES=110 + +source "${JUNEST_BASE}/lib/utils/utils.sh" + + +################################ MAIN FUNCTIONS ########################### + +function chroot_add_mount() { + $MOUNT "$@" && CHROOT_ACTIVE_MOUNTS=("${@: -1}" "${CHROOT_ACTIVE_MOUNTS[@]}") +} + +function chroot_teardown() { + $UMOUNT "${CHROOT_ACTIVE_MOUNTS[@]}" + unset CHROOT_ACTIVE_MOUNTS +} + +function chroot_maybe_add_mount() { + local cond=$1 + shift + if eval "$cond"; then + chroot_add_mount "$@" + return + fi + return 1 +} + +function chroot_setup() { + CHROOT_ACTIVE_MOUNTS=() + check_and_trap 'chroot_teardown' EXIT + + if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" + then + warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..." + return 0 + fi + + local re='(.*):(.*)' + for binds in ${BINDINGS[@]} + do + local host_path="" + local guest_path="" + if [[ $binds =~ $re ]] + then + local host_path="${BASH_REMATCH[1]}" + local guest_path="${BASH_REMATCH[2]}" + else + local host_path="$binds" + local guest_path="$binds" + fi + + create_node "${host_path}" "${CHROOTDIR}${guest_path}" + chroot_add_mount --rbind "${host_path}" "${CHROOTDIR}${guest_path}" + done +} + +function create_node() { + local src="$1" + local dst="$2" + if [[ ! -e $src ]] + then + die_on_status $NOT_EXISTING_FILE "${src} does not exist." + elif [[ $src != /* ]] + then + die_on_status $NOT_ABSOLUTE_PATH "${src} is not an absolute path." + elif [[ -f $src ]] + then + $TOUCH "$dst" + elif [[ -d $src ]] + then + $MKDIR -p "$dst" + fi +} + +function usage() { + cat < [command]] + +Options: + -b, --bind + Make the content of accessible in the guest rootfs. + + This option makes any file or directory of the host rootfs + accessible in the confined environment just as if it were part of + the guest rootfs. By default the host path is bound to the same + path in the guest rootfs but users can specify any other location + with the syntax: -b :. This option can + be invoked multiple times and the paths specified must be absolutes. + + -h, --help Print this help message + + -V, --version Show the $NAME version + +If 'command' is unspecified, $CMD will launch $SHELL. + +EOF +} + +version() { + echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" +} + +function parse_arguments() { + OPT_BIND=false + BINDINGS=() + OPT_HELP=false + OPT_VERSION=false + for opt in "$@" + do + case "$1" in + -b|--bind) OPT_BIND=true ; shift ; BINDINGS+=("$1") ; shift ;; + -h|--help) OPT_HELP=true ; shift ;; + -V|--version) OPT_VERSION=true ; shift ;; + -*) die "Invalid option $1" ;; + *) break ;; + esac + done + + if [[ ! -z $1 ]] + then + CHROOTDIR="$1" + shift + fi + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done +} + +function is_user_root() { + (( EUID == 0 )) +} + +function execute_operation() { + $OPT_HELP && usage && return + $OPT_VERSION && version && return + + is_user_root || die_on_status $NO_ROOT_PRIVILEGES 'This script must be run with root privileges' + + [[ -d $CHROOTDIR ]] || die_on_status $NOT_EXISTING_FILE "Can't create chroot on non-directory $CHROOTDIR" + + chroot_setup "$CHROOTDIR" || die "Failed to setup chroot $CHROOTDIR" + + $CHROOTCMD "$CHROOTDIR" "${ARGS[@]}" +} + + +function main() { + parse_arguments "$@" + execute_operation +} + +main "$@" diff --git a/bin/jchroot b/bin/jchroot deleted file mode 100755 index fe43661..0000000 --- a/bin/jchroot +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/bash -# -# This script is the simplified and portable version of arch-chroot -# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) -# - -set -e - -JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" - -source "${JUNEST_BASE}/lib/utils/utils.sh" - -################################ MAIN FUNCTIONS ########################### - -chroot_add_mount() { - mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}") -} - -chroot_maybe_add_mount() { - local cond=$1; shift - if eval "$cond"; then - chroot_add_mount "$@" - fi -} - -chroot_setup() { - CHROOT_ACTIVE_MOUNTS=() - [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' - trap 'chroot_teardown' EXIT - - chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind && - chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && - chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && - chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && - chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && - chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && - chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 && - chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,atime,nodev,nosuid && - mkdir -p "$1/$HOME" && - chroot_add_mount $HOME "$1/$HOME" --bind - - mkdir -p "$1/run/lock" -} - -chroot_teardown() { - umount "${CHROOT_ACTIVE_MOUNTS[@]}" - unset CHROOT_ACTIVE_MOUNTS -} - -usage() { - cat < Arguments for backend program (PRoot or jchroot)" + echo -e "-r, --root Run $NAME with root privileges via GRoot" + echo -e "-p, --backend-args Arguments for backend program (PRoot or GRoot)" echo -e " ($CMD -p \"--help\" to check out the PRoot options" - echo -e " $CMD -u -p \"--help\" to check out the jchroot options)" + echo -e " $CMD -u -p \"--help\" to check out the GRoot options)" echo -e "-u, --user-namespace Use Linux User Namespace instead of PRoot" echo echo -e "Building options:" @@ -47,7 +51,7 @@ usage() { echo echo -e "General options:" echo -e "-h, --help Show this help message" - echo -e "-v, --version Show the $NAME version" + echo -e "-V, --version Show the $NAME version" } version() { @@ -169,7 +173,7 @@ function parse_arguments(){ -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; - -v|--version) OPT_VERSION=true ; shift ;; + -V|--version) OPT_VERSION=true ; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -231,11 +235,11 @@ function execute_operation(){ } -function cli() { +function main() { parse_arguments "$@" check_cli execute_operation } -cli "$@" +main "$@" # vim: set ts=4 sw=4 noet: diff --git a/lib/core/build.sh b/lib/core/build.sh index 017ccad..fd87d86 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -69,11 +69,11 @@ function build_image_env(){ # sed command is required for locale-gen sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen + sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" info "Setting up the pacman keyring (this might take a while!)..." - sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ + sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root bash -c \ "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" sudo rm ${maindir}/root/var/cache/pacman/pkg/* diff --git a/lib/core/common.sh b/lib/core/common.sh index 87b5812..d7e050c 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -7,8 +7,6 @@ # # vim: ft=sh -set -e - NAME='JuNest' CMD='junest' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' @@ -79,7 +77,7 @@ SH=("/bin/sh" "--login") # List of executables that are run in the host OS: PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" -JCHROOT=${JUNEST_BASE}/bin/jchroot +GROOT=${JUNEST_BASE}/bin/groot CLASSIC_CHROOT=chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" @@ -125,7 +123,8 @@ function mkdir_cmd(){ } function zgrep_cmd(){ - $ZGREP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$ZGREP $@ + # No need for LD_EXEC as zgrep is a POSIX shell script + $ZGREP $@ || ${JUNEST_HOME}/usr/bin/$ZGREP $@ } function unshare_cmd(){ @@ -151,7 +150,7 @@ function download_cmd(){ } function chroot_cmd(){ - $JCHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" + $GROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" } ############## COMMON FUNCTIONS ############### diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index dddf521..7c3da65 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -59,7 +59,7 @@ function run_env_as_user_with_namespace() { local bindings=${RESULT} unset RESULT - unshare_cmd --mount --user --map-root-user $JCHROOT $bindings $backend_args "$JUNEST_HOME" + unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" } function run_env_as_fakeroot_with_namespace() { @@ -69,9 +69,19 @@ function run_env_as_fakeroot_with_namespace() { copy_common_files + #mkdir -p "$chrootdir/$HOME" + #mkdir -p "$chrootdir/run/lock" + #chroot_add_mount --rbind /proc "$chrootdir/proc/" + #chroot_add_mount --rbind /dev "$chrootdir/dev/" + #chroot_add_mount --rbind /sys "$chrootdir/sys/" + #chroot_add_mount --rbind /tmp "$chrootdir/tmp/" + ## alternately create a new tmp istead of binding it: + ##chroot_add_mount -t tmpfs tmp "$chrootdir/tmp/" + #chroot_add_mount --rbind $HOME "$chrootdir/$HOME" provide_common_bindings local bindings=${RESULT} unset RESULT - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $JCHROOT $bindings $backend_args "$JUNEST_HOME" + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" + } diff --git a/lib/utils/utils.sh b/lib/utils/utils.sh index 840fbe9..00e2cb6 100644 --- a/lib/utils/utils.sh +++ b/lib/utils/utils.sh @@ -170,6 +170,20 @@ function ask(){ [ "$res" == "Y" ] } +function check_and_trap() { + local sigs="${@:2:${#@}}" + local traps="$(trap -p $sigs)" + [[ $traps ]] && die "Attempting to overwrite existing $sigs trap: $traps" + trap $@ +} + +function check_and_force_trap() { + local sigs="${@:2:${#@}}" + local traps="$(trap -p $sigs)" + [[ $traps ]] && warn "Attempting to overwrite existing $sigs trap: $traps" + trap $@ +} + function insert_quotes_on_spaces(){ # It inserts quotes between arguments. # Useful to preserve quotes on command diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index 33beefa..a95c32a 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -104,10 +104,16 @@ function test_zgrep(){ ZGREP=echo assertCommandSuccess zgrep_cmd new_file assertEquals "new_file" "$(cat $STDOUTF)" - ZGREP=false assertCommandSuccess zgrep_cmd new_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false new_file" "$(cat $STDOUTF)" + mkdir -p ${JUNEST_HOME}/usr/bin + touch ${JUNEST_HOME}/usr/bin/false + chmod +x ${JUNEST_HOME}/usr/bin/false - ZGREP=false LD_EXEC=false assertCommandFail zgrep_cmd new_file + echo -e "#!/bin/bash\necho zgrep" > ${JUNEST_HOME}/usr/bin/false + ZGREP=false assertCommandSuccess zgrep_cmd new_file + assertEquals "zgrep" "$(cat $STDOUTF)" + + echo -e "#!/bin/bash\nexit 1" > ${JUNEST_HOME}/usr/bin/false + ZGREP=false assertCommandFail zgrep_cmd new_file } function test_unshare(){ @@ -121,16 +127,16 @@ function test_unshare(){ } function test_chroot(){ - JCHROOT=echo assertCommandSuccess chroot_cmd root + GROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - JCHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root + GROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - JCHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + GROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)" - JCHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root + GROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } function test_proot_cmd_compat(){ diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh new file mode 100755 index 0000000..02f05ec --- /dev/null +++ b/tests/unit-tests/test-groot.sh @@ -0,0 +1,137 @@ +#!/bin/bash +source "$(dirname $0)/../utils/utils.sh" + +JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/../..)" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + # Attempt to source the files under test to revert variable overrides + source $JUNEST_BASE/bin/groot -h &> /dev/null + set +e + + cwdSetUp + mkdir -p chrootdir + + init_mocks +} + +function tearDown(){ + cwdTearDown +} + +## Mock functions ## +function init_mocks() { + function usage(){ + echo "usage" + } + function is_user_root() { + return 0 + } + function chroot() { + echo "chroot($@)" + } + function mountpoint() { + echo "mountpoint($@)" + # As default suppose the mountpoint does not exist + return 1 + } + function mount() { + echo "mount($@)" + } + function umount() { + echo "umount($@)" + } + function check_and_trap() { + echo "check_and_trap($@)" + } +} + +function test_help(){ + assertCommandSuccess main -h + assertEquals "usage" "$(cat $STDOUTF)" + assertCommandSuccess main --help + assertEquals "usage" "$(cat $STDOUTF)" +} +function test_version(){ + assertCommandSuccess main -V + assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)" + assertCommandSuccess main --version + assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)" +} +function test_groot_no_root(){ + is_user_root() { + return 1 + } + assertCommandFailOnStatus $NO_ROOT_PRIVILEGES main +} +function test_groot_no_directory(){ + assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory +} +function test_groot_mountpoint_exist(){ + mountpoint_mock() { + echo "mountpoint($@)" + } + MOUNTPOINT=mountpoint_mock + assertCommandSuccess main chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_mountpoint_does_not_exist(){ + assertCommandSuccess main chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind(){ + assertCommandSuccess main -b /tmp chrootdir + [[ -d chrootdir/tmp ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_file(){ + touch file_src + assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir + [[ -f chrootdir/file_src ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_not_existing_node(){ + assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_not_absolute_path_node(){ + touch file_src + assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_guest_host(){ + assertCommandSuccess main -b /tmp:/home/tmp chrootdir + [[ -d chrootdir/home/tmp ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_multiple_bind(){ + assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir + [[ -d chrootdir/home/tmp ]] + assertEquals 0 $? + [[ -d chrootdir/dev ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_command(){ + assertCommandSuccess main chrootdir ls -la -h + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" +} +function test_groot_with_bind_and_command(){ + assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h + [[ -d chrootdir/home/tmp ]] + assertEquals 0 $? + [[ -d chrootdir/dev ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" +} + +source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-cli.sh b/tests/unit-tests/test-junest.sh similarity index 66% rename from tests/unit-tests/test-cli.sh rename to tests/unit-tests/test-junest.sh index efe55b5..c9f2d4a 100755 --- a/tests/unit-tests/test-cli.sh +++ b/tests/unit-tests/test-junest.sh @@ -1,7 +1,8 @@ #!/bin/bash source "$(dirname $0)/../utils/utils.sh" -source $(dirname $0)/../../bin/junest -h &> /dev/null +JUNEST_BASE="$(dirname $0)/../.." +source $JUNEST_BASE/bin/junest -h &> /dev/null # Disable the exiterr set +e @@ -68,149 +69,149 @@ function run_env_as_user_with_namespace(){ } function test_help(){ - assertCommandSuccess cli -h + assertCommandSuccess main -h assertEquals "usage" "$(cat $STDOUTF)" - assertCommandSuccess cli --help + assertCommandSuccess main --help assertEquals "usage" "$(cat $STDOUTF)" } function test_version(){ - assertCommandSuccess cli -v + assertCommandSuccess main -V assertEquals "version" "$(cat $STDOUTF)" - assertCommandSuccess cli --version + assertCommandSuccess main --version assertEquals "version" "$(cat $STDOUTF)" } function test_build_image_env(){ - assertCommandSuccess cli -b + assertCommandSuccess main -b assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli --build-image + assertCommandSuccess main --build-image assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli -b -s + assertCommandSuccess main -b -s assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)" - assertCommandSuccess cli -b -n + assertCommandSuccess main -b -n assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli -b -n -s + assertCommandSuccess main -b -n -s assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" - assertCommandSuccess cli --build-image --disable-validation --skip-root-tests + assertCommandSuccess main --build-image --disable-validation --skip-root-tests assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" } function test_check_env(){ - assertCommandSuccess cli -c myscript + assertCommandSuccess main -c myscript assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli --check myscript + assertCommandSuccess main --check myscript assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess cli -c myscript -s + assertCommandSuccess main -c myscript -s assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" - assertCommandSuccess cli --check myscript --skip-root-tests + assertCommandSuccess main --check myscript --skip-root-tests assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" } function test_delete_env(){ - assertCommandSuccess cli -d + assertCommandSuccess main -d assertEquals "delete_env" "$(cat $STDOUTF)" - assertCommandSuccess cli --delete + assertCommandSuccess main --delete assertEquals "delete_env" "$(cat $STDOUTF)" } function test_setup_env_from_file(){ is_env_installed(){ return 1 } - assertCommandSuccess cli -i myimage + assertCommandSuccess main -i myimage assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess cli --setup-from-file myimage + assertCommandSuccess main --setup-from-file myimage assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - assertCommandFail cli -i myimage + assertCommandFail main -i myimage } function test_setup_env(){ is_env_installed(){ return 1 } - assertCommandSuccess cli -a arm + assertCommandSuccess main -a arm assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess cli --arch arm + assertCommandSuccess main --arch arm assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess cli + assertCommandSuccess main assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - assertCommandFail cli -a arm + assertCommandFail main -a arm } function test_run_env_as_fakeroot(){ - assertCommandSuccess cli -f + assertCommandSuccess main -f assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli --fakeroot + assertCommandSuccess main --fakeroot assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -f -p "-b arg" + assertCommandSuccess main -f -p "-b arg" assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -f -p "-b arg" -- command -kv + assertCommandSuccess main -f -p "-b arg" -- command -kv assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)" - assertCommandSuccess cli -f command --as + assertCommandSuccess main -f command --as assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" - assertCommandFail cli -a "myarch" -f command --as + assertCommandFail main -a "myarch" -f command --as } function test_run_env_as_user(){ - assertCommandSuccess cli + assertCommandSuccess main assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -p "-b arg" + assertCommandSuccess main -p "-b arg" assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -p "-b arg" -- command -ll + assertCommandSuccess main -p "-b arg" -- command -ll assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess cli command -ls + assertCommandSuccess main command -ls assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" - assertCommandFail cli -a "myarch" -- command -ls + assertCommandFail main -a "myarch" -- command -ls } function test_run_env_as_root(){ - assertCommandSuccess cli -r + assertCommandSuccess main -r assertEquals "run_env_as_root " "$(cat $STDOUTF)" - assertCommandSuccess cli -r command + assertCommandSuccess main -r command assertEquals "run_env_as_root command" "$(cat $STDOUTF)" } function test_run_env_as_fakeroot_with_namespace(){ - assertCommandSuccess cli -u -f + assertCommandSuccess main -u -f assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli --user-namespace --fakeroot + assertCommandSuccess main --user-namespace --fakeroot assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -f -p "-b arg" + assertCommandSuccess main -u -f -p "-b arg" assertEquals "run_env_as_fakeroot_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -f -p "-b arg" -- command -kv + assertCommandSuccess main -u -f -p "-b arg" -- command -kv assertEquals "run_env_as_fakeroot_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -f command --as + assertCommandSuccess main -u -f command --as assertEquals "run_env_as_fakeroot_with_namespace(,command --as)" "$(cat $STDOUTF)" } function test_run_env_as_user_with_namespace(){ - assertCommandSuccess cli -u + assertCommandSuccess main -u assertEquals "run_env_as_user_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -p "-b arg" + assertCommandSuccess main -u -p "-b arg" assertEquals "run_env_as_user_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u -p "-b arg" -- command -ll + assertCommandSuccess main -u -p "-b arg" -- command -ll assertEquals "run_env_as_user_with_namespace(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess cli -u command -ls + assertCommandSuccess main -u command -ls assertEquals "run_env_as_user_with_namespace(,command -ls)" "$(cat $STDOUTF)" } function test_check_cli(){ - assertCommandFail cli -b -h - assertCommandFail cli -b -c - assertCommandFail cli -d -s - assertCommandFail cli -n -v - assertCommandFail cli -d -r - assertCommandFail cli -h -f - assertCommandFail cli -v -i fsd - assertCommandFail cli -f -r - assertCommandFail cli -p args -v - assertCommandFail cli -a arch -v - assertCommandFail cli -d args + assertCommandFail main -b -h + assertCommandFail main -b -c + assertCommandFail main -d -s + assertCommandFail main -n -v + assertCommandFail main -d -r + assertCommandFail main -h -f + assertCommandFail main -v -i fsd + assertCommandFail main -f -r + assertCommandFail main -p args -v + assertCommandFail main -a arch -v + assertCommandFail main -d args } source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-utils.sh b/tests/unit-tests/test-utils.sh index 8a5a127..c0b1ebf 100755 --- a/tests/unit-tests/test-utils.sh +++ b/tests/unit-tests/test-utils.sh @@ -79,6 +79,28 @@ function test_ask_wrong_default_answer() { assertEquals 33 $? } +function test_check_and_trap_fail() { + trap echo EXIT + trap ls QUIT + assertCommandFailOnStatus 1 check_and_trap 'pwd' EXIT QUIT +} + +function test_check_and_trap() { + trap - EXIT QUIT + assertCommandSuccess check_and_trap 'echo' EXIT QUIT +} + +function test_check_and_force_trap_fail() { + trap echo EXIT + trap ls QUIT + assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT +} + +function test_check_and_force_trap() { + trap - EXIT QUIT + assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT +} + function test_insert_quotes_on_spaces(){ assertCommandSuccess insert_quotes_on_spaces this is "a test" assertEquals "this is \"a test\"" "$(cat $STDOUTF)" diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index b96000c..ed7cb8c 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -1,3 +1,4 @@ +OLD_CWD=${PWD} function cwdSetUp(){ ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) cd $ORIGIN_CWD @@ -5,6 +6,7 @@ function cwdSetUp(){ function cwdTearDown(){ rm -rf $ORIGIN_CWD + cd $OLD_CWD } function junestSetUp(){ @@ -12,15 +14,12 @@ function junestSetUp(){ mkdir -p ${JUNEST_HOME}/etc/junest echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info mkdir -p ${JUNEST_HOME}/etc/ca-certificates - trap - QUIT EXIT ABRT KILL TERM INT - trap "rm -rf ${JUNEST_HOME}" EXIT QUIT ABRT KILL TERM INT } function junestTearDown(){ # the CA directories are read only and can be deleted only by changing the mod [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates rm -rf $JUNEST_HOME - trap - QUIT EXIT ABRT KILL TERM INT unset JUNEST_HOME } From 8e5531a27ac74b4997b297de7e955f37d7ef3925 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 3 Apr 2017 22:26:19 +0100 Subject: [PATCH 165/326] Issue #174: Add unit test for namespace --- lib/core/build.sh | 1 + lib/core/namespace.sh | 62 +++++++++++++++---- lib/core/proot.sh | 24 +++++--- tests/unit-tests/test-namespace.sh | 97 +++++++++++++++++++++++++++++- tests/unit-tests/test-proot.sh | 38 ++++++------ 5 files changed, 181 insertions(+), 41 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index fd87d86..1945185 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -137,4 +137,5 @@ function check_env(){ info "Removing the previous packages..." JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop + JUNEST_HOME=${testdir} ${cmd} -u -- ls -la } diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 7c3da65..6c44bbb 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -26,7 +26,7 @@ function _is_user_namespace_enabled() { return $NOT_EXISTING_FILE fi - if ! zgrep_cmd "CONFIG_USER_NS=y" $config_file + if ! zgrep_cmd -q "CONFIG_USER_NS=y" $config_file then return $NO_CONFIG_FOUND fi @@ -42,6 +42,35 @@ function _check_user_namespace() { set -e } +function _run_env_with_namespace(){ + local backend_args="$1" + shift + + if [[ "$1" != "" ]] + then + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + else + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" + fi +} + + +####################################### +# Run JuNest as normal user via user namespace. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# GROOT (RO) : The groot program. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# Depends on the unshare command outcome. +# Output: +# - : The command output. +####################################### function run_env_as_user_with_namespace() { local backend_args="$1" shift @@ -59,9 +88,26 @@ function run_env_as_user_with_namespace() { local bindings=${RESULT} unset RESULT - unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" + # TODO make sure to run the environment as normal user + _run_env_with_namespace "$backend_args" "$@" } +####################################### +# Run JuNest as fakeroot via user namespace. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# GROOT (RO) : The groot program. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# Depends on the unshare command outcome. +# Output: +# - : The command output. +####################################### function run_env_as_fakeroot_with_namespace() { local backend_args="$1" shift @@ -69,19 +115,9 @@ function run_env_as_fakeroot_with_namespace() { copy_common_files - #mkdir -p "$chrootdir/$HOME" - #mkdir -p "$chrootdir/run/lock" - #chroot_add_mount --rbind /proc "$chrootdir/proc/" - #chroot_add_mount --rbind /dev "$chrootdir/dev/" - #chroot_add_mount --rbind /sys "$chrootdir/sys/" - #chroot_add_mount --rbind /tmp "$chrootdir/tmp/" - ## alternately create a new tmp istead of binding it: - ##chroot_add_mount -t tmpfs tmp "$chrootdir/tmp/" - #chroot_add_mount --rbind $HOME "$chrootdir/$HOME" provide_common_bindings local bindings=${RESULT} unset RESULT - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" - + _run_env_with_namespace "$backend_args" "$@" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index 3460f18..edad2c3 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -44,20 +44,23 @@ function _run_env_with_qemu(){ # Run JuNest as fakeroot. # # Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# EUID (RO) : The user ID. -# SH (RO) : Contains the default command to run in JuNest. +# JUNEST_HOME (RO) : The JuNest home directory. +# EUID (RO) : The user ID. +# SH (RO) : Contains the default command to run in JuNest. # Arguments: -# cmd ($@?) : The command to run inside JuNest environment. +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. # Default command is defined by SH variable. # Returns: -# $ROOT_ACCESS_ERROR : If the user is the real root. +# $ROOT_ACCESS_ERROR : If the user is the real root. # Output: -# - : The command output. +# - : The command output. ####################################### function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + local backend_args="$1" + shift copy_common_files @@ -67,7 +70,7 @@ function run_env_as_fakeroot(){ # An alternative is via -S option: #_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" - _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}" + _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $backend_args" "$@" } ####################################### @@ -78,7 +81,8 @@ function run_env_as_fakeroot(){ # EUID (RO) : The user ID. # SH (RO) : Contains the default command to run in JuNest. # Arguments: -# cmd ($@?) : The command to run inside JuNest environment. +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. # Default command is defined by SH variable. # Returns: # $ROOT_ACCESS_ERROR : If the user is the real root. @@ -88,6 +92,8 @@ function run_env_as_fakeroot(){ function run_env_as_user(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + local backend_args="$1" + shift # Files to bind are visible in `proot --help`. # This function excludes /etc/mtab file so that @@ -105,5 +111,5 @@ function run_env_as_user(){ local bindings=${RESULT} unset RESULT - _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}" + _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $backend_args" "$@" } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index deb90d2..b1e52d5 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -5,8 +5,6 @@ JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" source "$JUNEST_ROOT/lib/utils/utils.sh" -source "$JUNEST_ROOT/lib/core/common.sh" -source "$JUNEST_ROOT/lib/core/namespace.sh" # Disable the exiterr set +e @@ -15,14 +13,49 @@ function oneTimeSetUp(){ setUpUnitTests } +## Mock functions ## +function init_mocks() { + function unshare_cmd(){ + echo "unshare $@" + } +} + function setUp(){ cwdSetUp + junestSetUp + + # Attempt to source the files under test to revert variable + # overrides (i.e. SH variable) + source "$JUNEST_ROOT/lib/core/common.sh" + source "$JUNEST_ROOT/lib/core/namespace.sh" + set +e + + init_mocks } function tearDown(){ + junestTearDown cwdTearDown } +function _test_copy_common_files() { + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" +} + +function _test_copy_remaining_files() { + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" + [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat ${JUNEST_HOME}/etc/networks)" + + [[ -e ${JUNEST_HOME}/etc/passwd ]] + assertEquals 0 $? + [[ -e ${JUNEST_HOME}/etc/group ]] + assertEquals 0 $? +} + function test_is_user_namespace_enabled_no_config_file(){ CONFIG_PROC_FILE="blah" CONFIG_BOOT_FILE="blah" @@ -45,4 +78,64 @@ function test_is_user_namespace_enabled_with_config(){ assertCommandSuccess _is_user_namespace_enabled } +function test_run_env_as_user_with_namespace() { + assertCommandSuccess run_env_as_user_with_namespace "" "" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files + _test_copy_remaining_files +} + +function test_run_env_as_user_with_namespace_with_bindings() { + assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files + _test_copy_remaining_files +} + +function test_run_env_as_user_with_namespace_with_command() { + assertCommandSuccess run_env_as_user_with_namespace "" "ls -la" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + + _test_copy_common_files + _test_copy_remaining_files +} + +function test_run_env_as_user_with_namespace_with_bindings_and_command() { + assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + + _test_copy_common_files + _test_copy_remaining_files +} + +function test_run_env_as_fakeroot_with_namespace() { + assertCommandSuccess run_env_as_fakeroot_with_namespace "" "" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_fakeroot_with_namespace_with_bindings() { + assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_fakeroot_with_namespace_with_command() { + assertCommandSuccess run_env_as_fakeroot_with_namespace "" "ls -la" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_fakeroot_with_namespace_with_bindings_and_command() { + assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" + assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + + _test_copy_common_files +} + source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index fdc83b2..6640035 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -29,6 +29,24 @@ function tearDown(){ cwdTearDown } +function _test_copy_common_files() { + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" +} + +function _test_copy_remaining_files() { + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" + [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat ${JUNEST_HOME}/etc/networks)" + + [[ -e ${JUNEST_HOME}/etc/passwd ]] + assertEquals 0 $? + [[ -e ${JUNEST_HOME}/etc/group ]] + assertEquals 0 $? +} + function test_run_env_as_user(){ _run_env_with_qemu() { echo $@ @@ -40,19 +58,8 @@ function test_run_env_as_user(){ assertCommandSuccess run_env_as_user "-k 3.10" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" - - [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" - [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" - - [[ -e /etc/passwd ]] - assertEquals 0 $? - [[ -e /etc/group ]] - assertEquals 0 $? - + _test_copy_common_files + _test_copy_remaining_files } function test_run_env_as_fakeroot(){ @@ -66,10 +73,7 @@ function test_run_env_as_fakeroot(){ assertCommandSuccess run_env_as_fakeroot "-k 3.10" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" + _test_copy_common_files } function test_run_env_with_quotes(){ From fcb4a36f3090a75ee5856fb9b3335d31390bc679 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 7 Apr 2017 22:38:47 +0100 Subject: [PATCH 166/326] Issue #174: Add option -n in groot and umount directories in order --- bin/groot | 30 ++++++++++++++++++++---------- lib/core/namespace.sh | 7 +++++-- tests/unit-tests/test-groot.sh | 24 ++++++++++++++++++++++++ tests/unit-tests/test-namespace.sh | 16 ++++++++-------- 4 files changed, 57 insertions(+), 20 deletions(-) diff --git a/bin/groot b/bin/groot index 1d6e26b..97ccfef 100755 --- a/bin/groot +++ b/bin/groot @@ -19,6 +19,11 @@ UMOUNT=umount MOUNTPOINT=mountpoint MKDIR=mkdir TOUCH=touch +CUT=cut +SORT=sort +UNIQ=uniq +GREP=grep +MOUNTS_FILE=/proc/self/mounts NOT_EXISTING_FILE=103 NOT_ABSOLUTE_PATH=111 @@ -29,28 +34,29 @@ source "${JUNEST_BASE}/lib/utils/utils.sh" ################################ MAIN FUNCTIONS ########################### -function chroot_add_mount() { - $MOUNT "$@" && CHROOT_ACTIVE_MOUNTS=("${@: -1}" "${CHROOT_ACTIVE_MOUNTS[@]}") -} - function chroot_teardown() { - $UMOUNT "${CHROOT_ACTIVE_MOUNTS[@]}" - unset CHROOT_ACTIVE_MOUNTS + # Remove all mounts starting from the most nested ones. + # Suffix the CHROOTDIR with / to avoid umounting directories not belonging + # to CHROOTDIR. + for mp in $($GREP "${CHROOTDIR%/}/" $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) + do + $UMOUNT $mp + done + $UMOUNT ${CHROOTDIR%/} } function chroot_maybe_add_mount() { local cond=$1 shift if eval "$cond"; then - chroot_add_mount "$@" + $MOUNT "$@" return fi return 1 } function chroot_setup() { - CHROOT_ACTIVE_MOUNTS=() - check_and_trap 'chroot_teardown' EXIT + $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' EXIT if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" then @@ -73,7 +79,7 @@ function chroot_setup() { fi create_node "${host_path}" "${CHROOTDIR}${guest_path}" - chroot_add_mount --rbind "${host_path}" "${CHROOTDIR}${guest_path}" + $MOUNT --rbind "${host_path}" "${CHROOTDIR}${guest_path}" done } @@ -112,6 +118,8 @@ Options: path in the guest rootfs but users can specify any other location with the syntax: -b :. This option can be invoked multiple times and the paths specified must be absolutes. + -n, --no-umount + Do not umount after chroot session finished. -h, --help Print this help message @@ -129,12 +137,14 @@ version() { function parse_arguments() { OPT_BIND=false BINDINGS=() + OPT_NO_UMOUNT=false OPT_HELP=false OPT_VERSION=false for opt in "$@" do case "$1" in -b|--bind) OPT_BIND=true ; shift ; BINDINGS+=("$1") ; shift ;; + -n|--no-umount) OPT_NO_UMOUNT=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -V|--version) OPT_VERSION=true ; shift ;; -*) die "Invalid option $1" ;; diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 6c44bbb..8854c43 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -46,11 +46,14 @@ function _run_env_with_namespace(){ local backend_args="$1" shift + # Use option -n in groot because umount do not work sometimes. + # As soon as the process terminates, the namespace + # will terminate too with its own mounted directories. if [[ "$1" != "" ]] then - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT -n $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT -n $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" fi } diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index 02f05ec..472e027 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -133,5 +133,29 @@ function test_groot_with_bind_and_command(){ assertEquals 0 $? assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } +function test_groot_with_bind_no_umount(){ + assertCommandSuccess main -n chrootdir + assertEquals "$(echo -e "mountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} +function test_groot_with_chroot_teardown(){ + echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts + MOUNTS_FILE=./mounts + CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) +umount(/home/mychroot/proc) +umount(/home/mychroot/dev/shm) +umount(/home/mychroot/dev) +umount(/home/mychroot)")" "$(cat $STDOUTF)" +} +function test_groot_with_chroot_teardown_with_trailing_slash(){ + echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts + MOUNTS_FILE=./mounts + CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) +umount(/home/mychroot/proc) +umount(/home/mychroot/dev/shm) +umount(/home/mychroot/dev) +umount(/home/mychroot)")" "$(cat $STDOUTF)" +} source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index b1e52d5..e09db0a 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -80,7 +80,7 @@ function test_is_user_namespace_enabled_with_config(){ function test_run_env_as_user_with_namespace() { assertCommandSuccess run_env_as_user_with_namespace "" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -88,7 +88,7 @@ function test_run_env_as_user_with_namespace() { function test_run_env_as_user_with_namespace_with_bindings() { assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -96,7 +96,7 @@ function test_run_env_as_user_with_namespace_with_bindings() { function test_run_env_as_user_with_namespace_with_command() { assertCommandSuccess run_env_as_user_with_namespace "" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -104,7 +104,7 @@ function test_run_env_as_user_with_namespace_with_command() { function test_run_env_as_user_with_namespace_with_bindings_and_command() { assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -112,28 +112,28 @@ function test_run_env_as_user_with_namespace_with_bindings_and_command() { function test_run_env_as_fakeroot_with_namespace() { assertCommandSuccess run_env_as_fakeroot_with_namespace "" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_fakeroot_with_namespace_with_bindings() { assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_fakeroot_with_namespace_with_command() { assertCommandSuccess run_env_as_fakeroot_with_namespace "" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_fakeroot_with_namespace_with_bindings_and_command() { assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } From b817aa8445ace8c5e58cdff88e7f0e0a275a8e15 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 9 Apr 2017 17:34:43 +0100 Subject: [PATCH 167/326] Issue #174: Add -g option for Groot and integ tests for user namespace --- .travis.yml | 11 ++- README.md | 77 +++++++++++++++++--- bin/groot | 2 +- bin/junest | 77 +++++++------------- lib/checks/check.sh | 62 ++++++++++++++++ lib/core/build.sh | 46 +----------- lib/core/chroot.sh | 87 +++++++++++++++++------ lib/core/common.sh | 110 +++++++++++++++++++++-------- lib/core/namespace.sh | 48 +++---------- lib/core/proot.sh | 5 +- tests/unit-tests/test-chroot.sh | 45 ++++++++---- tests/unit-tests/test-common.sh | 46 ++++++++---- tests/unit-tests/test-groot.sh | 20 +++--- tests/unit-tests/test-junest.sh | 86 ++++++++-------------- tests/unit-tests/test-namespace.sh | 44 +++--------- 15 files changed, 433 insertions(+), 333 deletions(-) create mode 100755 lib/checks/check.sh diff --git a/.travis.yml b/.travis.yml index a1b6078..4e4536a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,9 +17,14 @@ install: script: - bash --version - - bash ./tests/unit-tests/unit-tests.sh - bash ./tests/checkstyle/checkstyle.sh - - junest --check ./bin/junest + - bash ./tests/unit-tests/unit-tests.sh + + # Multiple tests against different execution modes: + - junest -f -- ${PWD}/lib/checks/check.sh + - junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --run-root-tests - yes | junest --delete - - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests + + - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/README.md b/README.md index e747c4e..492e284 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Arch Linux based distro that runs upon any Linux distros without root access |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/Google Groups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/GoogleGroups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) @@ -48,19 +48,62 @@ JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/ Quickstart ========== -There are three different ways you can run JuNest: + +Backend programs +---------------- +There are three different ways you can run JuNest depending on the backend program you decide to use. + +### PRoot based ### +[Proot](https://wiki.archlinux.org/index.php/Proot) represents the default +program used for accessing to the JuNest environments. +The main reason to choose Proot as default backend program is because +it represents a portable solution that works well in most of GNU/Linux distros available. +One of the major drawbacks is the fact that Proot is not officially +supported anymore, therefore, Proot bugs may no longer be fixed. + +In order to run JuNest via Proot: - As normal user - Allow to make basic operations: ```junest``` - As fakeroot - Allow to install/remove packages: ```junest -f``` -- As root - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` +### Linux namespaces based ### +The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) +represents the next generation backend program for JuNest. +The major drawback about the namespace is portability, as certain requirements +need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes can +create the required user and mount namespaces. +2) Moreover, the Linux kernel distro must have the user namespace enabled. +Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. +For instance, Ubuntu (version 14.04+) already has such feature enabled. +In order to run JuNest via Linux namespaces: + +- As fakeroot - Allow to install/remove packages: ```junest -u``` + +### Chroot based ### +This solution suits only for privileged users. JuNest provides the possibility +to run the environment via `chroot` program. +In particular, it uses a special program called `GRoot`, an enhanced `chroot` +wrapper that allows to bind mount directories specified by the user, such as +/proc, /sys, /dev, /tmp and $HOME, before +executing any programs inside the JuNest sandbox. In case the mounting will not +work, JuNest is even providing the possibility to run the environment directly via +the pure `chroot` command. + +In order to run JuNest via `chroot` solutions: + +- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -g``` + +- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` + +After running JuNest +-------------------- If the JuNest image has not been downloaded yet, the script will download -the image and will place it to the default directory ~/.junest. -You can change the default directory by changing the environment variable *JUNEST\_HOME*. +the image from the repository and will place it to the default directory `~/.junest`. +You can change the default directory by changing the environment variable `JUNEST_HOME`. -If you are new on Archlinux and you are not familiar with *pacman* package manager +If you are new on Arch Linux and you are not familiar with `pacman` package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). Installation @@ -90,7 +133,7 @@ Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): ### Installation using AUR (Arch Linux only) ### If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/): - yogurt -S junest-git + yaourt -S junest-git export PATH=/opt/junest/bin:$PATH ## Method two ## @@ -98,7 +141,7 @@ Alternatively, another installation method would be to directly download the JuN ARCH= mkdir ~/.junest - curl https://dl.dropboxusercontent.com/u/42449030/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest + curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest export PATH=~/.junest/opt/junest/bin:$PATH Advanced usage @@ -141,12 +184,12 @@ To bind a host directory to a guest location, you can use proot arguments: junest -p "-b /mnt/mydata:/home/user/mydata" -Check out the proot options with: +This will works with PRoot, Namespace and GRoot backend programs. +Check out the backend program options by passing `--help` option: - junest -p "--help" + junest [-u|-g] -p "--help" ## Systemd integration ## - Although JuNest has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). The JuNest containter allows to run services inside the container that can be @@ -345,6 +388,18 @@ Troubleshooting > since JuNest will try to preserve the JuNest environment by assigning ownership > of the files to the real user. +## Not enabled User namespace or kernel too old ## + +> **Q**: Why do I get warning when I run JuNest via Linux namespaces? + + $> junest -u + User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway... + +> **A**: This means that JuNest detected that the host OS either +> does not have a newer Linux version or the user namespace is not enabled. +> JuNest does not stop the execution of the program but it attempts to run it +> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. + More documentation ================== There are additional tutorials in the diff --git a/bin/groot b/bin/groot index 97ccfef..4033705 100755 --- a/bin/groot +++ b/bin/groot @@ -56,7 +56,7 @@ function chroot_maybe_add_mount() { } function chroot_setup() { - $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' EXIT + $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" then diff --git a/bin/junest b/bin/junest index 9d2a527..a2b96e5 100755 --- a/bin/junest +++ b/bin/junest @@ -36,18 +36,17 @@ usage() { echo echo -e "Access options:" echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" - echo -e "-r, --root Run $NAME with root privileges via GRoot" + echo -e "-g, --groot Run $NAME with root privileges via GRoot" + echo -e "-r, --root Run $NAME with root privileges via classic chroot" + echo -e "-u, --namespace Use Linux Namespace (with GRoot) instead of PRoot" echo -e "-p, --backend-args Arguments for backend program (PRoot or GRoot)" echo -e " ($CMD -p \"--help\" to check out the PRoot options" - echo -e " $CMD -u -p \"--help\" to check out the GRoot options)" - echo -e "-u, --user-namespace Use Linux User Namespace instead of PRoot" + echo -e " $CMD -g -p \"--help\" to check out the GRoot options" + echo -e " $CMD -r -p \"--help\" to check out the chroot options)" echo echo -e "Building options:" echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" echo -e "-n, --disable-validation Disable the $NAME image validation" - echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}" - echo -e " using ${CMD}_script. This will alterate the environment" - echo -e "-s, --skip-root-tests Skip the root tests during the validation process" echo echo -e "General options:" echo -e "-h, --help Show this help message" @@ -60,33 +59,17 @@ version() { check_cli(){ if $OPT_BUILD_IMAGE - then - if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK - then - die "The build image option must be used exclusively" - fi - fi - if $OPT_SKIP_ROOT_TEST then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ $OPT_FAKEROOT || $OPT_ROOT then - die "The skip root tests option must be used with either build image or check options" - fi - fi - if $OPT_CHECK - then - if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_BUILD_IMAGE - then - die "The validation image option must be used exclusively" + die "The build image option must be used exclusively" fi fi if $OPT_DISABLE_VALIDATION then if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT then die "The disable validation option must be used with the build image option only" fi @@ -94,7 +77,7 @@ check_cli(){ if $OPT_DELETE then if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME delete option must be used exclusively" fi @@ -102,7 +85,7 @@ check_cli(){ if $OPT_HELP then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME help option must be used exclusively" fi @@ -110,7 +93,7 @@ check_cli(){ if $OPT_VERSION then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION then die "The $NAME version option must be used exclusively" fi @@ -122,7 +105,7 @@ check_cli(){ if $OPT_BACKEND_ARGS || $OPT_ARCH then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ - $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION then die "Invalid syntax: Proot and arch args are not allowed with the other options" fi @@ -130,7 +113,7 @@ check_cli(){ if [ "$ARGS" != "" ] then if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK + $OPT_VERSION || $OPT_DISABLE_VALIDATION then die "No arguments are needed. For the CLI syntax run: $CMD --help" fi @@ -145,6 +128,7 @@ function parse_arguments(){ IMAGE_FILE="" OPT_FAKEROOT=false OPT_ROOT=false + OPT_GROOT=false OPT_USER_NAMESPACE=false OPT_BACKEND_ARGS=false BACKEND_ARGS="" @@ -152,9 +136,7 @@ function parse_arguments(){ ARCH_ARG="" OPT_BUILD_IMAGE=false OPT_DISABLE_VALIDATION=false - OPT_CHECK=false CHECK_ARG="" - OPT_SKIP_ROOT_TEST=false OPT_DELETE=false OPT_HELP=false OPT_VERSION=false @@ -164,13 +146,12 @@ function parse_arguments(){ -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; -r|--root) OPT_ROOT=true ; shift ;; - -u|--user-namespace) OPT_USER_NAMESPACE=true ; shift ;; + -g|--groot) OPT_GROOT=true ; shift ;; + -u|--namespace) OPT_USER_NAMESPACE=true ; shift ;; -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; - -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; - -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -V|--version) OPT_VERSION=true ; shift ;; @@ -192,14 +173,11 @@ function execute_operation(){ $OPT_VERSION && version && return if $OPT_BUILD_IMAGE; then - build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST + build_image_env $OPT_DISABLE_VALIDATION return elif $OPT_DELETE; then delete_env return - elif $OPT_CHECK; then - check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST - return fi if ! is_env_installed @@ -217,22 +195,21 @@ function execute_operation(){ [ -z "${ARCH_ARG}" ] || \ die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" + local run_env if $OPT_USER_NAMESPACE; then - if $OPT_FAKEROOT; then - run_env_as_fakeroot_with_namespace "${BACKEND_ARGS}" "${ARGS[@]}" - else - run_env_as_user_with_namespace "${BACKEND_ARGS}" "${ARGS[@]}" - fi + run_env=run_env_with_namespace + elif $OPT_FAKEROOT; then + run_env=run_env_as_fakeroot + elif $OPT_ROOT; then + run_env=run_env_as_chroot + elif $OPT_GROOT; then + run_env=run_env_as_groot else - if $OPT_FAKEROOT; then - run_env_as_fakeroot "${BACKEND_ARGS}" "${ARGS[@]}" - elif $OPT_ROOT; then - run_env_as_root "${ARGS[@]}" - else - run_env_as_user "${BACKEND_ARGS}" "${ARGS[@]}" - fi + run_env=run_env_as_user fi + $run_env "${BACKEND_ARGS}" "${ARGS[@]}" + } function main() { diff --git a/lib/checks/check.sh b/lib/checks/check.sh new file mode 100755 index 0000000..4a0cd73 --- /dev/null +++ b/lib/checks/check.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# +# This modules is used for: +# - Running checks against the building JuNest image +# - Integration tests on JuNest script against different execution modes (i.e. -f, -u, -r modes) +# +# Dependencies: +# - None +# +# vim: ft=sh + +set -eu + +OPT_RUN_ROOT_TESTS=${1:-false} +RUN_ROOT_TESTS=false +[[ ${OPT_RUN_ROOT_TESTS} == "--run-root-tests" ]] && RUN_ROOT_TESTS=true + +OPT_SKIP_AUR_TESTS=${1:-false} +SKIP_AUR_TESTS=false +[[ ${OPT_SKIP_AUR_TESTS} == "--skip-aur-tests" ]] && SKIP_AUR_TESTS=true + +JUNEST_HOME=${JUNEST_HOME:-$HOME/.junest} + +# JUNEST_BASE can be overridden for testing purposes. +# There is no need for doing it for normal usage. +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}" + +source "${JUNEST_BASE}/lib/utils/utils.sh" +source "${JUNEST_BASE}/lib/core/common.sh" + +info "Validating JuNest located in ${JUNEST_HOME}..." + +info "Initial JuNest setup..." +echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist +pacman --noconfirm -Syy +pacman --noconfirm -S base-devel + +info "Checking essential executables work..." +pacman -Qi pacman 1> /dev/null +yogurt -V 1> /dev/null +/opt/proot/proot-$ARCH --help 1> /dev/null + +repo_package1=tree +echo "Checking ${repo_package1} package from official repo..." +pacman --noconfirm -S ${repo_package1} +tree -L 1 +pacman --noconfirm -Rsn ${repo_package1} + +repo_package2=iftop +info "Checking ${repo_package2} package from official repo..." +pacman --noconfirm -S ${repo_package2} +$RUN_ROOT_TESTS && iftop -t -s 5 +pacman --noconfirm -Rsn ${repo_package2} + +if ! $SKIP_AUR_TESTS +then + aur_package=tcptraceroute + info "Checking ${aur_package} package from AUR repo..." + yogurt -A --noconfirm -S ${aur_package} + $RUN_ROOT_TESTS && tcptraceroute localhost + pacman --noconfirm -Rsn ${aur_package} +fi diff --git a/lib/core/build.sh b/lib/core/build.sh index 1945185..4a00f22 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -40,7 +40,6 @@ function build_image_env(){ _check_package git local disable_validation=$1 - local skip_root_tests=$2 local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) sudo mkdir -p ${maindir}/root @@ -88,7 +87,8 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests + JUNEST_HOME="${maindir}/root_test" ${maindir}/root_test/opt/${CMD}/bin/${CMD} -f ./lib/checks/check.sh + JUNEST_HOME="${maindir}/root_test" sudo -E ${maindir}/root_test/opt/${CMD}/bin/${CMD} -g ./lib/checks/check.sh --run-root-tests fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} @@ -97,45 +97,3 @@ function build_image_env(){ trap - QUIT EXIT ABRT KILL TERM INT sudo rm -fr "$maindir" } - -function check_env(){ - local testdir=$1 - local cmd=$2 - local skip_root_tests=$3 - info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." - echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy - - # Check most basic executables work - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null - JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null - - local repo_package=tree - info "Installing ${repo_package} package from official repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - JUNEST_HOME=${testdir} ${cmd} tree - JUNEST_HOME=${testdir} ${cmd} -f tree - - local repo_package=iftop - info "Installing ${repo_package} package from official repo using root..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 - - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel - local aur_package=tcptraceroute - info "Installing ${aur_package} package from AUR repo using proot..." - JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package} - $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost - - info "Removing the previous packages..." - JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop - - JUNEST_HOME=${testdir} ${cmd} -u -- ls -la -} diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index ff8465d..9a104aa 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -8,27 +8,12 @@ # # vim: ft=sh -####################################### -# Run JuNest as real root. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# 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. -# Arguments: -# cmd ($@?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Output: -# - : The command output. -####################################### -function run_env_as_root(){ - source ${JUNEST_HOME}/etc/junest/info - [ "$JUNEST_ARCH" != "$ARCH" ] && \ - die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" +function _run_env_as_xroot(){ + local cmd=$1 + local backend_args="$2" + shift 2 + + check_same_arch local uid=$UID # SUDO_USER is more reliable compared to SUDO_UID @@ -41,5 +26,63 @@ function run_env_as_root(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT - JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" + copy_common_files + + check_nested_env + + JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" +} + +####################################### +# Run JuNest as real root via GRoot command. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# 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. +# Arguments: +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### +function run_env_as_groot(){ + local backend_args="$1" + shift + + provide_common_bindings + local bindings=${RESULT} + unset RESULT + + _run_env_as_xroot "$GROOT $bindings" "$backend_args" "$@" +} + +####################################### +# Run JuNest as real root via chroot command. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# 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. +# Arguments: +# backend_args ($1) : The arguments to pass to proot +# cmd ($2-?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### +function run_env_as_chroot(){ + local backend_args="$1" + shift + + _run_env_as_xroot chroot_cmd "$backend_args" "$@" } diff --git a/lib/core/common.sh b/lib/core/common.sh index d7e050c..17b0d5b 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -19,20 +19,9 @@ NESTED_ENVIRONMENT=106 VARIABLE_NOT_SET=107 NO_CONFIG_FOUND=108 -if [ "$JUNEST_ENV" == "1" ] -then - die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" -elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] -then - die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" -fi - -[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} -[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest -if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] -then - JUNEST_TEMPDIR=/tmp -fi +JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}} +JUNEST_BASE=${JUNEST_BASE:-${JUNEST_HOME}/opt/junest} +JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} # The update of the variable PATH ensures that the executables are # found on different locations @@ -99,36 +88,55 @@ LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" # image. function ln_cmd(){ - $LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@ + $LN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN "$@" } function getent_cmd(){ - $GETENT $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT $@ + $GETENT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT "$@" } function cp_cmd(){ - $CP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP $@ + $CP "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP "$@" } function rm_cmd(){ - $RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@ + $RM "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM "$@" } function chown_cmd(){ - $CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@ + $CHOWN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN "$@" } function mkdir_cmd(){ - $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ + $MKDIR "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR "$@" } function zgrep_cmd(){ # No need for LD_EXEC as zgrep is a POSIX shell script - $ZGREP $@ || ${JUNEST_HOME}/usr/bin/$ZGREP $@ + $ZGREP "$@" || ${JUNEST_HOME}/usr/bin/$ZGREP "$@" +} + +function download_cmd(){ + $WGET "$@" || $CURL "$@" +} + +function chroot_cmd(){ + $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" } function unshare_cmd(){ - $UNSHARE $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE $@ + # Most of the distros do not have the `unshare` command updated + # with --user option available. + # Hence, give priority to the `unshare` executable in JuNest image. + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${SH[@]}" "-c" ":" + then + $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE "${@}" + elif $UNSHARE --user "${SH[@]}" "-c" ":" + then + $UNSHARE "$@" + else + die "Error: Something went wrong with unshare command. Exiting" + fi } function proot_cmd(){ @@ -141,20 +149,60 @@ function proot_cmd(){ then PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else - die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" + die "Error: Something went wrong with proot command. Exiting" fi } -function download_cmd(){ - $WGET $@ || $CURL $@ -} - -function chroot_cmd(){ - $GROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" -} - ############## COMMON FUNCTIONS ############### +####################################### +# Check if the executable is being running inside a JuNest environment. +# +# Globals: +# JUNEST_ENV (RO) : The boolean junest env check +# NESTED_ENVIRONMENT (RO) : The nest env exception +# VARIABLE_NOT_SET (RO) : The var not set exception +# NAME (RO) : The JuNest name +# Arguments: +# None +# Returns: +# VARIABLE_NOT_SET : If no JUNEST_ENV is not properly set +# NESTED_ENVIRONMENT : If the script is executed inside JuNest env +# Output: +# None +####################################### +function check_nested_env() { + if [[ $JUNEST_ENV == "1" ]] + then + die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" + elif [[ ! -z $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]] + then + die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" + fi +} + +####################################### +# Check if the architecture between Host OS and Guest OS is the same. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home path. +# ARCHITECTURE_MISMATCH (RO) : The arch mismatch exception +# ARCH (RO) : The host OS arch +# JUNEST_ARCH (RO) : The JuNest arch +# Arguments: +# None +# Returns: +# ARCHITECTURE_MISMATCH : If arch between host and guest is not the same +# Output: +# None +####################################### +function check_same_arch() { + source ${JUNEST_HOME}/etc/junest/info + [ "$JUNEST_ARCH" != "$ARCH" ] && \ + die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" + return 0 +} + ####################################### # Provide the proot common binding options for both normal user and fakeroot. # The list of bindings can be found in `proot --help`. This function excludes diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 8854c43..9f4596f 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -46,6 +46,12 @@ function _run_env_with_namespace(){ local backend_args="$1" shift + check_nested_env + + provide_common_bindings + local bindings=${RESULT} + unset RESULT + # Use option -n in groot because umount do not work sometimes. # As soon as the process terminates, the namespace # will terminate too with its own mounted directories. @@ -59,7 +65,7 @@ function _run_env_with_namespace(){ ####################################### -# Run JuNest as normal user via user namespace. +# Run JuNest as fakeroot user via user namespace. # # Globals: # JUNEST_HOME (RO) : The JuNest home directory. @@ -70,15 +76,18 @@ function _run_env_with_namespace(){ # cmd ($2-?) : The command to run inside JuNest environment. # Default command is defined by SH variable. # Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. # Depends on the unshare command outcome. # Output: # - : The command output. ####################################### -function run_env_as_user_with_namespace() { +function run_env_with_namespace() { local backend_args="$1" shift _check_user_namespace + check_same_arch + copy_common_files copy_file /etc/hosts.equiv copy_file /etc/netgroup @@ -87,40 +96,5 @@ function run_env_as_user_with_namespace() { #copy_file /etc/localtime copy_passwd_and_group - provide_common_bindings - local bindings=${RESULT} - unset RESULT - - # TODO make sure to run the environment as normal user - _run_env_with_namespace "$backend_args" "$@" -} - -####################################### -# Run JuNest as fakeroot via user namespace. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# GROOT (RO) : The groot program. -# SH (RO) : Contains the default command to run in JuNest. -# Arguments: -# backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. -# Default command is defined by SH variable. -# Returns: -# Depends on the unshare command outcome. -# Output: -# - : The command output. -####################################### -function run_env_as_fakeroot_with_namespace() { - local backend_args="$1" - shift - _check_user_namespace - - copy_common_files - - provide_common_bindings - local bindings=${RESULT} - unset RESULT - _run_env_with_namespace "$backend_args" "$@" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index edad2c3..f678d9d 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -12,6 +12,7 @@ function _run_env_with_proot(){ local proot_args="$1" shift + check_nested_env if [ "$1" != "" ] then JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" @@ -58,7 +59,7 @@ function _run_env_with_qemu(){ ####################################### function run_env_as_fakeroot(){ (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." local backend_args="$1" shift @@ -91,7 +92,7 @@ function run_env_as_fakeroot(){ ####################################### function run_env_as_user(){ (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." local backend_args="$1" shift diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 04b22a7..aa491e5 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -18,6 +18,7 @@ function oneTimeSetUp(){ function setUp(){ cwdSetUp junestSetUp + init_mocks } function tearDown(){ @@ -25,28 +26,42 @@ function tearDown(){ cwdTearDown } -function test_run_env_as_root_different_arch(){ - echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info - assertCommandFailOnStatus 104 run_env_as_root pwd -} - -function _test_run_env_as_root() { +function init_mocks() { chroot_cmd() { [ "$JUNEST_ENV" != "1" ] && return 1 - echo $@ + echo "chroot_cmd $@" } - - assertCommandSuccess run_env_as_root $@ + GROOT=chroot_cmd } -function test_run_env_as_root_cmd(){ - _test_run_env_as_root pwd - assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +function test_run_env_as_groot_cmd(){ + assertCommandSuccess run_env_as_groot "" pwd + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } -function test_run_env_as_classic_root_no_cmd(){ - _test_run_env_as_root - assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +function test_run_env_as_groot_no_cmd(){ + assertCommandSuccess run_env_as_groot "" + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +} + +function test_run_env_as_groot_cmd_with_backend_args(){ + assertCommandSuccess run_env_as_groot "-n -b /home/blah" pwd + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +} + +function test_run_env_as_chroot_cmd(){ + assertCommandSuccess run_env_as_chroot "" pwd + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" +} + +function test_run_env_as_chroot_no_cmd(){ + assertCommandSuccess run_env_as_chroot "" + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" +} + +function test_run_env_as_chroot_cmd_with_backend_args(){ + assertCommandSuccess run_env_as_chroot "-n -b /home/blah" pwd + assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index a95c32a..e9286fa 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -20,10 +20,20 @@ function oneTimeTearDown(){ } function setUp(){ - ld_exec() { + ld_exec_mock() { echo "ld_exec $@" } - LD_EXEC=ld_exec + ld_exec_mock_false() { + echo "ld_exec $@" + return 1 + } + LD_EXEC=ld_exec_mock + + unshare_mock() { + echo "unshare $@" + } + UNSHARE=unshare_mock + } function test_ln(){ @@ -117,26 +127,23 @@ function test_zgrep(){ } function test_unshare(){ - UNSHARE=echo assertCommandSuccess unshare_cmd new_program - assertEquals "new_program" "$(cat $STDOUTF)" + assertCommandSuccess unshare_cmd new_program + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh --login -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat $STDOUTF)" - UNSHARE=false assertCommandSuccess unshare_cmd new_program - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false new_program" "$(cat $STDOUTF)" + LD_EXEC=ld_exec_mock_false assertCommandSuccess unshare_cmd new_program + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh --login -c :\nunshare --user /bin/sh --login -c :\nunshare new_program")" "$(cat $STDOUTF)" UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program } function test_chroot(){ - GROOT=echo assertCommandSuccess chroot_cmd root + CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" - GROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root - assertEquals "root" "$(cat $STDOUTF)" - - GROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)" - GROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root + CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } function test_proot_cmd_compat(){ @@ -187,11 +194,22 @@ function test_copy_passwd_and_group_failure(){ } function test_nested_env(){ - JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" + JUNEST_ENV=1 assertCommandFailOnStatus 106 check_nested_env } function test_nested_env_not_set_variable(){ - JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" + JUNEST_ENV=aaa assertCommandFailOnStatus 107 check_nested_env } +function test_check_same_arch_not_same(){ + echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + assertCommandFailOnStatus 104 check_same_arch +} + +function test_check_same_arch(){ + echo "JUNEST_ARCH=$ARCH" > ${JUNEST_HOME}/etc/junest/info + assertCommandSuccess check_same_arch +} + + source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index 472e027..c7b5f36 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -79,39 +79,39 @@ function test_groot_mountpoint_exist(){ } MOUNTPOINT=mountpoint_mock assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_mountpoint_does_not_exist(){ assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind(){ assertCommandSuccess main -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_file(){ touch file_src assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir [[ -f chrootdir/file_src ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_existing_node(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_absolute_path_node(){ touch file_src assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_guest_host(){ assertCommandSuccess main -b /tmp:/home/tmp chrootdir [[ -d chrootdir/home/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_multiple_bind(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir @@ -119,11 +119,11 @@ function test_groot_with_multiple_bind(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_command(){ assertCommandSuccess main chrootdir ls -la -h - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_and_command(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h @@ -131,7 +131,7 @@ function test_groot_with_bind_and_command(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown EXIT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_no_umount(){ assertCommandSuccess main -n chrootdir diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index c9f2d4a..2176cea 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -26,14 +26,7 @@ function version(){ } function build_image_env(){ local disable_validation=$1 - local skip_root_tests=$2 - echo "build_image_env($disable_validation,$skip_root_tests)" -} -function check_env(){ - local env_home=$1 - local cmd_script=$2 - local skip_root_tests=$3 - echo "check_env($env_home,$cmd_script,$skip_root_tests)" + echo "build_image_env($disable_validation)" } function delete_env(){ echo "delete_env" @@ -49,23 +42,21 @@ function run_env_as_fakeroot(){ shift echo "run_env_as_fakeroot($backend_args,$@)" } -function run_env_as_root(){ - echo "run_env_as_root $@" +function run_env_as_groot(){ + echo "run_env_as_groot $@" +} +function run_env_as_chroot(){ + echo "run_env_as_chroot $@" } function run_env_as_user(){ local backend_args="$1" shift echo "run_env_as_user($backend_args,$@)" } -function run_env_as_fakeroot_with_namespace(){ +function run_env_with_namespace(){ local backend_args="$1" shift - echo "run_env_as_fakeroot_with_namespace($backend_args,$@)" -} -function run_env_as_user_with_namespace(){ - local backend_args="$1" - shift - echo "run_env_as_user_with_namespace($backend_args,$@)" + echo "run_env_with_namespace($backend_args,$@)" } function test_help(){ @@ -82,27 +73,13 @@ function test_version(){ } function test_build_image_env(){ assertCommandSuccess main -b - assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" + assertEquals "build_image_env(false)" "$(cat $STDOUTF)" assertCommandSuccess main --build-image - assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" - assertCommandSuccess main -b -s - assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)" + assertEquals "build_image_env(false)" "$(cat $STDOUTF)" assertCommandSuccess main -b -n - assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)" - assertCommandSuccess main -b -n -s - assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" - assertCommandSuccess main --build-image --disable-validation --skip-root-tests - assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" -} -function test_check_env(){ - assertCommandSuccess main -c myscript - assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess main --check myscript - assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" - assertCommandSuccess main -c myscript -s - assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" - assertCommandSuccess main --check myscript --skip-root-tests - assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" + assertEquals "build_image_env(true)" "$(cat $STDOUTF)" + assertCommandSuccess main --build-image --disable-validation + assertEquals "build_image_env(true)" "$(cat $STDOUTF)" } function test_delete_env(){ assertCommandSuccess main -d @@ -168,36 +145,31 @@ function test_run_env_as_user(){ assertCommandFail main -a "myarch" -- command -ls } -function test_run_env_as_root(){ +function test_run_env_as_groot(){ + assertCommandSuccess main -g + assertEquals "run_env_as_groot " "$(cat $STDOUTF)" + assertCommandSuccess main -g command + assertEquals "run_env_as_groot command" "$(cat $STDOUTF)" +} +function test_run_env_as_chroot(){ assertCommandSuccess main -r - assertEquals "run_env_as_root " "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot " "$(cat $STDOUTF)" assertCommandSuccess main -r command - assertEquals "run_env_as_root command" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)" } -function test_run_env_as_fakeroot_with_namespace(){ +function test_run_env_with_namespace(){ assertCommandSuccess main -u -f - assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess main --user-namespace --fakeroot - assertEquals "run_env_as_fakeroot_with_namespace(,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertCommandSuccess main --namespace --fakeroot + assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" assertCommandSuccess main -u -f -p "-b arg" - assertEquals "run_env_as_fakeroot_with_namespace(-b arg,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)" assertCommandSuccess main -u -f -p "-b arg" -- command -kv - assertEquals "run_env_as_fakeroot_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main -u -f command --as - assertEquals "run_env_as_fakeroot_with_namespace(,command --as)" "$(cat $STDOUTF)" -} -function test_run_env_as_user_with_namespace(){ - assertCommandSuccess main -u - assertEquals "run_env_as_user_with_namespace(,)" "$(cat $STDOUTF)" - - assertCommandSuccess main -u -p "-b arg" - assertEquals "run_env_as_user_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main -u -p "-b arg" -- command -ll - assertEquals "run_env_as_user_with_namespace(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess main -u command -ls - assertEquals "run_env_as_user_with_namespace(,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" } function test_check_cli(){ diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index e09db0a..9cc60a7 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -78,64 +78,36 @@ function test_is_user_namespace_enabled_with_config(){ assertCommandSuccess _is_user_namespace_enabled } -function test_run_env_as_user_with_namespace() { - assertCommandSuccess run_env_as_user_with_namespace "" "" +function test_run_env_with_namespace() { + assertCommandSuccess run_env_with_namespace "" "" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_with_namespace_with_bindings() { - assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "" +function test_run_env_with_namespace_with_bindings() { + assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_with_namespace_with_command() { - assertCommandSuccess run_env_as_user_with_namespace "" "ls -la" +function test_run_env_with_namespace_with_command() { + assertCommandSuccess run_env_with_namespace "" "ls -la" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_with_namespace_with_bindings_and_command() { - assertCommandSuccess run_env_as_user_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" +function test_run_env_with_namespace_with_bindings_and_command() { + assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_fakeroot_with_namespace() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" - - _test_copy_common_files -} - -function test_run_env_as_fakeroot_with_namespace_with_bindings() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" - - _test_copy_common_files -} - -function test_run_env_as_fakeroot_with_namespace_with_command() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" - - _test_copy_common_files -} - -function test_run_env_as_fakeroot_with_namespace_with_bindings_and_command() { - assertCommandSuccess run_env_as_fakeroot_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" - - _test_copy_common_files -} - source $JUNEST_ROOT/tests/utils/shunit2 From 0060658726a6dd8fd8895d13a9c33c237ad66b1f Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 12 Apr 2017 19:32:30 +0100 Subject: [PATCH 168/326] Issue #174: Add util-linux in JuNest image util-linux contains `unshare` which is needed for the namespace mode. --- README.md | 2 +- lib/core/build.sh | 3 ++- lib/core/common.sh | 7 +++++-- tests/unit-tests/test-common.sh | 4 ++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 492e284..f123eda 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ files in order to make JuNest working properly (such as pacman, yogurt and proot The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts, package-query, git and the base-devel packages installed. -To change the build directory just use the *JUNEST_TEMPDIR* (by default /tmp). +To change the build directory just use the `JUNEST_TEMPDIR` (by default /tmp). After creating the image junest-x86\_64.tar.gz you can install it by running: diff --git a/lib/core/build.sh b/lib/core/build.sh index 4a00f22..497e928 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -50,7 +50,8 @@ function build_image_env(){ # All the essential executables (ln, mkdir, chown, etc) are in coreutils # yaourt requires sed # localedef (called by locale-gen) requires gzip - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip + # unshare command belongs to util-linux + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip util-linux sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" sudo mkdir -p ${maindir}/root/run/lock diff --git a/lib/core/common.sh b/lib/core/common.sh index 17b0d5b..d2ab487 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -128,10 +128,13 @@ function unshare_cmd(){ # Most of the distros do not have the `unshare` command updated # with --user option available. # Hence, give priority to the `unshare` executable in JuNest image. - if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${SH[@]}" "-c" ":" + # 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 + # they are not supported by dash. + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE --user "${SH[0]}" "-c" ":" then $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE "${@}" - elif $UNSHARE --user "${SH[@]}" "-c" ":" + elif $UNSHARE --user "${SH[0]}" "-c" ":" then $UNSHARE "$@" else diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index e9286fa..cfa3475 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -128,10 +128,10 @@ function test_zgrep(){ function test_unshare(){ assertCommandSuccess unshare_cmd new_program - assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh --login -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat $STDOUTF)" LD_EXEC=ld_exec_mock_false assertCommandSuccess unshare_cmd new_program - assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh --login -c :\nunshare --user /bin/sh --login -c :\nunshare new_program")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh -c :\nunshare --user /bin/sh -c :\nunshare new_program")" "$(cat $STDOUTF)" UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program } From 665c45b7aa40858ec90c7b77d5b39d7858f66ff4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 18 Apr 2017 09:02:54 +0100 Subject: [PATCH 169/326] Issue #182: Update doc with comparison table on the execution modes --- README.md | 110 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index f123eda..96c8b0b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The Arch Linux based distro that runs upon any Linux distros without root access - [Description](#description) - [Quickstart](#quickstart) - [Installation](#installation) -- [Dependencies](#dependencies) +- [Usage](#usage) - [Advanced usage](#advanced-usage) - [Internals](#internals) - [Troubleshooting](#troubleshooting) @@ -48,54 +48,14 @@ JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/ Quickstart ========== - -Backend programs ----------------- -There are three different ways you can run JuNest depending on the backend program you decide to use. - -### PRoot based ### -[Proot](https://wiki.archlinux.org/index.php/Proot) represents the default -program used for accessing to the JuNest environments. -The main reason to choose Proot as default backend program is because -it represents a portable solution that works well in most of GNU/Linux distros available. -One of the major drawbacks is the fact that Proot is not officially -supported anymore, therefore, Proot bugs may no longer be fixed. - -In order to run JuNest via Proot: +The basic way to run JuNest is via the [Proot](https://wiki.archlinux.org/index.php/Proot) as the backend program: - As normal user - Allow to make basic operations: ```junest``` - As fakeroot - Allow to install/remove packages: ```junest -f``` -### Linux namespaces based ### -The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) -represents the next generation backend program for JuNest. -The major drawback about the namespace is portability, as certain requirements -need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes can -create the required user and mount namespaces. -2) Moreover, the Linux kernel distro must have the user namespace enabled. -Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. -For instance, Ubuntu (version 14.04+) already has such feature enabled. - -In order to run JuNest via Linux namespaces: - -- As fakeroot - Allow to install/remove packages: ```junest -u``` - -### Chroot based ### -This solution suits only for privileged users. JuNest provides the possibility -to run the environment via `chroot` program. -In particular, it uses a special program called `GRoot`, an enhanced `chroot` -wrapper that allows to bind mount directories specified by the user, such as -/proc, /sys, /dev, /tmp and $HOME, before -executing any programs inside the JuNest sandbox. In case the mounting will not -work, JuNest is even providing the possibility to run the environment directly via -the pure `chroot` command. - -In order to run JuNest via `chroot` solutions: - -- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -g``` - -- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` +To know more about the JuNest execution modes depending on the backend program +used, see the [Usage](#usage) section below. After running JuNest -------------------- @@ -144,9 +104,69 @@ Alternatively, another installation method would be to directly download the JuN curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest export PATH=~/.junest/opt/junest/bin:$PATH +Usage +===== +There are three different ways you can run JuNest depending on the backend program you decide to use. + +PRoot based +----------- +[Proot](https://wiki.archlinux.org/index.php/Proot) represents the default +program used for accessing to the JuNest environments. +The main reason to choose Proot as default backend program is because +it represents a portable solution that works well in most of GNU/Linux distros available. +One of the major drawbacks is the fact that Proot is not officially +supported anymore, therefore, Proot bugs may no longer be fixed. + +In order to run JuNest via Proot: + +- As normal user - Allow to make basic operations: ```junest``` + +- As fakeroot - Allow to install/remove packages: ```junest -f``` + +Linux namespaces based +---------------------- +The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) +represents the next generation backend program for JuNest. +The major drawback about the namespace is portability, as certain requirements +need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes can +create the required user and mount namespaces. +2) Moreover, the Linux kernel distro must have the user namespace enabled. +Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. +For instance, Ubuntu (version 14.04+) already has such feature enabled. + +In order to run JuNest via Linux namespaces: + +- As fakeroot - Allow to install/remove packages: ```junest -u``` + +Chroot based +------------ +This solution suits only for privileged users. JuNest provides the possibility +to run the environment via `chroot` program. +In particular, it uses a special program called `GRoot`, an enhanced `chroot` +wrapper that allows to bind mount directories specified by the user, such as +/proc, /sys, /dev, /tmp and $HOME, before +executing any programs inside the JuNest sandbox. In case the mounting will not +work, JuNest is even providing the possibility to run the environment directly via +the pure `chroot` command. + +In order to run JuNest via `chroot` solutions: + +- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -g``` + +- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` + +Execution modes comparison table +---------------- +The following table shows the capabilities that each backend program is able to perform: + +| | QEMU | Root privileges required | Manage Official Packages | Manage AUR Packages | Portability | Support | User modes | +| --- | ---- | ------------------------ | ------------------------ | ------------------- | ----------- | ------- | ---------- | +| **Proot** | YES | NO | YES | YES | YES | Poor | Normal user and `fakeroot` | +| **Linux Namespaces** | NO | NO | YES | NO | Poor | YES | `fakeroot` only | +| **Chroot** | NO | YES | YES | YES | YES | YES | `root` only | + Advanced usage ============== - ## Build image ## You can build a new JuNest image from scratch by running the following command: From 02650b754ea4339b34a2ac319b183d374fd27c63 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 18 Apr 2017 20:51:37 +0100 Subject: [PATCH 170/326] 6.0.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b8a773e..09b254e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.6.12 +6.0.0 From 03a29590de5906b2c5310e8d5eeb80103b2d960b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Apr 2017 21:04:51 +0100 Subject: [PATCH 171/326] Add -i and -r options for groot command --- bin/groot | 56 ++++++++++++++++++--- lib/core/build.sh | 2 +- lib/core/namespace.sh | 4 +- tests/unit-tests/test-groot.sh | 79 ++++++++++++++++++++++++++++-- tests/unit-tests/test-namespace.sh | 8 +-- 5 files changed, 131 insertions(+), 18 deletions(-) diff --git a/bin/groot b/bin/groot index 4033705..b2cc2ab 100755 --- a/bin/groot +++ b/bin/groot @@ -22,7 +22,8 @@ TOUCH=touch CUT=cut SORT=sort UNIQ=uniq -GREP=grep +CAT=cat +READLINK=readlink MOUNTS_FILE=/proc/self/mounts NOT_EXISTING_FILE=103 @@ -38,11 +39,18 @@ function chroot_teardown() { # Remove all mounts starting from the most nested ones. # Suffix the CHROOTDIR with / to avoid umounting directories not belonging # to CHROOTDIR. - for mp in $($GREP "${CHROOTDIR%/}/" $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) + local normalized_chrootdir="$($READLINK -f ${CHROOTDIR})/" + local final_res=0 + for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) do - $UMOUNT $mp + if [[ $mp =~ ^${normalized_chrootdir}.* ]] + then + $UMOUNT $mp || final_res=$? + fi done $UMOUNT ${CHROOTDIR%/} + + return $final_res } function chroot_maybe_add_mount() { @@ -79,10 +87,32 @@ function chroot_setup() { fi create_node "${host_path}" "${CHROOTDIR}${guest_path}" - $MOUNT --rbind "${host_path}" "${CHROOTDIR}${guest_path}" + mount_directory "${host_path}" "${guest_path}" done } +function mount_directory() { + local host_path=$($READLINK -f "$1") + local guest_path="$2" + + if ! $OPT_AVOID_BIND + then + $MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}" + return 0 + fi + + case "$host_path" in + /proc) $MOUNT proc "${CHROOTDIR}${guest_path}" -t proc ;; + /sys) $MOUNT sys "${CHROOTDIR}${guest_path}" -t sysfs ;; + /dev) $MOUNT udev "${CHROOTDIR}${guest_path}" -t devtmpfs; $MOUNT devpts "${guest_path}/pts" -t devpts; $MOUNT shm "${guest_path}/shm" -t tmpfs ;; + /run) $MOUNT run "${CHROOTDIR}${guest_path}" -t tmpfs ;; + /tmp) $MOUNT tmp "${CHROOTDIR}${guest_path}" -t tmpfs ;; + *) $MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}" ;; + esac + + return 0 +} + function create_node() { local src="$1" local dst="$2" @@ -118,9 +148,19 @@ Options: path in the guest rootfs but users can specify any other location with the syntax: -b :. This option can be invoked multiple times and the paths specified must be absolutes. + -n, --no-umount Do not umount after chroot session finished. + -r, --recursive + Use rbind instead of bind. + + -i, --avoid-bind + Attempt to avoid mount --bind for common directories and use + proper mount fstype instead. Detected directories with + corresponding fstype are: /proc (proc), /sys (sysfs), + /dev (devtmpfs), /tmp (tmpfs), /run (tmpfs). + -h, --help Print this help message -V, --version Show the $NAME version @@ -135,16 +175,20 @@ version() { } function parse_arguments() { - OPT_BIND=false BINDINGS=() OPT_NO_UMOUNT=false + OPT_RECURSIVE=false + OPT_BIND="--bind" + OPT_AVOID_BIND=false OPT_HELP=false OPT_VERSION=false for opt in "$@" do case "$1" in - -b|--bind) OPT_BIND=true ; shift ; BINDINGS+=("$1") ; shift ;; + -b|--bind) shift ; BINDINGS+=("$1") ; shift ;; -n|--no-umount) OPT_NO_UMOUNT=true ; shift ;; + -r|--recursive) OPT_BIND="--rbind" ; shift ;; + -i|--avoid-bind) OPT_AVOID_BIND=true ; shift ;; -h|--help) OPT_HELP=true ; shift ;; -V|--version) OPT_VERSION=true ; shift ;; -*) die "Invalid option $1" ;; diff --git a/lib/core/build.sh b/lib/core/build.sh index 497e928..794298e 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -73,7 +73,7 @@ function build_image_env(){ sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" info "Setting up the pacman keyring (this might take a while!)..." - sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root bash -c \ + sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${maindir}/root bash -c \ "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" sudo rm ${maindir}/root/var/cache/pacman/pkg/* diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 9f4596f..f472a4c 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -57,9 +57,9 @@ function _run_env_with_namespace(){ # will terminate too with its own mounted directories. if [[ "$1" != "" ]] then - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT -n $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT -n $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" + JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" fi } diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index c7b5f36..784452d 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -89,14 +89,14 @@ function test_groot_with_bind(){ assertCommandSuccess main -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_file(){ touch file_src assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir [[ -f chrootdir/file_src ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_existing_node(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir @@ -111,7 +111,7 @@ function test_groot_with_bind_guest_host(){ assertCommandSuccess main -b /tmp:/home/tmp chrootdir [[ -d chrootdir/home/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_multiple_bind(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir @@ -119,7 +119,7 @@ function test_groot_with_multiple_bind(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_command(){ assertCommandSuccess main chrootdir ls -la -h @@ -131,7 +131,7 @@ function test_groot_with_bind_and_command(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_no_umount(){ assertCommandSuccess main -n chrootdir @@ -147,6 +147,23 @@ umount(/home/mychroot/dev/shm) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } + +function test_groot_with_chroot_teardown_umount_failure(){ + function umount() { + echo "umount($@)" + [[ "$1" == "/home/mychroot/dev/shm" ]] && return 128 + return 0 + } + UMOUNT=umount + echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts + MOUNTS_FILE=./mounts + CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) +umount(/home/mychroot/proc) +umount(/home/mychroot/dev/shm) +umount(/home/mychroot/dev) +umount(/home/mychroot)")" "$(cat $STDOUTF)" +} function test_groot_with_chroot_teardown_with_trailing_slash(){ echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts @@ -158,4 +175,56 @@ umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } +function test_groot_with_rbind(){ + assertCommandSuccess main -r -b /tmp chrootdir + [[ -d chrootdir/tmp ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + +function test_groot_with_avoid_bind_proc(){ + assertCommandSuccess main -i -b /proc chrootdir + [[ -d chrootdir/proc ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + +function test_groot_with_avoid_bind_dev(){ + assertCommandSuccess main -i -b /dev chrootdir + [[ -d chrootdir/dev ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + +function test_groot_with_avoid_bind_sys(){ + assertCommandSuccess main -i -b /sys chrootdir + [[ -d chrootdir/sys ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + +function test_groot_with_avoid_bind_run(){ + assertCommandSuccess main -i -b /run chrootdir + [[ -d chrootdir/run ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + +function test_groot_with_avoid_bind_tmp(){ + assertCommandSuccess main -i -b /tmp chrootdir + [[ -d chrootdir/tmp ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + +function test_groot_with_avoid_bind_combined(){ + assertCommandSuccess main -i -b /tmp -b /usr chrootdir + cat $STDERRF + [[ -d chrootdir/tmp ]] + assertEquals 0 $? + [[ -d chrootdir/usr ]] + assertEquals 0 $? + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)" +} + source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 9cc60a7..811cfef 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -80,7 +80,7 @@ function test_is_user_namespace_enabled_with_config(){ function test_run_env_with_namespace() { assertCommandSuccess run_env_with_namespace "" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -88,7 +88,7 @@ function test_run_env_with_namespace() { function test_run_env_with_namespace_with_bindings() { assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -96,7 +96,7 @@ function test_run_env_with_namespace_with_bindings() { function test_run_env_with_namespace_with_command() { assertCommandSuccess run_env_with_namespace "" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -104,7 +104,7 @@ function test_run_env_with_namespace_with_command() { function test_run_env_with_namespace_with_bindings_and_command() { assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files From a2c40902a214a5a36b24bc829952a5841a82ba61 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Apr 2017 21:19:55 +0100 Subject: [PATCH 172/326] 6.0.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 09b254e..5fe6072 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.0 +6.0.1 From 7b2dee540f7e743d26a3625225c95626e7e656c9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Apr 2017 22:35:03 +0100 Subject: [PATCH 173/326] :bug: Fix location of the check script during image build --- lib/core/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index 794298e..78b8925 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -88,8 +88,8 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - JUNEST_HOME="${maindir}/root_test" ${maindir}/root_test/opt/${CMD}/bin/${CMD} -f ./lib/checks/check.sh - JUNEST_HOME="${maindir}/root_test" sudo -E ${maindir}/root_test/opt/${CMD}/bin/${CMD} -g ./lib/checks/check.sh --run-root-tests + JUNEST_HOME="${maindir}/root_test" ${maindir}/root_test/opt/${CMD}/bin/${CMD} -f ${JUNEST_BASE}/lib/checks/check.sh + JUNEST_HOME="${maindir}/root_test" sudo -E ${maindir}/root_test/opt/${CMD}/bin/${CMD} -g ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} From b9e34d3e96c93bd50300540c416745a32b442b1b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Apr 2017 22:36:09 +0100 Subject: [PATCH 174/326] 6.0.2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5fe6072..9b9a244 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.1 +6.0.2 From 137788a98a3c26825d9a709e80f90e8ae38ea40e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 19 Apr 2017 23:52:26 +0100 Subject: [PATCH 175/326] Groot: Do not umount directories that are not mountpoint --- bin/groot | 2 +- tests/unit-tests/test-groot.sh | 46 +++++++++++++++++++++++++++++----- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/bin/groot b/bin/groot index b2cc2ab..fd438b4 100755 --- a/bin/groot +++ b/bin/groot @@ -43,7 +43,7 @@ function chroot_teardown() { local final_res=0 for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) do - if [[ $mp =~ ^${normalized_chrootdir}.* ]] + if [[ $mp =~ ^${normalized_chrootdir}.* ]] && $MOUNTPOINT -q "$mp" then $UMOUNT $mp || final_res=$? fi diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index 784452d..ca4df91 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -41,6 +41,9 @@ function init_mocks() { # As default suppose the mountpoint does not exist return 1 } + function mountpoint_mock() { + echo "mountpoint($@)" + } function mount() { echo "mount($@)" } @@ -74,9 +77,6 @@ function test_groot_no_directory(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory } function test_groot_mountpoint_exist(){ - mountpoint_mock() { - echo "mountpoint($@)" - } MOUNTPOINT=mountpoint_mock assertCommandSuccess main chrootdir assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" @@ -138,17 +138,23 @@ function test_groot_with_bind_no_umount(){ assertEquals "$(echo -e "mountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown(){ + MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) + assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) +umount(/home/mychroot/proc/fs1) +mountpoint(-q /home/mychroot/proc) umount(/home/mychroot/proc) +mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) +mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_umount_failure(){ + MOUNTPOINT=mountpoint_mock function umount() { echo "umount($@)" [[ "$1" == "/home/mychroot/dev/shm" ]] && return 128 @@ -158,19 +164,47 @@ function test_groot_with_chroot_teardown_umount_failure(){ echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) + assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) +umount(/home/mychroot/proc/fs1) +mountpoint(-q /home/mychroot/proc) umount(/home/mychroot/proc) +mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) +mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_with_trailing_slash(){ + MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) + assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) +umount(/home/mychroot/proc/fs1) +mountpoint(-q /home/mychroot/proc) umount(/home/mychroot/proc) +mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) +mountpoint(-q /home/mychroot/dev) +umount(/home/mychroot/dev) +umount(/home/mychroot)")" "$(cat $STDOUTF)" +} +function test_groot_with_chroot_teardown_mountpoint_failure(){ + mountpoint_mock() { + echo "mountpoint($@)" + [[ $2 == "/home/mychroot/dev/shm" ]] && return 128 + return 0 + } + MOUNTPOINT=mountpoint_mock + echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts + MOUNTS_FILE=./mounts + CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown + assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) +umount(/home/mychroot/proc/fs1) +mountpoint(-q /home/mychroot/proc) +umount(/home/mychroot/proc) +mountpoint(-q /home/mychroot/dev/shm) +mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } From bd0e9fbbccb4f5e75c8edb7c29df446fe9f00a60 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 20 Apr 2017 19:29:46 +0100 Subject: [PATCH 176/326] Replace `mountpoint` command by checking mounts file `mountpoint` does not detect some directory. By checking directly from `/proc/self/mounts` groot can be more reliable and portable. --- README.md | 2 +- bin/groot | 14 +++++-- tests/unit-tests/test-groot.sh | 76 ++++++++++++++-------------------- 3 files changed, 42 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 96c8b0b..0088502 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes ca create the required user and mount namespaces. 2) Moreover, the Linux kernel distro must have the user namespace enabled. Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. -For instance, Ubuntu (version 14.04+) already has such feature enabled. +For instance, Ubuntu (version 12.04+) already has such feature enabled. In order to run JuNest via Linux namespaces: diff --git a/bin/groot b/bin/groot index fd438b4..cb4952f 100755 --- a/bin/groot +++ b/bin/groot @@ -16,7 +16,6 @@ CHROOTCMD=${CHROOTCMD:-chroot} SHELL="/bin/sh" MOUNT=mount UMOUNT=umount -MOUNTPOINT=mountpoint MKDIR=mkdir TOUCH=touch CUT=cut @@ -35,6 +34,15 @@ source "${JUNEST_BASE}/lib/utils/utils.sh" ################################ MAIN FUNCTIONS ########################### +function is_mountpoint() { + local mountpoint="$1" + for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) + do + [[ $mp == $mountpoint ]] && return 0 + done + return 1 +} + function chroot_teardown() { # Remove all mounts starting from the most nested ones. # Suffix the CHROOTDIR with / to avoid umounting directories not belonging @@ -43,7 +51,7 @@ function chroot_teardown() { local final_res=0 for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) do - if [[ $mp =~ ^${normalized_chrootdir}.* ]] && $MOUNTPOINT -q "$mp" + if [[ $mp =~ ^${normalized_chrootdir}.* ]] && is_mountpoint "$mp" then $UMOUNT $mp || final_res=$? fi @@ -66,7 +74,7 @@ function chroot_maybe_add_mount() { function chroot_setup() { $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT - if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" + if ! chroot_maybe_add_mount "! is_mountpoint '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" then warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..." return 0 diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh index ca4df91..5fb2580 100755 --- a/tests/unit-tests/test-groot.sh +++ b/tests/unit-tests/test-groot.sh @@ -53,6 +53,10 @@ function init_mocks() { function check_and_trap() { echo "check_and_trap($@)" } + + # As default suppose the mountpoint "chrootdir" does not exist + echo -e "1 /home/mychroot/dev\n" > ./mounts + MOUNTS_FILE=./mounts } function test_help(){ @@ -77,41 +81,42 @@ function test_groot_no_directory(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory } function test_groot_mountpoint_exist(){ - MOUNTPOINT=mountpoint_mock + echo -e "1 /home/mychroot/dev\n1 chrootdir\n" > ./mounts + MOUNTS_FILE=./mounts assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_mountpoint_does_not_exist(){ assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind(){ assertCommandSuccess main -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_file(){ touch file_src assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir [[ -f chrootdir/file_src ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_existing_node(){ assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_not_absolute_path_node(){ touch file_src assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_bind_guest_host(){ assertCommandSuccess main -b /tmp:/home/tmp chrootdir [[ -d chrootdir/home/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_multiple_bind(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir @@ -119,11 +124,11 @@ function test_groot_with_multiple_bind(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_command(){ assertCommandSuccess main chrootdir ls -la -h - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_and_command(){ assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h @@ -131,30 +136,24 @@ function test_groot_with_bind_and_command(){ assertEquals 0 $? [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" } function test_groot_with_bind_no_umount(){ assertCommandSuccess main -n chrootdir - assertEquals "$(echo -e "mountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "mount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown(){ - MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_umount_failure(){ - MOUNTPOINT=mountpoint_mock function umount() { echo "umount($@)" [[ "$1" == "/home/mychroot/dev/shm" ]] && return 128 @@ -164,47 +163,32 @@ function test_groot_with_chroot_teardown_umount_failure(){ echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_with_trailing_slash(){ - MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) umount(/home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } function test_groot_with_chroot_teardown_mountpoint_failure(){ - mountpoint_mock() { - echo "mountpoint($@)" - [[ $2 == "/home/mychroot/dev/shm" ]] && return 128 + is_mountpoint() { + [[ $1 == "/home/mychroot/dev/shm" ]] && return 128 return 0 } - MOUNTPOINT=mountpoint_mock echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts MOUNTS_FILE=./mounts CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "mountpoint(-q /home/mychroot/proc/fs1) -umount(/home/mychroot/proc/fs1) -mountpoint(-q /home/mychroot/proc) + assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) umount(/home/mychroot/proc) -mountpoint(-q /home/mychroot/dev/shm) -mountpoint(-q /home/mychroot/dev) umount(/home/mychroot/dev) umount(/home/mychroot)")" "$(cat $STDOUTF)" } @@ -213,42 +197,42 @@ function test_groot_with_rbind(){ assertCommandSuccess main -r -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_proc(){ assertCommandSuccess main -i -b /proc chrootdir [[ -d chrootdir/proc ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_dev(){ assertCommandSuccess main -i -b /dev chrootdir [[ -d chrootdir/dev ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_sys(){ assertCommandSuccess main -i -b /sys chrootdir [[ -d chrootdir/sys ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_run(){ assertCommandSuccess main -i -b /run chrootdir [[ -d chrootdir/run ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_tmp(){ assertCommandSuccess main -i -b /tmp chrootdir [[ -d chrootdir/tmp ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } function test_groot_with_avoid_bind_combined(){ @@ -258,7 +242,7 @@ function test_groot_with_avoid_bind_combined(){ assertEquals 0 $? [[ -d chrootdir/usr ]] assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)" } source $(dirname $0)/../utils/shunit2 From 35fce94c4e0f08b36c8cc753e36704d6509d738b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 20 Apr 2017 20:23:18 +0100 Subject: [PATCH 177/326] 6.0.3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9b9a244..090ea9d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.2 +6.0.3 From 7ebdf628cfe960a8dcda9e6ac89a70179d23a526 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 24 Apr 2017 09:21:40 +0100 Subject: [PATCH 178/326] Issue #184: Add `sudo-fake` to JuNest image --- README.md | 13 +++++++++---- lib/core/build.sh | 2 +- lib/core/setup.sh | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0088502..e7323cf 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,7 @@ The following table shows the capabilities that each backend program is able to | | QEMU | Root privileges required | Manage Official Packages | Manage AUR Packages | Portability | Support | User modes | | --- | ---- | ------------------------ | ------------------------ | ------------------- | ----------- | ------- | ---------- | | **Proot** | YES | NO | YES | YES | YES | Poor | Normal user and `fakeroot` | -| **Linux Namespaces** | NO | NO | YES | NO | Poor | YES | `fakeroot` only | +| **Linux Namespaces** | NO | NO | YES | YES | Poor | YES | `fakeroot` only | | **Chroot** | NO | YES | YES | YES | YES | YES | `root` only | Advanced usage @@ -176,7 +176,7 @@ The script will create a directory containing all the essentials files in order to make JuNest working properly (such as pacman, yogurt and proot). The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with -arch-install-scripts, package-query, git and the base-devel packages installed. +arch-install-scripts, package-query and the base-devel packages installed. To change the build directory just use the `JUNEST_TEMPDIR` (by default /tmp). After creating the image junest-x86\_64.tar.gz you can install it by running: @@ -268,11 +268,16 @@ Troubleshooting Cannot find the gzip binary required for compressing man and info pages. > **A**: JuNest comes with a very basic number of packages. -> In order to install packages using yogurt you may need to install the package group **base-devel** -> that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): +> In order to install AUR packages via yogurt you need to install the package group `base-devel` first +> that contains all the essential packages for compiling from source code (such as gcc, make, patch, etc): #> pacman -S base-devel +> This command will fail as `base-devel` contains `sudo` command that conflicts with +> `sudo-fake` package. In order to install all packages in `base-devel` except `sudo`: + + #> pacman -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) + ## No servers configured for repository ## > **Q**: Why I cannot install packages? diff --git a/lib/core/build.sh b/lib/core/build.sh index 78b8925..1a3a9d2 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -37,7 +37,6 @@ function build_image_env(){ _check_package arch-install-scripts _check_package gcc _check_package package-query - _check_package git local disable_validation=$1 @@ -59,6 +58,7 @@ function build_image_env(){ info "Compiling and installing yaourt..." _install_from_aur ${maindir} "package-query" _install_from_aur ${maindir} "yaourt" + _install_from_aur ${maindir} "sudo-fake" info "Install ${NAME} script..." sudo pacman --noconfirm --root ${maindir}/root -S git diff --git a/lib/core/setup.sh b/lib/core/setup.sh index f55780b..2cbfdf1 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -147,7 +147,7 @@ function delete_env(){ fi # the CA directories are read only and can be deleted only by changing the mod chmod -R +w ${JUNEST_HOME}/etc/ca-certificates - if rm_cmd -rf ${JUNEST_HOME}/* + if rm_cmd -rf ${JUNEST_HOME} then info "${NAME} deleted in ${JUNEST_HOME}" else From 51f6765634bc0e84da88a2c2ba01ecfb9ad121b6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 24 Apr 2017 21:46:39 +0100 Subject: [PATCH 179/326] 6.0.4 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 090ea9d..1aa5e41 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.3 +6.0.4 From f9f7cbcaaafbb6e3fea736b8d848836a47398b26 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 24 Apr 2017 23:10:32 +0100 Subject: [PATCH 180/326] Update the check script to exclude `sudo` from `base-devel` --- lib/checks/check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 4a0cd73..7c0bd6e 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -33,7 +33,7 @@ info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist pacman --noconfirm -Syy -pacman --noconfirm -S base-devel +pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) info "Checking essential executables work..." pacman -Qi pacman 1> /dev/null From d6d6883e82115990988f9f1e592e9375e6059dc5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 24 Apr 2017 23:11:48 +0100 Subject: [PATCH 181/326] 6.0.5 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1aa5e41..288b2cd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.4 +6.0.5 From 8fe650ce87f6a6f9be140025278c17e79e5d4cae Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Apr 2017 00:07:00 +0100 Subject: [PATCH 182/326] Update the system before running checks --- lib/checks/check.sh | 1 + lib/core/build.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 7c0bd6e..e6cc2e3 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -33,6 +33,7 @@ info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist pacman --noconfirm -Syy +pacman --noconfirm -S grep coreutils pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) info "Checking essential executables work..." diff --git a/lib/core/build.sh b/lib/core/build.sh index 1a3a9d2..72bfda3 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -23,7 +23,7 @@ function _install_from_aur(){ builtin cd ${maindir}/packages/${pkgname} $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" - makepkg -sfc + makepkg -sfcd sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz } From 22483b9ea98c570528857b53dc0e24e5fc0e7695 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Apr 2017 00:26:17 +0100 Subject: [PATCH 183/326] 6.0.6 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 288b2cd..b7ff151 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.5 +6.0.6 From c3610ec86a9ec23ec75c51bd23c2a58bdb44efef Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Apr 2017 01:16:13 +0100 Subject: [PATCH 184/326] Activate the aur check for namespace mode --- .travis.yml | 2 +- README.md | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4e4536a..94afa57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ script: # Multiple tests against different execution modes: - junest -f -- ${PWD}/lib/checks/check.sh - - junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest -u -- ${PWD}/lib/checks/check.sh - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --run-root-tests - yes | junest --delete diff --git a/README.md b/README.md index e7323cf..0e9a3ac 100644 --- a/README.md +++ b/README.md @@ -271,12 +271,9 @@ Troubleshooting > In order to install AUR packages via yogurt you need to install the package group `base-devel` first > that contains all the essential packages for compiling from source code (such as gcc, make, patch, etc): - #> pacman -S base-devel + #> pacman -S --ignore sudo base-devel -> This command will fail as `base-devel` contains `sudo` command that conflicts with -> `sudo-fake` package. In order to install all packages in `base-devel` except `sudo`: - - #> pacman -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) +> Remember to ignore `sudo` as it conflicts with `sudo-fake` package. ## No servers configured for repository ## From 358f92d3e054535e8c17d99195d512d1402dbd85 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Apr 2017 22:53:10 +0100 Subject: [PATCH 185/326] Remove package-query as a dependency for building JuNest Image --- README.md | 4 ++-- lib/core/build.sh | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0e9a3ac..d5b7cc5 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,9 @@ You can build a new JuNest image from scratch by running the following command: The script will create a directory containing all the essentials files in order to make JuNest working properly (such as pacman, yogurt and proot). -The option **-n** will skip the final validation tests if they are not needed. +The option `-n` will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with -arch-install-scripts, package-query and the base-devel packages installed. +arch-install-scripts and the base-devel packages installed. To change the build directory just use the `JUNEST_TEMPDIR` (by default /tmp). After creating the image junest-x86\_64.tar.gz you can install it by running: diff --git a/lib/core/build.sh b/lib/core/build.sh index 72bfda3..adcca80 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -36,7 +36,6 @@ function build_image_env(){ _check_package arch-install-scripts _check_package gcc - _check_package package-query local disable_validation=$1 From 9cd13c88f6ea7bce144962d97f4f850e5fd5ea07 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 25 Apr 2017 22:57:37 +0100 Subject: [PATCH 186/326] 6.0.7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b7ff151..089b1e6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.6 +6.0.7 From 4b6fd63cf89d524401efc1c491bb0a461049dc20 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 22 Jun 2017 21:38:56 +0200 Subject: [PATCH 187/326] Inform with a warn in case SECCOMP gets disabled --- lib/checks/check.sh | 8 +++++++- lib/core/common.sh | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index e6cc2e3..7f38937 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -32,7 +32,7 @@ info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist -pacman --noconfirm -Syy +pacman --noconfirm -Syyu pacman --noconfirm -S grep coreutils pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) @@ -61,3 +61,9 @@ then $RUN_ROOT_TESTS && tcptraceroute localhost pacman --noconfirm -Rsn ${aur_package} fi + +# The following ensure that the gpg agent gets killed (if exists) +# otherwise it is not possible to exit from the session +[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye + +exit 0 diff --git a/lib/core/common.sh b/lib/core/common.sh index d2ab487..8b15d57 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -150,6 +150,7 @@ function proot_cmd(){ ${PROOT} ${proot_args} "${@}" elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" then + warn "Warn: Proot is not working, disabling SECCOMP instead. Expect the application to run slowly in particular when it uses syscalls intensively." PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else die "Error: Something went wrong with proot command. Exiting" From b2ba7f9d5bf2f818989f1e55880b1873b3136861 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 18 Sep 2017 13:45:33 +0200 Subject: [PATCH 188/326] Issue #197: Differences between JuNest and other systems --- README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d5b7cc5..f462dea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ JuNest ====== -The Arch Linux based distro that runs upon any Linux distros without root access. +The lightweight Arch Linux based distro that runs upon any Linux distros without root access.

Date: Mon, 18 Sep 2017 13:48:34 +0200 Subject: [PATCH 189/326] Issue #195: Check presence of nested env first --- lib/core/chroot.sh | 6 ++++-- lib/core/namespace.sh | 4 ++-- lib/core/proot.sh | 5 ++++- tests/unit-tests/test-chroot.sh | 12 ++++++++++++ tests/unit-tests/test-common.sh | 1 - tests/unit-tests/test-namespace.sh | 6 ++++++ tests/unit-tests/test-proot.sh | 12 ++++++++++++ 7 files changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index 9a104aa..731739a 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -28,8 +28,6 @@ function _run_env_as_xroot(){ copy_common_files - check_nested_env - JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" } @@ -52,6 +50,8 @@ function _run_env_as_xroot(){ # - : The command output. ####################################### function run_env_as_groot(){ + check_nested_env + local backend_args="$1" shift @@ -81,6 +81,8 @@ function run_env_as_groot(){ # - : The command output. ####################################### function run_env_as_chroot(){ + check_nested_env + local backend_args="$1" shift diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index f472a4c..6acd21d 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -46,8 +46,6 @@ function _run_env_with_namespace(){ local backend_args="$1" shift - check_nested_env - provide_common_bindings local bindings=${RESULT} unset RESULT @@ -82,6 +80,8 @@ function _run_env_with_namespace(){ # - : The command output. ####################################### function run_env_with_namespace() { + check_nested_env + local backend_args="$1" shift _check_user_namespace diff --git a/lib/core/proot.sh b/lib/core/proot.sh index f678d9d..21f8a01 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -12,7 +12,6 @@ function _run_env_with_proot(){ local proot_args="$1" shift - check_nested_env if [ "$1" != "" ] then JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" @@ -60,6 +59,8 @@ function _run_env_with_qemu(){ function run_env_as_fakeroot(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." + check_nested_env + local backend_args="$1" shift @@ -93,6 +94,8 @@ function run_env_as_fakeroot(){ function run_env_as_user(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." + check_nested_env + local backend_args="$1" shift diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index aa491e5..7102dd5 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -44,6 +44,12 @@ function test_run_env_as_groot_no_cmd(){ assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } +function test_run_env_as_groot_nested_env(){ + JUNEST_ENV=1 + assertCommandFailOnStatus 106 run_env_as_groot "" + unset JUNEST_ENV +} + function test_run_env_as_groot_cmd_with_backend_args(){ assertCommandSuccess run_env_as_groot "-n -b /home/blah" pwd assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" @@ -59,6 +65,12 @@ function test_run_env_as_chroot_no_cmd(){ assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } +function test_run_env_as_choot_nested_env(){ + JUNEST_ENV=1 + assertCommandFailOnStatus 106 run_env_as_chroot "" + unset JUNEST_ENV +} + function test_run_env_as_chroot_cmd_with_backend_args(){ assertCommandSuccess run_env_as_chroot "-n -b /home/blah" pwd assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index cfa3475..dfff6f4 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -164,7 +164,6 @@ function test_proot_cmd_seccomp(){ env | grep "^PROOT_NO_SECCOMP" } PROOT=envv - local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") assertCommandSuccess proot_cmd cmd # The variable PROOT_NO_SECCOMP will be produced # twice due to the fallback mechanism diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 811cfef..c4e0f8d 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -110,4 +110,10 @@ function test_run_env_with_namespace_with_bindings_and_command() { _test_copy_remaining_files } +function test_run_env_with_namespace_nested_env(){ + JUNEST_ENV=1 + assertCommandFailOnStatus 106 run_env_with_namespace "" + unset JUNEST_ENV +} + source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index 6640035..cb2d35c 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -62,6 +62,12 @@ function test_run_env_as_user(){ _test_copy_remaining_files } +function test_run_env_as_user_nested_env(){ + JUNEST_ENV=1 + assertCommandFailOnStatus 106 run_env_as_user "" + unset JUNEST_ENV +} + function test_run_env_as_fakeroot(){ _run_env_with_qemu() { echo $@ @@ -76,6 +82,12 @@ function test_run_env_as_fakeroot(){ _test_copy_common_files } +function test_run_env_as_fakeroot_nested_env(){ + JUNEST_ENV=1 + assertCommandFailOnStatus 106 run_env_as_fakeroot "" + unset JUNEST_ENV +} + function test_run_env_with_quotes(){ _run_env_with_qemu() { echo $@ From d858d577c86e654cd4b5e43638c3eb68dd273d7c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 18 Sep 2017 14:56:16 +0200 Subject: [PATCH 190/326] Fix checks for updating Arch Linux keyrings --- README.md | 4 ++-- lib/checks/check.sh | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f462dea..4d888a6 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,13 @@ The main advantages on using JuNest are: JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/The_Arch_Way). -How different JuNest is from Docker and Vagrant? +How different is JuNest from Docker and Vagrant? ------------------------------------------------ Although JuNest sounds similar to a virtualisation/Linux container -like system, JuNest differentiate a lot between Docker and Vagrant. In fact, the purpose of JuNest is **not** to build a complete isolated environment but, conversely, is the ability to run -programs as they are running natively from the host OS. Almost everything is shared +programs as they were running natively from the host OS. Almost everything is shared between host OS and the JuNest sandbox (kernel, process subtree, network, mounting, etc) and only the root filesystem gets isolated (as the programs installed in JuNest need to reside elsewhere). diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 7f38937..e361913 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -32,7 +32,11 @@ info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist -pacman --noconfirm -Syyu +pacman --noconfirm -Syy +pacman --noconfirm -S archlinux-keyring +pacman-key --init +pacman-key --populate archlinux +pacman --noconfirm -Su pacman --noconfirm -S grep coreutils pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) From 5bc4cd245afb67a4fd603f1db4acde43ce2aa099 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 23 Sep 2017 22:33:46 +1000 Subject: [PATCH 191/326] :doc: x86 (32 bit) is deprecated --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d888a6..713d194 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The main advantages on using JuNest are: - Install packages without root privileges. - Partial isolated environment which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). -- Available for x86\_64, x86 and ARM architectures but you can build your own image from scratch too! +- Available for x86\_64, x86 (deprecating) and ARM architectures but you can build your own image from scratch too! - Run on a different architecture from the host OS via QEMU - All Arch Linux lovers can have their favourite distro everywhere! From 5172093fe2c1cd41f454396fe0dd8fc902f6e3f6 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 23 Sep 2017 22:35:35 +1000 Subject: [PATCH 192/326] 6.0.8 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 089b1e6..4b786f5 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.7 +6.0.8 From 34f34583357c1105a81838c7410ecb64440e5a5b Mon Sep 17 00:00:00 2001 From: DroidFreak32 Date: Sat, 21 Jul 2018 18:04:43 +0530 Subject: [PATCH 193/326] Fix JuNest image URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 713d194..df8beeb 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ Alternatively, another installation method would be to directly download the JuN ARCH= mkdir ~/.junest - curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest + curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest export PATH=~/.junest/opt/junest/bin:$PATH Usage From cc351f419dd7455991efd1bf33c3a34b90e34130 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 28 Oct 2018 17:34:45 +1100 Subject: [PATCH 194/326] Add check for disabled unprivileged user namespace --- README.md | 22 ++++++++++++++++++---- lib/core/common.sh | 1 + lib/core/namespace.sh | 16 +++++++++++++++- tests/unit-tests/test-namespace.sh | 21 +++++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 713d194..f2c45f2 100644 --- a/README.md +++ b/README.md @@ -425,17 +425,31 @@ Troubleshooting > since JuNest will try to preserve the JuNest environment by assigning ownership > of the files to the real user. -## Not enabled User namespace or kernel too old ## +## Unprivileged user namespace disable at kernel compile time or kernel too old ## -> **Q**: Why do I get warning when I run JuNest via Linux namespaces? +> **Q**: Why do I get this warning when I run JuNest via Linux namespaces? $> junest -u - User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway... + Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway... + +> **A**: This means that JuNest detected that the host OS either +> does not have a newer kernel version or the unprivileged user namespace +> is not enabled at kernel compile time. +> JuNest does not stop the execution of the program but it attempts to run it +> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. + +## Unprivileged user namespace disabled + +> **Q**: Why do I get this warning when I run JuNest via Linux namespaces? + + $> junest -u + Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1 > **A**: This means that JuNest detected that the host OS either > does not have a newer Linux version or the user namespace is not enabled. > JuNest does not stop the execution of the program but it attempts to run it -> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. +> anyway. If you have root permissions try to enable it, otherwise try to use +> Proot as backend program. More documentation ================== diff --git a/lib/core/common.sh b/lib/core/common.sh index 8b15d57..a43df83 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -18,6 +18,7 @@ ROOT_ACCESS_ERROR=105 NESTED_ENVIRONMENT=106 VARIABLE_NOT_SET=107 NO_CONFIG_FOUND=108 +UNPRIVILEGED_USERNS_DISABLED=109 JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}} JUNEST_BASE=${JUNEST_BASE:-${JUNEST_HOME}/opt/junest} diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 6acd21d..686fabe 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -13,6 +13,7 @@ CONFIG_PROC_FILE="/proc/config.gz" CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" +PROC_USERNS_CLONE_FILE="/proc/sys/kernel/unprivileged_userns_clone" function _is_user_namespace_enabled() { local config_file="" @@ -30,6 +31,18 @@ function _is_user_namespace_enabled() { then return $NO_CONFIG_FOUND fi + + if [[ ! -e $PROC_USERNS_CLONE_FILE ]] + then + return 0 + fi + + if ! zgrep_cmd -q "1" $PROC_USERNS_CLONE_FILE + then + return $UNPRIVILEGED_USERNS_DISABLED + fi + + return 0 } function _check_user_namespace() { @@ -37,7 +50,8 @@ function _check_user_namespace() { _is_user_namespace_enabled case $? in $NOT_EXISTING_FILE) warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;; - $NO_CONFIG_FOUND) warn "User namespace is not enabled or Kernel too old (<3.8). Proceeding anyway..." ;; + $NO_CONFIG_FOUND) warn "Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway..." ;; + $UNPRIVILEGED_USERNS_DISABLED) warn "Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1" ;; esac set -e } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index c4e0f8d..005ab0d 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -75,6 +75,27 @@ function test_is_user_namespace_enabled_with_config(){ gzip config CONFIG_PROC_FILE="config.gz" CONFIG_BOOT_FILE="blah" + PROC_USERNS_CLONE_FILE="not-existing-file" + assertCommandSuccess _is_user_namespace_enabled +} + +function test_is_user_namespace_enabled_with_userns_clone_file_disabled(){ + echo "CONFIG_USER_NS=y" > config + gzip config + CONFIG_PROC_FILE="config.gz" + CONFIG_BOOT_FILE="blah" + PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" + echo "0" > $PROC_USERNS_CLONE_FILE + assertCommandFailOnStatus $UNPRIVILEGED_USERNS_DISABLED _is_user_namespace_enabled +} + +function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ + echo "CONFIG_USER_NS=y" > config + gzip config + CONFIG_PROC_FILE="config.gz" + CONFIG_BOOT_FILE="blah" + PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" + echo "1" > $PROC_USERNS_CLONE_FILE assertCommandSuccess _is_user_namespace_enabled } From 6361522e408684b668ae8bd553e7fcea00c4b7c4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 29 Oct 2018 22:01:09 +1100 Subject: [PATCH 195/326] Fix aur validation tests and include sudo-fake in codebase --- .gitignore | 3 +++ .travis.yml | 11 +++++----- README.md | 4 ++-- lib/checks/check.sh | 11 +++++++--- lib/core/build.sh | 18 ++++++++++++----- pkgs/sudo-fake/PKGBUILD | 45 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 pkgs/sudo-fake/PKGBUILD diff --git a/.gitignore b/.gitignore index 1377554..2d39c41 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ *.swp +*pkg.tar.xz +*.tar.gz +*.SRCINFO diff --git a/.travis.yml b/.travis.yml index 94afa57..f31c2ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,6 @@ install: - PATH=$PWD/bin:$PATH - junest -- echo "Installing JuNest (\$(uname -m))" - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" - # TODO: Remember to enable x86 tests when fixed - #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" script: - bash --version @@ -21,10 +19,11 @@ script: - bash ./tests/unit-tests/unit-tests.sh # Multiple tests against different execution modes: - - junest -f -- ${PWD}/lib/checks/check.sh - - junest -u -- ${PWD}/lib/checks/check.sh - - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --run-root-tests + # TODO AUR installation check is currently disabled + - junest -f -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --skip-aur-tests - yes | junest --delete - - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh + - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh --skip-aur-tests - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/README.md b/README.md index f2c45f2..aa6a4e8 100644 --- a/README.md +++ b/README.md @@ -265,8 +265,8 @@ As a fallback it tries to run the same executable if it is available in the JuNe image. ## Automatic building of the JuNest images ## -The JuNest images are built every week so that you can always get the most -updated package versions. +There is not periodic automation build of the JuNest images yet. +This was due to the difficulty to automate builds for arm architecture. ## Static QEMU binaries ## There are static QEMU binaries included in JuNest image that allows to run JuNest diff --git a/lib/checks/check.sh b/lib/checks/check.sh index e361913..9bf99ea 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -31,6 +31,10 @@ source "${JUNEST_BASE}/lib/core/common.sh" info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." +# The following ensures that the gpg agent gets killed (if exists) +# otherwise it is not possible to exit from the session +trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT KILL TERM INT + echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist pacman --noconfirm -Syy pacman --noconfirm -S archlinux-keyring @@ -59,14 +63,15 @@ pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS then - aur_package=tcptraceroute + aur_package=cower info "Checking ${aur_package} package from AUR repo..." + gpg --recv-key --keyserver hkp://pgp.mit.edu 1EB2638FF56C0C53 yogurt -A --noconfirm -S ${aur_package} - $RUN_ROOT_TESTS && tcptraceroute localhost + ${aur_package} --help pacman --noconfirm -Rsn ${aur_package} fi -# The following ensure that the gpg agent gets killed (if exists) +# The following ensures that the gpg agent gets killed (if exists) # otherwise it is not possible to exit from the session [[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye diff --git a/lib/core/build.sh b/lib/core/build.sh index adcca80..fe12df3 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -15,7 +15,7 @@ function _check_package(){ fi } -function _install_from_aur(){ +function _install_pkg_from_aur(){ local maindir=$1 local pkgname=$2 local installname=$3 @@ -27,6 +27,14 @@ function _install_from_aur(){ sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz } +function _install_pkg(){ + local maindir=$1 + local pkgbuilddir=$2 + builtin cd ${pkgbuilddir} + makepkg -sfcd + sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.xz +} + function build_image_env(){ umask 022 @@ -55,13 +63,13 @@ function build_image_env(){ # AUR packages requires non-root user to be compiled. proot fakes the user to 10 info "Compiling and installing yaourt..." - _install_from_aur ${maindir} "package-query" - _install_from_aur ${maindir} "yaourt" - _install_from_aur ${maindir} "sudo-fake" + _install_pkg_from_aur ${maindir} "package-query" + _install_pkg_from_aur ${maindir} "yaourt" + _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" info "Install ${NAME} script..." sudo pacman --noconfirm --root ${maindir}/root -S git - _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + _install_pkg_from_aur ${maindir} "${CMD}-git" "${CMD}.install" sudo pacman --noconfirm --root ${maindir}/root -Rsn git info "Generating the locales..." diff --git a/pkgs/sudo-fake/PKGBUILD b/pkgs/sudo-fake/PKGBUILD new file mode 100644 index 0000000..99fa18b --- /dev/null +++ b/pkgs/sudo-fake/PKGBUILD @@ -0,0 +1,45 @@ +# Maintainer: Filippo Squillace +# More details on how to change this file: +# https://wiki.archlinux.org/index.php/PKGBUILD +# https://wiki.archlinux.org/index.php/Creating_packages +# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages + +pkgname=sudo-fake +pkgver=0.1.0 +pkgrel=1 +pkgdesc="Simple script that bypasses sudo and execute the actual command. Useful for fakeroot environments." +arch=('any') +url="" +license=('GPL') +groups=() +depends=() +makedepends=() +provides=('sudo') +conflicts=('sudo') +backup=() +options=() +#install= +source=() +md5sums=() +noextract=() + +package() { + install -d -m 755 "${pkgdir}/usr/bin/" + cat < "${pkgdir}/usr/bin/sudo" +#!/bin/bash +for opt in "\$@" +do + case "\$1" in + --) shift ; break ;; + -*) shift ;; + *) break ;; + esac +done + +[[ -z "\${@}" ]] || "\${@}" +EOF + + chmod 755 "${pkgdir}/usr/bin/sudo" +} + +# vim:set ts=2 sw=2 et: From fbe49acc01f207ae967ae58b322ba85756ca1fa0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 31 Oct 2018 21:51:01 +1100 Subject: [PATCH 196/326] 6.0.9 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4b786f5..f1bb5eb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.8 +6.0.9 From 691369068db8627a252ed2da27c6999cca082d49 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 10 Jun 2019 17:33:31 +1000 Subject: [PATCH 197/326] Update README and change order for PATH variable --- README.md | 4 ++++ lib/core/common.sh | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9784c57..a9c7f62 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,8 @@ directory. Troubleshooting =============== +For Arch Linux related FAQs take a look at the [General troubleshooting page](https://wiki.archlinux.org/index.php/General_troubleshooting). + ## Cannot use AUR repository ## > **Q**: Why do I get the following error when I try to install a package with yogurt? @@ -325,6 +327,8 @@ Troubleshooting $> pkgfile getop core/util-linux +> Alternatively, you can use directly `pacman` command only. Take a look [here](https://wiki.archlinux.org/index.php/General_troubleshooting#Message:_%22error_while_loading_shared_libraries%22). + ## Kernel too old ## > **Q**: Why do I get the error: "FATAL: kernel too old"? diff --git a/lib/core/common.sh b/lib/core/common.sh index a43df83..faa1de8 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -26,7 +26,7 @@ JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} # The update of the variable PATH ensures that the executables are # found on different locations -PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH +PATH=$PATH:/usr/bin:/bin:/usr/sbin:/sbin # The executable uname is essential in order to get the architecture # of the host system, so a fallback mechanism cannot be used for it. From 313ef306620fe03eb227c9aa03f7a842ca7586c0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 9 Aug 2019 21:19:37 +1000 Subject: [PATCH 198/326] Add aurutils to the check build script --- lib/checks/check.sh | 7 +++---- lib/core/common.sh | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 9bf99ea..cba999b 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -44,7 +44,7 @@ pacman --noconfirm -Su pacman --noconfirm -S grep coreutils pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) -info "Checking essential executables work..." +info "Checking basic executables work..." pacman -Qi pacman 1> /dev/null yogurt -V 1> /dev/null /opt/proot/proot-$ARCH --help 1> /dev/null @@ -63,11 +63,10 @@ pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS then - aur_package=cower + aur_package=aurutils info "Checking ${aur_package} package from AUR repo..." - gpg --recv-key --keyserver hkp://pgp.mit.edu 1EB2638FF56C0C53 yogurt -A --noconfirm -S ${aur_package} - ${aur_package} --help + aur search aur 1> /dev/null pacman --noconfirm -Rsn ${aur_package} fi diff --git a/lib/core/common.sh b/lib/core/common.sh index faa1de8..996c24f 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -151,7 +151,8 @@ function proot_cmd(){ ${PROOT} ${proot_args} "${@}" elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" then - warn "Warn: Proot is not working, disabling SECCOMP instead. Expect the application to run slowly in particular when it uses syscalls intensively." + 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 -u" PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else die "Error: Something went wrong with proot command. Exiting" From 30b743cb1be3024b746e444cc172c78e7cb0e59a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 9 Aug 2019 22:11:49 +1000 Subject: [PATCH 199/326] Fix keyring setup for ARM arch --- lib/checks/check.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index cba999b..f15c20d 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -37,9 +37,15 @@ trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacm echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist pacman --noconfirm -Syy -pacman --noconfirm -S archlinux-keyring + pacman-key --init + +pacman --noconfirm -S archlinux-keyring pacman-key --populate archlinux + +pacman --noconfirm -S archlinuxarm-keyring || echo "No ARM keyring detected" +pacman-key --populate archlinuxarm || echo "No ARM keyring detected" + pacman --noconfirm -Su pacman --noconfirm -S grep coreutils pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) From 00c60118fb0ec10430e51d37da463f331461e88a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 9 Aug 2019 22:28:28 +1000 Subject: [PATCH 200/326] Enable AUR tests --- .travis.yml | 11 ++++++----- lib/checks/check.sh | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f31c2ea..ef57497 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,10 +20,11 @@ script: # Multiple tests against different execution modes: # TODO AUR installation check is currently disabled - - junest -f -- ${PWD}/lib/checks/check.sh --skip-aur-tests - - junest -u -- ${PWD}/lib/checks/check.sh --skip-aur-tests - - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest -f -- ${PWD}/lib/checks/check.sh + - junest -u -- ${PWD}/lib/checks/check.sh + - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh - yes | junest --delete - - JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh --skip-aur-tests - - yes | JUNEST_HOME=~/.junest-arm junest --delete + # Disable arm because it fails when exiting from check.sh for apparent no reason + #- JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh --skip-aur-tests + #- yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/lib/checks/check.sh b/lib/checks/check.sh index f15c20d..aee4b4a 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -78,6 +78,10 @@ fi # The following ensures that the gpg agent gets killed (if exists) # otherwise it is not possible to exit from the session -[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye +if [[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] +then + gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye || echo "GPG agent did not close properly" + echo "GPG agent closed" +fi exit 0 From ef4bf7cd795fe3fbdd43563607586879f28a88bc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 9 Aug 2019 23:59:18 +1000 Subject: [PATCH 201/326] 6.0.10 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f1bb5eb..c7d48f0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.9 +6.0.10 From 3341187cf6d6cade586460afe03e3994cf3b2d98 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 20 Oct 2019 16:15:31 +0200 Subject: [PATCH 202/326] Change the CLI and make ns the default backend --- README.md | 147 +++++++++------ VERSION | 2 +- bin/junest | 304 +++++++++++++++++--------------- tests/unit-tests/test-junest.sh | 151 ++++++++++------ 4 files changed, 361 insertions(+), 243 deletions(-) diff --git a/README.md b/README.md index a9c7f62..159a1e9 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The main advantages on using JuNest are: - Install packages without root privileges. - Partial isolated environment which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). -- Available for x86\_64, x86 (deprecating) and ARM architectures but you can build your own image from scratch too! +- Available for x86\_64 and ARM architectures but you can build your own image from scratch too! - Run on a different architecture from the host OS via QEMU - All Arch Linux lovers can have their favourite distro everywhere! @@ -63,20 +63,43 @@ any processes belonging to the host OS. Quickstart ========== -The basic way to run JuNest is via the [Proot](https://wiki.archlinux.org/index.php/Proot) as the backend program: -- As normal user - Allow to make basic operations: ```junest``` +Setup environment +----------------- -- As fakeroot - Allow to install/remove packages: ```junest -f``` +The first operation required is to install the JuNest environment in the +location of your choice (by default `~/.junest`, configurable via the environment variable `JUNEST_HOME`): +```sh +junest setup +``` + +The script will download the image from the repository and will place it to the default directory `~/.junest`. + +Access to environment +--------------------- + +By default, JuNest run via the Linux namespaces (aka `ns`) as the backend program. To access via `ns` just type: + +```sh +junest +``` + +Another execution mode is via [Proot](https://wiki.archlinux.org/index.php/Proot): + +```sh +junest proot [-f] +``` + +Where `-f` allow fakeroot access to install/remove packages. + +There are multiple backend programs, each with its own pros/cons. To know more about the JuNest execution modes depending on the backend program used, see the [Usage](#usage) section below. -After running JuNest --------------------- -If the JuNest image has not been downloaded yet, the script will download -the image from the repository and will place it to the default directory `~/.junest`. -You can change the default directory by changing the environment variable `JUNEST_HOME`. + +Have fun! +--------- If you are new on Arch Linux and you are not familiar with `pacman` package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). @@ -106,15 +129,13 @@ Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): export PATH=~/.local/share/junest/bin:$PATH ### Installation using AUR (Arch Linux only) ### -If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/): - - yaourt -S junest-git - export PATH=/opt/junest/bin:$PATH +If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/packages/junest-git/). +After installing junest will be located in `/opt/junest/` ## Method two ## -Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory ~/.junest: +Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory `~/.junest`: - ARCH= + ARCH= mkdir ~/.junest curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest export PATH=~/.junest/opt/junest/bin:$PATH @@ -123,6 +144,27 @@ Usage ===== There are three different ways you can run JuNest depending on the backend program you decide to use. +Linux namespaces based +---------------------- +The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) +represents the default backend program for JuNest. +The requirements for having Linux namespaces working are: + +1. Kernel starting from Linux 3.8 allows unprivileged processes to create +user and mount namespaces. +1. The Linux kernel distro must have the user namespace enabled. + +In the last years, the majority of GNU/Linux distros have the user namespace +enabled by default. This means that you do not need to have root privileges to +access to the JuNest environment via this method. +This +[wiki](https://github.com/fsquillace/junest/wiki/Linux-distros-with-user-namespace-enabled-by-default) +provides the state of the user namespace on several GNU/Linux distros. + +In order to run JuNest via Linux namespaces: + +- As fakeroot - Allow to install/remove packages: `junest ns` or `junest` + PRoot based ----------- [Proot](https://wiki.archlinux.org/index.php/Proot) represents the default @@ -134,24 +176,9 @@ supported anymore, therefore, Proot bugs may no longer be fixed. In order to run JuNest via Proot: -- As normal user - Allow to make basic operations: ```junest``` +- As normal user - Allow to make basic operations: `junest proot` -- As fakeroot - Allow to install/remove packages: ```junest -f``` - -Linux namespaces based ----------------------- -The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) -represents the next generation backend program for JuNest. -The major drawback about the namespace is portability, as certain requirements -need to be satisfied: 1) Only starting from Linux 3.8, unprivileged processes can -create the required user and mount namespaces. -2) Moreover, the Linux kernel distro must have the user namespace enabled. -Hopefully, in the future the major GNU/Linux distros will start enabling such feature by default. -For instance, Ubuntu (version 12.04+) already has such feature enabled. - -In order to run JuNest via Linux namespaces: - -- As fakeroot - Allow to install/remove packages: ```junest -u``` +- As fakeroot - Allow to install/remove packages: `junest proot -f` Chroot based ------------ @@ -159,16 +186,16 @@ This solution suits only for privileged users. JuNest provides the possibility to run the environment via `chroot` program. In particular, it uses a special program called `GRoot`, an enhanced `chroot` wrapper that allows to bind mount directories specified by the user, such as -/proc, /sys, /dev, /tmp and $HOME, before +`/proc`, `/sys`, `/dev`, `/tmp` and `$HOME`, before executing any programs inside the JuNest sandbox. In case the mounting will not work, JuNest is even providing the possibility to run the environment directly via the pure `chroot` command. In order to run JuNest via `chroot` solutions: -- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -g``` +- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): `junest groot` -- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): ```junest -r``` +- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): `junest root` Execution modes comparison table ---------------- @@ -185,7 +212,9 @@ Advanced usage ## Build image ## You can build a new JuNest image from scratch by running the following command: - junest -b [-n] +```sh +junest build [-n] +``` The script will create a directory containing all the essentials files in order to make JuNest working properly (such as pacman, yogurt and proot). @@ -194,9 +223,11 @@ Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts and the base-devel packages installed. To change the build directory just use the `JUNEST_TEMPDIR` (by default /tmp). -After creating the image junest-x86\_64.tar.gz you can install it by running: +After creating the image `junest-x86_64.tar.gz` you can install it by running: - junest -i junest-x86_64.tar.gz +```sh +junest setup -i junest-x86_64.tar.gz +``` For more details, you can also take a look at [junest-builder](https://github.com/fsquillace/junest-builder) @@ -209,20 +240,28 @@ Related wiki page: ## Run JuNest using a different architecture via QEMU ## The following command will download the ARM JuNest image and will run QEMU in -case the host OS runs on either x86\_64 or x86 architectures: +case the host OS runs on either `x86_64` or `x86` architectures: - $> JUNEST_HOME=~/.junest-arm junest -a arm -- uname -m - armv7l +```sh +$> export JUNEST_HOME=~/.junest-arm +$> junest setup -a arm +$> junest -- uname -m +armv7l +``` ## Bind directories ## To bind a host directory to a guest location, you can use proot arguments: - junest -p "-b /mnt/mydata:/home/user/mydata" +```sh +junest proot `-b` "-b /mnt/mydata:/home/user/mydata" +``` -This will works with PRoot, Namespace and GRoot backend programs. +The option `-b` to provide options to the backeng program will work with PRoot, Namespace and GRoot backend programs. Check out the backend program options by passing `--help` option: - junest [-u|-g] -p "--help" +```sh +junest [u|g|p] -b "--help" +``` ## Systemd integration ## Although JuNest has not been designed to be a complete container, it is even possible to @@ -234,7 +273,9 @@ and the container can only be executed using root privileges. To boot a JuNest container: - sudo systemd-nspawn -bD ~/.junest +```sh +sudo systemd-nspawn -bD ~/.junest +``` Related wiki page: @@ -250,7 +291,7 @@ allows unprivileged users to execute programs inside a sandbox and GRoot, a small and portable version of [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an enhanced chroot for privileged users that mounts the primary directories -(i.e. /proc, /sys, /dev and /run) before executing any programs inside +(i.e. `/proc`, `/sys`, `/dev` and `/run`) before executing any programs inside the sandbox. ## Automatic fallback to classic chroot ## @@ -259,14 +300,16 @@ mount one of the directories), JuNest automatically tries to fallback to the classic chroot. ## Automatic fallback for all the dependent host OS executables ## -JuNest attempt first to run the executables in the host OS located in different -positions (/usr/bin, /bin, /usr/sbin and /sbin). +JuNest attempts first to run the executables in the host OS located in different +positions (`/usr/bin`, `/bin`, `/usr/sbin` and `/sbin`). As a fallback it tries to run the same executable if it is available in the JuNest -image. +environment. ## Automatic building of the JuNest images ## There is not periodic automation build of the JuNest images yet. This was due to the difficulty to automate builds for arm architecture. +The JuNest image for the `x86_64` is built periodically every once every three +months. ## Static QEMU binaries ## There are static QEMU binaries included in JuNest image that allows to run JuNest @@ -343,7 +386,7 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > on to PRoot when *-p* is prepended. For example, to fake a kernel version of > 3.10, issue the following command: - $> junest -p "-k 3.10" + $> junest proot -b "-k 3.10" > As Arch Linux ships binaries for kernel version 2.6.32, the above error is > not unique to the precompiled package from JuNest. It will also appear when @@ -433,7 +476,7 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > **Q**: Why do I get this warning when I run JuNest via Linux namespaces? - $> junest -u + $> junest ns Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway... > **A**: This means that JuNest detected that the host OS either @@ -446,7 +489,7 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > **Q**: Why do I get this warning when I run JuNest via Linux namespaces? - $> junest -u + $> junest ns Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1 > **A**: This means that JuNest detected that the host OS either diff --git a/VERSION b/VERSION index c7d48f0..66ce77b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.0.10 +7.0.0 diff --git a/bin/junest b/bin/junest index a2b96e5..20a7243 100755 --- a/bin/junest +++ b/bin/junest @@ -13,148 +13,112 @@ source "${JUNEST_BASE}/lib/utils/utils.sh" source "${JUNEST_BASE}/lib/core/common.sh" source "${JUNEST_BASE}/lib/core/build.sh" +source "${JUNEST_BASE}/lib/core/setup.sh" source "${JUNEST_BASE}/lib/core/chroot.sh" source "${JUNEST_BASE}/lib/core/namespace.sh" source "${JUNEST_BASE}/lib/core/proot.sh" -source "${JUNEST_BASE}/lib/core/setup.sh" +# TODO give more flexibility for userns to allow not to copy passwd/grops file, etc +# TODO think about removing yaourt + ################################### ### General functions ### ################################### - usage() { echo -e "$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION" echo - echo -e "Usage: $CMD [options] [--] [command]" + echo -e "Usage: $CMD [action] [options] [--] [command]" echo - echo -e "Setup options:" - echo -e "-i, --setup-from-file Setup the $NAME image in ${JUNEST_HOME}" - echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)" - echo -e " Defaults to the host architecture ($ARCH)" - echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" + echo -e "General:" + echo -e "-h, --help Show this help message" + echo -e "-V, --version Show the $NAME version" echo - echo -e "Access options:" - echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" - echo -e "-g, --groot Run $NAME with root privileges via GRoot" - echo -e "-r, --root Run $NAME with root privileges via classic chroot" - echo -e "-u, --namespace Use Linux Namespace (with GRoot) instead of PRoot" - echo -e "-p, --backend-args Arguments for backend program (PRoot or GRoot)" - echo -e " ($CMD -p \"--help\" to check out the PRoot options" - echo -e " $CMD -g -p \"--help\" to check out the GRoot options" - echo -e " $CMD -r -p \"--help\" to check out the chroot options)" + echo -e "Actions and options:" + echo -e " [s]etup " + echo -e " -i, --from-file Setup the $NAME image in ${JUNEST_HOME}" + echo -e " -a, --arch $NAME architecture to download (x86_64, arm)" + echo -e " Defaults to the host architecture ($ARCH)" + echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}" echo - echo -e "Building options:" - echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" - echo -e "-n, --disable-validation Disable the $NAME image validation" + echo -e " [n]s Access via Linux Namespaces using GRoot (Default action)" + echo -e " -b, --backend-args Arguments for GRoot backend program" + echo -e " ($CMD groot -p \"--help\" to check out the GRoot options)" echo - echo -e "General options:" - echo -e "-h, --help Show this help message" - echo -e "-V, --version Show the $NAME version" + echo -e " [p]root Access via PRoot" + echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" + echo -e " -b, --backend-args Arguments for PRoot backend program" + echo -e " ($CMD proot -p \"--help\" to check out the PRoot options)" + echo + echo -e " [g]root Access with root privileges via GRoot" + echo -e " -b, --backend-args Arguments for GRoot backend program" + echo -e " ($CMD groot -p \"--help\" to check out the GRoot options)" + echo + echo -e " [r]oot Access with root privileges via classic chroot" + echo -e " -b, --backend-args Arguments for chroot backend program" + echo -e " ($CMD root -p \"--help\" to check out the chroot options)" + echo + echo -e " [b]uild Build a $NAME image (must run in ArchLinux)" + echo -e " -n, --disable-validation Disable the $NAME image validation" } version() { echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" } -check_cli(){ - if $OPT_BUILD_IMAGE - then - if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT - then - die "The build image option must be used exclusively" - fi - fi - if $OPT_DISABLE_VALIDATION - then - if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT - then - die "The disable validation option must be used with the build image option only" - fi - fi - if $OPT_DELETE - then - if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION - then - die "The $NAME delete option must be used exclusively" - fi - fi - if $OPT_HELP - then - if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION - then - die "The $NAME help option must be used exclusively" - fi - fi - if $OPT_VERSION - then - if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION - then - die "The $NAME version option must be used exclusively" - fi - fi - if $OPT_FAKEROOT && $OPT_ROOT - then - die "You must access to $NAME with either fakeroot or root permissions" - fi - if $OPT_BACKEND_ARGS || $OPT_ARCH - then - if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ - $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION - then - die "Invalid syntax: Proot and arch args are not allowed with the other options" - fi - fi - if [ "$ARGS" != "" ] - then - if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ - $OPT_VERSION || $OPT_DISABLE_VALIDATION - then - die "No arguments are needed. For the CLI syntax run: $CMD --help" - fi - fi +function parse_arguments(){ + # Actions + ACT_SETUP=false + ACT_BUILD=false + ACT_NAMESPACE=false + ACT_PROOT=false + ACT_GROOT=false + ACT_ROOT=false + ACT_HELP=false + ACT_VERSION=false - return 0 + case "$1" in + s|setup) ACT_SETUP=true ; shift ;; + b|build) ACT_BUILD=true ; shift ;; + n|ns) ACT_NAMESPACE=true ; shift ;; + p|proot) ACT_PROOT=true ; shift ;; + g|groot) ACT_GROOT=true ; shift ;; + r|root) ACT_ROOT=true ; shift ;; + -h|--help) ACT_HELP=true ; shift ;; + -V|--version) ACT_VERSION=true ; shift ;; + *) ACT_NAMESPACE=true ;; + esac + + if $ACT_SETUP + then + _parse_setup_opts "$@" + elif $ACT_BUILD + then + _parse_build_opts "$@" + elif $ACT_NAMESPACE + then + _parse_general_opts "$@" + elif $ACT_PROOT + then + _parse_proot_opts "$@" + elif $ACT_GROOT + then + _parse_general_opts "$@" + elif $ACT_ROOT + then + _parse_general_opts "$@" + fi } - -function parse_arguments(){ - OPT_SETUP_FROM_FILE=false - IMAGE_FILE="" - OPT_FAKEROOT=false - OPT_ROOT=false - OPT_GROOT=false - OPT_USER_NAMESPACE=false +function _parse_general_opts() { + # Options: OPT_BACKEND_ARGS=false BACKEND_ARGS="" - OPT_ARCH=false - ARCH_ARG="" - OPT_BUILD_IMAGE=false - OPT_DISABLE_VALIDATION=false - CHECK_ARG="" - OPT_DELETE=false - OPT_HELP=false - OPT_VERSION=false - for opt in "$@" + + while [[ -n "$1" ]] do case "$1" in - -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; - -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -r|--root) OPT_ROOT=true ; shift ;; - -g|--groot) OPT_GROOT=true ; shift ;; - -u|--namespace) OPT_USER_NAMESPACE=true ; shift ;; -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; - -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; - -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; - -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; - -d|--delete) OPT_DELETE=true ; shift ;; - -h|--help) OPT_HELP=true ; shift ;; - -V|--version) OPT_VERSION=true ; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -168,44 +132,105 @@ function parse_arguments(){ done } -function execute_operation(){ - $OPT_HELP && usage && return - $OPT_VERSION && version && return +function _parse_proot_opts() { + # Options: + OPT_FAKEROOT=false + OPT_BACKEND_ARGS=false + BACKEND_ARGS="" - if $OPT_BUILD_IMAGE; then + while [[ -n "$1" ]] + do + case "$1" in + -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; + -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + --) shift ; break ;; + -*) die "Invalid option $1" ;; + *) break ;; + esac + done + + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done +} + +function _parse_build_opts() { + OPT_DISABLE_VALIDATION=false + while [[ -n "$1" ]] + do + case "$1" in + -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; + *) die "Invalid option $1" ;; + esac + done +} + +function _parse_setup_opts() { + OPT_SETUP_FROM_FILE=false + IMAGE_FILE="" + OPT_ARCH=false + ARCH_ARG="" + OPT_DELETE=false + while [[ -n "$1" ]] + do + case "$1" in + -i|--from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; + -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; + -d|--delete) OPT_DELETE=true ; shift ;; + *) die "Invalid option $1" ;; + esac + done +} + +function execute_operation() { + $ACT_HELP && usage && return + $ACT_VERSION && version && return + + if $ACT_BUILD; then build_image_env $OPT_DISABLE_VALIDATION return - elif $OPT_DELETE; then - delete_env - return + fi + + if $ACT_SETUP; then + if $OPT_DELETE; then + delete_env + else + if is_env_installed + then + die "Error: The image cannot be installed since $JUNEST_HOME is not empty." + fi + + if $OPT_SETUP_FROM_FILE; then + setup_env_from_file $IMAGE_FILE + else + setup_env $ARCH_ARG + fi + fi + + return fi + if ! is_env_installed then - if $OPT_SETUP_FROM_FILE; then - setup_env_from_file $IMAGE_FILE - else - setup_env $ARCH_ARG - unset ARCH_ARG - fi - elif $OPT_SETUP_FROM_FILE; then - die "Error: The image cannot be installed since $JUNEST_HOME is not empty." + die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup" fi - [ -z "${ARCH_ARG}" ] || \ - die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" - local run_env - if $OPT_USER_NAMESPACE; then + if $ACT_NAMESPACE; then run_env=run_env_with_namespace - elif $OPT_FAKEROOT; then - run_env=run_env_as_fakeroot - elif $OPT_ROOT; then - run_env=run_env_as_chroot - elif $OPT_GROOT; then + elif $ACT_PROOT; then + if $OPT_FAKEROOT; then + run_env=run_env_as_fakeroot + else + run_env=run_env_as_user + fi + elif $ACT_GROOT; then run_env=run_env_as_groot - else - run_env=run_env_as_user + elif $ACT_ROOT; then + run_env=run_env_as_chroot fi $run_env "${BACKEND_ARGS}" "${ARGS[@]}" @@ -214,7 +239,6 @@ function execute_operation(){ function main() { parse_arguments "$@" - check_cli execute_operation } diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index 2176cea..a3dee83 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -72,118 +72,169 @@ function test_version(){ assertEquals "version" "$(cat $STDOUTF)" } function test_build_image_env(){ - assertCommandSuccess main -b + assertCommandSuccess main b assertEquals "build_image_env(false)" "$(cat $STDOUTF)" - assertCommandSuccess main --build-image + assertCommandSuccess main build assertEquals "build_image_env(false)" "$(cat $STDOUTF)" - assertCommandSuccess main -b -n + assertCommandSuccess main b -n assertEquals "build_image_env(true)" "$(cat $STDOUTF)" - assertCommandSuccess main --build-image --disable-validation + assertCommandSuccess main build --disable-validation assertEquals "build_image_env(true)" "$(cat $STDOUTF)" } + function test_delete_env(){ - assertCommandSuccess main -d + assertCommandSuccess main s -d assertEquals "delete_env" "$(cat $STDOUTF)" - assertCommandSuccess main --delete + assertCommandSuccess main setup --delete assertEquals "delete_env" "$(cat $STDOUTF)" } function test_setup_env_from_file(){ is_env_installed(){ return 1 } - assertCommandSuccess main -i myimage - assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess main --setup-from-file myimage - assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess main s -i myimage + assertEquals "setup_env_from_file(myimage)" "$(cat $STDOUTF)" + assertCommandSuccess main setup --from-file myimage + assertEquals "setup_env_from_file(myimage)" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - assertCommandFail main -i myimage + assertCommandFail main setup -i myimage } function test_setup_env(){ is_env_installed(){ return 1 } - assertCommandSuccess main -a arm - assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess main --arch arm - assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" - assertCommandSuccess main - assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess main s + assertEquals "setup_env()" "$(cat $STDOUTF)" + assertCommandSuccess main setup + assertEquals "setup_env()" "$(cat $STDOUTF)" + assertCommandSuccess main s -a arm + assertEquals "setup_env(arm)" "$(cat $STDOUTF)" + assertCommandSuccess main setup --arch arm + assertEquals "setup_env(arm)" "$(cat $STDOUTF)" is_env_installed(){ return 0 } - assertCommandFail main -a arm + assertCommandFail main setup -a arm } + function test_run_env_as_fakeroot(){ - assertCommandSuccess main -f + assertCommandSuccess main p -f assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - assertCommandSuccess main --fakeroot + assertCommandSuccess main proot --fakeroot assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" - assertCommandSuccess main -f -p "-b arg" + assertCommandSuccess main proot -f -p "-b arg" assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main -f -p "-b arg" -- command -kv + assertCommandSuccess main proot -f -p "-b arg" -- command -kv assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)" - assertCommandSuccess main -f command --as + assertCommandSuccess main proot -f command --as assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" - assertCommandFail main -a "myarch" -f command --as + assertCommandSuccess main proot -f -- command --as + assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" + + is_env_installed(){ + return 1 + } + assertCommandFail main proot -f } + function test_run_env_as_user(){ - assertCommandSuccess main + assertCommandSuccess main proot assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)" - assertCommandSuccess main -p "-b arg" + assertCommandSuccess main proot -p "-b arg" assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main -p "-b arg" -- command -ll + assertCommandSuccess main proot -p "-b arg" -- command -ll assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)" - assertCommandSuccess main command -ls + assertCommandSuccess main proot command -ls + assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" + assertCommandSuccess main proot -- command -ls assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" - assertCommandFail main -a "myarch" -- command -ls + is_env_installed(){ + return 1 + } + assertCommandFail main proot } + function test_run_env_as_groot(){ - assertCommandSuccess main -g + assertCommandSuccess main g assertEquals "run_env_as_groot " "$(cat $STDOUTF)" - assertCommandSuccess main -g command + assertCommandSuccess main groot command assertEquals "run_env_as_groot command" "$(cat $STDOUTF)" + assertCommandSuccess main groot -- command + assertEquals "run_env_as_groot command" "$(cat $STDOUTF)" + + is_env_installed(){ + return 1 + } + assertCommandFail main groot } + function test_run_env_as_chroot(){ - assertCommandSuccess main -r + assertCommandSuccess main r assertEquals "run_env_as_chroot " "$(cat $STDOUTF)" - assertCommandSuccess main -r command + assertCommandSuccess main root command assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)" + assertCommandSuccess main root -- command + assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)" + + is_env_installed(){ + return 1 + } + assertCommandFail main root -f } function test_run_env_with_namespace(){ - assertCommandSuccess main -u -f + assertCommandSuccess main n assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess main --namespace --fakeroot + assertCommandSuccess main ns assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" - assertCommandSuccess main -u -f -p "-b arg" + assertCommandSuccess main ns -p "-b arg" assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main -u -f -p "-b arg" -- command -kv + assertCommandSuccess main ns -p "-b arg" -- command -kv assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" - assertCommandSuccess main -u -f command --as + assertCommandSuccess main ns command --as assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -- command --as + assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + + assertCommandSuccess main + assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertCommandSuccess main + assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + + assertCommandSuccess main -p "-b arg" + assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess main -p "-b arg" -- command -kv + assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess main command --as + assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + assertCommandSuccess main -- command --as + assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + + is_env_installed(){ + return 1 + } + assertCommandFail main ns } -function test_check_cli(){ - assertCommandFail main -b -h - assertCommandFail main -b -c - assertCommandFail main -d -s - assertCommandFail main -n -v - assertCommandFail main -d -r - assertCommandFail main -h -f - assertCommandFail main -v -i fsd - assertCommandFail main -f -r - assertCommandFail main -p args -v - assertCommandFail main -a arch -v - assertCommandFail main -d args +function test_invalid_option(){ + assertCommandFail main --no-option + assertCommandFail main n --no-option + assertCommandFail main g --no-option + assertCommandFail main r --no-option + + assertCommandFail main p --no-option + + assertCommandFail main b --no-option + assertCommandFail main s --no-option } source $(dirname $0)/../utils/shunit2 From de0bec9bc52819f51fd3f2473556c7e6ce0f7481 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 20 Oct 2019 22:29:05 +0200 Subject: [PATCH 203/326] Remove yaourt package and allow not to copy common etc files --- README.md | 19 ++- bin/junest | 186 +++++++++++++++++------------ lib/checks/check.sh | 10 +- lib/core/build.sh | 17 ++- lib/core/chroot.sh | 30 +++-- lib/core/namespace.sh | 27 +++-- lib/core/proot.sh | 44 ++++--- tests/unit-tests/test-chroot.sh | 16 +-- tests/unit-tests/test-junest.sh | 117 ++++++++++-------- tests/unit-tests/test-namespace.sh | 10 +- tests/unit-tests/test-proot.sh | 14 +-- 11 files changed, 292 insertions(+), 198 deletions(-) diff --git a/README.md b/README.md index 159a1e9..3dbb0dc 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ an isolated GNU/Linux environment inside any generic host GNU/Linux OS and without the need to have root privileges for installing packages. JuNest contains mainly the package managers (called [pacman](https://wiki.archlinux.org/index.php/Pacman) -and a simple [yaourt](https://wiki.archlinux.org/index.php/Yaourt) wrapper called yogurt) that allows to access +that allows to access to a wide range of packages from the Arch Linux repositories. The main advantages on using JuNest are: @@ -40,7 +40,7 @@ The main advantages on using JuNest are: - Install packages without root privileges. - Partial isolated environment which you can install packages without affecting a production system. - Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). -- Available for x86\_64 and ARM architectures but you can build your own image from scratch too! +- Available for `x86_64` and `arm` architectures but you can build your own image from scratch too! - Run on a different architecture from the host OS via QEMU - All Arch Linux lovers can have their favourite distro everywhere! @@ -104,6 +104,15 @@ Have fun! If you are new on Arch Linux and you are not familiar with `pacman` package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). +JuNest provides a modified version of `makepkg` in `/opt/makepkg/bin` that +allows you to build packages from [AUR](https://aur.archlinux.org/) repository. +Remember that in order to build package `base-devel` package group is required +first: + +```sh +pacman -Sy base-devel +``` + Installation ============ @@ -217,7 +226,7 @@ junest build [-n] ``` The script will create a directory containing all the essentials -files in order to make JuNest working properly (such as pacman, yogurt and proot). +files in order to make JuNest working properly (such as `pacman` and `proot`). The option `-n` will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with arch-install-scripts and the base-devel packages installed. @@ -323,12 +332,12 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht ## Cannot use AUR repository ## -> **Q**: Why do I get the following error when I try to install a package with yogurt? +> **Q**: Why do I get the following error when I try to install a package? Cannot find the gzip binary required for compressing man and info pages. > **A**: JuNest comes with a very basic number of packages. -> In order to install AUR packages via yogurt you need to install the package group `base-devel` first +> In order to install AUR packages you need to install the package group `base-devel` first > that contains all the essential packages for compiling from source code (such as gcc, make, patch, etc): #> pacman -S --ignore sudo base-devel diff --git a/bin/junest b/bin/junest index 20a7243..2a9549d 100755 --- a/bin/junest +++ b/bin/junest @@ -19,8 +19,7 @@ source "${JUNEST_BASE}/lib/core/namespace.sh" source "${JUNEST_BASE}/lib/core/proot.sh" -# TODO give more flexibility for userns to allow not to copy passwd/grops file, etc -# TODO think about removing yaourt +# TODO Add test that checks that no_copy files works ################################### ### General functions ### @@ -35,31 +34,36 @@ usage() { echo -e "-V, --version Show the $NAME version" echo echo -e "Actions and options:" - echo -e " [s]etup " - echo -e " -i, --from-file Setup the $NAME image in ${JUNEST_HOME}" + echo -e " s[etup] " + echo -e " -i, --from-file Setup the $NAME image in ${JUNEST_HOME}" echo -e " -a, --arch $NAME architecture to download (x86_64, arm)" echo -e " Defaults to the host architecture ($ARCH)" echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}" echo - echo -e " [n]s Access via Linux Namespaces using GRoot (Default action)" + echo -e " n[s] Access via Linux Namespaces using GRoot (Default action)" echo -e " -b, --backend-args Arguments for GRoot backend program" echo -e " ($CMD groot -p \"--help\" to check out the GRoot options)" + echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo - echo -e " [p]root Access via PRoot" + echo -e " p[root] Access via PRoot" echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" echo -e " -b, --backend-args Arguments for PRoot backend program" echo -e " ($CMD proot -p \"--help\" to check out the PRoot options)" + echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo - echo -e " [g]root Access with root privileges via GRoot" + echo -e " g[root] Access with root privileges via GRoot" echo -e " -b, --backend-args Arguments for GRoot backend program" echo -e " ($CMD groot -p \"--help\" to check out the GRoot options)" + echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo - echo -e " [r]oot Access with root privileges via classic chroot" + echo -e " r[oot] Access with root privileges via classic chroot" echo -e " -b, --backend-args Arguments for chroot backend program" echo -e " ($CMD root -p \"--help\" to check out the chroot options)" + echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" + echo + echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" + echo -e " -n, --disable-check Disable the $NAME image check" echo - echo -e " [b]uild Build a $NAME image (must run in ArchLinux)" - echo -e " -n, --disable-validation Disable the $NAME image validation" } version() { @@ -67,9 +71,9 @@ version() { } function parse_arguments(){ - # Actions - ACT_SETUP=false - ACT_BUILD=false + # Actions + ACT_SETUP=false + ACT_BUILD=false ACT_NAMESPACE=false ACT_PROOT=false ACT_GROOT=false @@ -77,48 +81,74 @@ function parse_arguments(){ ACT_HELP=false ACT_VERSION=false - case "$1" in - s|setup) ACT_SETUP=true ; shift ;; - b|build) ACT_BUILD=true ; shift ;; - n|ns) ACT_NAMESPACE=true ; shift ;; - p|proot) ACT_PROOT=true ; shift ;; - g|groot) ACT_GROOT=true ; shift ;; - r|root) ACT_ROOT=true ; shift ;; - -h|--help) ACT_HELP=true ; shift ;; - -V|--version) ACT_VERSION=true ; shift ;; - *) ACT_NAMESPACE=true ;; - esac + case "$1" in + s|setup) ACT_SETUP=true ; shift ;; + b|build) ACT_BUILD=true ; shift ;; + n|ns) ACT_NAMESPACE=true ; shift ;; + p|proot) ACT_PROOT=true ; shift ;; + g|groot) ACT_GROOT=true ; shift ;; + r|root) ACT_ROOT=true ; shift ;; + -h|--help) ACT_HELP=true ; shift ;; + -V|--version) ACT_VERSION=true ; shift ;; + *) ACT_NAMESPACE=true ;; + esac - if $ACT_SETUP - then - _parse_setup_opts "$@" - elif $ACT_BUILD - then - _parse_build_opts "$@" - elif $ACT_NAMESPACE - then - _parse_general_opts "$@" - elif $ACT_PROOT - then - _parse_proot_opts "$@" - elif $ACT_GROOT - then - _parse_general_opts "$@" - elif $ACT_ROOT - then - _parse_general_opts "$@" - fi + if $ACT_SETUP + then + _parse_setup_opts "$@" + elif $ACT_BUILD + then + _parse_build_opts "$@" + elif $ACT_NAMESPACE + then + _parse_ns_opts "$@" + elif $ACT_PROOT + then + _parse_proot_opts "$@" + elif $ACT_GROOT + then + _parse_root_opts "$@" + elif $ACT_ROOT + then + _parse_root_opts "$@" + fi } -function _parse_general_opts() { - # Options: +function _parse_root_opts() { + # Options: OPT_BACKEND_ARGS=false BACKEND_ARGS="" + OPT_NO_COPY_FILES=false - while [[ -n "$1" ]] + while [[ -n "$1" ]] do case "$1" in - -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; + --) shift ; break ;; + -*) die "Invalid option $1" ;; + *) break ;; + esac + done + + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done +} + +function _parse_ns_opts() { + # Options: + OPT_BACKEND_ARGS=false + BACKEND_ARGS="" + OPT_NO_COPY_FILES=false + + while [[ -n "$1" ]] + do + case "$1" in + -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -133,16 +163,18 @@ function _parse_general_opts() { } function _parse_proot_opts() { - # Options: + # Options: OPT_FAKEROOT=false OPT_BACKEND_ARGS=false BACKEND_ARGS="" + OPT_NO_COPY_FILES=false - while [[ -n "$1" ]] + while [[ -n "$1" ]] do case "$1" in -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -p|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -157,26 +189,26 @@ function _parse_proot_opts() { } function _parse_build_opts() { - OPT_DISABLE_VALIDATION=false - while [[ -n "$1" ]] + OPT_DISABLE_CHECK=false + while [[ -n "$1" ]] do case "$1" in - -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; + -n|--disable-check) OPT_DISABLE_CHECK=true ; shift ;; *) die "Invalid option $1" ;; esac done } function _parse_setup_opts() { - OPT_SETUP_FROM_FILE=false + OPT_FROM_FILE=false IMAGE_FILE="" OPT_ARCH=false ARCH_ARG="" OPT_DELETE=false - while [[ -n "$1" ]] + while [[ -n "$1" ]] do case "$1" in - -i|--from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; + -i|--from-file) OPT_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; *) die "Invalid option $1" ;; @@ -189,33 +221,33 @@ function execute_operation() { $ACT_VERSION && version && return if $ACT_BUILD; then - build_image_env $OPT_DISABLE_VALIDATION + build_image_env $OPT_DISABLE_CHECK return - fi - - if $ACT_SETUP; then - if $OPT_DELETE; then + fi + + if $ACT_SETUP; then + if $OPT_DELETE; then delete_env - else - if is_env_installed - then - die "Error: The image cannot be installed since $JUNEST_HOME is not empty." - fi + else + if is_env_installed + then + die "Error: The image cannot be installed since $JUNEST_HOME is not empty." + fi - if $OPT_SETUP_FROM_FILE; then - setup_env_from_file $IMAGE_FILE - else - setup_env $ARCH_ARG - fi - fi + if $OPT_FROM_FILE; then + setup_env_from_file $IMAGE_FILE + else + setup_env $ARCH_ARG + fi + fi - return + return fi if ! is_env_installed then - die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup" + die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup" fi local run_env @@ -224,16 +256,16 @@ function execute_operation() { elif $ACT_PROOT; then if $OPT_FAKEROOT; then run_env=run_env_as_fakeroot - else + else run_env=run_env_as_user - fi + fi elif $ACT_GROOT; then run_env=run_env_as_groot elif $ACT_ROOT; then run_env=run_env_as_chroot fi - $run_env "${BACKEND_ARGS}" "${ARGS[@]}" + $run_env "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } diff --git a/lib/checks/check.sh b/lib/checks/check.sh index aee4b4a..ac34171 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -52,7 +52,7 @@ pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) info "Checking basic executables work..." pacman -Qi pacman 1> /dev/null -yogurt -V 1> /dev/null +/opt/makepkg/bin/makepkg --help 1> /dev/null /opt/proot/proot-$ARCH --help 1> /dev/null repo_package1=tree @@ -71,7 +71,13 @@ if ! $SKIP_AUR_TESTS then aur_package=aurutils info "Checking ${aur_package} package from AUR repo..." - yogurt -A --noconfirm -S ${aur_package} + maindir=$(mktemp -d -t ${CMD}.XXXXXXXXXX) + builtin cd ${maindir} + curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${aur_package}" + curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/${aur_package}.install?h=${aur_package}" + /opt/makepkg/bin/makepkg -sfcd + + pacman --noconfirm -U ${aur_package}*.pkg.tar.xz aur search aur 1> /dev/null pacman --noconfirm -Rsn ${aur_package} fi diff --git a/lib/core/build.sh b/lib/core/build.sh index fe12df3..40c2181 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -54,30 +54,26 @@ function build_image_env(){ info "Installing pacman and its dependencies..." # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils - # yaourt requires sed - # localedef (called by locale-gen) requires gzip # unshare command belongs to util-linux - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip util-linux + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring util-linux sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" sudo mkdir -p ${maindir}/root/run/lock # AUR packages requires non-root user to be compiled. proot fakes the user to 10 - info "Compiling and installing yaourt..." - _install_pkg_from_aur ${maindir} "package-query" - _install_pkg_from_aur ${maindir} "yaourt" _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" info "Install ${NAME} script..." - sudo pacman --noconfirm --root ${maindir}/root -S git _install_pkg_from_aur ${maindir} "${CMD}-git" "${CMD}.install" - sudo pacman --noconfirm --root ${maindir}/root -Rsn git info "Generating the locales..." # sed command is required for locale-gen + # localedef (called by locale-gen) requires gzip + sudo pacman --noconfirm --root ${maindir}/root -S sed gzip sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" + sudo pacman --noconfirm --root ${maindir}/root -Rsn sed gzip info "Setting up the pacman keyring (this might take a while!)..." sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${maindir}/root bash -c \ @@ -95,8 +91,9 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - JUNEST_HOME="${maindir}/root_test" ${maindir}/root_test/opt/${CMD}/bin/${CMD} -f ${JUNEST_BASE}/lib/checks/check.sh - JUNEST_HOME="${maindir}/root_test" sudo -E ${maindir}/root_test/opt/${CMD}/bin/${CMD} -g ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} proot -f ${JUNEST_BASE}/lib/checks/check.sh + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} ns ${JUNEST_BASE}/lib/checks/check.sh + JUNEST_HOME="${maindir}/root_test" sudo -E ${JUNEST_BASE}/bin/${CMD} groot ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index 731739a..eb584f0 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -11,7 +11,8 @@ function _run_env_as_xroot(){ local cmd=$1 local backend_args="$2" - shift 2 + local no_copy_files="$3" + shift 3 check_same_arch @@ -26,7 +27,10 @@ function _run_env_as_xroot(){ trap - QUIT EXIT ABRT KILL TERM INT trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT - copy_common_files + if ! $no_copy_files + then + copy_common_files + fi JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" } @@ -41,8 +45,10 @@ function _run_env_as_xroot(){ # SUDO_GID (RO) : The sudo group ID. # SH (RO) : Contains the default command to run in JuNest. # Arguments: -# backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. +# 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. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. @@ -53,13 +59,14 @@ function run_env_as_groot(){ check_nested_env local backend_args="$1" - shift + local no_copy_files="$2" + shift 2 provide_common_bindings local bindings=${RESULT} unset RESULT - _run_env_as_xroot "$GROOT $bindings" "$backend_args" "$@" + _run_env_as_xroot "$GROOT $bindings" "$backend_args" "$no_copy_files" "$@" } ####################################### @@ -72,8 +79,10 @@ function run_env_as_groot(){ # SUDO_GID (RO) : The sudo group ID. # SH (RO) : Contains the default command to run in JuNest. # Arguments: -# backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. +# 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. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. @@ -84,7 +93,8 @@ function run_env_as_chroot(){ check_nested_env local backend_args="$1" - shift + local no_copy_files="$2" + shift 2 - _run_env_as_xroot chroot_cmd "$backend_args" "$@" + _run_env_as_xroot chroot_cmd "$backend_args" "$no_copy_files" "$@" } diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 686fabe..7943faa 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -84,8 +84,10 @@ function _run_env_with_namespace(){ # GROOT (RO) : The groot program. # SH (RO) : Contains the default command to run in JuNest. # Arguments: -# backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. +# backend_args ($1) : The arguments to pass to groot +# 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. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. @@ -97,18 +99,23 @@ function run_env_with_namespace() { check_nested_env local backend_args="$1" - shift + local no_copy_files="$2" + shift 2 + _check_user_namespace check_same_arch - copy_common_files - copy_file /etc/hosts.equiv - copy_file /etc/netgroup - copy_file /etc/networks - # No need for localtime as it is setup during the image build - #copy_file /etc/localtime - copy_passwd_and_group + if ! $no_copy_files + then + copy_common_files + copy_file /etc/hosts.equiv + copy_file /etc/netgroup + copy_file /etc/networks + # No need for localtime as it is setup during the image build + #copy_file /etc/localtime + copy_passwd_and_group + fi _run_env_with_namespace "$backend_args" "$@" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index 21f8a01..69502eb 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -49,7 +49,9 @@ function _run_env_with_qemu(){ # SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. +# 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. # Returns: # $ROOT_ACCESS_ERROR : If the user is the real root. @@ -62,9 +64,13 @@ function run_env_as_fakeroot(){ check_nested_env local backend_args="$1" - shift + local no_copy_files="$2" + shift 2 - copy_common_files + if ! $no_copy_files + then + copy_common_files + fi provide_common_bindings local bindings=${RESULT} @@ -84,7 +90,9 @@ function run_env_as_fakeroot(){ # SH (RO) : Contains the default command to run in JuNest. # Arguments: # backend_args ($1) : The arguments to pass to proot -# cmd ($2-?) : The command to run inside JuNest environment. +# 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. # Returns: # $ROOT_ACCESS_ERROR : If the user is the real root. @@ -97,19 +105,23 @@ function run_env_as_user(){ check_nested_env local backend_args="$1" - shift + local no_copy_files="$2" + shift 2 - # Files to bind are visible in `proot --help`. - # This function excludes /etc/mtab file so that - # it will not give conflicts with the related - # symlink in the Arch Linux image. - copy_common_files - copy_file /etc/hosts.equiv - copy_file /etc/netgroup - copy_file /etc/networks - # No need for localtime as it is setup during the image build - #copy_file /etc/localtime - copy_passwd_and_group + if ! $no_copy_files + then + # Files to bind are visible in `proot --help`. + # This function excludes /etc/mtab file so that + # it will not give conflicts with the related + # symlink in the Arch Linux image. + copy_common_files + copy_file /etc/hosts.equiv + copy_file /etc/netgroup + copy_file /etc/networks + # No need for localtime as it is setup during the image build + #copy_file /etc/localtime + copy_passwd_and_group + fi provide_common_bindings local bindings=${RESULT} diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 7102dd5..8e54041 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -35,44 +35,44 @@ function init_mocks() { } function test_run_env_as_groot_cmd(){ - assertCommandSuccess run_env_as_groot "" pwd + assertCommandSuccess run_env_as_groot "" "false" pwd assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } function test_run_env_as_groot_no_cmd(){ - assertCommandSuccess run_env_as_groot "" + 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)" } function test_run_env_as_groot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_groot "" + assertCommandFailOnStatus 106 run_env_as_groot "" "false" "" unset JUNEST_ENV } function test_run_env_as_groot_cmd_with_backend_args(){ - assertCommandSuccess run_env_as_groot "-n -b /home/blah" pwd + assertCommandSuccess run_env_as_groot "-n -b /home/blah" "false" pwd assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } function test_run_env_as_chroot_cmd(){ - assertCommandSuccess run_env_as_chroot "" pwd + assertCommandSuccess run_env_as_chroot "" "false" pwd assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } function test_run_env_as_chroot_no_cmd(){ - assertCommandSuccess run_env_as_chroot "" + assertCommandSuccess run_env_as_chroot "" "false" "" assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } function test_run_env_as_choot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_chroot "" + assertCommandFailOnStatus 106 run_env_as_chroot "" "false" "" unset JUNEST_ENV } function test_run_env_as_chroot_cmd_with_backend_args(){ - assertCommandSuccess run_env_as_chroot "-n -b /home/blah" pwd + assertCommandSuccess run_env_as_chroot "-n -b /home/blah" "false" pwd assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index a3dee83..98c6cb2 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -25,8 +25,8 @@ function version(){ echo "version" } function build_image_env(){ - local disable_validation=$1 - echo "build_image_env($disable_validation)" + local disable_check=$1 + echo "build_image_env($disable_check)" } function delete_env(){ echo "delete_env" @@ -39,24 +39,33 @@ function setup_env(){ } function run_env_as_fakeroot(){ local backend_args="$1" - shift - echo "run_env_as_fakeroot($backend_args,$@)" + local no_copy_files="$2" + shift 2 + echo "run_env_as_fakeroot($backend_args,$no_copy_files,$@)" } function run_env_as_groot(){ - echo "run_env_as_groot $@" + local backend_args="$1" + local no_copy_files="$2" + shift 2 + echo "run_env_as_groot($backend_args,$no_copy_files,$@)" } function run_env_as_chroot(){ - echo "run_env_as_chroot $@" + local backend_args="$1" + local no_copy_files="$2" + shift 2 + echo "run_env_as_chroot($backend_args,$no_copy_files,$@)" } function run_env_as_user(){ local backend_args="$1" - shift - echo "run_env_as_user($backend_args,$@)" + local no_copy_files="$2" + shift 2 + echo "run_env_as_user($backend_args,$no_copy_files,$@)" } function run_env_with_namespace(){ local backend_args="$1" - shift - echo "run_env_with_namespace($backend_args,$@)" + local no_copy_files="$2" + shift 2 + echo "run_env_with_namespace($backend_args,$no_copy_files,$@)" } function test_help(){ @@ -78,7 +87,7 @@ function test_build_image_env(){ assertEquals "build_image_env(false)" "$(cat $STDOUTF)" assertCommandSuccess main b -n assertEquals "build_image_env(true)" "$(cat $STDOUTF)" - assertCommandSuccess main build --disable-validation + assertCommandSuccess main build --disable-check assertEquals "build_image_env(true)" "$(cat $STDOUTF)" } @@ -124,18 +133,20 @@ function test_setup_env(){ function test_run_env_as_fakeroot(){ assertCommandSuccess main p -f - assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_fakeroot(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot --fakeroot - assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_fakeroot(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main p -f -n + assertEquals "run_env_as_fakeroot(,true,)" "$(cat $STDOUTF)" - assertCommandSuccess main proot -f -p "-b arg" - assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main proot -f -p "-b arg" -- command -kv - assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess main proot -f -b "-b arg" + assertEquals "run_env_as_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main proot -f -b "-b arg" -- command -kv + assertEquals "run_env_as_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f command --as - assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_fakeroot(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -- command --as - assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_fakeroot(,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -145,16 +156,18 @@ function test_run_env_as_fakeroot(){ function test_run_env_as_user(){ assertCommandSuccess main proot - assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_user(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main p -n + assertEquals "run_env_as_user(,true,)" "$(cat $STDOUTF)" - assertCommandSuccess main proot -p "-b arg" - assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main proot -p "-b arg" -- command -ll - assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)" + assertCommandSuccess main proot -b "-b arg" + assertEquals "run_env_as_user(-b arg,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main proot -b "-b arg" -- command -ll + assertEquals "run_env_as_user(-b arg,false,command -ll)" "$(cat $STDOUTF)" assertCommandSuccess main proot command -ls - assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_user(,false,command -ls)" "$(cat $STDOUTF)" assertCommandSuccess main proot -- command -ls - assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_user(,false,command -ls)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -164,11 +177,15 @@ function test_run_env_as_user(){ function test_run_env_as_groot(){ assertCommandSuccess main g - assertEquals "run_env_as_groot " "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main g -n + assertEquals "run_env_as_groot(,true,)" "$(cat $STDOUTF)" + assertCommandSuccess main g -b "-b arg" + assertEquals "run_env_as_groot(-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main groot command - assertEquals "run_env_as_groot command" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,false,command)" "$(cat $STDOUTF)" assertCommandSuccess main groot -- command - assertEquals "run_env_as_groot command" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,false,command)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -178,11 +195,13 @@ function test_run_env_as_groot(){ function test_run_env_as_chroot(){ assertCommandSuccess main r - assertEquals "run_env_as_chroot " "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main r -b "-b arg" + assertEquals "run_env_as_chroot(-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main root command - assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,false,command)" "$(cat $STDOUTF)" assertCommandSuccess main root -- command - assertEquals "run_env_as_chroot command" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,false,command)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -192,32 +211,34 @@ function test_run_env_as_chroot(){ function test_run_env_with_namespace(){ assertCommandSuccess main n - assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns - assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -n + assertEquals "run_env_with_namespace(,true,)" "$(cat $STDOUTF)" - assertCommandSuccess main ns -p "-b arg" - assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main ns -p "-b arg" -- command -kv - assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -b "-b arg" + assertEquals "run_env_with_namespace(-b arg,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -b "-b arg" -- command -kv + assertEquals "run_env_with_namespace(-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main ns command --as - assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main ns -- command --as - assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main - assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main - assertEquals "run_env_with_namespace(,)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" - assertCommandSuccess main -p "-b arg" - assertEquals "run_env_with_namespace(-b arg,)" "$(cat $STDOUTF)" - assertCommandSuccess main -p "-b arg" -- command -kv - assertEquals "run_env_with_namespace(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess main -b "-b arg" + assertEquals "run_env_with_namespace(-b arg,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main -b "-b arg" -- command -kv + assertEquals "run_env_with_namespace(-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main command --as - assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main -- command --as - assertEquals "run_env_with_namespace(,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 005ab0d..9cd730a 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -100,7 +100,7 @@ function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ } function test_run_env_with_namespace() { - assertCommandSuccess run_env_with_namespace "" "" + assertCommandSuccess run_env_with_namespace "" "false" "" assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files @@ -108,7 +108,7 @@ function test_run_env_with_namespace() { } function test_run_env_with_namespace_with_bindings() { - assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "" + assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "false" "" assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files @@ -116,7 +116,7 @@ function test_run_env_with_namespace_with_bindings() { } function test_run_env_with_namespace_with_command() { - assertCommandSuccess run_env_with_namespace "" "ls -la" + assertCommandSuccess run_env_with_namespace "" "false" "ls -la" assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files @@ -124,7 +124,7 @@ function test_run_env_with_namespace_with_command() { } function test_run_env_with_namespace_with_bindings_and_command() { - assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la" + assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "false" "ls -la" assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files @@ -133,7 +133,7 @@ function test_run_env_with_namespace_with_bindings_and_command() { function test_run_env_with_namespace_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_with_namespace "" + assertCommandFailOnStatus 106 run_env_with_namespace "" "false" "" unset JUNEST_ENV } diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index cb2d35c..c5a929a 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -51,11 +51,11 @@ function test_run_env_as_user(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_user "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_user "-k 3.10" + assertCommandSuccess run_env_as_user "-k 3.10" "false" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" _test_copy_common_files @@ -64,7 +64,7 @@ function test_run_env_as_user(){ function test_run_env_as_user_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_user "" + assertCommandFailOnStatus 106 run_env_as_user "" "false" unset JUNEST_ENV } @@ -72,11 +72,11 @@ function test_run_env_as_fakeroot(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_fakeroot "-k 3.10" + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "false" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" _test_copy_common_files @@ -84,7 +84,7 @@ function test_run_env_as_fakeroot(){ function test_run_env_as_fakeroot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_fakeroot "" + assertCommandFailOnStatus 106 run_env_as_fakeroot "" "false" "" unset JUNEST_ENV } @@ -92,7 +92,7 @@ function test_run_env_with_quotes(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + assertCommandSuccess run_env_as_user "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" } From 632aad46bd83fcb34bf77ac09e63bf1347c22a7d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 20 Oct 2019 23:14:31 +0200 Subject: [PATCH 204/326] Small fixes --- .travis.yml | 17 +++++++------ README.md | 39 +++++++++++++++--------------- bin/junest | 4 +-- tests/unit-tests/test-chroot.sh | 28 +++++++++++++++++++++ tests/unit-tests/test-namespace.sh | 26 ++++++++++++++++++++ tests/unit-tests/test-proot.sh | 29 ++++++++++++++++++++++ 6 files changed, 113 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef57497..dceb835 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,10 @@ before_install: install: - PATH=$PWD/bin:$PATH + - junest setup - junest -- echo "Installing JuNest (\$(uname -m))" - - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" + - JUNEST_HOME=~/.junest-arm junest setup --arch arm + - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))" script: - bash --version @@ -19,12 +21,11 @@ script: - bash ./tests/unit-tests/unit-tests.sh # Multiple tests against different execution modes: - # TODO AUR installation check is currently disabled - - junest -f -- ${PWD}/lib/checks/check.sh - - junest -u -- ${PWD}/lib/checks/check.sh - - sudo -E ${PWD}/bin/junest -g -- ${PWD}/lib/checks/check.sh - - yes | junest --delete + - junest proot --fakeroot -- ${PWD}/lib/checks/check.sh + - junest ns -- ${PWD}/lib/checks/check.sh + - sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh --run-root-tests + - yes | junest setup --delete # Disable arm because it fails when exiting from check.sh for apparent no reason - #- JUNEST_HOME=~/.junest-arm junest -f -- ./lib/checks/check.sh --skip-aur-tests - #- yes | JUNEST_HOME=~/.junest-arm junest --delete + #- JUNEST_HOME=~/.junest-arm junest proot -f -- ./lib/checks/check.sh --skip-aur-tests + #- yes | JUNEST_HOME=~/.junest-arm junest setup --delete diff --git a/README.md b/README.md index 3dbb0dc..856a9a8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Gratipay](https://img.shields.io/badge/Gratipay-Donate%20to%20JuNest-green.svg)](https://gratipay.com/junest/) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the IRC chat at https://webchat.freenode.net/?channels=junest](https://img.shields.io/badge/IRC-JuNest-yellow.svg)](https://webchat.freenode.net/?channels=junest) [![Join the group at https://groups.google.com/d/forum/junest](https://img.shields.io/badge/GoogleGroups-JuNest-red.svg)](https://groups.google.com/d/forum/junest) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) @@ -23,7 +23,7 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without - [Troubleshooting](#troubleshooting) - [More documentation](#more-documentation) - [Contributing](#contributing) -- [Author](#author) +- [Authors](#authors) Description =========== @@ -106,11 +106,11 @@ visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rose JuNest provides a modified version of `makepkg` in `/opt/makepkg/bin` that allows you to build packages from [AUR](https://aur.archlinux.org/) repository. -Remember that in order to build package `base-devel` package group is required +Remember that in order to build packages, `base-devel` package group is required first: ```sh -pacman -Sy base-devel +pacman -Sy --ignore sudo base-devel ``` Installation @@ -124,8 +124,8 @@ Before installing JuNest be sure that all dependencies are properly installed in - [bash (>=4.0)](https://www.gnu.org/software/bash/) - [GNU coreutils](https://www.gnu.org/software/coreutils/) -The minimum recommended Linux kernel of the host OS is 2.6.32 on x86 (32-bit -and 64 bit) and ARM architectures. It is still possible to run JuNest on lower +The minimum recommended Linux kernel of the host OS is 2.6.32 on x86 (64 bit) +and ARM architectures. It is still possible to run JuNest on lower 2.6.x host OS kernels but errors may appear, and some applications may crash. For further information, read the [Troubleshooting](#troubleshooting) section below. @@ -176,10 +176,8 @@ In order to run JuNest via Linux namespaces: PRoot based ----------- -[Proot](https://wiki.archlinux.org/index.php/Proot) represents the default -program used for accessing to the JuNest environments. -The main reason to choose Proot as default backend program is because -it represents a portable solution that works well in most of GNU/Linux distros available. +[Proot](https://wiki.archlinux.org/index.php/Proot) represents a portable +solution that works well in most of GNU/Linux distros available. One of the major drawbacks is the fact that Proot is not officially supported anymore, therefore, Proot bugs may no longer be fixed. @@ -194,7 +192,7 @@ Chroot based This solution suits only for privileged users. JuNest provides the possibility to run the environment via `chroot` program. In particular, it uses a special program called `GRoot`, an enhanced `chroot` -wrapper that allows to bind mount directories specified by the user, such as +wrapper, that allows to bind mount directories specified by the user, such as `/proc`, `/sys`, `/dev`, `/tmp` and `$HOME`, before executing any programs inside the JuNest sandbox. In case the mounting will not work, JuNest is even providing the possibility to run the environment directly via @@ -212,8 +210,8 @@ The following table shows the capabilities that each backend program is able to | | QEMU | Root privileges required | Manage Official Packages | Manage AUR Packages | Portability | Support | User modes | | --- | ---- | ------------------------ | ------------------------ | ------------------- | ----------- | ------- | ---------- | -| **Proot** | YES | NO | YES | YES | YES | Poor | Normal user and `fakeroot` | | **Linux Namespaces** | NO | NO | YES | YES | Poor | YES | `fakeroot` only | +| **Proot** | YES | NO | YES | YES | YES | Poor | Normal user and `fakeroot` | | **Chroot** | NO | YES | YES | YES | YES | YES | `root` only | Advanced usage @@ -249,12 +247,12 @@ Related wiki page: ## Run JuNest using a different architecture via QEMU ## The following command will download the ARM JuNest image and will run QEMU in -case the host OS runs on either `x86_64` or `x86` architectures: +case the host OS runs on `x86_64` architecture: ```sh $> export JUNEST_HOME=~/.junest-arm $> junest setup -a arm -$> junest -- uname -m +$> junest proot -- uname -m armv7l ``` @@ -262,7 +260,7 @@ armv7l To bind a host directory to a guest location, you can use proot arguments: ```sh -junest proot `-b` "-b /mnt/mydata:/home/user/mydata" +junest proot -b "-b /mnt/mydata:/home/user/mydata" ``` The option `-b` to provide options to the backeng program will work with PRoot, Namespace and GRoot backend programs. @@ -514,13 +512,16 @@ There are additional tutorials in the Contributing ============ -You could help improving JuNest in the following ways: +Contributions are welcome! You could help improving JuNest in the following ways: - [Reporting Bugs](CONTRIBUTING.md#reporting-bugs) - [Suggesting Enhancements](CONTRIBUTING.md#suggesting-enhancements) - [Writing Code](CONTRIBUTING.md#your-first-code-contribution) -Author -====== -Filippo Squillace +Authors +======= +JuNest was originally created in late 2014 by [Filippo Squillace (feel.sqoox@gmail.com)](https://github.com/fsquillace). +Here is a list of [**really appreciated contributors**](https://github.com/fsquillace/junest/graphs/contributors)! + +[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/0)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/0)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/1)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/1)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/2)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/2)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/3)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/3)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/4)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/4)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/5)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/5)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/6)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/6)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/7)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/7) diff --git a/bin/junest b/bin/junest index 2a9549d..381864b 100755 --- a/bin/junest +++ b/bin/junest @@ -19,8 +19,6 @@ source "${JUNEST_BASE}/lib/core/namespace.sh" source "${JUNEST_BASE}/lib/core/proot.sh" -# TODO Add test that checks that no_copy files works - ################################### ### General functions ### ################################### @@ -34,7 +32,7 @@ usage() { echo -e "-V, --version Show the $NAME version" echo echo -e "Actions and options:" - echo -e " s[etup] " + echo -e " s[etup] Setup $NAME in ${JUNEST_HOME} either from repo or from file" echo -e " -i, --from-file Setup the $NAME image in ${JUNEST_HOME}" echo -e " -a, --arch $NAME architecture to download (x86_64, arm)" echo -e " Defaults to the host architecture ($ARCH)" diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 8e54041..b2e5e70 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -44,6 +44,20 @@ function test_run_env_as_groot_no_cmd(){ assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } +function test_run_env_as_groot_no_copy(){ + assertCommandSuccess run_env_as_groot "" "true" pwd + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + + [[ ! -e ${JUNEST_HOME}/etc/hosts ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] + assertEquals 0 $? +} + function test_run_env_as_groot_nested_env(){ JUNEST_ENV=1 assertCommandFailOnStatus 106 run_env_as_groot "" "false" "" @@ -65,6 +79,20 @@ function test_run_env_as_chroot_no_cmd(){ assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } +function test_run_env_as_chroot_no_copy(){ + assertCommandSuccess run_env_as_chroot "" "true" pwd + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + + [[ ! -e ${JUNEST_HOME}/etc/hosts ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] + assertEquals 0 $? +} + function test_run_env_as_choot_nested_env(){ JUNEST_ENV=1 assertCommandFailOnStatus 106 run_env_as_chroot "" "false" "" diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 9cd730a..4ecc794 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -107,6 +107,32 @@ function test_run_env_with_namespace() { _test_copy_remaining_files } +function test_run_env_with_namespace_no_copy() { + assertCommandSuccess run_env_with_namespace "" "true" "" + assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" + + [[ ! -e ${JUNEST_HOME}/etc/hosts ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] + assertEquals 0 $? + + [[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/netgroup ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/networks ]] + assertEquals 0 $? + + [[ ! -e ${JUNEST_HOME}/etc/passwd ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/group ]] + assertEquals 0 $? +} + function test_run_env_with_namespace_with_bindings() { assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "false" "" assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index c5a929a..a951cd6 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -62,6 +62,35 @@ function test_run_env_as_user(){ _test_copy_remaining_files } +function test_run_env_as_user_no_copy(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_user "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + [[ ! -e ${JUNEST_HOME}/etc/hosts ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] + assertEquals 0 $? + + [[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/netgroup ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/networks ]] + assertEquals 0 $? + + [[ ! -e ${JUNEST_HOME}/etc/passwd ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/group ]] + assertEquals 0 $? +} + function test_run_env_as_user_nested_env(){ JUNEST_ENV=1 assertCommandFailOnStatus 106 run_env_as_user "" "false" From 27f92d0b3f781ae63e21843104abd9ac2ff0ffec Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 25 Oct 2019 20:46:27 +0200 Subject: [PATCH 205/326] Add rw permission to files in image --- lib/core/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/core/build.sh b/lib/core/build.sh index 40c2181..1406ed7 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -80,6 +80,9 @@ function build_image_env(){ "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" sudo rm ${maindir}/root/var/cache/pacman/pkg/* + # This is needed on system with busybox tar command. + # If the file does not have write permission, the tar command to extract files fails. + sudo chmod -R u+rw ${maindir}/root/etc/ca-certificates/extracted/cadir mkdir -p ${maindir}/output builtin cd ${maindir}/output From c5847b85836c30a5c3414af4767c4106ff737d85 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 25 Oct 2019 20:46:38 +0200 Subject: [PATCH 206/326] 7.0.1 --- VERSION | 2 +- lib/core/build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 66ce77b..9fe9ff9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0 +7.0.1 diff --git a/lib/core/build.sh b/lib/core/build.sh index 1406ed7..faf7f08 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -82,7 +82,7 @@ function build_image_env(){ sudo rm ${maindir}/root/var/cache/pacman/pkg/* # This is needed on system with busybox tar command. # If the file does not have write permission, the tar command to extract files fails. - sudo chmod -R u+rw ${maindir}/root/etc/ca-certificates/extracted/cadir + sudo chmod -R u+rw ${maindir}/root/ mkdir -p ${maindir}/output builtin cd ${maindir}/output From 8d91e18ab0235fbad0e609d5d9fbc9e3a0fdf53b Mon Sep 17 00:00:00 2001 From: Oscar Lai Date: Sun, 10 Nov 2019 02:22:42 +1100 Subject: [PATCH 207/326] fixed typos in --help message --- bin/junest | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/junest b/bin/junest index 381864b..8ea3b19 100755 --- a/bin/junest +++ b/bin/junest @@ -40,23 +40,23 @@ usage() { echo echo -e " n[s] Access via Linux Namespaces using GRoot (Default action)" echo -e " -b, --backend-args Arguments for GRoot backend program" - echo -e " ($CMD groot -p \"--help\" to check out the GRoot options)" + echo -e " ($CMD groot -b \"--help\" to check out the GRoot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " p[root] Access via PRoot" echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" echo -e " -b, --backend-args Arguments for PRoot backend program" - echo -e " ($CMD proot -p \"--help\" to check out the PRoot options)" + echo -e " ($CMD proot -b \"--help\" to check out the PRoot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " g[root] Access with root privileges via GRoot" echo -e " -b, --backend-args Arguments for GRoot backend program" - echo -e " ($CMD groot -p \"--help\" to check out the GRoot options)" + echo -e " ($CMD groot -b \"--help\" to check out the GRoot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " r[oot] Access with root privileges via classic chroot" echo -e " -b, --backend-args Arguments for chroot backend program" - echo -e " ($CMD root -p \"--help\" to check out the chroot options)" + echo -e " ($CMD root -b \"--help\" to check out the chroot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" From 82b146a57e0495f16afa06e7cad84c3e3d825eaf Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 25 Oct 2019 20:46:27 +0200 Subject: [PATCH 208/326] Add rw permission to files in image --- lib/core/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/core/build.sh b/lib/core/build.sh index 40c2181..1406ed7 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -80,6 +80,9 @@ function build_image_env(){ "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" sudo rm ${maindir}/root/var/cache/pacman/pkg/* + # This is needed on system with busybox tar command. + # If the file does not have write permission, the tar command to extract files fails. + sudo chmod -R u+rw ${maindir}/root/etc/ca-certificates/extracted/cadir mkdir -p ${maindir}/output builtin cd ${maindir}/output From 2e8f5905c7a3278eedfea237a4735817df70b959 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 25 Oct 2019 20:46:38 +0200 Subject: [PATCH 209/326] 7.0.1 --- VERSION | 2 +- lib/core/build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 66ce77b..9fe9ff9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.0 +7.0.1 diff --git a/lib/core/build.sh b/lib/core/build.sh index 1406ed7..faf7f08 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -82,7 +82,7 @@ function build_image_env(){ sudo rm ${maindir}/root/var/cache/pacman/pkg/* # This is needed on system with busybox tar command. # If the file does not have write permission, the tar command to extract files fails. - sudo chmod -R u+rw ${maindir}/root/etc/ca-certificates/extracted/cadir + sudo chmod -R u+rw ${maindir}/root/ mkdir -p ${maindir}/output builtin cd ${maindir}/output From 85aeda4ac9b7ed7cf9721ccdb01217e9c288edd9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 17 Nov 2019 10:09:10 +0100 Subject: [PATCH 210/326] Update the check for building image --- lib/checks/check.sh | 1 + lib/core/common.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index ac34171..6c550b3 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -75,6 +75,7 @@ then builtin cd ${maindir} curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${aur_package}" curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/${aur_package}.install?h=${aur_package}" + gpg --recv-keys DBE7D3DD8C81D58D0A13D0E76BC26A17B9B7018A /opt/makepkg/bin/makepkg -sfcd pacman --noconfirm -U ${aur_package}*.pkg.tar.xz diff --git a/lib/core/common.sh b/lib/core/common.sh index 996c24f..601e46c 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -152,7 +152,7 @@ function proot_cmd(){ elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${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 -u" + warn "Try to use Linux namespace instead as it is more reliable: junest ns" PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else die "Error: Something went wrong with proot command. Exiting" From 493b105faa1aee78a99e94190bb2c5ea554c20a9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 17 Nov 2019 13:18:41 +0100 Subject: [PATCH 211/326] Remove socket filename for gpg agent during build check --- lib/checks/check.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 6c550b3..9ee7505 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -69,17 +69,14 @@ pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS then - aur_package=aurutils + aur_package=tcptraceroute info "Checking ${aur_package} package from AUR repo..." maindir=$(mktemp -d -t ${CMD}.XXXXXXXXXX) builtin cd ${maindir} curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${aur_package}" - curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/${aur_package}.install?h=${aur_package}" - gpg --recv-keys DBE7D3DD8C81D58D0A13D0E76BC26A17B9B7018A - /opt/makepkg/bin/makepkg -sfcd + /opt/makepkg/bin/makepkg -sfc --noconfirm pacman --noconfirm -U ${aur_package}*.pkg.tar.xz - aur search aur 1> /dev/null pacman --noconfirm -Rsn ${aur_package} fi From 606353047c225223ec33232594cbd63fa1072577 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 1 Dec 2019 17:10:01 +0100 Subject: [PATCH 212/326] 7.0.2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9fe9ff9..a8907c0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.1 +7.0.2 From e0dd3257a8b2c5cbc719b074efbcdf482de64b43 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Dec 2019 11:55:27 +0000 Subject: [PATCH 213/326] Add support for ARM arch during build and check --- .travis.yml | 8 +++++--- lib/checks/check.sh | 5 +++-- lib/core/build.sh | 17 ++++++++++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index dceb835..13c3d4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,8 @@ script: - sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh --run-root-tests - yes | junest setup --delete - # Disable arm because it fails when exiting from check.sh for apparent no reason - #- JUNEST_HOME=~/.junest-arm junest proot -f -- ./lib/checks/check.sh --skip-aur-tests - #- yes | JUNEST_HOME=~/.junest-arm junest setup --delete + - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- ${PWD}/lib/checks/check.sh + - JUNEST_HOME=~/.junest-arm junest ns -- ${PWD}/lib/checks/check.sh + # Do not run root test because iftop does not work well in arm + - JUNEST_HOME=~/.junest-arm sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh + - yes | JUNEST_HOME=~/.junest-arm junest setup --delete diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 9ee7505..55acd1b 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -64,7 +64,7 @@ pacman --noconfirm -Rsn ${repo_package1} repo_package2=iftop info "Checking ${repo_package2} package from official repo..." pacman --noconfirm -S ${repo_package2} -$RUN_ROOT_TESTS && iftop -t -s 5 +$RUN_ROOT_TESTS && iftop -t -s 5 -i lo pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS @@ -74,7 +74,8 @@ then maindir=$(mktemp -d -t ${CMD}.XXXXXXXXXX) builtin cd ${maindir} curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${aur_package}" - /opt/makepkg/bin/makepkg -sfc --noconfirm + # -A allows to ignore arch for ARM + /opt/makepkg/bin/makepkg -Asfc --noconfirm pacman --noconfirm -U ${aur_package}*.pkg.tar.xz pacman --noconfirm -Rsn ${aur_package} diff --git a/lib/core/build.sh b/lib/core/build.sh index faf7f08..898551a 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -55,7 +55,9 @@ function build_image_env(){ # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils # unshare command belongs to util-linux - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring util-linux + local arm_keyring="" + [[ $(uname -m) == *"arm"* ]] && arm_keyring="archlinuxarm-keyring" + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring $arm_keyring util-linux sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" sudo mkdir -p ${maindir}/root/run/lock @@ -76,8 +78,17 @@ function build_image_env(){ sudo pacman --noconfirm --root ${maindir}/root -Rsn sed gzip info "Setting up the pacman keyring (this might take a while!)..." - sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${maindir}/root bash -c \ - "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" + # gawk command is required for pacman-key + sudo pacman --noconfirm --root ${maindir}/root -S gawk + sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${maindir}/root bash -c ' + pacman-key --init; + for keyring_file in /usr/share/pacman/keyrings/*.gpg; + do + keyring=$(basename $keyring_file | cut -f 1 -d "."); + pacman-key --populate $keyring; + done; + [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye' + sudo pacman --noconfirm --root ${maindir}/root -Rsn gawk sudo rm ${maindir}/root/var/cache/pacman/pkg/* # This is needed on system with busybox tar command. From 11a439499bfacc85e5b006f41d37237d29be06bc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Dec 2019 13:05:14 +0000 Subject: [PATCH 214/326] Remove interface lo when checking iftop --- .travis.yml | 3 --- lib/checks/check.sh | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 13c3d4a..38470dc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,4 @@ script: - yes | junest setup --delete - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- ${PWD}/lib/checks/check.sh - - JUNEST_HOME=~/.junest-arm junest ns -- ${PWD}/lib/checks/check.sh - # Do not run root test because iftop does not work well in arm - - JUNEST_HOME=~/.junest-arm sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh - yes | JUNEST_HOME=~/.junest-arm junest setup --delete diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 55acd1b..fb60ff0 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -64,7 +64,7 @@ pacman --noconfirm -Rsn ${repo_package1} repo_package2=iftop info "Checking ${repo_package2} package from official repo..." pacman --noconfirm -S ${repo_package2} -$RUN_ROOT_TESTS && iftop -t -s 5 -i lo +$RUN_ROOT_TESTS && iftop -t -s 5 pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS From 538e87f036e56d46f5ccda756071aa3c3d090ea9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 21 Feb 2020 23:05:46 +0100 Subject: [PATCH 215/326] Add FUNDING file --- .github/FUNDING.yml | 2 ++ README.md | 8 +++++++- VERSION | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..8efae1f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: fsquillace +custom: https://github.com/fsquillace/junest/blob/master/README.md#donating diff --git a/README.md b/README.md index 856a9a8..3f96180 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![PayPal](https://img.shields.io/badge/PayPal-Donate%20a%20beer-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) @@ -23,6 +23,7 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without - [Troubleshooting](#troubleshooting) - [More documentation](#more-documentation) - [Contributing](#contributing) +- [Donating](#donating) - [Authors](#authors) Description @@ -518,6 +519,11 @@ Contributions are welcome! You could help improving JuNest in the following ways - [Suggesting Enhancements](CONTRIBUTING.md#suggesting-enhancements) - [Writing Code](CONTRIBUTING.md#your-first-code-contribution) +Donating +======== +To sustain the project please consider funding by donations through +the [GitHub Sponsors page](https://github.com/sponsors/fsquillace/). + Authors ======= JuNest was originally created in late 2014 by [Filippo Squillace (feel.sqoox@gmail.com)](https://github.com/fsquillace). diff --git a/VERSION b/VERSION index a8907c0..a50da18 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.2 +7.0.3 From 9bfd7e047d97fea93d9fbde90705df76e21c8550 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 14 Mar 2020 17:05:40 +0100 Subject: [PATCH 216/326] Add bwrap as backend for ns --- .travis.yml | 10 +-- README.md | 62 ++++++++++------ bin/junest | 16 +++-- lib/checks/check.sh | 64 +++++++++-------- lib/core/build.sh | 78 ++++++++++++++------ lib/core/common.sh | 13 +++- lib/core/namespace.sh | 70 +++++++++++++----- lib/core/proot.sh | 4 +- pkgs/sudo-fake/PKGBUILD | 4 +- tests/unit-tests/test-junest.sh | 111 ++++++++++++++++++++--------- tests/unit-tests/test-namespace.sh | 98 ++++++++++++++++++++----- tests/unit-tests/test-proot.sh | 26 +++---- 12 files changed, 387 insertions(+), 169 deletions(-) diff --git a/.travis.yml b/.travis.yml index 38470dc..b3a3bea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,10 +21,12 @@ script: - bash ./tests/unit-tests/unit-tests.sh # Multiple tests against different execution modes: - - junest proot --fakeroot -- ${PWD}/lib/checks/check.sh - - junest ns -- ${PWD}/lib/checks/check.sh - - sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh --run-root-tests + - junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo + - junest ns --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest ns -- ${PWD}/lib/checks/check.sh --use-sudo + - sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh --run-root-tests --skip-aur-tests - yes | junest setup --delete - - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- ${PWD}/lib/checks/check.sh + - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - yes | JUNEST_HOME=~/.junest-arm junest setup --delete diff --git a/README.md b/README.md index 3f96180..fc9f320 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,9 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without Description =========== -**JuNest** (Jailed User NEST) is a lightweight Arch Linux based distribution that allows to have -an isolated GNU/Linux environment inside any generic host GNU/Linux OS +**JuNest** (Jailed User NEST) is a lightweight Arch Linux based distribution +that allows to have disposable and isolated GNU/Linux environments +within any generic GNU/Linux host OS and without the need to have root privileges for installing packages. JuNest contains mainly the package managers (called [pacman](https://wiki.archlinux.org/index.php/Pacman) @@ -86,14 +87,22 @@ By default, JuNest run via the Linux namespaces (aka `ns`) as the backend progra junest ``` +You can use the command `sudo` to acquire fakeroot privileges and +install/remove packages. + +Alternatively, you can access root privileges without using `sudo` with the +`-f` option: + +```sh +junest -f +``` + Another execution mode is via [Proot](https://wiki.archlinux.org/index.php/Proot): ```sh junest proot [-f] ``` -Where `-f` allow fakeroot access to install/remove packages. - There are multiple backend programs, each with its own pros/cons. To know more about the JuNest execution modes depending on the backend program used, see the [Usage](#usage) section below. @@ -105,15 +114,20 @@ Have fun! If you are new on Arch Linux and you are not familiar with `pacman` package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). -JuNest provides a modified version of `makepkg` in `/opt/makepkg/bin` that -allows you to build packages from [AUR](https://aur.archlinux.org/) repository. -Remember that in order to build packages, `base-devel` package group is required +In `ns` mode, you can easily install package from [AUR](https://aur.archlinux.org/) repository +using the already available [`yay`](https://aur.archlinux.org/packages/yay/) +command. In `proot` mode, JuNest does no longer support the building of AUR packages. + +**Remember** that in order to build packages from source, `base-devel` package group is required first: ```sh pacman -Sy --ignore sudo base-devel ``` +JuNest uses a modified version of `sudo`. That's why the original `sudo` +package has to be ignored in the previous command. + Installation ============ @@ -125,14 +139,14 @@ Before installing JuNest be sure that all dependencies are properly installed in - [bash (>=4.0)](https://www.gnu.org/software/bash/) - [GNU coreutils](https://www.gnu.org/software/coreutils/) -The minimum recommended Linux kernel of the host OS is 2.6.32 on x86 (64 bit) +In `proot` mode, the minimum recommended Linux kernel for the host OS is 2.6.32 on x86 (64 bit) and ARM architectures. It is still possible to run JuNest on lower 2.6.x host OS kernels but errors may appear, and some applications may crash. For further information, read the [Troubleshooting](#troubleshooting) section below. -## Method one (Recommended) ## +## Installation from git repository ## Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): git clone git://github.com/fsquillace/junest ~/.local/share/junest @@ -142,14 +156,6 @@ Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/packages/junest-git/). After installing junest will be located in `/opt/junest/` -## Method two ## -Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory `~/.junest`: - - ARCH= - mkdir ~/.junest - curl https://s3-eu-west-1.amazonaws.com/junest-repo/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest - export PATH=~/.junest/opt/junest/bin:$PATH - Usage ===== There are three different ways you can run JuNest depending on the backend program you decide to use. @@ -173,7 +179,12 @@ provides the state of the user namespace on several GNU/Linux distros. In order to run JuNest via Linux namespaces: -- As fakeroot - Allow to install/remove packages: `junest ns` or `junest` +- As normal user - Allow to make basic operations or install/remove packages +with `sudo` command: `junest ns` or `junest` +- As fakeroot - Allow to install/remove packages: `junest ns -f` or `junest -f` + +This mode is based on the fantastic +[`bubblewrap`](https://github.com/containers/bubblewrap) command. PRoot based ----------- @@ -211,8 +222,8 @@ The following table shows the capabilities that each backend program is able to | | QEMU | Root privileges required | Manage Official Packages | Manage AUR Packages | Portability | Support | User modes | | --- | ---- | ------------------------ | ------------------------ | ------------------- | ----------- | ------- | ---------- | -| **Linux Namespaces** | NO | NO | YES | YES | Poor | YES | `fakeroot` only | -| **Proot** | YES | NO | YES | YES | YES | Poor | Normal user and `fakeroot` | +| **Linux Namespaces** | NO | NO | YES | YES | Poor | YES | Normal user and `fakeroot` | +| **Proot** | YES | NO | YES | NO | YES | Poor | Normal user and `fakeroot` | | **Chroot** | NO | YES | YES | YES | YES | YES | `root` only | Advanced usage @@ -343,6 +354,17 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > Remember to ignore `sudo` as it conflicts with `sudo-fake` package. +## Can't set user and group as root + +> **Q**: In ns mode when installing package I get the following error: + + warning: warning given when extracting /usr/file... (Can't set user=0/group=0 for + /usr/file...) + +> **A**: This is because as fakeroot is not possible to set the owner/group of +> files as root. The package will still be installed correctly even though this +> message is showed. + ## No servers configured for repository ## > **Q**: Why I cannot install packages? diff --git a/bin/junest b/bin/junest index 8ea3b19..442b31e 100755 --- a/bin/junest +++ b/bin/junest @@ -38,9 +38,9 @@ usage() { echo -e " Defaults to the host architecture ($ARCH)" echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}" echo - echo -e " n[s] Access via Linux Namespaces using GRoot (Default action)" + echo -e " n[s] Access via Linux Namespaces using BubbleWrap (Default action)" echo -e " -b, --backend-args Arguments for GRoot backend program" - echo -e " ($CMD groot -b \"--help\" to check out the GRoot options)" + echo -e " ($CMD groot -b \"--help\" to check out the bwrap options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " p[root] Access via PRoot" @@ -138,6 +138,7 @@ function _parse_root_opts() { function _parse_ns_opts() { # Options: + OPT_FAKEROOT=false OPT_BACKEND_ARGS=false BACKEND_ARGS="" OPT_NO_COPY_FILES=false @@ -145,6 +146,7 @@ function _parse_ns_opts() { while [[ -n "$1" ]] do case "$1" in + -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; --) shift ; break ;; @@ -250,12 +252,16 @@ function execute_operation() { local run_env if $ACT_NAMESPACE; then - run_env=run_env_with_namespace + if $OPT_FAKEROOT; then + run_env=run_env_as_bwrap_fakeroot + else + run_env=run_env_as_bwrap_user + fi elif $ACT_PROOT; then if $OPT_FAKEROOT; then - run_env=run_env_as_fakeroot + run_env=run_env_as_proot_fakeroot else - run_env=run_env_as_user + run_env=run_env_as_proot_user fi elif $ACT_GROOT; then run_env=run_env_as_groot diff --git a/lib/checks/check.sh b/lib/checks/check.sh index fb60ff0..5214595 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -9,15 +9,26 @@ # # vim: ft=sh -set -eu +set -e + -OPT_RUN_ROOT_TESTS=${1:-false} RUN_ROOT_TESTS=false -[[ ${OPT_RUN_ROOT_TESTS} == "--run-root-tests" ]] && RUN_ROOT_TESTS=true - -OPT_SKIP_AUR_TESTS=${1:-false} SKIP_AUR_TESTS=false -[[ ${OPT_SKIP_AUR_TESTS} == "--skip-aur-tests" ]] && SKIP_AUR_TESTS=true +USE_SUDO=false +while [[ -n "$1" ]] +do + case "$1" in + --run-root-tests) RUN_ROOT_TESTS=true ; shift ;; + --skip-aur-tests) SKIP_AUR_TESTS=true ; shift ;; + --use-sudo) USE_SUDO=true ; shift ;; + *) die "Invalid option $1" ;; + esac +done + +set -u + +SUDO="" +[[ -n $USE_SUDO ]] && SUDO="sudo" JUNEST_HOME=${JUNEST_HOME:-$HOME/.junest} @@ -36,49 +47,42 @@ info "Initial JuNest setup..." trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT KILL TERM INT echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist -pacman --noconfirm -Syy +$SUDO pacman --noconfirm -Syy -pacman-key --init +$SUDO pacman-key --init -pacman --noconfirm -S archlinux-keyring -pacman-key --populate archlinux +$SUDO pacman --noconfirm -S archlinux-keyring +$SUDO pacman-key --populate archlinux -pacman --noconfirm -S archlinuxarm-keyring || echo "No ARM keyring detected" -pacman-key --populate archlinuxarm || echo "No ARM keyring detected" +$SUDO pacman --noconfirm -S archlinuxarm-keyring || echo "No ARM keyring detected" +$SUDO pacman-key --populate archlinuxarm || echo "No ARM keyring detected" -pacman --noconfirm -Su -pacman --noconfirm -S grep coreutils -pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) +$SUDO pacman --noconfirm -Su +$SUDO pacman --noconfirm -S grep coreutils +$SUDO pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) info "Checking basic executables work..." -pacman -Qi pacman 1> /dev/null -/opt/makepkg/bin/makepkg --help 1> /dev/null +$SUDO pacman -Qi pacman 1> /dev/null /opt/proot/proot-$ARCH --help 1> /dev/null repo_package1=tree echo "Checking ${repo_package1} package from official repo..." -pacman --noconfirm -S ${repo_package1} +$SUDO pacman --noconfirm -S ${repo_package1} tree -L 1 -pacman --noconfirm -Rsn ${repo_package1} +$SUDO pacman --noconfirm -Rsn ${repo_package1} repo_package2=iftop info "Checking ${repo_package2} package from official repo..." -pacman --noconfirm -S ${repo_package2} -$RUN_ROOT_TESTS && iftop -t -s 5 -pacman --noconfirm -Rsn ${repo_package2} +$SUDO pacman --noconfirm -S ${repo_package2} +$RUN_ROOT_TESTS && $SUDO iftop -t -s 5 +$SUDO pacman --noconfirm -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS then aur_package=tcptraceroute info "Checking ${aur_package} package from AUR repo..." - maindir=$(mktemp -d -t ${CMD}.XXXXXXXXXX) - builtin cd ${maindir} - curl -L -J -O -k "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${aur_package}" - # -A allows to ignore arch for ARM - /opt/makepkg/bin/makepkg -Asfc --noconfirm - - pacman --noconfirm -U ${aur_package}*.pkg.tar.xz - pacman --noconfirm -Rsn ${aur_package} + yay --noconfirm -S ${aur_package} + $SUDO pacman --noconfirm -Rsn ${aur_package} fi # The following ensures that the gpg agent gets killed (if exists) diff --git a/lib/core/build.sh b/lib/core/build.sh index 898551a..d4215eb 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -8,13 +8,6 @@ # # vim: ft=sh -function _check_package(){ - if ! pacman -Qq $1 > /dev/null - then - die "Package $1 must be installed" - fi -} - function _install_pkg_from_aur(){ local maindir=$1 local pkgname=$2 @@ -35,15 +28,50 @@ function _install_pkg(){ sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.xz } +function _prepare() { + # ArchLinux System initialization + sudo pacman --noconfirm -Syu + sudo pacman -S --noconfirm base-devel + sudo pacman -S --noconfirm git arch-install-scripts +} + +function _install_proot_and_qemu(){ + local maindir="$1" + local main_repo=https://s3-eu-west-1.amazonaws.com/${CMD}-repo + proot_link=${main_repo}/proot + qemu_link=${main_repo}/qemu + + info "Installing proot static binaries" + sudo bash -c " + mkdir -p '${maindir}/root/opt/proot/' + curl '$proot_link/proot-x86_64' > '${maindir}/root/opt/proot/proot-x86_64' + curl '$proot_link/proot-arm' > '${maindir}/root/opt/proot/proot-arm' + chmod -R 755 '${maindir}/root/opt/proot/' + " + + info "Installing qemu static binaries" + sudo bash -c " + mkdir -p '${maindir}/root/opt/qemu/' + if [[ $ARCH == 'arm' ]] + then + curl '${qemu_link}/arm/qemu-arm-static-x86_64' > '${maindir}/root/opt/qemu/qemu-arm-static-x86_64' + elif [[ $ARCH == 'x86_64' ]] + then + curl '${qemu_link}/x86_64/qemu-x86_64-static-arm' > '${maindir}/root/opt/qemu/qemu-x86_64-static-arm' + fi + chmod -R 755 '${maindir}/root/opt/qemu/' + " +} + function build_image_env(){ umask 022 # The function must runs on ArchLinux with non-root privileges. + # This is because installing AUR packages can be done by normal users only. (( EUID == 0 )) && \ die "You cannot build with root privileges." - _check_package arch-install-scripts - _check_package gcc + _prepare local disable_validation=$1 @@ -54,33 +82,41 @@ function build_image_env(){ info "Installing pacman and its dependencies..." # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils - # unshare command belongs to util-linux + # bwrap command belongs to bubblewrap local arm_keyring="" [[ $(uname -m) == *"arm"* ]] && arm_keyring="archlinuxarm-keyring" - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring $arm_keyring util-linux + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring $arm_keyring bubblewrap sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" sudo mkdir -p ${maindir}/root/run/lock # AUR packages requires non-root user to be compiled. proot fakes the user to 10 _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" - info "Install ${NAME} script..." - _install_pkg_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + info "Install yay..." + sudo pacman --noconfirm -S go + _install_pkg_from_aur ${maindir} "yay" + + _install_proot_and_qemu "${maindir}" + + echo "Generating the metadata info" + sudo install -d -m 755 "${maindir}/root/etc/${CMD}" + sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info" info "Generating the locales..." - # sed command is required for locale-gen + # sed command is required for locale-gen but it is required by fakeroot + # and cannot be removed # localedef (called by locale-gen) requires gzip sudo pacman --noconfirm --root ${maindir}/root -S sed gzip sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/opt/junest/bin/groot ${maindir}/root locale-gen + sudo ${JUNEST_BASE}/bin/groot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" - sudo pacman --noconfirm --root ${maindir}/root -Rsn sed gzip + sudo pacman --noconfirm --root ${maindir}/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." # gawk command is required for pacman-key sudo pacman --noconfirm --root ${maindir}/root -S gawk - sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${maindir}/root bash -c ' + sudo ${JUNEST_BASE}/bin/groot -b /dev ${maindir}/root bash -c ' pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; do @@ -105,9 +141,11 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} proot -f ${JUNEST_BASE}/lib/checks/check.sh - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} ns ${JUNEST_BASE}/lib/checks/check.sh - JUNEST_HOME="${maindir}/root_test" sudo -E ${JUNEST_BASE}/bin/${CMD} groot ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} proot --fakeroot ${JUNEST_BASE}/lib/checks/check.sh --skip-aur-tests + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} proot ${JUNEST_BASE}/lib/checks/check.sh --skip-aur-tests --use-sudo + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} ns --fakeroot ${JUNEST_BASE}/lib/checks/check.sh --skip-aur-tests + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} ns ${JUNEST_BASE}/lib/checks/check.sh --use-sudo + JUNEST_HOME="${maindir}/root_test" sudo -E ${JUNEST_BASE}/bin/${CMD} groot ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests --skip-aur-tests fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} diff --git a/lib/core/common.sh b/lib/core/common.sh index 601e46c..219622a 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -81,6 +81,7 @@ CP=cp # Used for checking user namespace in config.gz file ZGREP=zgrep UNSHARE=unshare +BWRAP=bwrap LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -139,7 +140,17 @@ function unshare_cmd(){ then $UNSHARE "$@" else - die "Error: Something went wrong with unshare command. Exiting" + die "Error: Something went wrong while executing unshare command. Exiting" + fi +} + +function bwrap_cmd(){ + # TODO re-evaluate this strategy: + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${SH[0]}" "-c" ":" + then + $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP "${@}" + else + die "Error: Something went wrong while executing bwrap command. Exiting" fi } diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 7943faa..39080e0 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -1,9 +1,8 @@ #!/usr/bin/env bash # -# This module contains all namespace functionalities for JuNest. +# This module contains functionalities for accessing to JuNest via bubblewrap. # -# http://man7.org/linux/man-pages/man7/namespaces.7.html -# http://man7.org/linux/man-pages/man2/unshare.2.html +# https://github.com/containers/bubblewrap # # Dependencies: # - lib/utils/utils.sh @@ -56,46 +55,75 @@ function _check_user_namespace() { set -e } -function _run_env_with_namespace(){ +function _run_env_with_bwrap(){ local backend_args="$1" shift - provide_common_bindings - local bindings=${RESULT} - unset RESULT - - # Use option -n in groot because umount do not work sometimes. - # As soon as the process terminates, the namespace - # will terminate too with its own mounted directories. if [[ "$1" != "" ]] then - JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + JUNEST_ENV=1 bwrap_cmd --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 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" + JUNEST_ENV=1 bwrap_cmd --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. +# 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. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# $ROOT_ACCESS_ERROR : If the user is the real root. +# Output: +# - : The command output. +####################################### +function run_env_as_bwrap_fakeroot(){ + check_nested_env + + local backend_args="$1" + local no_copy_files="$2" + shift 2 + + _check_user_namespace + + check_same_arch + + if ! $no_copy_files + then + copy_common_files + fi + + _run_env_with_bwrap "--uid 0 $backend_args" "$@" } ####################################### -# Run JuNest as fakeroot user via user namespace. +# Run JuNest as normal user via bwrap. # # Globals: # JUNEST_HOME (RO) : The JuNest home directory. -# GROOT (RO) : The groot program. # SH (RO) : Contains the default command to run in JuNest. # Arguments: -# backend_args ($1) : The arguments to pass to groot +# 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. # Returns: # $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Depends on the unshare command outcome. # Output: # - : The command output. ####################################### -function run_env_with_namespace() { +function run_env_as_bwrap_user() { check_nested_env local backend_args="$1" @@ -117,5 +145,9 @@ function run_env_with_namespace() { copy_passwd_and_group fi - _run_env_with_namespace "$backend_args" "$@" + _run_env_with_bwrap "$backend_args" "$@" } + + + + diff --git a/lib/core/proot.sh b/lib/core/proot.sh index 69502eb..abf91df 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -58,7 +58,7 @@ function _run_env_with_qemu(){ # Output: # - : The command output. ####################################### -function run_env_as_fakeroot(){ +function run_env_as_proot_fakeroot(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." check_nested_env @@ -99,7 +99,7 @@ function run_env_as_fakeroot(){ # Output: # - : The command output. ####################################### -function run_env_as_user(){ +function run_env_as_proot_user(){ (( EUID == 0 )) && \ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." check_nested_env diff --git a/pkgs/sudo-fake/PKGBUILD b/pkgs/sudo-fake/PKGBUILD index 99fa18b..3587807 100644 --- a/pkgs/sudo-fake/PKGBUILD +++ b/pkgs/sudo-fake/PKGBUILD @@ -12,7 +12,7 @@ arch=('any') url="" license=('GPL') groups=() -depends=() +depends=('fakeroot' 'fakechroot') makedepends=() provides=('sudo') conflicts=('sudo') @@ -36,7 +36,7 @@ do esac done -[[ -z "\${@}" ]] || "\${@}" +[[ -z "\${@}" ]] || fakechroot fakeroot "\${@}" EOF chmod 755 "${pkgdir}/usr/bin/sudo" diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index 98c6cb2..db7d184 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -37,11 +37,11 @@ function setup_env_from_file(){ function setup_env(){ echo "setup_env($1)" } -function run_env_as_fakeroot(){ +function run_env_as_proot_fakeroot(){ local backend_args="$1" local no_copy_files="$2" shift 2 - echo "run_env_as_fakeroot($backend_args,$no_copy_files,$@)" + echo "run_env_as_proot_fakeroot($backend_args,$no_copy_files,$@)" } function run_env_as_groot(){ local backend_args="$1" @@ -55,17 +55,23 @@ function run_env_as_chroot(){ shift 2 echo "run_env_as_chroot($backend_args,$no_copy_files,$@)" } -function run_env_as_user(){ +function run_env_as_proot_user(){ local backend_args="$1" local no_copy_files="$2" shift 2 - echo "run_env_as_user($backend_args,$no_copy_files,$@)" + echo "run_env_as_proot_user($backend_args,$no_copy_files,$@)" } -function run_env_with_namespace(){ +function run_env_as_bwrap_fakeroot(){ local backend_args="$1" local no_copy_files="$2" shift 2 - echo "run_env_with_namespace($backend_args,$no_copy_files,$@)" + echo "run_env_as_bwrap_fakeroot($backend_args,$no_copy_files,$@)" +} +function run_env_as_bwrap_user(){ + local backend_args="$1" + local no_copy_files="$2" + shift 2 + echo "run_env_as_bwrap_user($backend_args,$no_copy_files,$@)" } function test_help(){ @@ -131,22 +137,22 @@ function test_setup_env(){ assertCommandFail main setup -a arm } -function test_run_env_as_fakeroot(){ +function test_run_env_as_proot_fakeroot(){ assertCommandSuccess main p -f - assertEquals "run_env_as_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot --fakeroot - assertEquals "run_env_as_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main p -f -n - assertEquals "run_env_as_fakeroot(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,true,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -b "-b arg" - assertEquals "run_env_as_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -b "-b arg" -- command -kv - assertEquals "run_env_as_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f command --as - assertEquals "run_env_as_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -- command --as - assertEquals "run_env_as_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -156,18 +162,18 @@ function test_run_env_as_fakeroot(){ function test_run_env_as_user(){ assertCommandSuccess main proot - assertEquals "run_env_as_user(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main p -n - assertEquals "run_env_as_user(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,true,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -b "-b arg" - assertEquals "run_env_as_user(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -b "-b arg" -- command -ll - assertEquals "run_env_as_user(-b arg,false,command -ll)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(-b arg,false,command -ll)" "$(cat $STDOUTF)" assertCommandSuccess main proot command -ls - assertEquals "run_env_as_user(,false,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,false,command -ls)" "$(cat $STDOUTF)" assertCommandSuccess main proot -- command -ls - assertEquals "run_env_as_user(,false,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,false,command -ls)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -209,36 +215,73 @@ function test_run_env_as_chroot(){ assertCommandFail main root -f } -function test_run_env_with_namespace(){ +function test_run_env_as_bwrap_fakeroot(){ + assertCommandSuccess main n -f + assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -f + assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -n -f + assertEquals "run_env_as_bwrap_fakeroot(,true,)" "$(cat $STDOUTF)" + + assertCommandSuccess main ns -f -b "-b arg" + assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -f -b "-b arg" -- command -kv + assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -f command --as + assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertCommandSuccess main ns -f -- command --as + assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + + assertCommandSuccess main -f + assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main -f + assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + + assertCommandSuccess main -f -b "-b arg" + assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main -f -b "-b arg" -- command -kv + assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess main -f command --as + assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertCommandSuccess main -f -- command --as + assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + + is_env_installed(){ + return 1 + } + assertCommandFail main ns -f +} + +function test_run_env_as_bwrap_user(){ assertCommandSuccess main n - assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns - assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -n - assertEquals "run_env_with_namespace(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,true,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -b "-b arg" - assertEquals "run_env_with_namespace(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -b "-b arg" -- command -kv - assertEquals "run_env_with_namespace(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main ns command --as - assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main ns -- command --as - assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main - assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main - assertEquals "run_env_with_namespace(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -b "-b arg" - assertEquals "run_env_with_namespace(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -b "-b arg" -- command -kv - assertEquals "run_env_with_namespace(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main command --as - assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main -- command --as - assertEquals "run_env_with_namespace(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 4ecc794..03eb1cd 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -15,8 +15,8 @@ function oneTimeSetUp(){ ## Mock functions ## function init_mocks() { - function unshare_cmd(){ - echo "unshare $@" + function bwrap_cmd(){ + echo "bwrap $@" } } @@ -99,17 +99,24 @@ function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ assertCommandSuccess _is_user_namespace_enabled } -function test_run_env_with_namespace() { - assertCommandSuccess run_env_with_namespace "" "false" "" - assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" +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 /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_bwrap_user() { + assertCommandSuccess run_env_as_bwrap_user "" "false" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_with_namespace_no_copy() { - assertCommandSuccess run_env_with_namespace "" "true" "" - assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" +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 /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -133,33 +140,86 @@ function test_run_env_with_namespace_no_copy() { assertEquals 0 $? } -function test_run_env_with_namespace_with_bindings() { - assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "false" "" - assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)" +function test_run_env_as_bwrap_user_no_copy() { + assertCommandSuccess run_env_as_bwrap_user "" "true" "" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" + + [[ ! -e ${JUNEST_HOME}/etc/hosts ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] + assertEquals 0 $? + + [[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/netgroup ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/networks ]] + assertEquals 0 $? + + [[ ! -e ${JUNEST_HOME}/etc/passwd ]] + assertEquals 0 $? + [[ ! -e ${JUNEST_HOME}/etc/group ]] + assertEquals 0 $? +} + +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 --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_bwrap_user_with_backend_args() { + assertCommandSuccess run_env_as_bwrap_user "--bind /usr /usr" "false" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_with_namespace_with_command() { - assertCommandSuccess run_env_with_namespace "" "false" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" +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 /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_bwrap_user_with_command() { + assertCommandSuccess run_env_as_bwrap_user "" "false" "ls -la" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_with_namespace_with_bindings_and_command() { - assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "false" "ls -la" - assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" +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 --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + + _test_copy_common_files +} + +function test_run_env_as_bwrap_user_with_backend_args_and_command() { + assertCommandSuccess run_env_as_bwrap_user "--bind /usr /usr" "false" "ls -la" + assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_with_namespace_nested_env(){ +function test_run_env_as_bwrap_fakeroot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_with_namespace "" "false" "" + assertCommandFailOnStatus 106 run_env_as_bwrap_fakeroot "" "false" "" + unset JUNEST_ENV +} + +function test_run_env_as_bwrap_user_nested_env(){ + JUNEST_ENV=1 + assertCommandFailOnStatus 106 run_env_as_bwrap_user "" "false" "" unset JUNEST_ENV } diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index a951cd6..4463df7 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -47,26 +47,26 @@ function _test_copy_remaining_files() { assertEquals 0 $? } -function test_run_env_as_user(){ +function test_run_env_as_proot_user(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_user "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_proot_user "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_user "-k 3.10" "false" + assertCommandSuccess run_env_as_proot_user "-k 3.10" "false" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } -function test_run_env_as_user_no_copy(){ +function test_run_env_as_proot_user_no_copy(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_user "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_proot_user "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] @@ -91,29 +91,29 @@ function test_run_env_as_user_no_copy(){ assertEquals 0 $? } -function test_run_env_as_user_nested_env(){ +function test_run_env_as_proot_user_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_user "" "false" + assertCommandFailOnStatus 106 run_env_as_proot_user "" "false" unset JUNEST_ENV } -function test_run_env_as_fakeroot(){ +function test_run_env_as_proot_fakeroot(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_proot_fakeroot "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_fakeroot "-k 3.10" "false" + assertCommandSuccess run_env_as_proot_fakeroot "-k 3.10" "false" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" _test_copy_common_files } -function test_run_env_as_fakeroot_nested_env(){ +function test_run_env_as_proot_fakeroot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_fakeroot "" "false" "" + assertCommandFailOnStatus 106 run_env_as_proot_fakeroot "" "false" "" unset JUNEST_ENV } @@ -121,7 +121,7 @@ function test_run_env_with_quotes(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_user "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + assertCommandSuccess run_env_as_proot_user "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" } From 121f2c74f60a0e78e3164631dd1a4cbe3a2d63c8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Mar 2020 17:10:49 +0100 Subject: [PATCH 217/326] Improve build for ARM arch --- lib/checks/check.sh | 16 ++++++++++------ lib/core/build.sh | 7 +------ lib/core/common.sh | 1 - lib/core/setup.sh | 3 --- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 5214595..e7f924a 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -46,16 +46,20 @@ info "Initial JuNest setup..." # otherwise it is not possible to exit from the session trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT KILL TERM INT -echo "Server = ${DEFAULT_MIRROR}" >> /etc/pacman.d/mirrorlist $SUDO pacman --noconfirm -Syy +# Awk is required for pacman-key +$SUDO pacman --noconfirm -S gawk $SUDO pacman-key --init -$SUDO pacman --noconfirm -S archlinux-keyring -$SUDO pacman-key --populate archlinux - -$SUDO pacman --noconfirm -S archlinuxarm-keyring || echo "No ARM keyring detected" -$SUDO pacman-key --populate archlinuxarm || echo "No ARM keyring detected" +if [[ $(uname -m) == *"arm"* ]] +then + $SUDO pacman --noconfirm -S archlinuxarm-keyring + $SUDO pacman-key --populate archlinuxarm +else + $SUDO pacman --noconfirm -S archlinux-keyring + $SUDO pacman-key --populate archlinux +fi $SUDO pacman --noconfirm -Su $SUDO pacman --noconfirm -S grep coreutils diff --git a/lib/core/build.sh b/lib/core/build.sh index d4215eb..4cad766 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -80,16 +80,11 @@ function build_image_env(){ trap - QUIT EXIT ABRT KILL TERM INT trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT info "Installing pacman and its dependencies..." - # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils # bwrap command belongs to bubblewrap - local arm_keyring="" - [[ $(uname -m) == *"arm"* ]] && arm_keyring="archlinuxarm-keyring" - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring $arm_keyring bubblewrap - sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils bubblewrap sudo mkdir -p ${maindir}/root/run/lock - # AUR packages requires non-root user to be compiled. proot fakes the user to 10 _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" info "Install yay..." diff --git a/lib/core/common.sh b/lib/core/common.sh index 219622a..4622232 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -52,7 +52,6 @@ fi MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} -DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 2cbfdf1..d061281 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -52,7 +52,6 @@ function _setup_env(){ mkdir_cmd -p "${JUNEST_HOME}" $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} - info "The default mirror URL is ${DEFAULT_MIRROR}." info "Remember to refresh the package databases from the server:" info " pacman -Syy" info "${NAME} installed successfully" @@ -70,7 +69,6 @@ function _setup_env(){ # the JuNest system from the image. # ENV_REPO (RO) : URL of the site containing JuNest images. # NAME (RO) : The JuNest name. -# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. # Arguments: # arch ($1?) : The JuNest architecture image to download. # Defaults to the host architecture @@ -105,7 +103,6 @@ function setup_env(){ # JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs # to be installed. # NAME (RO) : The JuNest name. -# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. # Arguments: # imagefile ($1) : The JuNest image file. # Returns: From 6e55e0c6487a9f435d9926f45fb946993c89b53b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Mar 2020 23:26:25 +0100 Subject: [PATCH 218/326] See mirror URL only for non arm arch --- lib/core/build.sh | 8 +++++++- lib/core/common.sh | 1 + lib/core/setup.sh | 4 +++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index 4cad766..3260795 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -83,11 +83,17 @@ function build_image_env(){ # All the essential executables (ln, mkdir, chown, etc) are in coreutils # bwrap command belongs to bubblewrap sudo pacstrap -G -M -d ${maindir}/root pacman coreutils bubblewrap + + if [[ $(uname -m) != *"arm"* ]] + then + # x86_64 does not have any mirror set by default... + sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" + fi sudo mkdir -p ${maindir}/root/run/lock _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" - info "Install yay..." + info "Installing yay..." sudo pacman --noconfirm -S go _install_pkg_from_aur ${maindir} "yay" diff --git a/lib/core/common.sh b/lib/core/common.sh index 4622232..219622a 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -52,6 +52,7 @@ fi MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} +DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) diff --git a/lib/core/setup.sh b/lib/core/setup.sh index d061281..532f2a2 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -52,9 +52,11 @@ function _setup_env(){ mkdir_cmd -p "${JUNEST_HOME}" $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} + info "${NAME} installed successfully!" + echo + info "Please change the pacman mirror URL in /etc/pacman.d/mirrorlist according to your location." info "Remember to refresh the package databases from the server:" info " pacman -Syy" - info "${NAME} installed successfully" } From 385dd8c68c7f6e05194606f007dec2e75c16800c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Mar 2020 23:49:45 +0100 Subject: [PATCH 219/326] Add script to check all tests --- .travis.yml | 13 +++++-------- lib/checks/check.sh | 26 ++++++++++++++------------ lib/checks/check_all.sh | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 20 deletions(-) create mode 100755 lib/checks/check_all.sh diff --git a/.travis.yml b/.travis.yml index b3a3bea..a0feac4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,13 +20,10 @@ script: - bash ./tests/checkstyle/checkstyle.sh - bash ./tests/unit-tests/unit-tests.sh - # Multiple tests against different execution modes: - - junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - - junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo - - junest ns --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - - junest ns -- ${PWD}/lib/checks/check.sh --use-sudo - - sudo -E ${PWD}/bin/junest groot -- ${PWD}/lib/checks/check.sh --run-root-tests --skip-aur-tests + - export JUNEST_HOME=~/.junest + - ${PWD}/lib/checks/check_all.sh - yes | junest setup --delete - - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - - yes | JUNEST_HOME=~/.junest-arm junest setup --delete + - export JUNEST_HOME=~/.junest-arm + - ${PWD}/lib/checks/check_all.sh + - yes | junest setup --delete diff --git a/lib/checks/check.sh b/lib/checks/check.sh index e7f924a..e8bfc95 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -46,24 +46,26 @@ info "Initial JuNest setup..." # otherwise it is not possible to exit from the session trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT KILL TERM INT -$SUDO pacman --noconfirm -Syy +PACMAN_OPTIONS="--noconfirm --disable-download-timeout" + +$SUDO pacman $PACMAN_OPTIONS -Syy # Awk is required for pacman-key -$SUDO pacman --noconfirm -S gawk +$SUDO pacman $PACMAN_OPTIONS -S gawk $SUDO pacman-key --init if [[ $(uname -m) == *"arm"* ]] then - $SUDO pacman --noconfirm -S archlinuxarm-keyring + $SUDO pacman $PACMAN_OPTIONS -S archlinuxarm-keyring $SUDO pacman-key --populate archlinuxarm else - $SUDO pacman --noconfirm -S archlinux-keyring + $SUDO pacman $PACMAN_OPTIONS -S archlinux-keyring $SUDO pacman-key --populate archlinux fi -$SUDO pacman --noconfirm -Su -$SUDO pacman --noconfirm -S grep coreutils -$SUDO pacman --noconfirm -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) +$SUDO pacman $PACMAN_OPTIONS -Su +$SUDO pacman $PACMAN_OPTIONS -S grep coreutils +$SUDO pacman $PACMAN_OPTIONS -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) info "Checking basic executables work..." $SUDO pacman -Qi pacman 1> /dev/null @@ -71,22 +73,22 @@ $SUDO pacman -Qi pacman 1> /dev/null repo_package1=tree echo "Checking ${repo_package1} package from official repo..." -$SUDO pacman --noconfirm -S ${repo_package1} +$SUDO pacman $PACMAN_OPTIONS -S ${repo_package1} tree -L 1 -$SUDO pacman --noconfirm -Rsn ${repo_package1} +$SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package1} repo_package2=iftop info "Checking ${repo_package2} package from official repo..." -$SUDO pacman --noconfirm -S ${repo_package2} +$SUDO pacman $PACMAN_OPTIONS -S ${repo_package2} $RUN_ROOT_TESTS && $SUDO iftop -t -s 5 -$SUDO pacman --noconfirm -Rsn ${repo_package2} +$SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS then aur_package=tcptraceroute info "Checking ${aur_package} package from AUR repo..." yay --noconfirm -S ${aur_package} - $SUDO pacman --noconfirm -Rsn ${aur_package} + $SUDO pacman $PACMAN_OPTIONS -Rsn ${aur_package} fi # The following ensures that the gpg agent gets killed (if exists) diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh new file mode 100755 index 0000000..6e28ee5 --- /dev/null +++ b/lib/checks/check_all.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Multiple tests against different execution modes + +set -ex + +# JUNEST_BASE can be overridden for testing purposes. +# There is no need for doing it for normal usage. +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}" + +JUNEST_SCRIPT=${JUNEST_SCRIPT:-${JUNEST_BASE}/bin/junest} +CHECK_SCRIPT=${JUNEST_BASE}/lib/checks/check.sh + +$JUNEST_SCRIPT proot --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests +$JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo +$JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests +$JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo +sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests From 4b5b7b300b4d40a76a09df3f1c83236326313d57 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 16 Mar 2020 18:59:01 +0100 Subject: [PATCH 220/326] Add test for bwrap command --- lib/core/build.sh | 6 +----- lib/core/common.sh | 3 +-- tests/unit-tests/test-common.sh | 12 ++++++++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index 3260795..bd07c5b 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -142,11 +142,7 @@ function build_image_env(){ then mkdir -p ${maindir}/root_test $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} proot --fakeroot ${JUNEST_BASE}/lib/checks/check.sh --skip-aur-tests - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} proot ${JUNEST_BASE}/lib/checks/check.sh --skip-aur-tests --use-sudo - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} ns --fakeroot ${JUNEST_BASE}/lib/checks/check.sh --skip-aur-tests - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/bin/${CMD} ns ${JUNEST_BASE}/lib/checks/check.sh --use-sudo - JUNEST_HOME="${maindir}/root_test" sudo -E ${JUNEST_BASE}/bin/${CMD} groot ${JUNEST_BASE}/lib/checks/check.sh --run-root-tests --skip-aur-tests + JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/lib/checks/check_all.sh fi sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} diff --git a/lib/core/common.sh b/lib/core/common.sh index 219622a..fe43dde 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -145,8 +145,7 @@ function unshare_cmd(){ } function bwrap_cmd(){ - # TODO re-evaluate this strategy: - if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${SH[0]}" "-c" ":" + if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${SH[0]}" "-c" ":" then $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP "${@}" else diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index dfff6f4..dd77077 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -34,6 +34,11 @@ function setUp(){ } UNSHARE=unshare_mock + bwrap_mock() { + echo "bwrap $@" + } + BWRAP=bwrap_mock + } function test_ln(){ @@ -136,6 +141,13 @@ function test_unshare(){ UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program } +function test_bwrap(){ + assertCommandSuccess bwrap_cmd new_program + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$BWRAP new_program")" "$(cat $STDOUTF)" + + BWRAP=false LD_EXEC=false assertCommandFail bwrap_cmd new_program +} + function test_chroot(){ CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root assertEquals "root" "$(cat $STDOUTF)" From 628ac3c65516c70117b5bc6916dbc54aadd1177b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 16 Mar 2020 20:12:27 +0100 Subject: [PATCH 221/326] 7.1.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a50da18..a3fcc71 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.0.3 +7.1.0 From 1580ba9c8e86eff8c955da8fe499f1ad07c8a7b5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 16 Mar 2020 20:52:01 +0100 Subject: [PATCH 222/326] Fix travis for ARM tests --- .travis.yml | 3 ++- VERSION | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a0feac4..025ddc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,5 +25,6 @@ script: - yes | junest setup --delete - export JUNEST_HOME=~/.junest-arm - - ${PWD}/lib/checks/check_all.sh + - junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests + - junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo - yes | junest setup --delete diff --git a/VERSION b/VERSION index a3fcc71..21c8c7b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.1.0 +7.1.1 From 6592bc9bd22a6b389e1705e0732f5ca3469d7927 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 22 Mar 2020 17:33:59 +0100 Subject: [PATCH 223/326] Separate proot, qemu, groot into packages --- bin/junest | 4 +-- lib/checks/check.sh | 3 +- lib/core/build.sh | 41 ++++++------------------ lib/core/common.sh | 13 ++++---- lib/core/proot.sh | 2 +- pkgs/groot-git/PKGBUILD | 58 ++++++++++++++++++++++++++++++++++ pkgs/proot-static/PKGBUILD | 43 +++++++++++++++++++++++++ pkgs/qemu-static/PKGBUILD | 50 +++++++++++++++++++++++++++++ tests/unit-tests/test-proot.sh | 2 +- 9 files changed, 173 insertions(+), 43 deletions(-) create mode 100644 pkgs/groot-git/PKGBUILD create mode 100644 pkgs/proot-static/PKGBUILD create mode 100644 pkgs/qemu-static/PKGBUILD diff --git a/bin/junest b/bin/junest index 442b31e..3b7eb87 100755 --- a/bin/junest +++ b/bin/junest @@ -39,8 +39,8 @@ usage() { echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}" echo echo -e " n[s] Access via Linux Namespaces using BubbleWrap (Default action)" - echo -e " -b, --backend-args Arguments for GRoot backend program" - echo -e " ($CMD groot -b \"--help\" to check out the bwrap options)" + echo -e " -b, --backend-args Arguments for bwrap backend program" + echo -e " ($CMD ns -b \"--help\" to check out the bwrap options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " p[root] Access via PRoot" diff --git a/lib/checks/check.sh b/lib/checks/check.sh index e8bfc95..634044c 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -69,7 +69,8 @@ $SUDO pacman $PACMAN_OPTIONS -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep info "Checking basic executables work..." $SUDO pacman -Qi pacman 1> /dev/null -/opt/proot/proot-$ARCH --help 1> /dev/null +/usr/bin/proot --help 1> /dev/null +/usr/bin/groot --help 1> /dev/null repo_package1=tree echo "Checking ${repo_package1} package from official repo..." diff --git a/lib/core/build.sh b/lib/core/build.sh index bd07c5b..a25cef6 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -23,8 +23,12 @@ function _install_pkg_from_aur(){ function _install_pkg(){ local maindir=$1 local pkgbuilddir=$2 - builtin cd ${pkgbuilddir} + # Generate a working directory because sources will be downloaded to there + working_dir=$(TMPDIR=/tmp mktemp -d -t junest-wd.XXXXXXXXXX) + cp -R "$pkgbuilddir"/* "$working_dir" + builtin cd ${working_dir} makepkg -sfcd + makepkg --printsrcinfo > ${pkgbuilddir}/.SRCINFO sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.xz } @@ -35,34 +39,6 @@ function _prepare() { sudo pacman -S --noconfirm git arch-install-scripts } -function _install_proot_and_qemu(){ - local maindir="$1" - local main_repo=https://s3-eu-west-1.amazonaws.com/${CMD}-repo - proot_link=${main_repo}/proot - qemu_link=${main_repo}/qemu - - info "Installing proot static binaries" - sudo bash -c " - mkdir -p '${maindir}/root/opt/proot/' - curl '$proot_link/proot-x86_64' > '${maindir}/root/opt/proot/proot-x86_64' - curl '$proot_link/proot-arm' > '${maindir}/root/opt/proot/proot-arm' - chmod -R 755 '${maindir}/root/opt/proot/' - " - - info "Installing qemu static binaries" - sudo bash -c " - mkdir -p '${maindir}/root/opt/qemu/' - if [[ $ARCH == 'arm' ]] - then - curl '${qemu_link}/arm/qemu-arm-static-x86_64' > '${maindir}/root/opt/qemu/qemu-arm-static-x86_64' - elif [[ $ARCH == 'x86_64' ]] - then - curl '${qemu_link}/x86_64/qemu-x86_64-static-arm' > '${maindir}/root/opt/qemu/qemu-x86_64-static-arm' - fi - chmod -R 755 '${maindir}/root/opt/qemu/' - " -} - function build_image_env(){ umask 022 @@ -84,7 +60,7 @@ function build_image_env(){ # bwrap command belongs to bubblewrap sudo pacstrap -G -M -d ${maindir}/root pacman coreutils bubblewrap - if [[ $(uname -m) != *"arm"* ]] + if [[ ${ARCH} != "arm" ]] then # x86_64 does not have any mirror set by default... sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" @@ -92,13 +68,14 @@ function build_image_env(){ sudo mkdir -p ${maindir}/root/run/lock _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" + _install_pkg ${maindir} "$JUNEST_BASE/pkgs/proot-static" + _install_pkg ${maindir} "$JUNEST_BASE/pkgs/qemu-static" + _install_pkg ${maindir} "$JUNEST_BASE/pkgs/groot-git" info "Installing yay..." sudo pacman --noconfirm -S go _install_pkg_from_aur ${maindir} "yay" - _install_proot_and_qemu "${maindir}" - echo "Generating the metadata info" sudo install -d -m 755 "${maindir}/root/etc/${CMD}" sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info" diff --git a/lib/core/common.sh b/lib/core/common.sh index fe43dde..eb728e9 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -21,7 +21,6 @@ NO_CONFIG_FOUND=108 UNPRIVILEGED_USERNS_DISABLED=109 JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}} -JUNEST_BASE=${JUNEST_BASE:-${JUNEST_HOME}/opt/junest} JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} # The update of the variable PATH ensures that the executables are @@ -34,15 +33,17 @@ UNAME=uname ARCH_LIST=('x86_64' 'x86' 'arm') HOST_ARCH=$($UNAME -m) -if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] +# To check all available architectures look here: +# https://wiki.archlinux.org/index.php/PKGBUILD#arch +if [[ $HOST_ARCH == "i686" ]] || [[ $HOST_ARCH == "i386" ]] then ARCH="x86" LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2" -elif [ $HOST_ARCH == "x86_64" ] +elif [[ $HOST_ARCH == "x86_64" ]] then ARCH="x86_64" LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2" -elif [[ $HOST_ARCH =~ .*(arm).* ]] +elif [[ $HOST_ARCH =~ .*(arm).* ]] || [[ $HOST_ARCH == "aarch64" ]] then ARCH="arm" LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3" @@ -66,8 +67,8 @@ ORIGIN_WD=$(pwd) SH=("/bin/sh" "--login") # List of executables that are run in the host OS: -PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" -GROOT=${JUNEST_BASE}/bin/groot +PROOT="${JUNEST_HOME}/usr/bin/proot" +GROOT="${JUNEST_HOME}/usr/bin/groot" CLASSIC_CHROOT=chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" diff --git a/lib/core/proot.sh b/lib/core/proot.sh index abf91df..d2bfd5f 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -33,7 +33,7 @@ function _run_env_with_qemu(){ warn "Emulating $NAME via QEMU..." [ -e ${qemu_symlink} ] || \ - ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink} + ln_cmd -s ${JUNEST_HOME}/bin/${qemu_bin} ${qemu_symlink} proot_args="-q ${qemu_symlink} $proot_args" fi shift diff --git a/pkgs/groot-git/PKGBUILD b/pkgs/groot-git/PKGBUILD new file mode 100644 index 0000000..015f9a2 --- /dev/null +++ b/pkgs/groot-git/PKGBUILD @@ -0,0 +1,58 @@ +# Maintainer: Filippo Squillace +# More details on how to change this file: +# https://wiki.archlinux.org/index.php/PKGBUILD +# https://wiki.archlinux.org/index.php/Creating_packages +# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages + +pkgname=groot-git +pkgver=1.0.1 +pkgrel=1 +pkgdesc="" +arch=('any') +url="https://github.com/fsquillace/groot" +license=('GPL') +groups=() +depends=('coreutils') +makedepends=() +provides=('groot') +conflicts=() +replaces=() +backup=() +options=() +#install= +noextract=() + + +source=('groot::git+https://github.com/fsquillace/groot.git#branch=master') +md5sums=('SKIP') + + +pkgver() { + cd "$srcdir/${pkgname%-git}" + +# The examples below are not absolute and need to be adapted to each repo. The +# primary goal is to generate version numbers that will increase according to +# pacman's version comparisons with later commits to the repo. The format +# VERSION='VER_NUM.rREV_NUM.HASH', or a relevant subset in case VER_NUM or HASH +# are not available, is recommended. + +# Git, tags available + printf "%s" "$(git describe --tags | sed 's/\([^-]*-\)g/r\1/;s/-/./g')" + +# Git, no tags available +# printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" + +} + +build() { + : +} + +package() { + cd "$srcdir/${pkgname%-git}" + + install -d -m 755 "${pkgdir}/usr/bin" + install -m 755 "${srcdir}/${pkgname%-git}/bin/groot" ${pkgdir}/usr/bin/groot +} + +# vim:set ts=2 sw=2 et: diff --git a/pkgs/proot-static/PKGBUILD b/pkgs/proot-static/PKGBUILD new file mode 100644 index 0000000..fad9291 --- /dev/null +++ b/pkgs/proot-static/PKGBUILD @@ -0,0 +1,43 @@ +# Maintainer: Filippo Squillace +# More details on how to change this file: +# https://wiki.archlinux.org/index.php/PKGBUILD +# https://wiki.archlinux.org/index.php/Creating_packages +# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages + +pkgname=proot-static +_pkgname=proot +pkgver=5.1.0 +pkgrel=1 +pkgdesc="chroot, mount --bind, and binfmt_misc without privilege/setup. Static binary only" +arch=('any') +url="https://proot-me.github.io/" +license=('GPL') +groups=() +depends=() +makedepends=() +provides=('proot') +conflicts=('proot' 'proot-bin') +backup=() +options=() +#install= +source=() +md5sums=() +noextract=() + +MAIN_REPO=https://s3-eu-west-1.amazonaws.com/junest-repo +PROOT_LINK=${MAIN_REPO}/proot + +source_x86_64=("${_pkgname}"::"$PROOT_LINK/proot-x86_64") +source_i686=("${_pkgname}"::"$PROOT_LINK/proot-x86") +source_arm=("${_pkgname}"::"$PROOT_LINK/proot-arm") +md5sums_x86_64=('14080705dd45a6bafa20e909a68072cb') +md5sums_i686=('b1c08236b56d121e04e9e29b197d0eeb') +md5sums_arm=('8218c5f00e77e2e6e04c372ced27c7e7') + +package() { + echo "Installing proot static binaries" + install -d -m 755 "${pkgdir}/usr/bin/" + install -m 755 "${srcdir}/${_pkgname}" ${pkgdir}/usr/bin/proot +} + +# vim:set ts=2 sw=2 et: diff --git a/pkgs/qemu-static/PKGBUILD b/pkgs/qemu-static/PKGBUILD new file mode 100644 index 0000000..3b7fc65 --- /dev/null +++ b/pkgs/qemu-static/PKGBUILD @@ -0,0 +1,50 @@ +# Maintainer: Filippo Squillace +# More details on how to change this file: +# https://wiki.archlinux.org/index.php/PKGBUILD +# https://wiki.archlinux.org/index.php/Creating_packages +# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages + +pkgname=qemu-static +pkgver=2.3.0 +pkgrel=1 +pkgdesc="Statically linked binaries of Qemu with user emulation. Useful for containers/chroot environment with binfmt." +arch=('any') +url="http://wiki.qemu.org" +license=('GPL2') +groups=() +depends=() +makedepends=() +provides=() +conflicts=() +backup=() +options=() +#install= +source=() +md5sums=() +noextract=() + +MAIN_REPO=https://s3-eu-west-1.amazonaws.com/junest-repo +QEMU_LINK=$MAIN_REPO/qemu + +source_x86_64=("${QEMU_LINK}/x86_64/qemu-x86_64-static-x86" "${QEMU_LINK}/x86_64/qemu-x86_64-static-arm") +source_i686=("${QEMU_LINK}/x86/qemu-x86-static-x86_64" "${QEMU_LINK}/x86/qemu-x86_64-static-arm") +md5sums_x86_64=('8a706d734f8c790743a8114dda4c344a' '3ced729c95d2514f35d4899e944a4582') +md5sums_x86=('c28d5049193dbce75efa0c8655d71427' 'f75fd15722fcc2914e3de0b0a46eb982') + +source_arm=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") +md5sums_arm=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') +source_armv6h=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") +md5sums_armv6h=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') +source_armv7h=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") +md5sums_armv7h=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') +source_aarch64=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") +md5sums_aarch64=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') + + +package() { + echo "Installing qemu static binaries" + install -d -m 755 "${pkgdir}/usr/bin" + install -m 755 "${srcdir}"/qemu-* ${pkgdir}/usr/bin +} + +# vim:set ts=2 sw=2 et: diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index 4463df7..8fa636f 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -153,7 +153,7 @@ function test_qemu() { } RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" - assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "-s $JUNEST_HOME/bin/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" } source $JUNEST_ROOT/tests/utils/shunit2 From 348b73ce732215a5c6f7e44a4540fdb8beeb48d7 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 24 Mar 2020 21:18:25 +0100 Subject: [PATCH 224/326] Remove groot content --- bin/groot | 242 -------------------------------- tests/unit-tests/test-groot.sh | 248 --------------------------------- 2 files changed, 490 deletions(-) delete mode 100755 bin/groot delete mode 100755 tests/unit-tests/test-groot.sh diff --git a/bin/groot b/bin/groot deleted file mode 100755 index cb4952f..0000000 --- a/bin/groot +++ /dev/null @@ -1,242 +0,0 @@ -#!/bin/bash -# -# This script is the simplified and portable version of arch-chroot -# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) -# - -set -e - -# JUNEST_BASE can be overridden for testing purposes. -# There is no need for doing it for normal usage. -JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}" -NAME='GRoot' -CMD='groot' -DESCRIPTION="I am $NAME!" -CHROOTCMD=${CHROOTCMD:-chroot} -SHELL="/bin/sh" -MOUNT=mount -UMOUNT=umount -MKDIR=mkdir -TOUCH=touch -CUT=cut -SORT=sort -UNIQ=uniq -CAT=cat -READLINK=readlink -MOUNTS_FILE=/proc/self/mounts - -NOT_EXISTING_FILE=103 -NOT_ABSOLUTE_PATH=111 -NO_ROOT_PRIVILEGES=110 - -source "${JUNEST_BASE}/lib/utils/utils.sh" - - -################################ MAIN FUNCTIONS ########################### - -function is_mountpoint() { - local mountpoint="$1" - for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) - do - [[ $mp == $mountpoint ]] && return 0 - done - return 1 -} - -function chroot_teardown() { - # Remove all mounts starting from the most nested ones. - # Suffix the CHROOTDIR with / to avoid umounting directories not belonging - # to CHROOTDIR. - local normalized_chrootdir="$($READLINK -f ${CHROOTDIR})/" - local final_res=0 - for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ) - do - if [[ $mp =~ ^${normalized_chrootdir}.* ]] && is_mountpoint "$mp" - then - $UMOUNT $mp || final_res=$? - fi - done - $UMOUNT ${CHROOTDIR%/} - - return $final_res -} - -function chroot_maybe_add_mount() { - local cond=$1 - shift - if eval "$cond"; then - $MOUNT "$@" - return - fi - return 1 -} - -function chroot_setup() { - $OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT - - if ! chroot_maybe_add_mount "! is_mountpoint '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR" - then - warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..." - return 0 - fi - - local re='(.*):(.*)' - for binds in ${BINDINGS[@]} - do - local host_path="" - local guest_path="" - if [[ $binds =~ $re ]] - then - local host_path="${BASH_REMATCH[1]}" - local guest_path="${BASH_REMATCH[2]}" - else - local host_path="$binds" - local guest_path="$binds" - fi - - create_node "${host_path}" "${CHROOTDIR}${guest_path}" - mount_directory "${host_path}" "${guest_path}" - done -} - -function mount_directory() { - local host_path=$($READLINK -f "$1") - local guest_path="$2" - - if ! $OPT_AVOID_BIND - then - $MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}" - return 0 - fi - - case "$host_path" in - /proc) $MOUNT proc "${CHROOTDIR}${guest_path}" -t proc ;; - /sys) $MOUNT sys "${CHROOTDIR}${guest_path}" -t sysfs ;; - /dev) $MOUNT udev "${CHROOTDIR}${guest_path}" -t devtmpfs; $MOUNT devpts "${guest_path}/pts" -t devpts; $MOUNT shm "${guest_path}/shm" -t tmpfs ;; - /run) $MOUNT run "${CHROOTDIR}${guest_path}" -t tmpfs ;; - /tmp) $MOUNT tmp "${CHROOTDIR}${guest_path}" -t tmpfs ;; - *) $MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}" ;; - esac - - return 0 -} - -function create_node() { - local src="$1" - local dst="$2" - if [[ ! -e $src ]] - then - die_on_status $NOT_EXISTING_FILE "${src} does not exist." - elif [[ $src != /* ]] - then - die_on_status $NOT_ABSOLUTE_PATH "${src} is not an absolute path." - elif [[ -f $src ]] - then - $TOUCH "$dst" - elif [[ -d $src ]] - then - $MKDIR -p "$dst" - fi -} - -function usage() { - cat < [command]] - -Options: - -b, --bind - Make the content of accessible in the guest rootfs. - - This option makes any file or directory of the host rootfs - accessible in the confined environment just as if it were part of - the guest rootfs. By default the host path is bound to the same - path in the guest rootfs but users can specify any other location - with the syntax: -b :. This option can - be invoked multiple times and the paths specified must be absolutes. - - -n, --no-umount - Do not umount after chroot session finished. - - -r, --recursive - Use rbind instead of bind. - - -i, --avoid-bind - Attempt to avoid mount --bind for common directories and use - proper mount fstype instead. Detected directories with - corresponding fstype are: /proc (proc), /sys (sysfs), - /dev (devtmpfs), /tmp (tmpfs), /run (tmpfs). - - -h, --help Print this help message - - -V, --version Show the $NAME version - -If 'command' is unspecified, $CMD will launch $SHELL. - -EOF -} - -version() { - echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" -} - -function parse_arguments() { - BINDINGS=() - OPT_NO_UMOUNT=false - OPT_RECURSIVE=false - OPT_BIND="--bind" - OPT_AVOID_BIND=false - OPT_HELP=false - OPT_VERSION=false - for opt in "$@" - do - case "$1" in - -b|--bind) shift ; BINDINGS+=("$1") ; shift ;; - -n|--no-umount) OPT_NO_UMOUNT=true ; shift ;; - -r|--recursive) OPT_BIND="--rbind" ; shift ;; - -i|--avoid-bind) OPT_AVOID_BIND=true ; shift ;; - -h|--help) OPT_HELP=true ; shift ;; - -V|--version) OPT_VERSION=true ; shift ;; - -*) die "Invalid option $1" ;; - *) break ;; - esac - done - - if [[ ! -z $1 ]] - then - CHROOTDIR="$1" - shift - fi - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done -} - -function is_user_root() { - (( EUID == 0 )) -} - -function execute_operation() { - $OPT_HELP && usage && return - $OPT_VERSION && version && return - - is_user_root || die_on_status $NO_ROOT_PRIVILEGES 'This script must be run with root privileges' - - [[ -d $CHROOTDIR ]] || die_on_status $NOT_EXISTING_FILE "Can't create chroot on non-directory $CHROOTDIR" - - chroot_setup "$CHROOTDIR" || die "Failed to setup chroot $CHROOTDIR" - - $CHROOTCMD "$CHROOTDIR" "${ARGS[@]}" -} - - -function main() { - parse_arguments "$@" - execute_operation -} - -main "$@" diff --git a/tests/unit-tests/test-groot.sh b/tests/unit-tests/test-groot.sh deleted file mode 100755 index 5fb2580..0000000 --- a/tests/unit-tests/test-groot.sh +++ /dev/null @@ -1,248 +0,0 @@ -#!/bin/bash -source "$(dirname $0)/../utils/utils.sh" - -JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/../..)" - -# Disable the exiterr -set +e - -function oneTimeSetUp(){ - setUpUnitTests -} - -function setUp(){ - # Attempt to source the files under test to revert variable overrides - source $JUNEST_BASE/bin/groot -h &> /dev/null - set +e - - cwdSetUp - mkdir -p chrootdir - - init_mocks -} - -function tearDown(){ - cwdTearDown -} - -## Mock functions ## -function init_mocks() { - function usage(){ - echo "usage" - } - function is_user_root() { - return 0 - } - function chroot() { - echo "chroot($@)" - } - function mountpoint() { - echo "mountpoint($@)" - # As default suppose the mountpoint does not exist - return 1 - } - function mountpoint_mock() { - echo "mountpoint($@)" - } - function mount() { - echo "mount($@)" - } - function umount() { - echo "umount($@)" - } - function check_and_trap() { - echo "check_and_trap($@)" - } - - # As default suppose the mountpoint "chrootdir" does not exist - echo -e "1 /home/mychroot/dev\n" > ./mounts - MOUNTS_FILE=./mounts -} - -function test_help(){ - assertCommandSuccess main -h - assertEquals "usage" "$(cat $STDOUTF)" - assertCommandSuccess main --help - assertEquals "usage" "$(cat $STDOUTF)" -} -function test_version(){ - assertCommandSuccess main -V - assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)" - assertCommandSuccess main --version - assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)" -} -function test_groot_no_root(){ - is_user_root() { - return 1 - } - assertCommandFailOnStatus $NO_ROOT_PRIVILEGES main -} -function test_groot_no_directory(){ - assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory -} -function test_groot_mountpoint_exist(){ - echo -e "1 /home/mychroot/dev\n1 chrootdir\n" > ./mounts - MOUNTS_FILE=./mounts - assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_mountpoint_does_not_exist(){ - assertCommandSuccess main chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind(){ - assertCommandSuccess main -b /tmp chrootdir - [[ -d chrootdir/tmp ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind_file(){ - touch file_src - assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir - [[ -f chrootdir/file_src ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind_not_existing_node(){ - assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind_not_absolute_path_node(){ - touch file_src - assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind_guest_host(){ - assertCommandSuccess main -b /tmp:/home/tmp chrootdir - [[ -d chrootdir/home/tmp ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_multiple_bind(){ - assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir - [[ -d chrootdir/home/tmp ]] - assertEquals 0 $? - [[ -d chrootdir/dev ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_command(){ - assertCommandSuccess main chrootdir ls -la -h - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind_and_command(){ - assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h - [[ -d chrootdir/home/tmp ]] - assertEquals 0 $? - [[ -d chrootdir/dev ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)" -} -function test_groot_with_bind_no_umount(){ - assertCommandSuccess main -n chrootdir - assertEquals "$(echo -e "mount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} -function test_groot_with_chroot_teardown(){ - echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts - MOUNTS_FILE=./mounts - CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) -umount(/home/mychroot/proc) -umount(/home/mychroot/dev/shm) -umount(/home/mychroot/dev) -umount(/home/mychroot)")" "$(cat $STDOUTF)" -} - -function test_groot_with_chroot_teardown_umount_failure(){ - function umount() { - echo "umount($@)" - [[ "$1" == "/home/mychroot/dev/shm" ]] && return 128 - return 0 - } - UMOUNT=umount - echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts - MOUNTS_FILE=./mounts - CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) -umount(/home/mychroot/proc) -umount(/home/mychroot/dev/shm) -umount(/home/mychroot/dev) -umount(/home/mychroot)")" "$(cat $STDOUTF)" -} -function test_groot_with_chroot_teardown_with_trailing_slash(){ - echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts - MOUNTS_FILE=./mounts - CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) -umount(/home/mychroot/proc) -umount(/home/mychroot/dev/shm) -umount(/home/mychroot/dev) -umount(/home/mychroot)")" "$(cat $STDOUTF)" -} -function test_groot_with_chroot_teardown_mountpoint_failure(){ - is_mountpoint() { - [[ $1 == "/home/mychroot/dev/shm" ]] && return 128 - return 0 - } - echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts - MOUNTS_FILE=./mounts - CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown - assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1) -umount(/home/mychroot/proc) -umount(/home/mychroot/dev) -umount(/home/mychroot)")" "$(cat $STDOUTF)" -} - -function test_groot_with_rbind(){ - assertCommandSuccess main -r -b /tmp chrootdir - [[ -d chrootdir/tmp ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -function test_groot_with_avoid_bind_proc(){ - assertCommandSuccess main -i -b /proc chrootdir - [[ -d chrootdir/proc ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -function test_groot_with_avoid_bind_dev(){ - assertCommandSuccess main -i -b /dev chrootdir - [[ -d chrootdir/dev ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -function test_groot_with_avoid_bind_sys(){ - assertCommandSuccess main -i -b /sys chrootdir - [[ -d chrootdir/sys ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -function test_groot_with_avoid_bind_run(){ - assertCommandSuccess main -i -b /run chrootdir - [[ -d chrootdir/run ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -function test_groot_with_avoid_bind_tmp(){ - assertCommandSuccess main -i -b /tmp chrootdir - [[ -d chrootdir/tmp ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -function test_groot_with_avoid_bind_combined(){ - assertCommandSuccess main -i -b /tmp -b /usr chrootdir - cat $STDERRF - [[ -d chrootdir/tmp ]] - assertEquals 0 $? - [[ -d chrootdir/usr ]] - assertEquals 0 $? - assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)" -} - -source $(dirname $0)/../utils/shunit2 From 09b9c644d97589738aae4e69865a8db8082c2f51 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 27 Mar 2020 18:39:58 +0100 Subject: [PATCH 225/326] Add option to specify location of backend command --- bin/junest | 22 ++-- lib/core/chroot.sh | 22 ++-- lib/core/namespace.sh | 29 +++-- lib/core/proot.sh | 40 ++++--- tests/unit-tests/test-chroot.sh | 33 ++++-- tests/unit-tests/test-junest.sh | 182 +++++++++++++++++------------ tests/unit-tests/test-namespace.sh | 42 +++++-- tests/unit-tests/test-proot.sh | 51 ++++++-- 8 files changed, 273 insertions(+), 148 deletions(-) diff --git a/bin/junest b/bin/junest index 3b7eb87..17d32bc 100755 --- a/bin/junest +++ b/bin/junest @@ -39,22 +39,27 @@ usage() { echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}" echo echo -e " n[s] Access via Linux Namespaces using BubbleWrap (Default action)" + echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" + echo -e " --backend-command Bwrap command to use" echo -e " -b, --backend-args Arguments for bwrap backend program" echo -e " ($CMD ns -b \"--help\" to check out the bwrap options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " p[root] Access via PRoot" echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" + echo -e " --backend-command PRoot command to use" echo -e " -b, --backend-args Arguments for PRoot backend program" echo -e " ($CMD proot -b \"--help\" to check out the PRoot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " g[root] Access with root privileges via GRoot" + echo -e " --backend-command GRoot command to use" echo -e " -b, --backend-args Arguments for GRoot backend program" echo -e " ($CMD groot -b \"--help\" to check out the GRoot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" echo echo -e " r[oot] Access with root privileges via classic chroot" + echo -e " --backend-command Chroot command to use" echo -e " -b, --backend-args Arguments for chroot backend program" echo -e " ($CMD root -b \"--help\" to check out the chroot options)" echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" @@ -114,15 +119,16 @@ function parse_arguments(){ function _parse_root_opts() { # Options: - OPT_BACKEND_ARGS=false BACKEND_ARGS="" OPT_NO_COPY_FILES=false + BACKEND_COMMAND="" while [[ -n "$1" ]] do case "$1" in - -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;; -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; + --backend-command) shift; BACKEND_COMMAND="$1"; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -139,16 +145,17 @@ function _parse_root_opts() { function _parse_ns_opts() { # Options: OPT_FAKEROOT=false - OPT_BACKEND_ARGS=false BACKEND_ARGS="" OPT_NO_COPY_FILES=false + BACKEND_COMMAND="" while [[ -n "$1" ]] do case "$1" in -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;; -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; + --backend-command) shift; BACKEND_COMMAND="$1"; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -165,16 +172,17 @@ function _parse_ns_opts() { function _parse_proot_opts() { # Options: OPT_FAKEROOT=false - OPT_BACKEND_ARGS=false BACKEND_ARGS="" OPT_NO_COPY_FILES=false + BACKEND_COMMAND="" while [[ -n "$1" ]] do case "$1" in -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -b|--backend-args) OPT_BACKEND_ARGS=true ; shift ; BACKEND_ARGS=$1; shift ;; + -b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;; -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; + --backend-command) shift; BACKEND_COMMAND="$1"; shift ;; --) shift ; break ;; -*) die "Invalid option $1" ;; *) break ;; @@ -269,7 +277,7 @@ function execute_operation() { run_env=run_env_as_chroot fi - $run_env "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" + $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index eb584f0..635137b 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -58,15 +58,18 @@ function _run_env_as_xroot(){ function run_env_as_groot(){ check_nested_env - local backend_args="$1" - local no_copy_files="$2" - shift 2 + local backend_command="$1" + 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 - _run_env_as_xroot "$GROOT $bindings" "$backend_args" "$no_copy_files" "$@" + _run_env_as_xroot "$backend_command $bindings" "$backend_args" "$no_copy_files" "$@" } ####################################### @@ -92,9 +95,12 @@ function run_env_as_groot(){ function run_env_as_chroot(){ check_nested_env - local backend_args="$1" - local no_copy_files="$2" - shift 2 + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 - _run_env_as_xroot chroot_cmd "$backend_args" "$no_copy_files" "$@" + [[ -z "$backend_command" ]] && backend_command=chroot_cmd + + _run_env_as_xroot "$backend_command" "$backend_args" "$no_copy_files" "$@" } diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 39080e0..1307de0 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -56,14 +56,17 @@ function _check_user_namespace() { } function _run_env_with_bwrap(){ - local backend_args="$1" - shift + local backend_command="$1" + local backend_args="$2" + shift 2 + + [[ -z "$backend_command" ]] && backend_command=bwrap_cmd if [[ "$1" != "" ]] then - JUNEST_ENV=1 bwrap_cmd --bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try ${backend_args} "${SH[@]}" "-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} "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else - JUNEST_ENV=1 bwrap_cmd --bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try ${backend_args} "${SH[@]}" + 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 } @@ -89,9 +92,10 @@ function _run_env_with_bwrap(){ function run_env_as_bwrap_fakeroot(){ check_nested_env - local backend_args="$1" - local no_copy_files="$2" - shift 2 + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 _check_user_namespace @@ -102,7 +106,7 @@ function run_env_as_bwrap_fakeroot(){ copy_common_files fi - _run_env_with_bwrap "--uid 0 $backend_args" "$@" + _run_env_with_bwrap "$backend_command" "--uid 0 $backend_args" "$@" } @@ -126,9 +130,10 @@ function run_env_as_bwrap_fakeroot(){ function run_env_as_bwrap_user() { check_nested_env - local backend_args="$1" - local no_copy_files="$2" - shift 2 + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 _check_user_namespace @@ -145,7 +150,7 @@ function run_env_as_bwrap_user() { copy_passwd_and_group fi - _run_env_with_bwrap "$backend_args" "$@" + _run_env_with_bwrap "$backend_command" "$backend_args" "$@" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index d2bfd5f..a1eee73 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -9,19 +9,25 @@ # vim: ft=sh function _run_env_with_proot(){ - local proot_args="$1" - shift + local backend_command="$1" + local backend_args="$2" + shift 2 + + [[ -z "$backend_command" ]] && backend_command=proot_cmd if [ "$1" != "" ] then - JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + JUNEST_ENV=1 "${backend_command}" "${backend_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" else - JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" + JUNEST_ENV=1 "${backend_command}" "${backend_args}" "${SH[@]}" fi } function _run_env_with_qemu(){ - local proot_args="$1" + local backend_command="$1" + local backend_args="$2" + shift 2 + source ${JUNEST_HOME}/etc/junest/info if [ "$JUNEST_ARCH" != "$ARCH" ] @@ -34,10 +40,10 @@ function _run_env_with_qemu(){ warn "Emulating $NAME via QEMU..." [ -e ${qemu_symlink} ] || \ ln_cmd -s ${JUNEST_HOME}/bin/${qemu_bin} ${qemu_symlink} - proot_args="-q ${qemu_symlink} $proot_args" + backend_args="-q ${qemu_symlink} $backend_args" fi - shift - _run_env_with_proot "$proot_args" "${@}" + + _run_env_with_proot "$backend_args" "${@}" } ####################################### @@ -63,9 +69,10 @@ function run_env_as_proot_fakeroot(){ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." check_nested_env - local backend_args="$1" - local no_copy_files="$2" - shift 2 + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 if ! $no_copy_files then @@ -78,7 +85,7 @@ function run_env_as_proot_fakeroot(){ # An alternative is via -S option: #_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" - _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $backend_args" "$@" + _run_env_with_qemu "$backend_command" "-0 ${bindings} -r ${JUNEST_HOME} $backend_args" "$@" } ####################################### @@ -104,9 +111,10 @@ function run_env_as_proot_user(){ die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." check_nested_env - local backend_args="$1" - local no_copy_files="$2" - shift 2 + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 if ! $no_copy_files then @@ -127,5 +135,5 @@ function run_env_as_proot_user(){ local bindings=${RESULT} unset RESULT - _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $backend_args" "$@" + _run_env_with_qemu "$backend_command" "${bindings} -r ${JUNEST_HOME} $backend_args" "$@" } diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index b2e5e70..4556671 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -32,20 +32,28 @@ function init_mocks() { echo "chroot_cmd $@" } GROOT=chroot_cmd + mychroot() { + echo mychroot $@ + } } function test_run_env_as_groot_cmd(){ - assertCommandSuccess run_env_as_groot "" "false" pwd + assertCommandSuccess run_env_as_groot "" "" "false" pwd assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } function test_run_env_as_groot_no_cmd(){ - assertCommandSuccess run_env_as_groot "" "false" "" + 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)" } +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)" +} + function test_run_env_as_groot_no_copy(){ - assertCommandSuccess run_env_as_groot "" "true" pwd + assertCommandSuccess run_env_as_groot "" "" "true" pwd assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] @@ -60,27 +68,32 @@ function test_run_env_as_groot_no_copy(){ function test_run_env_as_groot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_groot "" "false" "" + assertCommandFailOnStatus 106 run_env_as_groot "" "" "false" "" unset JUNEST_ENV } function test_run_env_as_groot_cmd_with_backend_args(){ - assertCommandSuccess run_env_as_groot "-n -b /home/blah" "false" pwd + assertCommandSuccess run_env_as_groot "" "-n -b /home/blah" "false" pwd assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } function test_run_env_as_chroot_cmd(){ - assertCommandSuccess run_env_as_chroot "" "false" pwd + assertCommandSuccess run_env_as_chroot "" "" "false" pwd assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } function test_run_env_as_chroot_no_cmd(){ - assertCommandSuccess run_env_as_chroot "" "false" "" + assertCommandSuccess run_env_as_chroot "" "" "false" "" assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c /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)" +} + function test_run_env_as_chroot_no_copy(){ - assertCommandSuccess run_env_as_chroot "" "true" pwd + assertCommandSuccess run_env_as_chroot "" "" "true" pwd assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] @@ -95,12 +108,12 @@ function test_run_env_as_chroot_no_copy(){ function test_run_env_as_choot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_chroot "" "false" "" + assertCommandFailOnStatus 106 run_env_as_chroot "" "" "false" "" unset JUNEST_ENV } function test_run_env_as_chroot_cmd_with_backend_args(){ - assertCommandSuccess run_env_as_chroot "-n -b /home/blah" "false" pwd + assertCommandSuccess run_env_as_chroot "" "-n -b /home/blah" "false" pwd assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" } diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index db7d184..e3c7ee1 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -38,40 +38,46 @@ function setup_env(){ echo "setup_env($1)" } function run_env_as_proot_fakeroot(){ - local backend_args="$1" - local no_copy_files="$2" - shift 2 - echo "run_env_as_proot_fakeroot($backend_args,$no_copy_files,$@)" + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" } function run_env_as_groot(){ - local backend_args="$1" - local no_copy_files="$2" - shift 2 - echo "run_env_as_groot($backend_args,$no_copy_files,$@)" + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$@)" } function run_env_as_chroot(){ - local backend_args="$1" - local no_copy_files="$2" - shift 2 - echo "run_env_as_chroot($backend_args,$no_copy_files,$@)" + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$@)" } function run_env_as_proot_user(){ - local backend_args="$1" - local no_copy_files="$2" - shift 2 - echo "run_env_as_proot_user($backend_args,$no_copy_files,$@)" + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$@)" } function run_env_as_bwrap_fakeroot(){ - local backend_args="$1" - local no_copy_files="$2" - shift 2 - echo "run_env_as_bwrap_fakeroot($backend_args,$no_copy_files,$@)" + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" } function run_env_as_bwrap_user(){ - local backend_args="$1" - local no_copy_files="$2" - shift 2 - echo "run_env_as_bwrap_user($backend_args,$no_copy_files,$@)" + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$@)" } function test_help(){ @@ -139,20 +145,25 @@ function test_setup_env(){ function test_run_env_as_proot_fakeroot(){ assertCommandSuccess main p -f - assertEquals "run_env_as_proot_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot --fakeroot - assertEquals "run_env_as_proot_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main p -f -n - assertEquals "run_env_as_proot_fakeroot(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,true,)" "$(cat $STDOUTF)" + + assertCommandSuccess main p -f --backend-command blah + assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main proot -f --backend-command blah + assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -b "-b arg" - assertEquals "run_env_as_proot_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -b "-b arg" -- command -kv - assertEquals "run_env_as_proot_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f command --as - assertEquals "run_env_as_proot_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main proot -f -- command --as - assertEquals "run_env_as_proot_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -162,18 +173,23 @@ function test_run_env_as_proot_fakeroot(){ function test_run_env_as_user(){ assertCommandSuccess main proot - assertEquals "run_env_as_proot_user(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main p -n - assertEquals "run_env_as_proot_user(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,true,)" "$(cat $STDOUTF)" + + assertCommandSuccess main p --backend-command blah + assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main proot --backend-command blah + assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -b "-b arg" - assertEquals "run_env_as_proot_user(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main proot -b "-b arg" -- command -ll - assertEquals "run_env_as_proot_user(-b arg,false,command -ll)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,-b arg,false,command -ll)" "$(cat $STDOUTF)" assertCommandSuccess main proot command -ls - assertEquals "run_env_as_proot_user(,false,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat $STDOUTF)" assertCommandSuccess main proot -- command -ls - assertEquals "run_env_as_proot_user(,false,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -183,15 +199,21 @@ function test_run_env_as_user(){ function test_run_env_as_groot(){ assertCommandSuccess main g - assertEquals "run_env_as_groot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main g -n - assertEquals "run_env_as_groot(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,true,)" "$(cat $STDOUTF)" assertCommandSuccess main g -b "-b arg" - assertEquals "run_env_as_groot(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,-b arg,false,)" "$(cat $STDOUTF)" + + assertCommandSuccess main g --backend-command blah + assertEquals "run_env_as_groot(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main groot --backend-command blah + assertEquals "run_env_as_groot(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main groot command - assertEquals "run_env_as_groot(,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,false,command)" "$(cat $STDOUTF)" assertCommandSuccess main groot -- command - assertEquals "run_env_as_groot(,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,false,command)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -201,13 +223,19 @@ function test_run_env_as_groot(){ function test_run_env_as_chroot(){ assertCommandSuccess main r - assertEquals "run_env_as_chroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main r -b "-b arg" - assertEquals "run_env_as_chroot(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,-b arg,false,)" "$(cat $STDOUTF)" + + assertCommandSuccess main r --backend-command blah + assertEquals "run_env_as_chroot(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main root --backend-command blah + assertEquals "run_env_as_chroot(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main root command - assertEquals "run_env_as_chroot(,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,,false,command)" "$(cat $STDOUTF)" assertCommandSuccess main root -- command - assertEquals "run_env_as_chroot(,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,,false,command)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -217,34 +245,39 @@ function test_run_env_as_chroot(){ function test_run_env_as_bwrap_fakeroot(){ assertCommandSuccess main n -f - assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -f - assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -n -f - assertEquals "run_env_as_bwrap_fakeroot(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,true,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -f -b "-b arg" - assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -f -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main ns -f command --as - assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main ns -f -- command --as - assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + + assertCommandSuccess main ns -f --backend-command blah + assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main -f --backend-command blah + assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -f - assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -f - assertEquals "run_env_as_bwrap_fakeroot(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -f -b "-b arg" - assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -f -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_fakeroot(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main -f command --as - assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main -f -- command --as - assertEquals "run_env_as_bwrap_fakeroot(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 @@ -254,34 +287,39 @@ function test_run_env_as_bwrap_fakeroot(){ function test_run_env_as_bwrap_user(){ assertCommandSuccess main n - assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns - assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -n - assertEquals "run_env_as_bwrap_user(,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,true,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -b "-b arg" - assertEquals "run_env_as_bwrap_user(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main ns -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_user(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main ns command --as - assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main ns -- command --as - assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" + + assertCommandSuccess main ns --backend-command blah + assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat $STDOUTF)" + assertCommandSuccess main --backend-command blah + assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main - assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main - assertEquals "run_env_as_bwrap_user(,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -b "-b arg" - assertEquals "run_env_as_bwrap_user(-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat $STDOUTF)" assertCommandSuccess main -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_user(-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat $STDOUTF)" assertCommandSuccess main command --as - assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" assertCommandSuccess main -- command --as - assertEquals "run_env_as_bwrap_user(,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" is_env_installed(){ return 1 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 03eb1cd..9efbad3 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -18,6 +18,9 @@ function init_mocks() { function bwrap_cmd(){ echo "bwrap $@" } + function mybwrap(){ + echo "mybwrap $@" + } } function setUp(){ @@ -100,22 +103,37 @@ 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" + 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 /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 /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files +} + function test_run_env_as_bwrap_user() { - assertCommandSuccess run_env_as_bwrap_user "" "false" + assertCommandSuccess run_env_as_bwrap_user "" "" "false" assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } +function test_run_env_as_bwrap_user_with_backend_command() { + assertCommandSuccess run_env_as_bwrap_user "mybwrap" "" "false" + assertEquals "mybwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" + + _test_copy_common_files + _test_copy_remaining_files +} + function test_run_env_as_bwrap_fakeroot_no_copy() { - assertCommandSuccess run_env_as_bwrap_fakeroot "" "true" "" + 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 /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] @@ -141,7 +159,7 @@ function test_run_env_as_bwrap_fakeroot_no_copy() { } function test_run_env_as_bwrap_user_no_copy() { - assertCommandSuccess run_env_as_bwrap_user "" "true" "" + assertCommandSuccess run_env_as_bwrap_user "" "" "true" "" assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] @@ -167,14 +185,14 @@ 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" + 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 --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args() { - assertCommandSuccess run_env_as_bwrap_user "--bind /usr /usr" "false" + assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files @@ -182,14 +200,14 @@ 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" + 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 /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_command() { - assertCommandSuccess run_env_as_bwrap_user "" "false" "ls -la" + assertCommandSuccess run_env_as_bwrap_user "" "" "false" "ls -la" assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files @@ -197,14 +215,14 @@ 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" + 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 --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args_and_command() { - assertCommandSuccess run_env_as_bwrap_user "--bind /usr /usr" "false" "ls -la" + assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" "ls -la" assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files @@ -213,13 +231,13 @@ function test_run_env_as_bwrap_user_with_backend_args_and_command() { function test_run_env_as_bwrap_fakeroot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_bwrap_fakeroot "" "false" "" + assertCommandFailOnStatus 106 run_env_as_bwrap_fakeroot "" "" "false" "" unset JUNEST_ENV } function test_run_env_as_bwrap_user_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_bwrap_user "" "false" "" + assertCommandFailOnStatus 106 run_env_as_bwrap_user "" "" "false" "" unset JUNEST_ENV } diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index 8fa636f..9e152f9 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -51,22 +51,37 @@ function test_run_env_as_proot_user(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_proot_user "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_proot_user "-k 3.10" "false" + assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files } +function test_run_env_as_proot_user_with_backend_command(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + SH=("/usr/bin/echo") + assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" + assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + + _test_copy_common_files + _test_copy_remaining_files +} + function test_run_env_as_proot_user_no_copy(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_proot_user "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] @@ -93,7 +108,7 @@ function test_run_env_as_proot_user_no_copy(){ function test_run_env_as_proot_user_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_proot_user "" "false" + assertCommandFailOnStatus 106 run_env_as_proot_user "" "" "false" unset JUNEST_ENV } @@ -101,19 +116,33 @@ function test_run_env_as_proot_fakeroot(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_proot_fakeroot "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" + assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_proot_fakeroot "-k 3.10" "false" + assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" _test_copy_common_files } +function test_run_env_as_proot_fakeroot_with_backend_command(){ + _run_env_with_qemu() { + echo $@ + } + assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + + SH=("/usr/bin/echo") + assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" + assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + + _test_copy_common_files +} + function test_run_env_as_proot_fakeroot_nested_env(){ JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_proot_fakeroot "" "false" "" + assertCommandFailOnStatus 106 run_env_as_proot_fakeroot "" "" "false" "" unset JUNEST_ENV } @@ -121,7 +150,7 @@ function test_run_env_with_quotes(){ _run_env_with_qemu() { echo $@ } - assertCommandSuccess run_env_as_proot_user "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" } @@ -131,10 +160,10 @@ function test_run_env_with_proot_args(){ echo $@ } - assertCommandSuccess _run_env_with_proot --help + assertCommandSuccess _run_env_with_proot "" "--help" assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)" - assertCommandSuccess _run_env_with_proot --help mycommand + assertCommandSuccess _run_env_with_proot "" "--help" mycommand assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)" assertCommandFail _run_env_with_proot @@ -152,7 +181,7 @@ function test_qemu() { echo $@ } - RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" + RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" "" assertEquals "$(echo -e "-s $JUNEST_HOME/bin/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" } From 500546a0e25c2ae5fea6cd4971e1b6c7a65af217 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 28 Mar 2020 12:57:03 +0100 Subject: [PATCH 226/326] Fix build and proot --- lib/core/build.sh | 4 ++-- lib/core/proot.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index a25cef6..9a224f0 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -87,14 +87,14 @@ function build_image_env(){ sudo pacman --noconfirm --root ${maindir}/root -S sed gzip sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${JUNEST_BASE}/bin/groot ${maindir}/root locale-gen + sudo ${maindir}/root/bin/groot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" sudo pacman --noconfirm --root ${maindir}/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." # gawk command is required for pacman-key sudo pacman --noconfirm --root ${maindir}/root -S gawk - sudo ${JUNEST_BASE}/bin/groot -b /dev ${maindir}/root bash -c ' + sudo ${maindir}/root/bin/groot -b /dev ${maindir}/root bash -c ' pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; do diff --git a/lib/core/proot.sh b/lib/core/proot.sh index a1eee73..bce8295 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -43,7 +43,7 @@ function _run_env_with_qemu(){ backend_args="-q ${qemu_symlink} $backend_args" fi - _run_env_with_proot "$backend_args" "${@}" + _run_env_with_proot "${backend_command}" "$backend_args" "${@}" } ####################################### From 12e6f6214e588ce6fff36d5944be4cbe5a43854b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 28 Mar 2020 13:16:40 +0100 Subject: [PATCH 227/326] Add arm arch to proot --- pkgs/proot-static/PKGBUILD | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkgs/proot-static/PKGBUILD b/pkgs/proot-static/PKGBUILD index fad9291..95d34de 100644 --- a/pkgs/proot-static/PKGBUILD +++ b/pkgs/proot-static/PKGBUILD @@ -29,10 +29,19 @@ PROOT_LINK=${MAIN_REPO}/proot source_x86_64=("${_pkgname}"::"$PROOT_LINK/proot-x86_64") source_i686=("${_pkgname}"::"$PROOT_LINK/proot-x86") + source_arm=("${_pkgname}"::"$PROOT_LINK/proot-arm") +source_armv6h=("${_pkgname}"::"$PROOT_LINK/proot-arm") +source_armv7h=("${_pkgname}"::"$PROOT_LINK/proot-arm") +source_aarch64=("${_pkgname}"::"$PROOT_LINK/proot-arm") + md5sums_x86_64=('14080705dd45a6bafa20e909a68072cb') md5sums_i686=('b1c08236b56d121e04e9e29b197d0eeb') + md5sums_arm=('8218c5f00e77e2e6e04c372ced27c7e7') +md5sums_armv6h=('8218c5f00e77e2e6e04c372ced27c7e7') +md5sums_armv7h=('8218c5f00e77e2e6e04c372ced27c7e7') +md5sums_aarch64=('8218c5f00e77e2e6e04c372ced27c7e7') package() { echo "Installing proot static binaries" From b0169a8e5fdb8f938e4bea54d6fd20120976c7c2 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 28 Mar 2020 15:55:08 +0100 Subject: [PATCH 228/326] 7.2.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 21c8c7b..0ee843c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.1.1 +7.2.0 From 6d7bc4efa442f9177f79ef500e313ff2c3bc1b92 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 28 Mar 2020 16:38:53 +0100 Subject: [PATCH 229/326] Add all arch in proot-static package --- lib/checks/check.sh | 1 - lib/core/common.sh | 2 +- pkgs/proot-static/PKGBUILD | 19 +++---------------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 634044c..57dea5f 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -69,7 +69,6 @@ $SUDO pacman $PACMAN_OPTIONS -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep info "Checking basic executables work..." $SUDO pacman -Qi pacman 1> /dev/null -/usr/bin/proot --help 1> /dev/null /usr/bin/groot --help 1> /dev/null repo_package1=tree diff --git a/lib/core/common.sh b/lib/core/common.sh index eb728e9..624a33c 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -67,7 +67,7 @@ ORIGIN_WD=$(pwd) SH=("/bin/sh" "--login") # List of executables that are run in the host OS: -PROOT="${JUNEST_HOME}/usr/bin/proot" +PROOT="${JUNEST_HOME}/usr/bin/proot-${ARCH}" GROOT="${JUNEST_HOME}/usr/bin/groot" CLASSIC_CHROOT=chroot WGET="wget --no-check-certificate" diff --git a/pkgs/proot-static/PKGBUILD b/pkgs/proot-static/PKGBUILD index 95d34de..f73c126 100644 --- a/pkgs/proot-static/PKGBUILD +++ b/pkgs/proot-static/PKGBUILD @@ -27,26 +27,13 @@ noextract=() MAIN_REPO=https://s3-eu-west-1.amazonaws.com/junest-repo PROOT_LINK=${MAIN_REPO}/proot -source_x86_64=("${_pkgname}"::"$PROOT_LINK/proot-x86_64") -source_i686=("${_pkgname}"::"$PROOT_LINK/proot-x86") - -source_arm=("${_pkgname}"::"$PROOT_LINK/proot-arm") -source_armv6h=("${_pkgname}"::"$PROOT_LINK/proot-arm") -source_armv7h=("${_pkgname}"::"$PROOT_LINK/proot-arm") -source_aarch64=("${_pkgname}"::"$PROOT_LINK/proot-arm") - -md5sums_x86_64=('14080705dd45a6bafa20e909a68072cb') -md5sums_i686=('b1c08236b56d121e04e9e29b197d0eeb') - -md5sums_arm=('8218c5f00e77e2e6e04c372ced27c7e7') -md5sums_armv6h=('8218c5f00e77e2e6e04c372ced27c7e7') -md5sums_armv7h=('8218c5f00e77e2e6e04c372ced27c7e7') -md5sums_aarch64=('8218c5f00e77e2e6e04c372ced27c7e7') +source=("proot-x86_64"::"$PROOT_LINK/proot-x86_64" "proot-arm"::"$PROOT_LINK/proot-arm") +md5sums=('14080705dd45a6bafa20e909a68072cb' '8218c5f00e77e2e6e04c372ced27c7e7') package() { echo "Installing proot static binaries" install -d -m 755 "${pkgdir}/usr/bin/" - install -m 755 "${srcdir}/${_pkgname}" ${pkgdir}/usr/bin/proot + install -m 755 "${srcdir}/"${_pkgname}-* ${pkgdir}/usr/bin/ } # vim:set ts=2 sw=2 et: From 7b3685941dfc112bfeccf8de83822397d153b3ac Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 28 Mar 2020 18:48:51 +0100 Subject: [PATCH 230/326] 7.2.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0ee843c..b26a34e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.2.0 +7.2.1 From 98107ac07f394fb625bf2260c29f86b115036f48 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 15 Sep 2020 14:06:03 +0200 Subject: [PATCH 231/326] Change format package from xz --- .gitignore | 2 +- lib/core/build.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2d39c41..b47a408 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.swp -*pkg.tar.xz +*pkg.tar.* *.tar.gz *.SRCINFO diff --git a/lib/core/build.sh b/lib/core/build.sh index 9a224f0..af0c5bb 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -17,7 +17,7 @@ function _install_pkg_from_aur(){ $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" makepkg -sfcd - sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz + sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.* } function _install_pkg(){ @@ -29,7 +29,7 @@ function _install_pkg(){ builtin cd ${working_dir} makepkg -sfcd makepkg --printsrcinfo > ${pkgbuilddir}/.SRCINFO - sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.xz + sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.* } function _prepare() { From 84f4d2037022227d741c37b9fdc1992d93daadcf Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 15 Sep 2020 19:31:24 +0200 Subject: [PATCH 232/326] Disable integ test for ARM --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 025ddc7..b4126d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,8 @@ script: - ${PWD}/lib/checks/check_all.sh - yes | junest setup --delete - - export JUNEST_HOME=~/.junest-arm - - junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - - junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo - - yes | junest setup --delete + # ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. + #- export JUNEST_HOME=~/.junest-arm + #- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests + #- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo + #- yes | junest setup --delete From 440dde65643fd401eae30afd29fb14cca609000e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 15 Sep 2020 19:40:16 +0200 Subject: [PATCH 233/326] 7.2.2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b26a34e..77f5bec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.2.1 +7.2.2 From 26e58aaeec477aac25bd7f1d38d3870745376ff4 Mon Sep 17 00:00:00 2001 From: hodapp512 Date: Thu, 10 Dec 2020 11:27:15 -0600 Subject: [PATCH 234/326] Update README.md for updated bind usage --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fc9f320..ce38b1c 100644 --- a/README.md +++ b/README.md @@ -269,7 +269,13 @@ armv7l ``` ## Bind directories ## -To bind a host directory to a guest location, you can use proot arguments: +To bind a host directory to a guest location: + +```sh +junest -b "--bind /home/user/mydata /mnt/mydata" +``` + +Or using proot arguments: ```sh junest proot -b "-b /mnt/mydata:/home/user/mydata" From 95479ba41fd38330f66b16f406869a2c6a9cc722 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 21 Dec 2020 08:58:23 +0100 Subject: [PATCH 235/326] Use arch-travis in CI --- .travis.yml | 91 +++++++++++++++++++++++++++++++++++------------ lib/core/build.sh | 10 ++++-- 2 files changed, 77 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index b4126d8..e09143c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,78 @@ -language: bash - sudo: required +os: linux -env: - - TRAVIS_BASH_VERSION="4.0" +cache: + directories: + - ~/.ccache + - ~/.pkg-cache -before_install: - - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" +services: +- docker -install: - - PATH=$PWD/bin:$PATH - - junest setup - - junest -- echo "Installing JuNest (\$(uname -m))" - - JUNEST_HOME=~/.junest-arm junest setup --arch arm - - JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))" +archlinux: + mount: + - ~/.ccache:~/.ccache + - ~/.pkg-cache:/var/cache/pacman/pkg + repos: + - bartus=https://github.com/bartoszek/AUR-repo/raw/master + packages: + # pacman packages + - git + - ccache + - haveged + - aws-cli + + before_install: +# 1.Override `package-cleanup.hook` to preserve cache for travis. +# 2.Enable ccache +# 3.Multithreaded build and compress +# 4.Suppress all gcc warnings + - | + sudo mkdir /etc/pacman.d/hooks/ + sudo ln -s /dev/null /etc/pacman.d/hooks/package-cleanup.hook + sudo sed -i '/^BUILDENV/s/\!ccache/ccache/' /etc/makepkg.conf + sudo sed -i '/#MAKEFLAGS=/c MAKEFLAGS="-j2"' /etc/makepkg.conf + sudo sed -i '/^COMPRESSXZ/s/\xz/xz -T 2/' /etc/makepkg.conf + sudo sed -i '$a CFLAGS="$CFLAGS -w"' /etc/makepkg.conf + sudo sed -i '$a CXXFLAGS="$CXXFLAGS -w"' /etc/makepkg.conf + # TODO this is not used + script: + - "./bin/junest build -n" script: - - bash --version - - bash ./tests/checkstyle/checkstyle.sh - - bash ./tests/unit-tests/unit-tests.sh +- "curl -s https://raw.githubusercontent.com/bartoszek/arch-travis/master/arch-travis.sh | bash" +- "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" - - export JUNEST_HOME=~/.junest - - ${PWD}/lib/checks/check_all.sh - - yes | junest setup --delete - # ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. - #- export JUNEST_HOME=~/.junest-arm - #- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - #- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo + +#language: bash + +#sudo: required + +#env: + #- TRAVIS_BASH_VERSION="4.0" + +#before_install: + #- ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" + +#install: + #- PATH=$PWD/bin:$PATH + #- junest setup + #- junest -- echo "Installing JuNest (\$(uname -m))" + #- JUNEST_HOME=~/.junest-arm junest setup --arch arm + #- JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))" + +#script: + #- bash --version + #- bash ./tests/checkstyle/checkstyle.sh + #- bash ./tests/unit-tests/unit-tests.sh + + #- export JUNEST_HOME=~/.junest + #- ${PWD}/lib/checks/check_all.sh #- yes | junest setup --delete + + ## ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. + ##- export JUNEST_HOME=~/.junest-arm + ##- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests + ##- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo + ##- yes | junest setup --delete diff --git a/lib/core/build.sh b/lib/core/build.sh index af0c5bb..a3ed8bd 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -80,6 +80,7 @@ function build_image_env(){ sudo install -d -m 755 "${maindir}/root/etc/${CMD}" sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info" + set -x info "Generating the locales..." # sed command is required for locale-gen but it is required by fakeroot # and cannot be removed @@ -87,14 +88,18 @@ function build_image_env(){ sudo pacman --noconfirm --root ${maindir}/root -S sed gzip sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/bin/groot ${maindir}/root locale-gen + sudo ${maindir}/root/bin/groot --no-umount ${maindir}/root locale-gen + #sudo mount --bind ${maindir}/root ${maindir}/root + #sudo arch-chroot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" sudo pacman --noconfirm --root ${maindir}/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." # gawk command is required for pacman-key sudo pacman --noconfirm --root ${maindir}/root -S gawk - sudo ${maindir}/root/bin/groot -b /dev ${maindir}/root bash -c ' + #TODO sudo mount --bind /dev ${maindir}/root/dev + #sudo ${maindir}/root/bin/groot --no-umount -b /dev ${maindir}/root bash -c ' + sudo ${maindir}/root/bin/groot --no-umount ${maindir}/root bash -c ' pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; do @@ -102,6 +107,7 @@ function build_image_env(){ pacman-key --populate $keyring; done; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye' + sudo umount ${maindir}/root sudo pacman --noconfirm --root ${maindir}/root -Rsn gawk sudo rm ${maindir}/root/var/cache/pacman/pkg/* From b75faac48fccba542b82f7cfd786d2f0984853bd Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 26 Dec 2020 12:33:48 +0100 Subject: [PATCH 236/326] Add remaining junest tests in travis --- .travis.yml | 81 ++++++++++++++++++++++------------------- lib/checks/check.sh | 6 ++- lib/checks/check_all.sh | 11 +++--- lib/core/build.sh | 11 ++---- 4 files changed, 58 insertions(+), 51 deletions(-) diff --git a/.travis.yml b/.travis.yml index e09143c..cfd7148 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,20 +13,18 @@ archlinux: mount: - ~/.ccache:~/.ccache - ~/.pkg-cache:/var/cache/pacman/pkg - repos: - - bartus=https://github.com/bartoszek/AUR-repo/raw/master packages: - # pacman packages - - git - - ccache - - haveged + # Pacman packages - aws-cli + - ccache + - git + - haveged before_install: -# 1.Override `package-cleanup.hook` to preserve cache for travis. -# 2.Enable ccache -# 3.Multithreaded build and compress -# 4.Suppress all gcc warnings + # 1.Override `package-cleanup.hook` to preserve cache for travis. + # 2.Enable ccache + # 3.Multithreaded build and compress + # 4.Suppress all gcc warnings - | sudo mkdir /etc/pacman.d/hooks/ sudo ln -s /dev/null /etc/pacman.d/hooks/package-cleanup.hook @@ -35,44 +33,51 @@ archlinux: sudo sed -i '/^COMPRESSXZ/s/\xz/xz -T 2/' /etc/makepkg.conf sudo sed -i '$a CFLAGS="$CFLAGS -w"' /etc/makepkg.conf sudo sed -i '$a CXXFLAGS="$CXXFLAGS -w"' /etc/makepkg.conf - # TODO this is not used script: - - "./bin/junest build -n" + - ./bin/junest build -n + + +env: + - TRAVIS_BASH_VERSION="4.0" + +before_install: + - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" + +install: + - PATH=$PWD/bin:$PATH script: -- "curl -s https://raw.githubusercontent.com/bartoszek/arch-travis/master/arch-travis.sh | bash" -- "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" + ####################### + # Unit Tests + ####################### + - bash --version + - bash ./tests/checkstyle/checkstyle.sh + - bash ./tests/unit-tests/unit-tests.sh + # ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. + #- export JUNEST_HOME=~/.junest-arm + #- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests + #- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo + #- yes | junest setup --delete + ####################### + # Build and validation tests + ####################### + - "curl -s https://raw.githubusercontent.com/bartoszek/arch-travis/master/arch-travis.sh | bash" + - "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" + - ls -l + - pwd -#language: bash - -#sudo: required - -#env: - #- TRAVIS_BASH_VERSION="4.0" - -#before_install: - #- ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" - -#install: - #- PATH=$PWD/bin:$PATH + # TODO Test the new created JuNest image against Ubuntu host #- junest setup #- junest -- echo "Installing JuNest (\$(uname -m))" #- JUNEST_HOME=~/.junest-arm junest setup --arch arm #- JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))" + - export JUNEST_HOME=~/.junest + - junest setup -i junest-x86_64.tar.gz + - ${PWD}/lib/checks/check_all.sh + - yes | junest setup --delete -#script: - #- bash --version - #- bash ./tests/checkstyle/checkstyle.sh - #- bash ./tests/unit-tests/unit-tests.sh + # TODO test deployed image can be downloaded correctly - #- export JUNEST_HOME=~/.junest - #- ${PWD}/lib/checks/check_all.sh - #- yes | junest setup --delete - ## ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. - ##- export JUNEST_HOME=~/.junest-arm - ##- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests - ##- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo - ##- yes | junest setup --delete diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 57dea5f..6ae3e6a 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -80,7 +80,11 @@ $SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package1} repo_package2=iftop info "Checking ${repo_package2} package from official repo..." $SUDO pacman $PACMAN_OPTIONS -S ${repo_package2} -$RUN_ROOT_TESTS && $SUDO iftop -t -s 5 +if $RUN_ROOT_TESTS +then + # Time it out given that sometimes it gets stuck after few seconds. + $SUDO timeout 10 iftop -t -s 5 || true +fi $SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index 6e28ee5..91bc058 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -8,10 +8,11 @@ set -ex JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}" JUNEST_SCRIPT=${JUNEST_SCRIPT:-${JUNEST_BASE}/bin/junest} + CHECK_SCRIPT=${JUNEST_BASE}/lib/checks/check.sh -$JUNEST_SCRIPT proot --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests -$JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo -$JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests -$JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo -sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests +$JUNEST_SCRIPT proot --fakeroot --backend-args "-b ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --skip-aur-tests +$JUNEST_SCRIPT proot --backend-args "-b ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo +$JUNEST_SCRIPT ns --backend-args "--bind ${JUNEST_BASE} ${JUNEST_BASE}" --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests +$JUNEST_SCRIPT ns --backend-args "--bind ${JUNEST_BASE} ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --use-sudo +sudo -E $JUNEST_SCRIPT groot --backend-args "--bind ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests diff --git a/lib/core/build.sh b/lib/core/build.sh index a3ed8bd..fb41ede 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -88,18 +88,14 @@ function build_image_env(){ sudo pacman --noconfirm --root ${maindir}/root -S sed gzip sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/bin/groot --no-umount ${maindir}/root locale-gen - #sudo mount --bind ${maindir}/root ${maindir}/root - #sudo arch-chroot ${maindir}/root locale-gen + sudo ${maindir}/root/bin/groot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" sudo pacman --noconfirm --root ${maindir}/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." # gawk command is required for pacman-key sudo pacman --noconfirm --root ${maindir}/root -S gawk - #TODO sudo mount --bind /dev ${maindir}/root/dev - #sudo ${maindir}/root/bin/groot --no-umount -b /dev ${maindir}/root bash -c ' - sudo ${maindir}/root/bin/groot --no-umount ${maindir}/root bash -c ' + sudo ${maindir}/root/bin/groot --no-umount --avoid-bind -b /dev ${maindir}/root bash -c ' pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; do @@ -107,7 +103,8 @@ function build_image_env(){ pacman-key --populate $keyring; done; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye' - sudo umount ${maindir}/root + sudo umount --force --recursive --lazy ${maindir}/root/dev + sudo umount --force --recursive ${maindir}/root sudo pacman --noconfirm --root ${maindir}/root -Rsn gawk sudo rm ${maindir}/root/var/cache/pacman/pkg/* From 9d2e6e4bbf09b0630b7a4f388dab2abfe6bb18df Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 28 Dec 2020 10:22:13 +0100 Subject: [PATCH 237/326] Add deploy feature --- .travis.yml | 31 ++++++++------ ci/deploy.sh | 50 +++++++++++++++++++++++ {tests/integ-tests => ci}/install-bash.sh | 0 lib/checks/check.sh | 2 +- lib/checks/check_all.sh | 10 ++--- 5 files changed, 75 insertions(+), 18 deletions(-) create mode 100755 ci/deploy.sh rename {tests/integ-tests => ci}/install-bash.sh (100%) diff --git a/.travis.yml b/.travis.yml index cfd7148..648a0cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,6 @@ archlinux: - ~/.pkg-cache:/var/cache/pacman/pkg packages: # Pacman packages - - aws-cli - ccache - git - haveged @@ -34,14 +33,23 @@ archlinux: sudo sed -i '$a CFLAGS="$CFLAGS -w"' /etc/makepkg.conf sudo sed -i '$a CXXFLAGS="$CXXFLAGS -w"' /etc/makepkg.conf script: + # Here do not make any validation (-n) because it will be done later on in the Ubuntu host directly - ./bin/junest build -n env: + matrix: - TRAVIS_BASH_VERSION="4.0" + global: + # AWS_ACCESS_KEY_ID + - secure: "ZotyKKWH5ZrBXDdEnVmV22gbn86BBSiqDZn2d2jVAApgUQdDc3wa7/uYAZP1bts6oQ897nnkUSFHk3M3QAcIoPJerUITTU5D7yjKcFDejgHdpJ4t9XSajmpY9CgKftWapwliWG4wolAKwyAp5GnYqz4GGltHyGxbF/VzUNRF3lw=" + # AWS_SECRET_ACCESS_KEY + - secure: "AWixvJmhr6+rfF4cspMWMjkvLuOsdfNanLK5wrqkgx/0ezDGBBThH0qVhn5Mp1QFM6wVF+LRA6UESNnj0wNwByZHdM6LddkJWlWHb/qkVK+AO4RKUsXJWNyPyOkCNj/WEFpZHQKKUAlEtC8m8AmAcuoi90cr6ih0PXIePRyPFrM=" before_install: - - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" + - ./ci/install-bash.sh "$TRAVIS_BASH_VERSION" + - sudo apt-get update + - sudo apt-get -y install awscli install: - PATH=$PWD/bin:$PATH @@ -56,28 +64,27 @@ script: # ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. #- export JUNEST_HOME=~/.junest-arm + #- junest setup --arch arm + #- junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))" #- junest proot --fakeroot -- ${PWD}/lib/checks/check.sh --skip-aur-tests #- junest proot -- ${PWD}/lib/checks/check.sh --skip-aur-tests --use-sudo #- yes | junest setup --delete ####################### - # Build and validation tests + # Build and validation ####################### - "curl -s https://raw.githubusercontent.com/bartoszek/arch-travis/master/arch-travis.sh | bash" - "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" - ls -l - - pwd - - # TODO Test the new created JuNest image against Ubuntu host - #- junest setup - #- junest -- echo "Installing JuNest (\$(uname -m))" - #- JUNEST_HOME=~/.junest-arm junest setup --arch arm - #- JUNEST_HOME=~/.junest-arm junest proot --fakeroot -- echo "Installing JuNest (\$(uname -m))" + # Test the newly created JuNest image against Ubuntu host - export JUNEST_HOME=~/.junest - junest setup -i junest-x86_64.tar.gz - ${PWD}/lib/checks/check_all.sh - yes | junest setup --delete - # TODO test deployed image can be downloaded correctly - +after_success: + ####################### + # Deploy and validation + ####################### + - ./ci/deploy.sh ${PWD}/junest-x86_64.tar.gz diff --git a/ci/deploy.sh b/ci/deploy.sh new file mode 100755 index 0000000..fa2ff75 --- /dev/null +++ b/ci/deploy.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +set -e + +IMG_PATH=$1 + +set -u + +MAX_OLD_IMAGES=30 + +# ARCH can be one of: x86, x86_64, arm +HOST_ARCH=$(uname -m) +if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] +then + ARCH="x86" +elif [ $HOST_ARCH == "x86_64" ] +then + ARCH="x86_64" +elif [[ $HOST_ARCH =~ .*(arm).* ]] +then + ARCH="arm" +else + echo "Unknown architecture ${HOST_ARCH}" >&2 + exit 11 +fi + +if [[ "$TRAVIS_BRANCH" == "master" ]] +then + + export AWS_DEFAULT_REGION=eu-west-1 + # Upload image + # The put is done via a temporary filename in order to prevent outage on the + # production file for a longer period of time. + cp ${IMG_PATH} ${IMG_PATH}.temp + aws s3 cp ${IMG_PATH}.temp s3://junest-repo/junest/ + aws s3 mv s3://junest-repo/junest/${IMG_PATH}.temp s3://junest-repo/junest/${IMG_PATH} + aws s3api put-object-acl --acl public-read --bucket junest-repo --key junest/${IMG_PATH} + + DATE=$(date +'%Y-%m-%d-%H-%M-%S') + + aws s3 cp ${IMG_PATH} s3://junest-repo/junest/${IMG_PATH}.${DATE} + + # Cleanup old images + aws s3 ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} s3 rm "s3://junest-repo/junest/{}" + + # Test the newly deployed image can be downloaded correctly + junest setup + junest -- echo "Installed JuNest (\$(uname -m))" + yes | junest setup --delete +fi diff --git a/tests/integ-tests/install-bash.sh b/ci/install-bash.sh similarity index 100% rename from tests/integ-tests/install-bash.sh rename to ci/install-bash.sh diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 6ae3e6a..957156b 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -9,7 +9,7 @@ # # vim: ft=sh -set -e +set -ex RUN_ROOT_TESTS=false diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index 91bc058..cc1c4df 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -11,8 +11,8 @@ JUNEST_SCRIPT=${JUNEST_SCRIPT:-${JUNEST_BASE}/bin/junest} CHECK_SCRIPT=${JUNEST_BASE}/lib/checks/check.sh -$JUNEST_SCRIPT proot --fakeroot --backend-args "-b ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --skip-aur-tests -$JUNEST_SCRIPT proot --backend-args "-b ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo -$JUNEST_SCRIPT ns --backend-args "--bind ${JUNEST_BASE} ${JUNEST_BASE}" --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests -$JUNEST_SCRIPT ns --backend-args "--bind ${JUNEST_BASE} ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --use-sudo -sudo -E $JUNEST_SCRIPT groot --backend-args "--bind ${JUNEST_BASE}" -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests +$JUNEST_SCRIPT proot --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests +$JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo +$JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests +$JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo +sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests From 3d16ee2583de6fc071e787422d9d990238053acb Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 29 Dec 2020 10:46:49 +0100 Subject: [PATCH 238/326] First commit for wrappers --- bin/junest | 43 +++++++++++++++++++++++++++++++++++++++++++ lib/core/wrappers.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 lib/core/wrappers.sh diff --git a/bin/junest b/bin/junest index 17d32bc..a19e550 100755 --- a/bin/junest +++ b/bin/junest @@ -17,6 +17,7 @@ source "${JUNEST_BASE}/lib/core/setup.sh" source "${JUNEST_BASE}/lib/core/chroot.sh" source "${JUNEST_BASE}/lib/core/namespace.sh" source "${JUNEST_BASE}/lib/core/proot.sh" +source "${JUNEST_BASE}/lib/core/wrappers.sh" ################################### @@ -67,6 +68,12 @@ usage() { echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" echo -e " -n, --disable-check Disable the $NAME image check" echo + echo -e " c[reate-wrappers] Create wrappers in ${JUNEST_HOME}/usr/bin_wrappers of the executables under" + echo -e " ${JUNEST_HOME}/usr/bin to be run directly from the host." + echo -e " Use the variable JUNEST_ARGS to define how the wrapper will call $NAME (default "ns --fakeroot")." + echo -e " Use PATH variable to point directly to the bin_wrappers directory from the host." + echo -e " -r, --recreate-existing Instead of skipping existing wrappers recreate them" + echo } version() { @@ -80,6 +87,7 @@ function parse_arguments(){ ACT_NAMESPACE=false ACT_PROOT=false ACT_GROOT=false + ACT_WRAPPERS=false ACT_ROOT=false ACT_HELP=false ACT_VERSION=false @@ -91,6 +99,7 @@ function parse_arguments(){ p|proot) ACT_PROOT=true ; shift ;; g|groot) ACT_GROOT=true ; shift ;; r|root) ACT_ROOT=true ; shift ;; + c|create-wrappers) ACT_WRAPPERS=true ; shift ;; -h|--help) ACT_HELP=true ; shift ;; -V|--version) ACT_VERSION=true ; shift ;; *) ACT_NAMESPACE=true ;; @@ -114,9 +123,33 @@ function parse_arguments(){ elif $ACT_ROOT then _parse_root_opts "$@" + elif $ACT_WRAPPERS + then + _parse_wrappers_opts "$@" fi } +function _parse_wrappers_opts() { + # Options: + OPT_RECREATE_EXISTING=false + + while [[ -n "$1" ]] + do + case "$1" in + -r|--recreate-existing) OPT_RECREATE_EXISTING=true ; shift ;; + --) shift ; break ;; + -*) die "Invalid option $1" ;; + *) break ;; + esac + done + + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done +} + function _parse_root_opts() { # Options: BACKEND_ARGS="" @@ -247,6 +280,7 @@ function execute_operation() { else setup_env $ARCH_ARG fi + create_wrappers false fi return @@ -258,6 +292,11 @@ function execute_operation() { die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup" fi + if $ACT_WRAPPERS; then + create_wrappers $OPT_RECREATE_EXISTING + return + fi + local run_env if $ACT_NAMESPACE; then if $OPT_FAKEROOT; then @@ -279,6 +318,10 @@ function execute_operation() { $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" + # TODO use the run_env exit status + + # Call create_wrappers in case new bin files have been created + create_wrappers false } function main() { diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh new file mode 100644 index 0000000..184fca5 --- /dev/null +++ b/lib/core/wrappers.sh @@ -0,0 +1,31 @@ + + +function create_wrappers() { + mkdir -p ${JUNEST_HOME}/usr/bin_wrappers + + cd ${JUNEST_HOME}/usr/bin + for file in * + do + [[ -x $file ]] || continue + if [[ -e ${JUNEST_HOME}/usr/bin_wrappers/$file ]] + then + continue + fi + cat < ${JUNEST_HOME}/usr/bin_wrappers/${file} +#!/usr/bin/env bash + +JUNEST_ARGS=\${JUNEST_ARGS:-ns --fakeroot} + +junest \${JUNEST_ARGS} -- ${file} "\$@" +EOF + chmod +x ${JUNEST_HOME}/usr/bin_wrappers/${file} + done + + # Remove wrappers no longer needed + cd ${JUNEST_HOME}/usr/bin_wrappers + for file in * + do + [[ -e ${JUNEST_HOME}/usr/bin/$file ]] || rm -f $file + done + +} From 2aeb23b88283cd710855c6919203b4fa8ef71aa3 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 29 Dec 2020 13:09:35 +0100 Subject: [PATCH 239/326] Add tests for wrappers --- bin/junest | 46 ++------------------- lib/checks/check_all.sh | 3 ++ tests/unit-tests/test-wrappers.sh | 67 +++++++++++++++++++++++++++++++ tests/utils/utils.sh | 1 + 4 files changed, 74 insertions(+), 43 deletions(-) create mode 100755 tests/unit-tests/test-wrappers.sh diff --git a/bin/junest b/bin/junest index a19e550..2671e86 100755 --- a/bin/junest +++ b/bin/junest @@ -68,12 +68,6 @@ usage() { echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" echo -e " -n, --disable-check Disable the $NAME image check" echo - echo -e " c[reate-wrappers] Create wrappers in ${JUNEST_HOME}/usr/bin_wrappers of the executables under" - echo -e " ${JUNEST_HOME}/usr/bin to be run directly from the host." - echo -e " Use the variable JUNEST_ARGS to define how the wrapper will call $NAME (default "ns --fakeroot")." - echo -e " Use PATH variable to point directly to the bin_wrappers directory from the host." - echo -e " -r, --recreate-existing Instead of skipping existing wrappers recreate them" - echo } version() { @@ -87,7 +81,6 @@ function parse_arguments(){ ACT_NAMESPACE=false ACT_PROOT=false ACT_GROOT=false - ACT_WRAPPERS=false ACT_ROOT=false ACT_HELP=false ACT_VERSION=false @@ -99,7 +92,6 @@ function parse_arguments(){ p|proot) ACT_PROOT=true ; shift ;; g|groot) ACT_GROOT=true ; shift ;; r|root) ACT_ROOT=true ; shift ;; - c|create-wrappers) ACT_WRAPPERS=true ; shift ;; -h|--help) ACT_HELP=true ; shift ;; -V|--version) ACT_VERSION=true ; shift ;; *) ACT_NAMESPACE=true ;; @@ -123,33 +115,9 @@ function parse_arguments(){ elif $ACT_ROOT then _parse_root_opts "$@" - elif $ACT_WRAPPERS - then - _parse_wrappers_opts "$@" fi } -function _parse_wrappers_opts() { - # Options: - OPT_RECREATE_EXISTING=false - - while [[ -n "$1" ]] - do - case "$1" in - -r|--recreate-existing) OPT_RECREATE_EXISTING=true ; shift ;; - --) shift ; break ;; - -*) die "Invalid option $1" ;; - *) break ;; - esac - done - - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done -} - function _parse_root_opts() { # Options: BACKEND_ARGS="" @@ -280,7 +248,7 @@ function execute_operation() { else setup_env $ARCH_ARG fi - create_wrappers false + create_wrappers fi return @@ -292,11 +260,6 @@ function execute_operation() { die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup" fi - if $ACT_WRAPPERS; then - create_wrappers $OPT_RECREATE_EXISTING - return - fi - local run_env if $ACT_NAMESPACE; then if $OPT_FAKEROOT; then @@ -316,12 +279,9 @@ function execute_operation() { run_env=run_env_as_chroot fi - $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" - - # TODO use the run_env exit status - # Call create_wrappers in case new bin files have been created - create_wrappers false + trap "create_wrappers" EXIT QUIT TERM KILL + $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } function main() { diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index cc1c4df..9e5f0a6 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -16,3 +16,6 @@ $JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo $JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests $JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests + +# Test the wrappers work +$JUNEST_HOME/usr/bin_wrappers/pacman --help diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh new file mode 100755 index 0000000..a78c81f --- /dev/null +++ b/tests/unit-tests/test-wrappers.sh @@ -0,0 +1,67 @@ +#!/bin/bash +source "$(dirname $0)/../utils/utils.sh" + +source "$(dirname $0)/../../lib/core/wrappers.sh" + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + junestSetUp +} + +function tearDown(){ + junestTearDown +} + +function test_create_wrappers_empty_bin(){ + assertCommandSuccess create_wrappers + assertEquals "" "$(cat $STDOUTF)" + assertTrue "bin_wrappers does not exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" +} + +function test_create_wrappers_not_executable_file(){ + touch $JUNEST_HOME/usr/bin/myfile + assertCommandSuccess create_wrappers + assertEquals "" "$(cat $STDOUTF)" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" +} + +function test_create_wrappers_executable_file(){ + touch $JUNEST_HOME/usr/bin/myfile + chmod +x $JUNEST_HOME/usr/bin/myfile + assertCommandSuccess create_wrappers + assertEquals "" "$(cat $STDOUTF)" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" +} + +function test_create_wrappers_already_exist(){ + touch $JUNEST_HOME/usr/bin/myfile + chmod +x $JUNEST_HOME/usr/bin/myfile + mkdir -p $JUNEST_HOME/usr/bin_wrappers + touch $JUNEST_HOME/usr/bin_wrappers/myfile + chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile + assertCommandSuccess create_wrappers + assertEquals "" "$(cat $STDOUTF)" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" + assertEquals "" "$(touch $JUNEST_HOME/usr/bin_wrappers/myfile)" +} + +function test_create_wrappers_executable_no_longer_exist(){ + mkdir -p $JUNEST_HOME/usr/bin_wrappers + touch $JUNEST_HOME/usr/bin_wrappers/myfile + chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile + assertCommandSuccess create_wrappers + assertEquals "" "$(cat $STDOUTF)" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" +} + +source $(dirname $0)/../utils/shunit2 diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index ed7cb8c..542af68 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -11,6 +11,7 @@ function cwdTearDown(){ function junestSetUp(){ JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) + mkdir -p ${JUNEST_HOME}/usr/bin mkdir -p ${JUNEST_HOME}/etc/junest echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info mkdir -p ${JUNEST_HOME}/etc/ca-certificates From d25ae301588a9cdad51f4cd571032c3da17952ac Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 29 Dec 2020 14:42:41 +0100 Subject: [PATCH 240/326] Update README --- README.md | 75 +++++++++++++++++++++------------ VERSION | 2 +- lib/checks/check.sh | 8 ---- tests/unit-tests/test-junest.sh | 3 ++ 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index fc9f320..4779250 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without Description =========== **JuNest** (Jailed User NEST) is a lightweight Arch Linux based distribution -that allows to have disposable and isolated GNU/Linux environments +that allows to have disposable and partial isolated GNU/Linux environments within any generic GNU/Linux host OS and without the need to have root privileges for installing packages. @@ -41,7 +41,7 @@ The main advantages on using JuNest are: - Install packages without root privileges. - Partial isolated environment which you can install packages without affecting a production system. -- Access to a wide range of packages in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). +- Access to a wide range of packages, in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). - Available for `x86_64` and `arm` architectures but you can build your own image from scratch too! - Run on a different architecture from the host OS via QEMU - All Arch Linux lovers can have their favourite distro everywhere! @@ -57,7 +57,7 @@ build a complete isolated environment but, conversely, is the ability to run programs as they were running natively from the host OS. Almost everything is shared between host OS and the JuNest sandbox (kernel, process subtree, network, mounting, etc) and only the root filesystem gets isolated -(as the programs installed in JuNest need to reside elsewhere). +(since the programs installed in JuNest need to reside elsewhere). This allows interaction between processes belonging to both host OS and JuNest. For instance, you can install `top` command in JuNest in order to monitor @@ -107,6 +107,27 @@ There are multiple backend programs, each with its own pros/cons. To know more about the JuNest execution modes depending on the backend program used, see the [Usage](#usage) section below. +Run commands installed in JuNest directly from host +--------------------------------------- + +Installed programs can be accessible directly from host. +For instance, supposing the host OS is an Ubuntu distro you can directly +run `pacman` by simply updating the `PATH` variable: + +```sh +export PATH="$PATH:~/.junest/usr/bin_wrappers" +pacman -S htop +htop +``` + +By default the wrappers use `"ns --fakeroot"` but you can change it via `JUNEST_ARGS`. +For instance, if you want to run `iftop` with real root privileges: + +``` +pacman -S iftop +sudo JUNEST_ARGS="groot" iftop +``` + Have fun! --------- @@ -149,12 +170,22 @@ section below. ## Installation from git repository ## Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): - git clone git://github.com/fsquillace/junest ~/.local/share/junest - export PATH=~/.local/share/junest/bin:$PATH +```sh +git clone git://github.com/fsquillace/junest ~/.local/share/junest +export PATH=~/.local/share/junest/bin:$PATH +``` + +Optionally you want to use the wrappers to run commands +installed in JuNest directly from host: + +```sh +export PATH="$PATH:~/.junest/usr/bin_wrappers" +``` +Update your `~/.bashrc` or `~/.zshrc` to get always the wrappers available. ### Installation using AUR (Arch Linux only) ### If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/packages/junest-git/). -After installing junest will be located in `/opt/junest/` +JuNest will be located in `/opt/junest/` Usage ===== @@ -189,7 +220,8 @@ This mode is based on the fantastic PRoot based ----------- [Proot](https://wiki.archlinux.org/index.php/Proot) represents a portable -solution that works well in most of GNU/Linux distros available. +solution which allows unprivileged users to execute programs inside a sandbox +and works well in most of GNU/Linux distros available. One of the major drawbacks is the fact that Proot is not officially supported anymore, therefore, Proot bugs may no longer be fixed. @@ -203,7 +235,9 @@ Chroot based ------------ This solution suits only for privileged users. JuNest provides the possibility to run the environment via `chroot` program. -In particular, it uses a special program called `GRoot`, an enhanced `chroot` +In particular, it uses a special program called `GRoot`, a small and portable +version of +[arch-chroot](https://wiki.archlinux.org/index.php/Chroot) wrapper, that allows to bind mount directories specified by the user, such as `/proc`, `/sys`, `/dev`, `/tmp` and `$HOME`, before executing any programs inside the JuNest sandbox. In case the mounting will not @@ -275,7 +309,7 @@ To bind a host directory to a guest location, you can use proot arguments: junest proot -b "-b /mnt/mydata:/home/user/mydata" ``` -The option `-b` to provide options to the backeng program will work with PRoot, Namespace and GRoot backend programs. +The option `-b` to provide options to the backend program will work with PRoot, Namespace and GRoot backend programs. Check out the backend program options by passing `--help` option: ```sh @@ -303,21 +337,6 @@ Related wiki page: Internals ========= - -There are two main chroot jail used in JuNest. -The main one is [proot](https://wiki.archlinux.org/index.php/Proot) which -allows unprivileged users to execute programs inside a sandbox and -GRoot, a small and portable version of -[arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an -enhanced chroot for privileged users that mounts the primary directories -(i.e. `/proc`, `/sys`, `/dev` and `/run`) before executing any programs inside -the sandbox. - -## Automatic fallback to classic chroot ## -If GRoot fails for some reasons in the host system (i.e. it is not able to -mount one of the directories), -JuNest automatically tries to fallback to the classic chroot. - ## Automatic fallback for all the dependent host OS executables ## JuNest attempts first to run the executables in the host OS located in different positions (`/usr/bin`, `/bin`, `/usr/sbin` and `/sbin`). @@ -325,10 +344,10 @@ As a fallback it tries to run the same executable if it is available in the JuNe environment. ## Automatic building of the JuNest images ## -There is not periodic automation build of the JuNest images yet. -This was due to the difficulty to automate builds for arm architecture. -The JuNest image for the `x86_64` is built periodically every once every three -months. +There is a periodic automation build of the JuNest images for `x86_64` arch +only. +The JuNest image for `arm` architecture may not be always up to date because +the build is performed manually. ## Static QEMU binaries ## There are static QEMU binaries included in JuNest image that allows to run JuNest diff --git a/VERSION b/VERSION index 77f5bec..1502020 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.2.2 +7.3.0 diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 957156b..7af5832 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -95,12 +95,4 @@ then $SUDO pacman $PACMAN_OPTIONS -Rsn ${aur_package} fi -# The following ensures that the gpg agent gets killed (if exists) -# otherwise it is not possible to exit from the session -if [[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] -then - gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye || echo "GPG agent did not close properly" - echo "GPG agent closed" -fi - exit 0 diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index e3c7ee1..0ba7cf5 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -31,6 +31,9 @@ function build_image_env(){ function delete_env(){ echo "delete_env" } +function create_wrappers(){ + : +} function setup_env_from_file(){ echo "setup_env_from_file($1)" } From d3f9f13ccd3c5a9798bb61c12686260c4bd9b973 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 30 Dec 2020 00:13:58 +0100 Subject: [PATCH 241/326] Fix deploy --- .travis.yml | 2 +- ci/deploy.sh | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 648a0cb..1122ce2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,4 +87,4 @@ after_success: ####################### # Deploy and validation ####################### - - ./ci/deploy.sh ${PWD}/junest-x86_64.tar.gz + - ./ci/deploy.sh ./junest-x86_64.tar.gz diff --git a/ci/deploy.sh b/ci/deploy.sh index fa2ff75..6053424 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -4,7 +4,7 @@ set -e IMG_PATH=$1 -set -u +set -ux MAX_OLD_IMAGES=30 @@ -31,14 +31,15 @@ then # Upload image # The put is done via a temporary filename in order to prevent outage on the # production file for a longer period of time. + img_name=$(basename ${IMG_PATH}) cp ${IMG_PATH} ${IMG_PATH}.temp aws s3 cp ${IMG_PATH}.temp s3://junest-repo/junest/ - aws s3 mv s3://junest-repo/junest/${IMG_PATH}.temp s3://junest-repo/junest/${IMG_PATH} - aws s3api put-object-acl --acl public-read --bucket junest-repo --key junest/${IMG_PATH} + aws s3 mv s3://junest-repo/junest/$img_name.temp s3://junest-repo/junest/$img_name + aws s3api put-object-acl --acl public-read --bucket junest-repo --key junest/$img_name DATE=$(date +'%Y-%m-%d-%H-%M-%S') - aws s3 cp ${IMG_PATH} s3://junest-repo/junest/${IMG_PATH}.${DATE} + aws s3 cp s3://junest-repo/junest/$img_name s3://junest-repo/junest/${img_name}.${DATE} # Cleanup old images aws s3 ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} s3 rm "s3://junest-repo/junest/{}" From f98fa897bf7809a4642d9a377563a33b42c40fb2 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 30 Dec 2020 00:59:00 +0100 Subject: [PATCH 242/326] 7.3.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1502020..643916c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.0 +7.3.1 From 6291e5cc83cbe03f90671129fdc75bed122652d5 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 30 Dec 2020 13:08:01 +0100 Subject: [PATCH 243/326] Use the Junest repo to install package deps --- VERSION | 2 +- lib/core/build.sh | 17 +++++++---- pkgs/groot-git/PKGBUILD | 58 -------------------------------------- pkgs/proot-static/PKGBUILD | 39 ------------------------- pkgs/qemu-static/PKGBUILD | 50 -------------------------------- pkgs/sudo-fake/PKGBUILD | 45 ----------------------------- 6 files changed, 13 insertions(+), 198 deletions(-) delete mode 100644 pkgs/groot-git/PKGBUILD delete mode 100644 pkgs/proot-static/PKGBUILD delete mode 100644 pkgs/qemu-static/PKGBUILD delete mode 100644 pkgs/sudo-fake/PKGBUILD diff --git a/VERSION b/VERSION index 643916c..eab246c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.1 +7.3.2 diff --git a/lib/core/build.sh b/lib/core/build.sh index fb41ede..b387582 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -21,6 +21,8 @@ function _install_pkg_from_aur(){ } function _install_pkg(){ + # This function allows to install packages from AUR. + # At the moment is not used. local maindir=$1 local pkgbuilddir=$2 # Generate a working directory because sources will be downloaded to there @@ -40,6 +42,7 @@ function _prepare() { } function build_image_env(){ + set -x umask 022 # The function must runs on ArchLinux with non-root privileges. @@ -67,10 +70,13 @@ function build_image_env(){ fi sudo mkdir -p ${maindir}/root/run/lock - _install_pkg ${maindir} "$JUNEST_BASE/pkgs/sudo-fake" - _install_pkg ${maindir} "$JUNEST_BASE/pkgs/proot-static" - _install_pkg ${maindir} "$JUNEST_BASE/pkgs/qemu-static" - _install_pkg ${maindir} "$JUNEST_BASE/pkgs/groot-git" + sudo tee -a ${maindir}/root/etc/pacman.conf > /dev/null < ${maindir}/root/etc/${CMD}/info" - set -x info "Generating the locales..." # sed command is required for locale-gen but it is required by fakeroot # and cannot be removed @@ -130,4 +135,6 @@ function build_image_env(){ builtin cd ${ORIGIN_WD} trap - QUIT EXIT ABRT KILL TERM INT sudo rm -fr "$maindir" + + set +x } diff --git a/pkgs/groot-git/PKGBUILD b/pkgs/groot-git/PKGBUILD deleted file mode 100644 index 015f9a2..0000000 --- a/pkgs/groot-git/PKGBUILD +++ /dev/null @@ -1,58 +0,0 @@ -# Maintainer: Filippo Squillace -# More details on how to change this file: -# https://wiki.archlinux.org/index.php/PKGBUILD -# https://wiki.archlinux.org/index.php/Creating_packages -# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages - -pkgname=groot-git -pkgver=1.0.1 -pkgrel=1 -pkgdesc="" -arch=('any') -url="https://github.com/fsquillace/groot" -license=('GPL') -groups=() -depends=('coreutils') -makedepends=() -provides=('groot') -conflicts=() -replaces=() -backup=() -options=() -#install= -noextract=() - - -source=('groot::git+https://github.com/fsquillace/groot.git#branch=master') -md5sums=('SKIP') - - -pkgver() { - cd "$srcdir/${pkgname%-git}" - -# The examples below are not absolute and need to be adapted to each repo. The -# primary goal is to generate version numbers that will increase according to -# pacman's version comparisons with later commits to the repo. The format -# VERSION='VER_NUM.rREV_NUM.HASH', or a relevant subset in case VER_NUM or HASH -# are not available, is recommended. - -# Git, tags available - printf "%s" "$(git describe --tags | sed 's/\([^-]*-\)g/r\1/;s/-/./g')" - -# Git, no tags available -# printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)" - -} - -build() { - : -} - -package() { - cd "$srcdir/${pkgname%-git}" - - install -d -m 755 "${pkgdir}/usr/bin" - install -m 755 "${srcdir}/${pkgname%-git}/bin/groot" ${pkgdir}/usr/bin/groot -} - -# vim:set ts=2 sw=2 et: diff --git a/pkgs/proot-static/PKGBUILD b/pkgs/proot-static/PKGBUILD deleted file mode 100644 index f73c126..0000000 --- a/pkgs/proot-static/PKGBUILD +++ /dev/null @@ -1,39 +0,0 @@ -# Maintainer: Filippo Squillace -# More details on how to change this file: -# https://wiki.archlinux.org/index.php/PKGBUILD -# https://wiki.archlinux.org/index.php/Creating_packages -# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages - -pkgname=proot-static -_pkgname=proot -pkgver=5.1.0 -pkgrel=1 -pkgdesc="chroot, mount --bind, and binfmt_misc without privilege/setup. Static binary only" -arch=('any') -url="https://proot-me.github.io/" -license=('GPL') -groups=() -depends=() -makedepends=() -provides=('proot') -conflicts=('proot' 'proot-bin') -backup=() -options=() -#install= -source=() -md5sums=() -noextract=() - -MAIN_REPO=https://s3-eu-west-1.amazonaws.com/junest-repo -PROOT_LINK=${MAIN_REPO}/proot - -source=("proot-x86_64"::"$PROOT_LINK/proot-x86_64" "proot-arm"::"$PROOT_LINK/proot-arm") -md5sums=('14080705dd45a6bafa20e909a68072cb' '8218c5f00e77e2e6e04c372ced27c7e7') - -package() { - echo "Installing proot static binaries" - install -d -m 755 "${pkgdir}/usr/bin/" - install -m 755 "${srcdir}/"${_pkgname}-* ${pkgdir}/usr/bin/ -} - -# vim:set ts=2 sw=2 et: diff --git a/pkgs/qemu-static/PKGBUILD b/pkgs/qemu-static/PKGBUILD deleted file mode 100644 index 3b7fc65..0000000 --- a/pkgs/qemu-static/PKGBUILD +++ /dev/null @@ -1,50 +0,0 @@ -# Maintainer: Filippo Squillace -# More details on how to change this file: -# https://wiki.archlinux.org/index.php/PKGBUILD -# https://wiki.archlinux.org/index.php/Creating_packages -# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages - -pkgname=qemu-static -pkgver=2.3.0 -pkgrel=1 -pkgdesc="Statically linked binaries of Qemu with user emulation. Useful for containers/chroot environment with binfmt." -arch=('any') -url="http://wiki.qemu.org" -license=('GPL2') -groups=() -depends=() -makedepends=() -provides=() -conflicts=() -backup=() -options=() -#install= -source=() -md5sums=() -noextract=() - -MAIN_REPO=https://s3-eu-west-1.amazonaws.com/junest-repo -QEMU_LINK=$MAIN_REPO/qemu - -source_x86_64=("${QEMU_LINK}/x86_64/qemu-x86_64-static-x86" "${QEMU_LINK}/x86_64/qemu-x86_64-static-arm") -source_i686=("${QEMU_LINK}/x86/qemu-x86-static-x86_64" "${QEMU_LINK}/x86/qemu-x86_64-static-arm") -md5sums_x86_64=('8a706d734f8c790743a8114dda4c344a' '3ced729c95d2514f35d4899e944a4582') -md5sums_x86=('c28d5049193dbce75efa0c8655d71427' 'f75fd15722fcc2914e3de0b0a46eb982') - -source_arm=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") -md5sums_arm=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') -source_armv6h=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") -md5sums_armv6h=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') -source_armv7h=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") -md5sums_armv7h=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') -source_aarch64=("${QEMU_LINK}/arm/qemu-arm-static-x86_64" "${QEMU_LINK}/arm/qemu-arm-static-x86") -md5sums_aarch64=('bd9de1927aae4eb26dc0e5615159a616' 'a7c2b6ca53fa166f0c06ec76cc5edd7d') - - -package() { - echo "Installing qemu static binaries" - install -d -m 755 "${pkgdir}/usr/bin" - install -m 755 "${srcdir}"/qemu-* ${pkgdir}/usr/bin -} - -# vim:set ts=2 sw=2 et: diff --git a/pkgs/sudo-fake/PKGBUILD b/pkgs/sudo-fake/PKGBUILD deleted file mode 100644 index 3587807..0000000 --- a/pkgs/sudo-fake/PKGBUILD +++ /dev/null @@ -1,45 +0,0 @@ -# Maintainer: Filippo Squillace -# More details on how to change this file: -# https://wiki.archlinux.org/index.php/PKGBUILD -# https://wiki.archlinux.org/index.php/Creating_packages -# https://wiki.archlinux.org/index.php/Arch_User_Repository#Submitting_packages - -pkgname=sudo-fake -pkgver=0.1.0 -pkgrel=1 -pkgdesc="Simple script that bypasses sudo and execute the actual command. Useful for fakeroot environments." -arch=('any') -url="" -license=('GPL') -groups=() -depends=('fakeroot' 'fakechroot') -makedepends=() -provides=('sudo') -conflicts=('sudo') -backup=() -options=() -#install= -source=() -md5sums=() -noextract=() - -package() { - install -d -m 755 "${pkgdir}/usr/bin/" - cat < "${pkgdir}/usr/bin/sudo" -#!/bin/bash -for opt in "\$@" -do - case "\$1" in - --) shift ; break ;; - -*) shift ;; - *) break ;; - esac -done - -[[ -z "\${@}" ]] || fakechroot fakeroot "\${@}" -EOF - - chmod 755 "${pkgdir}/usr/bin/sudo" -} - -# vim:set ts=2 sw=2 et: From 4527297be101e048c39a408965fd9ce75478b891 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 31 Dec 2020 12:05:23 +0100 Subject: [PATCH 244/326] Remove warnings when using pacman --- README.md | 14 ++++++++++++++ VERSION | 2 +- lib/core/namespace.sh | 2 +- tests/unit-tests/test-namespace.sh | 12 ++++++------ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 285d160..1d950d5 100644 --- a/README.md +++ b/README.md @@ -390,6 +390,20 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > files as root. The package will still be installed correctly even though this > message is showed. +## 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/VERSION b/VERSION index eab246c..44e98ad 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.2 +7.3.3 diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 1307de0..6be2c5f 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -106,7 +106,7 @@ function run_env_as_bwrap_fakeroot(){ copy_common_files fi - _run_env_with_bwrap "$backend_command" "--uid 0 $backend_args" "$@" + _run_env_with_bwrap "$backend_command" "--uid 0 --gid 0 $backend_args" "$@" } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 9efbad3..02149b4 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 /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 /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 /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 /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 /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 /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 --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 /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 /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 /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 --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 /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } From f0b6f0962e453a2dc3ea3da9b2f334a03c568dfb Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 4 Jan 2021 15:34:52 +0100 Subject: [PATCH 245/326] 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 } From 8d4217492ac4a95ca98065f727469884ce89d1cb Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 4 Jan 2021 21:09:50 +0100 Subject: [PATCH 246/326] 7.3.4 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 44e98ad..c968a57 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.3 +7.3.4 From 6548e19eb58d2a5753b7b2754e629bb3d56b3584 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 10 Jan 2021 13:12:11 +0100 Subject: [PATCH 247/326] Use proper proc,dev,sys binds for ns mode --- README.md | 3 +++ lib/core/namespace.sh | 5 +++-- tests/unit-tests/test-namespace.sh | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 48337a6..29d9df5 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,9 @@ first: ```sh pacman -Sy --ignore sudo base-devel +:: sudo is in IgnorePkg/IgnoreGroup. Install anyway? [Y/n] n +... +... ``` JuNest uses a modified version of `sudo`. That's why the original `sudo` diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 45c7c09..c80b80d 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -10,6 +10,7 @@ # # vim: ft=sh +COMMON_BWRAP_OPTION="--bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --bind /sys /sys --bind /proc /proc --dev-bind-try /dev /dev --unshare-user-try" CONFIG_PROC_FILE="/proc/config.gz" CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" PROC_USERNS_CLONE_FILE="/proc/sys/kernel/unprivileged_userns_clone" @@ -94,7 +95,7 @@ function run_env_as_bwrap_fakeroot(){ 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[@]}" + JUNEST_ENV=1 "$backend_command" $COMMON_BWRAP_OPTION --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" } @@ -141,7 +142,7 @@ function run_env_as_bwrap_user() { 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[@]}" + JUNEST_ENV=1 "$backend_command" $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index e24311f..d2cafd9 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -104,21 +104,21 @@ 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 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --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 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mybwrap $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user() { assertCommandSuccess run_env_as_bwrap_user "" "" "false" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -126,7 +126,7 @@ function test_run_env_as_bwrap_user() { function test_run_env_as_bwrap_user_with_backend_command() { assertCommandSuccess run_env_as_bwrap_user "mybwrap" "" "false" - assertEquals "mybwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mybwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_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 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -160,7 +160,7 @@ function test_run_env_as_bwrap_fakeroot_no_copy() { function test_run_env_as_bwrap_user_no_copy() { assertCommandSuccess run_env_as_bwrap_user "" "" "true" "" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -186,14 +186,14 @@ 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 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args() { assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -201,14 +201,14 @@ 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 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_command() { assertCommandSuccess run_env_as_bwrap_user "" "" "false" "ls -la" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -216,14 +216,14 @@ 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 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args_and_command() { assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" "ls -la" - assertEquals "bwrap --bind $JUNEST_HOME / --bind $HOME $HOME --bind /tmp /tmp --proc /proc --dev /dev --unshare-user-try --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files From b8ad2182be7e281f1637ebc75734eee5e7fd0bc4 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 10 Jan 2021 13:25:49 +0100 Subject: [PATCH 248/326] Update README --- README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 29d9df5..fc0f5ba 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ The script will download the image from the repository and will place it to the Access to environment --------------------- -By default, JuNest run via the Linux namespaces (aka `ns`) as the backend program. To access via `ns` just type: +JuNest uses the Linux namespaces (aka `ns`) as the default backend program. To access via `ns` just type: ```sh junest @@ -90,8 +90,8 @@ junest You can use the command `sudo` to acquire fakeroot privileges and install/remove packages. -Alternatively, you can access root privileges without using `sudo` with the -`-f` option: +Alternatively, you can access fakeroot privileges without using `sudo` all the +time with the `-f` (or `--fakeroot`) option: ```sh junest -f @@ -107,7 +107,7 @@ There are multiple backend programs, each with its own pros/cons. To know more about the JuNest execution modes depending on the backend program used, see the [Usage](#usage) section below. -Run commands installed in JuNest directly from host +Run JuNest installed programs directly from host OS --------------------------------------- Installed programs can be accessible directly from host. @@ -120,7 +120,7 @@ pacman -S htop htop ``` -By default the wrappers use `"ns --fakeroot"` but you can change it via `JUNEST_ARGS`. +By default the wrappers use `"ns --fakeroot"` but you can change it via `JUNEST_ARGS` environment variable. For instance, if you want to run `iftop` with real root privileges: ``` @@ -128,18 +128,14 @@ pacman -S iftop sudo JUNEST_ARGS="groot" iftop ``` - -Have fun! ---------- - -If you are new on Arch Linux and you are not familiar with `pacman` package manager -visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). +Install packages from AUR +------------------------- In `ns` mode, you can easily install package from [AUR](https://aur.archlinux.org/) repository using the already available [`yay`](https://aur.archlinux.org/packages/yay/) command. In `proot` mode, JuNest does no longer support the building of AUR packages. -**Remember** that in order to build packages from source, `base-devel` package group is required +**Remember** that in order to build packages from AUR, `base-devel` package group is required first: ```sh @@ -150,7 +146,13 @@ pacman -Sy --ignore sudo base-devel ``` JuNest uses a modified version of `sudo`. That's why the original `sudo` -package has to be ignored in the previous command. +package must be ignored in the previous command. + +Have fun! +--------- + +If you are new on Arch Linux and you are not familiar with `pacman` package manager +visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). Installation ============ From 79e4107196a7019877c994f8e31ad6ce112e9b4d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 10 Jan 2021 13:26:07 +0100 Subject: [PATCH 249/326] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c968a57..d9edd15 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.4 +7.3.5 From 8e560b4a8af6dc50ea0d62872ee56d7bab65771e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 16 Feb 2021 18:13:27 +0100 Subject: [PATCH 250/326] Make namespace check more robust and update README --- README.md | 4 ++-- lib/core/namespace.sh | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fc0f5ba..ee832f1 100644 --- a/README.md +++ b/README.md @@ -139,14 +139,14 @@ command. In `proot` mode, JuNest does no longer support the building of AUR pack first: ```sh -pacman -Sy --ignore sudo base-devel +pacman -Syu --ignore sudo base-devel :: sudo is in IgnorePkg/IgnoreGroup. Install anyway? [Y/n] n ... ... ``` JuNest uses a modified version of `sudo`. That's why the original `sudo` -package must be ignored in the previous command. +package **must be ignored** in the previous command. Have fun! --------- diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index c80b80d..e9d3a53 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -27,7 +27,9 @@ function _is_user_namespace_enabled() { return $NOT_EXISTING_FILE fi - if ! zgrep_cmd -q "CONFIG_USER_NS=y" $config_file + # `-q` option in zgrep may cause a gzip: stdout: Broken pipe + # Use redirect to /dev/null instead + if ! zgrep_cmd "CONFIG_USER_NS=y" $config_file > /dev/null then return $NO_CONFIG_FOUND fi @@ -37,7 +39,9 @@ function _is_user_namespace_enabled() { return 0 fi - if ! zgrep_cmd -q "1" $PROC_USERNS_CLONE_FILE + # `-q` option in zgrep may cause a gzip: stdout: Broken pipe + # Use redirect to /dev/null instead + if ! zgrep_cmd "1" $PROC_USERNS_CLONE_FILE > /dev/null then return $UNPRIVILEGED_USERNS_DISABLED fi From 700b809fbedacb26cc82b7d360950ac90365e5a3 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 16 Feb 2021 18:18:24 +0100 Subject: [PATCH 251/326] 7.3.6 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d9edd15..ee11304 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.5 +7.3.6 From 6af7bae41836a4a866950a660537ab3d3cab3aad Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 24 Mar 2021 11:49:28 +0100 Subject: [PATCH 252/326] Fix wrappers using eval #262 --- README.md | 7 ++++--- VERSION | 2 +- lib/core/wrappers.sh | 5 ++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ee832f1..eb5927b 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ to a wide range of packages from the Arch Linux repositories. The main advantages on using JuNest are: - Install packages without root privileges. -- Partial isolated environment which you can install packages without affecting a production system. +- Partial isolated environment in which you can install packages without affecting a production system. - Access to a wide range of packages, in particular on GNU/Linux distros that may contain limited repositories (such as CentOS and RedHat). - Available for `x86_64` and `arm` architectures but you can build your own image from scratch too! - Run on a different architecture from the host OS via QEMU @@ -51,7 +51,7 @@ JuNest follows the [Arch Linux philosophy](https://wiki.archlinux.org/index.php/ How different is JuNest from Docker and Vagrant? ------------------------------------------------ Although JuNest sounds similar to a virtualisation/Linux container -like system, -JuNest differentiate a lot between Docker and Vagrant. +JuNest is quite different from solutions like Docker or Vagrant. In fact, the purpose of JuNest is **not** to build a complete isolated environment but, conversely, is the ability to run programs as they were running natively from the host OS. Almost everything is shared @@ -110,7 +110,8 @@ used, see the [Usage](#usage) section below. Run JuNest installed programs directly from host OS --------------------------------------- -Installed programs can be accessible directly from host. +Installed programs can be accessible directly from host without +calling `junest` command. For instance, supposing the host OS is an Ubuntu distro you can directly run `pacman` by simply updating the `PATH` variable: diff --git a/VERSION b/VERSION index ee11304..704726e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.6 +7.3.7 diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index 184fca5..b3c63f3 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -11,12 +11,15 @@ function create_wrappers() { then continue fi + # Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes + # are not recognized normally unless using `eval`. More info here: + # https://github.com/fsquillace/junest/issues/262 cat < ${JUNEST_HOME}/usr/bin_wrappers/${file} #!/usr/bin/env bash JUNEST_ARGS=\${JUNEST_ARGS:-ns --fakeroot} -junest \${JUNEST_ARGS} -- ${file} "\$@" +eval junest \${JUNEST_ARGS[@]} -- ${file} "\$@" EOF chmod +x ${JUNEST_HOME}/usr/bin_wrappers/${file} done From 08553a447eba53a2ebab083e4a6a30269a92bf91 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 24 Mar 2021 11:54:17 +0100 Subject: [PATCH 253/326] Remove @ from wrapper --- lib/core/wrappers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index b3c63f3..1fd8696 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -19,7 +19,7 @@ function create_wrappers() { JUNEST_ARGS=\${JUNEST_ARGS:-ns --fakeroot} -eval junest \${JUNEST_ARGS[@]} -- ${file} "\$@" +eval junest \${JUNEST_ARGS} -- ${file} "\$@" EOF chmod +x ${JUNEST_HOME}/usr/bin_wrappers/${file} done From e9406123b9da8c5c8f67370a3c2e364c7ac9863f Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 18 Jun 2021 18:47:14 +0200 Subject: [PATCH 254/326] Test travis --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1122ce2..de3ab23 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,6 +45,8 @@ env: - secure: "ZotyKKWH5ZrBXDdEnVmV22gbn86BBSiqDZn2d2jVAApgUQdDc3wa7/uYAZP1bts6oQ897nnkUSFHk3M3QAcIoPJerUITTU5D7yjKcFDejgHdpJ4t9XSajmpY9CgKftWapwliWG4wolAKwyAp5GnYqz4GGltHyGxbF/VzUNRF3lw=" # AWS_SECRET_ACCESS_KEY - secure: "AWixvJmhr6+rfF4cspMWMjkvLuOsdfNanLK5wrqkgx/0ezDGBBThH0qVhn5Mp1QFM6wVF+LRA6UESNnj0wNwByZHdM6LddkJWlWHb/qkVK+AO4RKUsXJWNyPyOkCNj/WEFpZHQKKUAlEtC8m8AmAcuoi90cr6ih0PXIePRyPFrM=" + # DOCKER_USERNAME + # DOCKER_PASSWORD before_install: - ./ci/install-bash.sh "$TRAVIS_BASH_VERSION" @@ -73,7 +75,8 @@ script: ####################### # Build and validation ####################### - - "curl -s https://raw.githubusercontent.com/bartoszek/arch-travis/master/arch-travis.sh | bash" + #- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + - "curl -s https://raw.githubusercontent.com/fsquillace/arch-travis/master/arch-travis.sh | bash" - "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" - ls -l # Test the newly created JuNest image against Ubuntu host From fc3b54e97f652353ee403134d326d1a21288874e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 19 Jun 2021 16:26:07 +0200 Subject: [PATCH 255/326] Authenticate to Docker hub --- .travis.yml | 4 +--- VERSION | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index de3ab23..786b363 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,8 +45,6 @@ env: - secure: "ZotyKKWH5ZrBXDdEnVmV22gbn86BBSiqDZn2d2jVAApgUQdDc3wa7/uYAZP1bts6oQ897nnkUSFHk3M3QAcIoPJerUITTU5D7yjKcFDejgHdpJ4t9XSajmpY9CgKftWapwliWG4wolAKwyAp5GnYqz4GGltHyGxbF/VzUNRF3lw=" # AWS_SECRET_ACCESS_KEY - secure: "AWixvJmhr6+rfF4cspMWMjkvLuOsdfNanLK5wrqkgx/0ezDGBBThH0qVhn5Mp1QFM6wVF+LRA6UESNnj0wNwByZHdM6LddkJWlWHb/qkVK+AO4RKUsXJWNyPyOkCNj/WEFpZHQKKUAlEtC8m8AmAcuoi90cr6ih0PXIePRyPFrM=" - # DOCKER_USERNAME - # DOCKER_PASSWORD before_install: - ./ci/install-bash.sh "$TRAVIS_BASH_VERSION" @@ -75,7 +73,7 @@ script: ####################### # Build and validation ####################### - #- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin - "curl -s https://raw.githubusercontent.com/fsquillace/arch-travis/master/arch-travis.sh | bash" - "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" - ls -l diff --git a/VERSION b/VERSION index 704726e..8837f2c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.7 +7.3.8 From e45d76651ef0d4cf8c2b17c03673896520df6c03 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 9 Sep 2021 20:54:52 +0200 Subject: [PATCH 256/326] First commit --- lib/core/build.sh | 4 +++- lib/core/common.sh | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index b387582..b57cce2 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -76,7 +76,7 @@ function build_image_env(){ SigLevel = Optional TrustedOnly Server = https://raw.githubusercontent.com/fsquillace/junest-repo/master/any EOT - sudo pacman --noconfirm --config ${maindir}/root/etc/pacman.conf --root ${maindir}/root -Sy sudo-fake groot-git proot-static qemu-static + sudo pacman --noconfirm --config ${maindir}/root/etc/pacman.conf --root ${maindir}/root -Sy sudo-fake groot-git proot-static qemu-user-static-bin-alt info "Installing yay..." sudo pacman --noconfirm -S go @@ -100,7 +100,9 @@ EOT info "Setting up the pacman keyring (this might take a while!)..." # gawk command is required for pacman-key sudo pacman --noconfirm --root ${maindir}/root -S gawk + # TODO check why the following did not fail! sudo ${maindir}/root/bin/groot --no-umount --avoid-bind -b /dev ${maindir}/root bash -c ' + set -e pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; do diff --git a/lib/core/common.sh b/lib/core/common.sh index a496522..f7c52ec 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -53,7 +53,7 @@ fi MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} -DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' +DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) From 86277fd58919af710f35c7b2a2613e4045fee0f8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 9 Sep 2021 22:54:00 +0200 Subject: [PATCH 257/326] Put the original mirror back --- lib/core/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index f7c52ec..c8cc8a1 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -53,7 +53,7 @@ fi MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} -DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' +DEFAULT_MIRROR='https://mirrors.kernel.com/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) From 9ecabcd5249577d2969e025ef4a9c5cb4b92f1bc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 11 Sep 2021 14:15:48 +0200 Subject: [PATCH 258/326] Change mirrorlist, update the initial message, do not inherit PATH variable and use precompiled yay during build phase --- lib/core/build.sh | 18 +----------------- lib/core/common.sh | 4 ++-- lib/core/setup.sh | 5 ++++- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index b57cce2..e17650a 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -8,18 +8,6 @@ # # vim: ft=sh -function _install_pkg_from_aur(){ - local maindir=$1 - local pkgname=$2 - local installname=$3 - mkdir -p ${maindir}/packages/${pkgname} - builtin cd ${maindir}/packages/${pkgname} - $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" - [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" - makepkg -sfcd - sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.* -} - function _install_pkg(){ # This function allows to install packages from AUR. # At the moment is not used. @@ -76,11 +64,7 @@ function build_image_env(){ SigLevel = Optional TrustedOnly Server = https://raw.githubusercontent.com/fsquillace/junest-repo/master/any EOT - sudo pacman --noconfirm --config ${maindir}/root/etc/pacman.conf --root ${maindir}/root -Sy sudo-fake groot-git proot-static qemu-user-static-bin-alt - - info "Installing yay..." - sudo pacman --noconfirm -S go - _install_pkg_from_aur ${maindir} "yay" + sudo pacman --noconfirm --config ${maindir}/root/etc/pacman.conf --root ${maindir}/root -Sy sudo-fake groot-git proot-static qemu-user-static-bin-alt yay echo "Generating the metadata info" sudo install -d -m 755 "${maindir}/root/etc/${CMD}" diff --git a/lib/core/common.sh b/lib/core/common.sh index c8cc8a1..113fb14 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -25,7 +25,7 @@ JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} # The update of the variable PATH ensures that the executables are # found on different locations -PATH=$PATH:/usr/bin:/bin:/usr/sbin:/sbin +PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:${HOME}/.local/bin # The executable uname is essential in order to get the architecture # of the host system, so a fallback mechanism cannot be used for it. @@ -53,7 +53,7 @@ fi MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} -DEFAULT_MIRROR='https://mirrors.kernel.com/archlinux/$repo/os/$arch' +DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 532f2a2..28b04d3 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -54,7 +54,10 @@ function _setup_env(){ $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} info "${NAME} installed successfully!" echo - info "Please change the pacman mirror URL in /etc/pacman.d/mirrorlist according to your location." + info "Default mirror URL set to: ${DEFAULT_MIRROR}" + info "You can change the pacman mirror URL in /etc/pacman.d/mirrorlist according to your location:" + info " \$EDITOR ${JUNEST_HOME}/etc/pacman.d/mirrorlist" + echo info "Remember to refresh the package databases from the server:" info " pacman -Syy" } From 38ab252f98f222acb6545e60832a57c992a1a280 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 21 Sep 2021 14:20:16 +0200 Subject: [PATCH 259/326] Enable all capabilities in ns fakeroot mode --- lib/core/namespace.sh | 2 +- tests/unit-tests/test-namespace.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index e9d3a53..f15bbb4 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -99,7 +99,7 @@ function run_env_as_bwrap_fakeroot(){ local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - JUNEST_ENV=1 "$backend_command" $COMMON_BWRAP_OPTION --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" + JUNEST_ENV=1 "$backend_command" $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index d2cafd9..6b53e9c 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 $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --cap-add ALL --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 $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mybwrap $COMMON_BWRAP_OPTION --cap-add ALL --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 $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --cap-add ALL --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 $COMMON_BWRAP_OPTION --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --cap-add ALL --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 $COMMON_BWRAP_OPTION --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --cap-add ALL --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 $COMMON_BWRAP_OPTION --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "bwrap $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } From 7fe9c0e9ec6a50e50050b601076edec9bbf1e675 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 13 Oct 2021 12:23:41 +0200 Subject: [PATCH 260/326] Fix the --backend-command option --- lib/checks/check_all.sh | 4 ++++ lib/core/common.sh | 6 +++--- lib/core/namespace.sh | 10 ++++++---- lib/core/proot.sh | 4 ++-- tests/unit-tests/test-common.sh | 2 +- tests/unit-tests/test-namespace.sh | 25 +++++++++++-------------- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index 9e5f0a6..c975542 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -13,8 +13,12 @@ CHECK_SCRIPT=${JUNEST_BASE}/lib/checks/check.sh $JUNEST_SCRIPT proot --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests $JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo +# Test the backend command option +$JUNEST_SCRIPT proot --backend-command "$JUNEST_HOME/usr/bin/proot-x86_64" -- exit $JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests $JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo +# Test the backend command option +$JUNEST_SCRIPT ns --backend-command "$JUNEST_HOME/usr/bin/bwrap" -- exit sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests # Test the wrappers work diff --git a/lib/core/common.sh b/lib/core/common.sh index 113fb14..ad2b0f7 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -67,6 +67,7 @@ ORIGIN_WD=$(pwd) DEFAULT_SH=("/bin/sh" "--login") # List of executables that are run in the host OS: +BWRAP="${JUNEST_HOME}/usr/bin/bwrap" PROOT="${JUNEST_HOME}/usr/bin/proot-${ARCH}" GROOT="${JUNEST_HOME}/usr/bin/groot" CLASSIC_CHROOT=chroot @@ -82,7 +83,6 @@ CP=cp # Used for checking user namespace in config.gz file ZGREP=zgrep UNSHARE=unshare -BWRAP=bwrap LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -146,9 +146,9 @@ function unshare_cmd(){ } function bwrap_cmd(){ - if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":" + if $LD_EXEC $BWRAP --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":" then - $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP "${@}" + $LD_EXEC $BWRAP "${@}" else die "Error: Something went wrong while executing bwrap command. Exiting" fi diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index f15bbb4..0567989 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -67,6 +67,7 @@ function _check_user_namespace() { # Globals: # JUNEST_HOME (RO) : The JuNest home directory. # DEFAULT_SH (RO) : Contains the default command to run in JuNest. +# BWRAP (RO): : The location of the bwrap binary. # Arguments: # backend_args ($1) : The arguments to pass to bwrap # no_copy_files ($2?) : If false it will copy some files in /etc @@ -82,7 +83,7 @@ function _check_user_namespace() { function run_env_as_bwrap_fakeroot(){ check_nested_env - local backend_command="${1:-bwrap_cmd}" + local backend_command="${1:-$BWRAP}" local backend_args="$2" local no_copy_files="$3" shift 3 @@ -99,7 +100,7 @@ function run_env_as_bwrap_fakeroot(){ local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - JUNEST_ENV=1 "$backend_command" $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" + BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" } @@ -109,6 +110,7 @@ function run_env_as_bwrap_fakeroot(){ # Globals: # JUNEST_HOME (RO) : The JuNest home directory. # DEFAULT_SH (RO) : Contains the default command to run in JuNest. +# BWRAP (RO): : The location of the bwrap binary. # Arguments: # backend_args ($1) : The arguments to pass to bwrap # no_copy_files ($2?) : If false it will copy some files in /etc @@ -123,7 +125,7 @@ function run_env_as_bwrap_fakeroot(){ function run_env_as_bwrap_user() { check_nested_env - local backend_command="${1:-bwrap_cmd}" + local backend_command="${1:-$BWRAP}" local backend_args="$2" local no_copy_files="$3" shift 3 @@ -146,7 +148,7 @@ function run_env_as_bwrap_user() { local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - JUNEST_ENV=1 "$backend_command" $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}" + BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index 1e258f2..f074b47 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -9,14 +9,14 @@ # vim: ft=sh function _run_env_with_proot(){ - local backend_command="${1:-proot_cmd}" + local backend_command="${1:-$PROOT}" local backend_args="$2" shift 2 local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - JUNEST_ENV=1 "${backend_command}" "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}" + PROOT="${backend_command}" JUNEST_ENV=1 proot_cmd "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}" } function _run_env_with_qemu(){ diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index dd77077..0aba4b7 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -143,7 +143,7 @@ function test_unshare(){ function test_bwrap(){ assertCommandSuccess bwrap_cmd new_program - assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$BWRAP new_program")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "ld_exec $BWRAP --dev-bind / / /bin/sh -c :\nld_exec $BWRAP new_program")" "$(cat $STDOUTF)" BWRAP=false LD_EXEC=false assertCommandFail bwrap_cmd new_program } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 6b53e9c..72b9035 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -16,10 +16,7 @@ function oneTimeSetUp(){ ## Mock functions ## function init_mocks() { function bwrap_cmd(){ - echo "bwrap $@" - } - function mybwrap(){ - echo "mybwrap $@" + echo "$BWRAP $@" } } @@ -104,7 +101,7 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } @@ -118,7 +115,7 @@ function test_run_env_as_bwrap_fakeroot_with_backend_command() { function test_run_env_as_bwrap_user() { assertCommandSuccess run_env_as_bwrap_user "" "" "false" - assertEquals "bwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -134,7 +131,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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -160,7 +157,7 @@ function test_run_env_as_bwrap_fakeroot_no_copy() { function test_run_env_as_bwrap_user_no_copy() { assertCommandSuccess run_env_as_bwrap_user "" "" "true" "" - assertEquals "bwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -186,14 +183,14 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args() { assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" - assertEquals "bwrap $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -201,14 +198,14 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_command() { assertCommandSuccess run_env_as_bwrap_user "" "" "false" "ls -la" - assertEquals "bwrap $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files @@ -216,14 +213,14 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args_and_command() { assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" "ls -la" - assertEquals "bwrap $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" _test_copy_common_files _test_copy_remaining_files From 6e872c5f2657f17651c52933e74f8a963e99a08e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 13 Oct 2021 22:33:09 +0200 Subject: [PATCH 261/326] Update version and README --- README.md | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eb5927b..3f25266 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The lightweight Arch Linux based distro that runs upon any Linux distros without |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.org/fsquillace/junest.png?branch=master)](https://travis-ci.org/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.com/fsquillace/junest.png?branch=master)](https://app.travis-ci.com/github/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | **Table of Contents** - [Description](#description) diff --git a/VERSION b/VERSION index 8837f2c..7dc1035 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.8 +7.3.9 From 4036a7737be9bcfba87a953141e2c6509717dae5 Mon Sep 17 00:00:00 2001 From: Ayaka Mikazuki Date: Wed, 3 Nov 2021 11:18:42 +0800 Subject: [PATCH 262/326] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce38b1c..61cddb1 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ section below. ## Installation from git repository ## Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): - git clone git://github.com/fsquillace/junest ~/.local/share/junest + git clone https://github.com/fsquillace/junest.git ~/.local/share/junest export PATH=~/.local/share/junest/bin:$PATH ### Installation using AUR (Arch Linux only) ### From 5e975243381d036dc95d92424d2152a365d81a3b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 20 Dec 2021 18:45:43 +0000 Subject: [PATCH 263/326] Update README with proot updates --- README.md | 21 +++++++++------------ VERSION | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3f25266..564f013 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ JuNest ====== -The lightweight Arch Linux based distro that runs upon any Linux distros without root access. +The lightweight Arch Linux based distro that runs, without root privileges, upon any Linux distro.

=4.0)](https://www.gnu.org/software/bash/) - [GNU coreutils](https://www.gnu.org/software/coreutils/) -In `proot` mode, the minimum recommended Linux kernel for the host OS is 2.6.32 on x86 (64 bit) -and ARM architectures. It is still possible to run JuNest on lower -2.6.x host OS kernels but errors may appear, and some applications may -crash. For further information, read the [Troubleshooting](#troubleshooting) -section below. - - ## Installation from git repository ## Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): ```sh -git clone git://github.com/fsquillace/junest ~/.local/share/junest +git clone https://github.com/fsquillace/junest.git ~/.local/share/junest export PATH=~/.local/share/junest/bin:$PATH ``` @@ -228,8 +221,6 @@ PRoot based [Proot](https://wiki.archlinux.org/index.php/Proot) represents a portable solution which allows unprivileged users to execute programs inside a sandbox and works well in most of GNU/Linux distros available. -One of the major drawbacks is the fact that Proot is not officially -supported anymore, therefore, Proot bugs may no longer be fixed. In order to run JuNest via Proot: @@ -237,6 +228,12 @@ In order to run JuNest via Proot: - As fakeroot - Allow to install/remove packages: `junest proot -f` +In `proot` mode, the minimum recommended Linux kernel for the host OS is 2.6.32 on x86 (64 bit) +and ARM architectures. It is still possible to run JuNest on lower +2.6.x host OS kernels but errors may appear, and some applications may +crash. For further information, read the [Troubleshooting](#troubleshooting) +section below. + Chroot based ------------ This solution suits only for privileged users. JuNest provides the possibility @@ -263,7 +260,7 @@ The following table shows the capabilities that each backend program is able to | | QEMU | Root privileges required | Manage Official Packages | Manage AUR Packages | Portability | Support | User modes | | --- | ---- | ------------------------ | ------------------------ | ------------------- | ----------- | ------- | ---------- | | **Linux Namespaces** | NO | NO | YES | YES | Poor | YES | Normal user and `fakeroot` | -| **Proot** | YES | NO | YES | NO | YES | Poor | Normal user and `fakeroot` | +| **Proot** | YES | NO | YES | NO | YES | YES | Normal user and `fakeroot` | | **Chroot** | NO | YES | YES | YES | YES | YES | `root` only | Advanced usage diff --git a/VERSION b/VERSION index 7dc1035..6fddc82 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.9 +7.3.10 From 4a1c11d4edf4207b27db2bfc63d861e1e5fc5019 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 20 Dec 2021 21:19:47 +0000 Subject: [PATCH 264/326] Fix deploy script --- ci/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 6053424..617755b 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -42,7 +42,7 @@ then aws s3 cp s3://junest-repo/junest/$img_name s3://junest-repo/junest/${img_name}.${DATE} # Cleanup old images - aws s3 ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} s3 rm "s3://junest-repo/junest/{}" + aws s3 ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} aws s3 rm "s3://junest-repo/junest/{}" # Test the newly deployed image can be downloaded correctly junest setup From de63bdf96a980b1edb57f603458d360f102334b9 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 31 Dec 2021 18:09:10 +0100 Subject: [PATCH 265/326] Change url main repo --- ci/deploy.sh | 1 - lib/core/common.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 617755b..d953f04 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -35,7 +35,6 @@ then cp ${IMG_PATH} ${IMG_PATH}.temp aws s3 cp ${IMG_PATH}.temp s3://junest-repo/junest/ aws s3 mv s3://junest-repo/junest/$img_name.temp s3://junest-repo/junest/$img_name - aws s3api put-object-acl --acl public-read --bucket junest-repo --key junest/$img_name DATE=$(date +'%Y-%m-%d-%H-%M-%S') diff --git a/lib/core/common.sh b/lib/core/common.sh index ad2b0f7..7618af5 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -51,7 +51,7 @@ else die "Unknown architecture ${HOST_ARCH}" fi -MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo +MAIN_REPO=https://dwa8bhj1f036z.cloudfront.net ENV_REPO=${MAIN_REPO}/${CMD} DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' From 6efc4d0f528cdbbf52cac44e1e9e45f6bf310d5d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 31 Dec 2021 18:20:27 +0100 Subject: [PATCH 266/326] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6fddc82..de0fc6a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.10 +7.3.11 From 7d8c619ee06127f8dd28d2238d881a3cfbfdb321 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 5 Jan 2022 23:47:55 +0100 Subject: [PATCH 267/326] #284 Fix copy command --- lib/core/common.sh | 8 +++++--- tests/unit-tests/test-common.sh | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index 7618af5..7d23d07 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -276,20 +276,22 @@ function copy_passwd_and_group(){ ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd then warn "getent command failed or does not exist. Binding directly from /etc/passwd." - copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd + copy_file /etc/passwd fi if ! getent_cmd group > ${JUNEST_HOME}/etc/group then warn "getent command failed or does not exist. Binding directly from /etc/group." - copy_file /etc/group ${JUNEST_HOME}/etc/group + copy_file /etc/group fi return 0 } function copy_file() { local file="${1}" - [[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file" + # -f option ensure to remove destination file if it cannot be opened + # https://github.com/fsquillace/junest/issues/284 + [[ -r "$file" ]] && cp_cmd -f "$file" "${JUNEST_HOME}/$file" return 0 } diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index 0aba4b7..7037f98 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -197,7 +197,7 @@ function test_copy_passwd_and_group_fallback(){ echo $@ } CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess copy_passwd_and_group - assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "-f /etc/passwd $JUNEST_HOME//etc/passwd\n-f /etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" } function test_copy_passwd_and_group_failure(){ From 5f7eaff50eec7c9beb4b4deb1f2ebbd56aa96810 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 8 Jan 2022 11:57:53 +0100 Subject: [PATCH 268/326] 7.3.12 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index de0fc6a..1cef271 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.11 +7.3.12 From bc543a928566f8457b07755726e1a1a183ced0bf Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Fri, 11 Feb 2022 12:12:42 +0100 Subject: [PATCH 269/326] Fix quoting in wrapper script The 'eval' introduced in #262 unfortunately breaks command invocations were a parameter contains spaces, such as rg "my pattern with spaces" as it would be called as `rg my pattern with spaces`. This can be fixed using printf. Using parameter extension quoting with ${@@Q} only works with bash >4.4 (but only >4.0 is required). At least the above invocation then works correctly! --- lib/core/wrappers.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index 1fd8696..45206bb 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -1,9 +1,9 @@ function create_wrappers() { - mkdir -p ${JUNEST_HOME}/usr/bin_wrappers + mkdir -p "${JUNEST_HOME}/usr/bin_wrappers" - cd ${JUNEST_HOME}/usr/bin + cd "${JUNEST_HOME}/usr/bin" || return 1 for file in * do [[ -x $file ]] || continue @@ -14,21 +14,21 @@ function create_wrappers() { # Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes # are not recognized normally unless using `eval`. More info here: # https://github.com/fsquillace/junest/issues/262 - cat < ${JUNEST_HOME}/usr/bin_wrappers/${file} + cat < "${JUNEST_HOME}/usr/bin_wrappers/${file}" #!/usr/bin/env bash JUNEST_ARGS=\${JUNEST_ARGS:-ns --fakeroot} -eval junest \${JUNEST_ARGS} -- ${file} "\$@" +eval junest "\${JUNEST_ARGS}" -- ${file} "\$(printf "%q" "\$@")" EOF - chmod +x ${JUNEST_HOME}/usr/bin_wrappers/${file} + chmod +x "${JUNEST_HOME}/usr/bin_wrappers/${file}" done # Remove wrappers no longer needed - cd ${JUNEST_HOME}/usr/bin_wrappers + cd "${JUNEST_HOME}/usr/bin_wrappers" || return 1 for file in * do - [[ -e ${JUNEST_HOME}/usr/bin/$file ]] || rm -f $file + [[ -e ${JUNEST_HOME}/usr/bin/$file ]] || rm -f "$file" done } From 2b9f1839f117dcd04fb575c5bada5155ac441d0d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 13 Feb 2022 20:02:08 +0100 Subject: [PATCH 270/326] Add create-bin-wrappers command --- README.md | 2 +- bin/junest | 24 ++++++++++++++++++++++++ lib/core/wrappers.sh | 23 +++++++++++++++++++++-- tests/unit-tests/test-wrappers.sh | 19 ++++++++++++++++--- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 564f013..458c1ac 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Run JuNest installed programs directly from host OS --------------------------------------- Installed programs can be accessible directly from host without -calling `junest` command. +entering directly into a JuNest session (no need to call `junest` command). For instance, supposing the host OS is an Ubuntu distro you can directly run `pacman` by simply updating the `PATH` variable: diff --git a/bin/junest b/bin/junest index 7040197..22540fb 100755 --- a/bin/junest +++ b/bin/junest @@ -68,6 +68,9 @@ usage() { echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" echo -e " -n, --disable-check Disable the $NAME image check" echo + echo -e " create-bin-wrappers Create bin wrappers in $JUNEST_HOME/usr/bin_wrappers" + echo -e " -f, --force Replace the wrapper files even if they already exist" + echo } version() { @@ -78,6 +81,7 @@ function parse_arguments(){ # Actions ACT_SETUP=false ACT_BUILD=false + ACT_CREATE_WRAPPERS=false ACT_NAMESPACE=false ACT_PROOT=false ACT_GROOT=false @@ -88,6 +92,7 @@ function parse_arguments(){ case "$1" in s|setup) ACT_SETUP=true ; shift ;; b|build) ACT_BUILD=true ; shift ;; + create-bin-wrappers) ACT_CREATE_WRAPPERS=true ; shift ;; n|ns) ACT_NAMESPACE=true ; shift ;; p|proot) ACT_PROOT=true ; shift ;; g|groot) ACT_GROOT=true ; shift ;; @@ -103,6 +108,9 @@ function parse_arguments(){ elif $ACT_BUILD then _parse_build_opts "$@" + elif $ACT_CREATE_WRAPPERS + then + _parse_create_wrappers_opts "$@" elif $ACT_NAMESPACE then _parse_ns_opts "$@" @@ -204,6 +212,17 @@ function _parse_build_opts() { done } +function _parse_create_wrappers_opts() { + OPT_FORCE=false + while [[ -n "$1" ]] + do + case "$1" in + -f|--force) OPT_FORCE=true ; shift ;; + *) die "Invalid option $1" ;; + esac + done +} + function _parse_setup_opts() { OPT_FROM_FILE=false IMAGE_FILE="" @@ -256,6 +275,11 @@ function execute_operation() { die "Error: The image is still not installed in $JUNEST_HOME. Run this first: $CMD setup" fi + if $ACT_CREATE_WRAPPERS; then + create_wrappers $OPT_FORCE + exit + fi + local run_env if $ACT_NAMESPACE; then if $OPT_FAKEROOT; then diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index 45206bb..da5517f 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -1,13 +1,32 @@ +#!/usr/bin/env bash +# +# Dependencies: +# None +# +# vim: ft=sh - +####################################### +# Create bin wrappers +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# Arguments: +# force ($1?) : Create bin wrappers even if the bin file exists. +# Defaults to false. +# Returns: +# None +# Output: +# None +####################################### function create_wrappers() { + local force=${1:-false} mkdir -p "${JUNEST_HOME}/usr/bin_wrappers" cd "${JUNEST_HOME}/usr/bin" || return 1 for file in * do [[ -x $file ]] || continue - if [[ -e ${JUNEST_HOME}/usr/bin_wrappers/$file ]] + if [[ -e ${JUNEST_HOME}/usr/bin_wrappers/$file ]] && ! $force then continue fi diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index a78c81f..9daf0f9 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -45,13 +45,26 @@ function test_create_wrappers_already_exist(){ touch $JUNEST_HOME/usr/bin/myfile chmod +x $JUNEST_HOME/usr/bin/myfile mkdir -p $JUNEST_HOME/usr/bin_wrappers - touch $JUNEST_HOME/usr/bin_wrappers/myfile + echo "original" > $JUNEST_HOME/usr/bin_wrappers/myfile chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile - assertCommandSuccess create_wrappers + assertCommandSuccess create_wrappers false assertEquals "" "$(cat $STDOUTF)" assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" - assertEquals "" "$(touch $JUNEST_HOME/usr/bin_wrappers/myfile)" + assertEquals "original" "$(cat $JUNEST_HOME/usr/bin_wrappers/myfile)" +} + +function test_create_wrappers_forced_already_exist(){ + echo "new" > $JUNEST_HOME/usr/bin/myfile + chmod +x $JUNEST_HOME/usr/bin/myfile + mkdir -p $JUNEST_HOME/usr/bin_wrappers + echo "original" > $JUNEST_HOME/usr/bin_wrappers/myfile + chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile + assertCommandSuccess create_wrappers true + assertEquals "" "$(cat $STDOUTF)" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" + assertNotEquals "original" "$(cat $JUNEST_HOME/usr/bin_wrappers/myfile)" } function test_create_wrappers_executable_no_longer_exist(){ From e794a6150cdb3d6298685dcd3c8cb12ffe06aa24 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 16 Feb 2022 22:55:40 +0100 Subject: [PATCH 271/326] Add more unit tests --- bin/junest | 2 +- lib/checks/check_all.sh | 1 + tests/unit-tests/test-junest.sh | 143 +++++++++++++++++--------------- 3 files changed, 79 insertions(+), 67 deletions(-) diff --git a/bin/junest b/bin/junest index 22540fb..c09f339 100755 --- a/bin/junest +++ b/bin/junest @@ -69,7 +69,7 @@ usage() { echo -e " -n, --disable-check Disable the $NAME image check" echo echo -e " create-bin-wrappers Create bin wrappers in $JUNEST_HOME/usr/bin_wrappers" - echo -e " -f, --force Replace the wrapper files even if they already exist" + echo -e " -f, --force Create the wrapper files even if they already exist" echo } diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index c975542..210ebfb 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -22,4 +22,5 @@ $JUNEST_SCRIPT ns --backend-command "$JUNEST_HOME/usr/bin/bwrap" -- exit sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests # Test the wrappers work +$JUNEST_SCRIPT create-bin-wrappers --force $JUNEST_HOME/usr/bin_wrappers/pacman --help diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index 0ba7cf5..123b4bd 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -12,75 +12,74 @@ function oneTimeSetUp(){ } function setUp(){ + ## Mock functions ## + function usage(){ + echo "usage" + } + function version(){ + echo "version" + } + function build_image_env(){ + local disable_check=$1 + echo "build_image_env($disable_check)" + } + function delete_env(){ + echo "delete_env" + } + function setup_env_from_file(){ + echo "setup_env_from_file($1)" + } + function setup_env(){ + echo "setup_env($1)" + } + function run_env_as_proot_fakeroot(){ + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" + } + function run_env_as_groot(){ + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$@)" + } + function run_env_as_chroot(){ + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$@)" + } + function run_env_as_proot_user(){ + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$@)" + } + function run_env_as_bwrap_fakeroot(){ + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" + } + function run_env_as_bwrap_user(){ + local backend_command="$1" + local backend_args="$2" + local no_copy_files="$3" + shift 3 + echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$@)" + } function is_env_installed(){ return 0 } -} - -## Mock functions ## -function usage(){ - echo "usage" -} -function version(){ - echo "version" -} -function build_image_env(){ - local disable_check=$1 - echo "build_image_env($disable_check)" -} -function delete_env(){ - echo "delete_env" -} -function create_wrappers(){ - : -} -function setup_env_from_file(){ - echo "setup_env_from_file($1)" -} -function setup_env(){ - echo "setup_env($1)" -} -function run_env_as_proot_fakeroot(){ - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" -} -function run_env_as_groot(){ - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$@)" -} -function run_env_as_chroot(){ - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$@)" -} -function run_env_as_proot_user(){ - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$@)" -} -function run_env_as_bwrap_fakeroot(){ - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" -} -function run_env_as_bwrap_user(){ - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$@)" + function create_wrappers(){ + : + } } function test_help(){ @@ -106,6 +105,18 @@ function test_build_image_env(){ assertEquals "build_image_env(true)" "$(cat $STDOUTF)" } +function test_create_wrappers(){ + function create_wrappers(){ + local force=$1 + echo "create_wrappers($force)" + } + assertCommandSuccess main create-bin-wrappers + assertEquals "create_wrappers(false)" "$(cat $STDOUTF)" + + assertCommandSuccess main create-bin-wrappers --force + assertEquals "create_wrappers(true)" "$(cat $STDOUTF)" +} + function test_delete_env(){ assertCommandSuccess main s -d assertEquals "delete_env" "$(cat $STDOUTF)" From 0295f37758c0fdeb9b45f05f7ed10941a9e52bd3 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 27 Feb 2022 22:43:12 +0100 Subject: [PATCH 272/326] Add shellcheck --- .travis.yml | 1 + bin/junest | 16 +-- ci/deploy.sh | 14 +-- ci/install-bash.sh | 6 +- lib/checks/check.sh | 18 ++- lib/checks/check_all.sh | 8 +- lib/core/build.sh | 62 +++++----- lib/core/chroot.sh | 6 +- lib/core/common.sh | 57 ++++----- lib/core/namespace.sh | 17 +-- lib/core/proot.sh | 14 ++- lib/core/setup.sh | 38 +++--- lib/utils/utils.sh | 54 ++++----- tests/checkstyle/checkstyle.sh | 17 +-- tests/unit-tests/test-chroot.sh | 30 ++--- tests/unit-tests/test-common.sh | 112 +++++++++--------- tests/unit-tests/test-junest.sh | 178 +++++++++++++++-------------- tests/unit-tests/test-namespace.sh | 54 +++++---- tests/unit-tests/test-proot.sh | 88 ++++++++------ tests/unit-tests/test-setup.sh | 31 ++--- tests/unit-tests/test-utils.sh | 64 ++++------- tests/unit-tests/test-wrappers.sh | 56 ++++----- tests/unit-tests/unit-tests.sh | 3 +- tests/utils/utils.sh | 31 ++--- 24 files changed, 519 insertions(+), 456 deletions(-) diff --git a/.travis.yml b/.travis.yml index 786b363..2ad29e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,6 +61,7 @@ script: - bash --version - bash ./tests/checkstyle/checkstyle.sh - bash ./tests/unit-tests/unit-tests.sh + - shellcheck bin/junest lib/**/*.sh ci/*.sh tests/**/*.sh # ARM with qemu does seem to work properly. Disabling integ tests for ARM for now. #- export JUNEST_HOME=~/.junest-arm diff --git a/bin/junest b/bin/junest index c09f339..d3435fe 100755 --- a/bin/junest +++ b/bin/junest @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC1091 # # This file is part of JuNest (https://github.com/fsquillace/junest). # @@ -7,7 +8,7 @@ set -e # JUNEST_BASE can be overridden for testing purposes. # There is no need for doing it for normal usage. -JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}" +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/..)}" source "${JUNEST_BASE}/lib/utils/utils.sh" source "${JUNEST_BASE}/lib/core/common.sh" @@ -24,7 +25,7 @@ source "${JUNEST_BASE}/lib/core/wrappers.sh" ### General functions ### ################################### usage() { - echo -e "$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION" + echo -e "$NAME (v$(cat "$JUNEST_BASE"/VERSION)): $DESCRIPTION" echo echo -e "Usage: $CMD [action] [options] [--] [command]" echo @@ -74,7 +75,7 @@ usage() { } version() { - echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" + echo -e "$NAME $(cat "$JUNEST_BASE"/VERSION)" } function parse_arguments(){ @@ -226,14 +227,13 @@ function _parse_create_wrappers_opts() { function _parse_setup_opts() { OPT_FROM_FILE=false IMAGE_FILE="" - OPT_ARCH=false ARCH_ARG="" OPT_DELETE=false while [[ -n "$1" ]] do case "$1" in -i|--from-file) OPT_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; - -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; + -a|--arch) shift ; ARCH_ARG=$1; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; *) die "Invalid option $1" ;; esac @@ -259,9 +259,9 @@ function execute_operation() { fi if $OPT_FROM_FILE; then - setup_env_from_file $IMAGE_FILE + setup_env_from_file "$IMAGE_FILE" else - setup_env $ARCH_ARG + setup_env "$ARCH_ARG" fi create_wrappers fi @@ -300,7 +300,7 @@ function execute_operation() { fi # Call create_wrappers in case new bin files have been created - trap "create_wrappers" EXIT QUIT TERM KILL + trap "create_wrappers" EXIT QUIT TERM $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } diff --git a/ci/deploy.sh b/ci/deploy.sh index d953f04..b3ba92c 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -10,10 +10,10 @@ MAX_OLD_IMAGES=30 # ARCH can be one of: x86, x86_64, arm HOST_ARCH=$(uname -m) -if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] +if [ "$HOST_ARCH" == "i686" ] || [ "$HOST_ARCH" == "i386" ] then ARCH="x86" -elif [ $HOST_ARCH == "x86_64" ] +elif [ "$HOST_ARCH" == "x86_64" ] then ARCH="x86_64" elif [[ $HOST_ARCH =~ .*(arm).* ]] @@ -31,14 +31,14 @@ then # Upload image # The put is done via a temporary filename in order to prevent outage on the # production file for a longer period of time. - img_name=$(basename ${IMG_PATH}) - cp ${IMG_PATH} ${IMG_PATH}.temp - aws s3 cp ${IMG_PATH}.temp s3://junest-repo/junest/ - aws s3 mv s3://junest-repo/junest/$img_name.temp s3://junest-repo/junest/$img_name + img_name=$(basename "${IMG_PATH}") + cp "${IMG_PATH}" "${IMG_PATH}".temp + aws s3 cp "${IMG_PATH}".temp s3://junest-repo/junest/ + aws s3 mv s3://junest-repo/junest/"$img_name".temp s3://junest-repo/junest/"$img_name" DATE=$(date +'%Y-%m-%d-%H-%M-%S') - aws s3 cp s3://junest-repo/junest/$img_name s3://junest-repo/junest/${img_name}.${DATE} + aws s3 cp "s3://junest-repo/junest/$img_name" "s3://junest-repo/junest/${img_name}.${DATE}" # Cleanup old images aws s3 ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} aws s3 rm "s3://junest-repo/junest/{}" diff --git a/ci/install-bash.sh b/ci/install-bash.sh index 575c9c5..b766123 100755 --- a/ci/install-bash.sh +++ b/ci/install-bash.sh @@ -4,10 +4,10 @@ set -ex VERSION=$1 cd /tmp -wget http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz +wget "http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz" -tar -zxf bash-$VERSION.tar.gz -cd /tmp/bash-$VERSION* +tar -zxf "bash-$VERSION.tar.gz" +cd /tmp/bash-"$VERSION"* ./configure make sudo make install diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 7af5832..f984d96 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC1091 # # This modules is used for: # - Running checks against the building JuNest image @@ -34,7 +35,7 @@ JUNEST_HOME=${JUNEST_HOME:-$HOME/.junest} # JUNEST_BASE can be overridden for testing purposes. # There is no need for doing it for normal usage. -JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}" +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/../..)}" source "${JUNEST_BASE}/lib/utils/utils.sh" source "${JUNEST_BASE}/lib/core/common.sh" @@ -44,27 +45,35 @@ info "Validating JuNest located in ${JUNEST_HOME}..." info "Initial JuNest setup..." # The following ensures that the gpg agent gets killed (if exists) # otherwise it is not possible to exit from the session -trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT KILL TERM INT +trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT TERM INT PACMAN_OPTIONS="--noconfirm --disable-download-timeout" +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Syy # Awk is required for pacman-key +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S gawk $SUDO pacman-key --init if [[ $(uname -m) == *"arm"* ]] then + # shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S archlinuxarm-keyring $SUDO pacman-key --populate archlinuxarm else + # shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S archlinux-keyring $SUDO pacman-key --populate archlinux fi +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Su +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S grep coreutils +# shellcheck disable=SC2086 +# shellcheck disable=SC2046 $SUDO pacman $PACMAN_OPTIONS -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) info "Checking basic executables work..." @@ -73,18 +82,22 @@ $SUDO pacman -Qi pacman 1> /dev/null repo_package1=tree echo "Checking ${repo_package1} package from official repo..." +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S ${repo_package1} tree -L 1 +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package1} repo_package2=iftop info "Checking ${repo_package2} package from official repo..." +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S ${repo_package2} if $RUN_ROOT_TESTS then # Time it out given that sometimes it gets stuck after few seconds. $SUDO timeout 10 iftop -t -s 5 || true fi +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS @@ -92,6 +105,7 @@ then aur_package=tcptraceroute info "Checking ${aur_package} package from AUR repo..." yay --noconfirm -S ${aur_package} + # shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Rsn ${aur_package} fi diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index 210ebfb..394309c 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -5,7 +5,7 @@ set -ex # JUNEST_BASE can be overridden for testing purposes. # There is no need for doing it for normal usage. -JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/../..)}" +JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/../..)}" JUNEST_SCRIPT=${JUNEST_SCRIPT:-${JUNEST_BASE}/bin/junest} @@ -19,8 +19,8 @@ $JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests $JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo # Test the backend command option $JUNEST_SCRIPT ns --backend-command "$JUNEST_HOME/usr/bin/bwrap" -- exit -sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests +sudo -E "$JUNEST_SCRIPT" groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests # Test the wrappers work -$JUNEST_SCRIPT create-bin-wrappers --force -$JUNEST_HOME/usr/bin_wrappers/pacman --help +"$JUNEST_SCRIPT" create-bin-wrappers --force +"$JUNEST_HOME"/usr/bin_wrappers/pacman --help diff --git a/lib/core/build.sh b/lib/core/build.sh index e17650a..48996f9 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -16,10 +16,10 @@ function _install_pkg(){ # Generate a working directory because sources will be downloaded to there working_dir=$(TMPDIR=/tmp mktemp -d -t junest-wd.XXXXXXXXXX) cp -R "$pkgbuilddir"/* "$working_dir" - builtin cd ${working_dir} + builtin cd "${working_dir}" || return 1 makepkg -sfcd - makepkg --printsrcinfo > ${pkgbuilddir}/.SRCINFO - sudo pacman --noconfirm --root ${maindir}/root -U *.pkg.tar.* + makepkg --printsrcinfo > "${pkgbuilddir}"/.SRCINFO + sudo pacman --noconfirm --root "${maindir}"/root -U ./*.pkg.tar.* } function _prepare() { @@ -42,29 +42,31 @@ function build_image_env(){ local disable_validation=$1 - local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) - sudo mkdir -p ${maindir}/root - trap - QUIT EXIT ABRT KILL TERM INT - trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT + local maindir + maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t "${CMD}".XXXXXXXXXX) + sudo mkdir -p "${maindir}"/root + trap - QUIT EXIT ABRT TERM INT + # shellcheck disable=SC2064 + trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT TERM INT info "Installing pacman and its dependencies..." # All the essential executables (ln, mkdir, chown, etc) are in coreutils # bwrap command belongs to bubblewrap - sudo pacstrap -G -M -d ${maindir}/root pacman coreutils bubblewrap + sudo pacstrap -G -M -d "${maindir}"/root pacman coreutils bubblewrap if [[ ${ARCH} != "arm" ]] then # x86_64 does not have any mirror set by default... sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" fi - sudo mkdir -p ${maindir}/root/run/lock + sudo mkdir -p "${maindir}"/root/run/lock - sudo tee -a ${maindir}/root/etc/pacman.conf > /dev/null < /dev/null <> ${maindir}/root/etc/locale.gen" - sudo ${maindir}/root/bin/groot ${maindir}/root locale-gen + sudo "${maindir}"/root/bin/groot "${maindir}"/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" - sudo pacman --noconfirm --root ${maindir}/root -Rsn gzip + sudo pacman --noconfirm --root "${maindir}"/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." # gawk command is required for pacman-key - sudo pacman --noconfirm --root ${maindir}/root -S gawk + sudo pacman --noconfirm --root "${maindir}"/root -S gawk # TODO check why the following did not fail! - sudo ${maindir}/root/bin/groot --no-umount --avoid-bind -b /dev ${maindir}/root bash -c ' + sudo "${maindir}"/root/bin/groot --no-umount --avoid-bind -b /dev "${maindir}"/root bash -c ' set -e pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; @@ -94,31 +96,31 @@ EOT pacman-key --populate $keyring; done; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye' - sudo umount --force --recursive --lazy ${maindir}/root/dev - sudo umount --force --recursive ${maindir}/root - sudo pacman --noconfirm --root ${maindir}/root -Rsn gawk + sudo umount --force --recursive --lazy "${maindir}"/root/dev + sudo umount --force --recursive "${maindir}"/root + sudo pacman --noconfirm --root "${maindir}"/root -Rsn gawk - sudo rm ${maindir}/root/var/cache/pacman/pkg/* + sudo rm "${maindir}"/root/var/cache/pacman/pkg/* # This is needed on system with busybox tar command. # If the file does not have write permission, the tar command to extract files fails. - sudo chmod -R u+rw ${maindir}/root/ + sudo chmod -R u+rw "${maindir}"/root/ - mkdir -p ${maindir}/output - builtin cd ${maindir}/output + mkdir -p "${maindir}"/output + builtin cd "${maindir}"/output || return 1 local imagefile="${CMD}-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." - sudo $TAR -zcpf ${imagefile} -C ${maindir}/root . + sudo "$TAR" -zcpf "${imagefile}" -C "${maindir}"/root . if ! $disable_validation then - mkdir -p ${maindir}/root_test - $TAR -zxpf ${imagefile} -C "${maindir}/root_test" - JUNEST_HOME="${maindir}/root_test" ${JUNEST_BASE}/lib/checks/check_all.sh + mkdir -p "${maindir}"/root_test + $TAR -zxpf "${imagefile}" -C "${maindir}/root_test" + JUNEST_HOME="${maindir}/root_test" "${JUNEST_BASE}"/lib/checks/check_all.sh fi - sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} + sudo cp "${maindir}"/output/"${imagefile}" "${ORIGIN_WD}" - builtin cd ${ORIGIN_WD} + builtin cd "${ORIGIN_WD}" || return 1 trap - QUIT EXIT ABRT KILL TERM INT sudo rm -fr "$maindir" diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index afabc71..c2237a9 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -18,20 +18,22 @@ function _run_env_as_xroot(){ local uid=$UID # SUDO_USER is more reliable compared to SUDO_UID - [ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID + [[ -z $SUDO_USER ]] || uid=$SUDO_USER:$SUDO_GID 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 - trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT + # shellcheck disable=SC2064 + trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT TERM INT if ! $no_copy_files then copy_common_files fi + # shellcheck disable=SC2086 JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/lib/core/common.sh b/lib/core/common.sh index 7d23d07..a75aff9 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -1,4 +1,6 @@ #!/usr/bin/env bash +# shellcheck disable=SC2034 +# shellcheck disable=SC1091 # # This module contains all common functionalities for JuNest. # @@ -29,7 +31,7 @@ PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:${HOME}/.local/bin # The executable uname is essential in order to get the architecture # of the host system, so a fallback mechanism cannot be used for it. -UNAME=uname +UNAME="uname" ARCH_LIST=('x86_64' 'x86' 'arm') HOST_ARCH=$($UNAME -m) @@ -53,6 +55,7 @@ fi MAIN_REPO=https://dwa8bhj1f036z.cloudfront.net ENV_REPO=${MAIN_REPO}/${CMD} +# shellcheck disable=SC2016 DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) @@ -73,16 +76,16 @@ GROOT="${JUNEST_HOME}/usr/bin/groot" CLASSIC_CHROOT=chroot WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" -TAR=tar +TAR="tar" CHOWN="chown" -LN=ln -RM=rm -MKDIR=mkdir -GETENT=getent -CP=cp +LN="ln" +RM="rm" +MKDIR="mkdir" +GETENT="getent" +CP="cp" # Used for checking user namespace in config.gz file -ZGREP=zgrep -UNSHARE=unshare +ZGREP="zgrep" +UNSHARE="unshare" LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -91,32 +94,32 @@ LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" # image. function ln_cmd(){ - $LN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN "$@" + $LN "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$LN "$@" } function getent_cmd(){ - $GETENT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT "$@" + $GETENT "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$GETENT "$@" } function cp_cmd(){ - $CP "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP "$@" + $CP "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CP "$@" } function rm_cmd(){ - $RM "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM "$@" + $RM "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$RM "$@" } function chown_cmd(){ - $CHOWN "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN "$@" + $CHOWN "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CHOWN "$@" } function mkdir_cmd(){ - $MKDIR "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR "$@" + $MKDIR "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$MKDIR "$@" } function zgrep_cmd(){ # No need for LD_EXEC as zgrep is a POSIX shell script - $ZGREP "$@" || ${JUNEST_HOME}/usr/bin/$ZGREP "$@" + $ZGREP "$@" || "${JUNEST_HOME}"/usr/bin/$ZGREP "$@" } function download_cmd(){ @@ -124,7 +127,7 @@ function download_cmd(){ } function chroot_cmd(){ - $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CLASSIC_CHROOT "$@" + $CLASSIC_CHROOT "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CLASSIC_CHROOT "$@" } function unshare_cmd(){ @@ -134,9 +137,9 @@ function unshare_cmd(){ # Also, unshare provides an environment in which /bin/sh maps to dash shell, # 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 "${DEFAULT_SH[0]}" "-c" ":" + if $LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" then - $LD_EXEC ${JUNEST_HOME}/usr/bin/$UNSHARE "${@}" + $LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE "${@}" elif $UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" then $UNSHARE "$@" @@ -146,9 +149,9 @@ function unshare_cmd(){ } function bwrap_cmd(){ - if $LD_EXEC $BWRAP --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":" + if $LD_EXEC "$BWRAP" --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":" then - $LD_EXEC $BWRAP "${@}" + $LD_EXEC "$BWRAP" "${@}" else die "Error: Something went wrong while executing bwrap command. Exiting" fi @@ -157,8 +160,10 @@ function bwrap_cmd(){ function proot_cmd(){ local proot_args="$1" shift + # shellcheck disable=SC2086 if ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":" then + # shellcheck disable=SC2086 ${PROOT} ${proot_args} "${@}" elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":" then @@ -192,7 +197,7 @@ function check_nested_env() { if [[ $JUNEST_ENV == "1" ]] then die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" - elif [[ ! -z $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]] + elif [[ -n $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]] then die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" fi @@ -214,7 +219,7 @@ function check_nested_env() { # None ####################################### function check_same_arch() { - source ${JUNEST_HOME}/etc/junest/info + source "${JUNEST_HOME}"/etc/junest/info [ "$JUNEST_ARCH" != "$ARCH" ] && \ die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" return 0 @@ -272,14 +277,14 @@ function copy_passwd_and_group(){ # is configured. # Try to at least get the current user via `getent passwd $USER` since it uses # a more reliable and faster system call (getpwnam(3)). - if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \ - ! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd + if ! getent_cmd passwd > "${JUNEST_HOME}"/etc/passwd || \ + ! getent_cmd passwd "${USER}" >> "${JUNEST_HOME}"/etc/passwd then warn "getent command failed or does not exist. Binding directly from /etc/passwd." copy_file /etc/passwd fi - if ! getent_cmd group > ${JUNEST_HOME}/etc/group + if ! getent_cmd group > "${JUNEST_HOME}"/etc/group then warn "getent command failed or does not exist. Binding directly from /etc/group." copy_file /etc/group diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 0567989..2754dab 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -10,6 +10,7 @@ # # vim: ft=sh +# shellcheck disable=SC2027 COMMON_BWRAP_OPTION="--bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --bind /sys /sys --bind /proc /proc --dev-bind-try /dev /dev --unshare-user-try" CONFIG_PROC_FILE="/proc/config.gz" CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" @@ -24,14 +25,14 @@ function _is_user_namespace_enabled() { then config_file=$CONFIG_BOOT_FILE else - return $NOT_EXISTING_FILE + return "$NOT_EXISTING_FILE" fi # `-q` option in zgrep may cause a gzip: stdout: Broken pipe # Use redirect to /dev/null instead - if ! zgrep_cmd "CONFIG_USER_NS=y" $config_file > /dev/null + if ! zgrep_cmd "CONFIG_USER_NS=y" "$config_file" > /dev/null then - return $NO_CONFIG_FOUND + return "$NO_CONFIG_FOUND" fi if [[ ! -e $PROC_USERNS_CLONE_FILE ]] @@ -43,7 +44,7 @@ function _is_user_namespace_enabled() { # Use redirect to /dev/null instead if ! zgrep_cmd "1" $PROC_USERNS_CLONE_FILE > /dev/null then - return $UNPRIVILEGED_USERNS_DISABLED + return "$UNPRIVILEGED_USERNS_DISABLED" fi return 0 @@ -53,9 +54,9 @@ function _check_user_namespace() { set +e _is_user_namespace_enabled case $? in - $NOT_EXISTING_FILE) warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;; - $NO_CONFIG_FOUND) warn "Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway..." ;; - $UNPRIVILEGED_USERNS_DISABLED) warn "Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1" ;; + "$NOT_EXISTING_FILE") warn "Could not understand if user namespace is enabled. No config.gz file found. Proceeding anyway..." ;; + "$NO_CONFIG_FOUND") warn "Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway..." ;; + "$UNPRIVILEGED_USERNS_DISABLED") warn "Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1" ;; esac set -e } @@ -100,6 +101,7 @@ function run_env_as_bwrap_fakeroot(){ local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + # shellcheck disable=SC2086 BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" } @@ -148,6 +150,7 @@ function run_env_as_bwrap_user() { local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + # shellcheck disable=SC2086 BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index f074b47..259c8b7 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# shellcheck disable=SC1091 # # This module contains all proot functionalities for JuNest. # @@ -24,18 +25,19 @@ function _run_env_with_qemu(){ local backend_args="$2" shift 2 - source ${JUNEST_HOME}/etc/junest/info + source "${JUNEST_HOME}"/etc/junest/info if [ "$JUNEST_ARCH" != "$ARCH" ] then local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH" local qemu_symlink="/tmp/${qemu_bin}-$RANDOM" trap - QUIT EXIT ABRT KILL TERM INT - trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT + # shellcheck disable=SC2064 + trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT TERM INT warn "Emulating $NAME via QEMU..." - [ -e ${qemu_symlink} ] || \ - ln_cmd -s ${JUNEST_HOME}/bin/${qemu_bin} ${qemu_symlink} + [[ -e ${qemu_symlink} ]] || \ + ln_cmd -s "${JUNEST_HOME}/bin/${qemu_bin}" "${qemu_symlink}" backend_args="-q ${qemu_symlink} $backend_args" fi @@ -62,7 +64,7 @@ function _run_env_with_qemu(){ ####################################### function run_env_as_proot_fakeroot(){ (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." + die_on_status "$ROOT_ACCESS_ERROR" "You cannot access with root privileges. Use --groot option instead." check_nested_env local backend_command="$1" @@ -104,7 +106,7 @@ function run_env_as_proot_fakeroot(){ ####################################### function run_env_as_proot_user(){ (( EUID == 0 )) && \ - die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --groot option instead." + die_on_status "$ROOT_ACCESS_ERROR" "You cannot access with root privileges. Use --groot option instead." check_nested_env local backend_command="$1" diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 28b04d3..749fd66 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -22,7 +22,7 @@ # None ####################################### function is_env_installed(){ - [ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0 + [[ -d "$JUNEST_HOME" ]] && [[ "$(ls -A "$JUNEST_HOME")" ]] && return 0 return 1 } @@ -30,7 +30,7 @@ function is_env_installed(){ function _cleanup_build_directory(){ local maindir=$1 check_not_null "$maindir" - builtin cd $ORIGIN_WD + builtin cd "$ORIGIN_WD" || return 1 trap - QUIT EXIT ABRT KILL TERM INT rm_cmd -fr "$maindir" } @@ -40,7 +40,8 @@ function _prepare_build_directory(){ local maindir=$1 check_not_null "$maindir" trap - QUIT EXIT ABRT KILL TERM INT - trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT + # shellcheck disable=SC2064 + trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT TERM INT } @@ -51,7 +52,7 @@ function _setup_env(){ is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME" mkdir_cmd -p "${JUNEST_HOME}" - $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} + $TAR -zxpf "${imagepath}" -C "${JUNEST_HOME}" info "${NAME} installed successfully!" echo info "Default mirror URL set to: ${DEFAULT_MIRROR}" @@ -84,21 +85,22 @@ function _setup_env(){ ####################################### function setup_env(){ local arch=${1:-$ARCH} - contains_element $arch "${ARCH_LIST[@]}" || \ - die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}" + contains_element "$arch" "${ARCH_LIST[@]}" || \ + die_on_status "$NOT_AVAILABLE_ARCH" "The architecture is not one of: ${ARCH_LIST[*]}" - local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) - _prepare_build_directory $maindir + local maindir + maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t "${CMD}".XXXXXXXXXX) + _prepare_build_directory "$maindir" info "Downloading ${NAME}..." - builtin cd ${maindir} + builtin cd "${maindir}" || return 1 local imagefile=${CMD}-${arch}.tar.gz - download_cmd ${ENV_REPO}/${imagefile} + download_cmd "${ENV_REPO}/${imagefile}" info "Installing ${NAME}..." - _setup_env ${maindir}/${imagefile} + _setup_env "${maindir}/${imagefile}" - _cleanup_build_directory ${maindir} + _cleanup_build_directory "${maindir}" } ####################################### @@ -118,10 +120,10 @@ function setup_env(){ function setup_env_from_file(){ local imagefile=$1 check_not_null "$imagefile" - [ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist" + [[ ! -e ${imagefile} ]] && die_on_status "$NOT_EXISTING_FILE" "Error: The ${NAME} image file ${imagefile} does not exist" info "Installing ${NAME} from ${imagefile}..." - _setup_env ${imagefile} + _setup_env "${imagefile}" } ####################################### @@ -138,18 +140,18 @@ function setup_env_from_file(){ ####################################### function delete_env(){ ! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return - if mountpoint -q ${JUNEST_HOME} + if mountpoint -q "${JUNEST_HOME}" then info "There are mounted directories inside ${JUNEST_HOME}" - if ! umount --force ${JUNEST_HOME} + if ! umount --force "${JUNEST_HOME}" then error "Cannot umount directories in ${JUNEST_HOME}" die "Try to delete ${NAME} using root permissions" fi fi # the CA directories are read only and can be deleted only by changing the mod - chmod -R +w ${JUNEST_HOME}/etc/ca-certificates - if rm_cmd -rf ${JUNEST_HOME} + chmod -R +w "${JUNEST_HOME}"/etc/ca-certificates + if rm_cmd -rf "${JUNEST_HOME}" then info "${NAME} deleted in ${JUNEST_HOME}" else diff --git a/lib/utils/utils.sh b/lib/utils/utils.sh index 00e2cb6..5659568 100644 --- a/lib/utils/utils.sh +++ b/lib/utils/utils.sh @@ -50,7 +50,7 @@ function echoerr() { # Message printed to stderr. ####################################### function die() { - error $@ + error "$@" exit 1 } @@ -70,8 +70,8 @@ function die() { function die_on_status() { status=$1 shift - error $@ - exit $status + error "$@" + exit "$status" } ####################################### @@ -87,7 +87,7 @@ function die_on_status() { # Message printed to stderr. ####################################### function error() { - echoerr -e "\033[1;31m$@\033[0m" + echoerr -e "\033[1;31m$*\033[0m" } ####################################### @@ -104,7 +104,7 @@ function error() { ####################################### function warn() { # $@: msg (mandatory) - str: Message to print - echoerr -e "\033[1;33m$@\033[0m" + echoerr -e "\033[1;33m$*\033[0m" } ####################################### @@ -120,7 +120,7 @@ function warn() { # Message printed to stdout. ####################################### function info(){ - echo -e "\033[1;36m$@\033[0m" + echo -e "\033[1;36m$*\033[0m" } ####################################### @@ -142,12 +142,12 @@ function info(){ function ask(){ local question=$1 local default_answer=$2 - check_not_null $question + check_not_null "$question" - if [ ! -z "$default_answer" ] + if [ -n "$default_answer" ] then local answers="Y y N n" - [[ "$answers" =~ "$default_answer" ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; } + [[ "$answers" =~ $default_answer ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; } fi local default="Y" @@ -156,12 +156,13 @@ function ask(){ local other="n" [ "$default" == "N" ] && other="y" - local prompt=$(info "$question (${default}/${other})> ") + local prompt + prompt=$(info "$question (${default}/${other})> ") local res="none" while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ]; do - read -p "$prompt" res + read -r -p "$prompt" res res=$(echo "$res" | tr '[:lower:]' '[:upper:]') done @@ -170,36 +171,31 @@ function ask(){ [ "$res" == "Y" ] } -function check_and_trap() { - local sigs="${@:2:${#@}}" - local traps="$(trap -p $sigs)" - [[ $traps ]] && die "Attempting to overwrite existing $sigs trap: $traps" - trap $@ -} - -function check_and_force_trap() { - local sigs="${@:2:${#@}}" - local traps="$(trap -p $sigs)" - [[ $traps ]] && warn "Attempting to overwrite existing $sigs trap: $traps" - trap $@ -} - function insert_quotes_on_spaces(){ # It inserts quotes between arguments. # Useful to preserve quotes on command # to be used inside sh -c/bash -c - C='' + local C="" whitespace="[[:space:]]" for i in "$@" do if [[ $i =~ $whitespace ]] then - C="$C \"$i\"" + temp_C="\"$i\"" else - C="$C $i" + temp_C="$i" fi + + # Handle edge case when C is empty to avoid adding an extra space + if [[ -z $C ]] + then + C="$temp_C" + else + C="$C $temp_C" + fi + done - echo $C + echo "$C" } contains_element () { diff --git a/tests/checkstyle/checkstyle.sh b/tests/checkstyle/checkstyle.sh index 27cb82a..4f71965 100755 --- a/tests/checkstyle/checkstyle.sh +++ b/tests/checkstyle/checkstyle.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash +# shellcheck disable=SC1091 -source "$(dirname $0)/../utils/utils.sh" +source "$(dirname "$0")/../utils/utils.sh" # Disable the exiterr set +e @@ -10,12 +11,12 @@ function oneTimeSetUp(){ } function test_check_no_tabs(){ - assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../bin/* - assertEquals "" "$(cat $STDOUTF)" - assertEquals "" "$(cat $STDERRF)" - assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../lib/* - assertEquals "" "$(cat $STDOUTF)" - assertEquals "" "$(cat $STDERRF)" + assertCommandFailOnStatus 1 grep -R "$(printf '\t')" "$(dirname "$0")"/../../bin/* + assertEquals "" "$(cat "$STDOUTF")" + assertEquals "" "$(cat "$STDERRF")" + assertCommandFailOnStatus 1 grep -R "$(printf '\t')" "$(dirname "$0")"/../../lib/* + assertEquals "" "$(cat "$STDOUTF")" + assertEquals "" "$(cat "$STDERRF")" } -source $(dirname $0)/../utils/shunit2 +source "$(dirname "$0")"/../utils/shunit2 diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 44999f7..f634b5b 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -1,6 +1,7 @@ #!/bin/bash +# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) +JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -29,32 +30,33 @@ function tearDown(){ function init_mocks() { chroot_cmd() { [ "$JUNEST_ENV" != "1" ] && return 1 - echo "chroot_cmd $@" + echo "chroot_cmd $*" } + # shellcheck disable=SC2034 GROOT=chroot_cmd mychroot() { - echo mychroot $@ + echo mychroot "$*" } } function test_run_env_as_groot_cmd(){ assertCommandSuccess run_env_as_groot "" "" "false" pwd - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" } 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" "$(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" "$(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(){ assertCommandSuccess run_env_as_groot "" "" "true" pwd - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -74,27 +76,27 @@ function test_run_env_as_groot_nested_env(){ function test_run_env_as_groot_cmd_with_backend_args(){ assertCommandSuccess run_env_as_groot "" "-n -b /home/blah" "false" pwd - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" } function test_run_env_as_chroot_cmd(){ assertCommandSuccess run_env_as_chroot "" "" "false" pwd - assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" } function test_run_env_as_chroot_no_cmd(){ assertCommandSuccess run_env_as_chroot "" "" "false" "" - assertEquals "chroot_cmd $JUNEST_HOME /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" "$(cat $STDOUTF)" + assertEquals "mychroot $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")" } function test_run_env_as_chroot_no_copy(){ assertCommandSuccess run_env_as_chroot "" "" "true" pwd - assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -114,7 +116,7 @@ function test_run_env_as_choot_nested_env(){ function test_run_env_as_chroot_cmd_with_backend_args(){ assertCommandSuccess run_env_as_chroot "" "-n -b /home/blah" "false" pwd - assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)" + assertEquals "chroot_cmd -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" } -source $JUNEST_ROOT/tests/utils/shunit2 +source "$JUNEST_ROOT"/tests/utils/shunit2 diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index 7037f98..d0a6c0b 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -1,6 +1,7 @@ #!/bin/bash +# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) +JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -21,52 +22,55 @@ function oneTimeTearDown(){ function setUp(){ ld_exec_mock() { - echo "ld_exec $@" + echo "ld_exec $*" } ld_exec_mock_false() { - echo "ld_exec $@" + echo "ld_exec $*" return 1 } + # shellcheck disable=SC2034 LD_EXEC=ld_exec_mock unshare_mock() { - echo "unshare $@" + echo "unshare $*" } + # shellcheck disable=SC2034 UNSHARE=unshare_mock bwrap_mock() { - echo "bwrap $@" + echo "bwrap $*" } + # shellcheck disable=SC2034 BWRAP=bwrap_mock } function test_ln(){ - LN=echo assertCommandSuccess ln_cmd -s ln_file new_file - assertEquals "-s ln_file new_file" "$(cat $STDOUTF)" + LN="echo" assertCommandSuccess ln_cmd -s ln_file new_file + assertEquals "-s ln_file new_file" "$(cat "$STDOUTF")" LN=false assertCommandSuccess ln_cmd -s ln_file new_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)" + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat "$STDOUTF")" LN=false LD_EXEC=false assertCommandFail ln_cmd } function test_getent(){ - GETENT=echo assertCommandSuccess getent_cmd passwd - assertEquals "passwd" "$(cat $STDOUTF)" + 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" 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="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)" + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat "$STDOUTF")" CP=false LD_EXEC=false assertCommandFail cp_cmd } @@ -76,7 +80,9 @@ function test_download(){ CURL=/bin/false assertCommandSuccess download_cmd + # shellcheck disable=SC2034 WGET=/bin/false + # shellcheck disable=SC2034 CURL=/bin/true assertCommandSuccess download_cmd @@ -84,76 +90,77 @@ function test_download(){ } function test_rm(){ - RM=echo assertCommandSuccess rm_cmd rm_file - assertEquals "rm_file" "$(cat $STDOUTF)" + RM="echo" assertCommandSuccess rm_cmd rm_file + assertEquals "rm_file" "$(cat "$STDOUTF")" - RM=false assertCommandSuccess rm_cmd rm_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)" + RM="false" assertCommandSuccess rm_cmd rm_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat "$STDOUTF")" RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file } function test_chown(){ - local id=$(id -u) + local id + id=$(id -u) - CHOWN=echo assertCommandSuccess chown_cmd $id chown_file - assertEquals "$id chown_file" "$(cat $STDOUTF)" + CHOWN="echo" assertCommandSuccess chown_cmd "$id" chown_file + assertEquals "$id chown_file" "$(cat "$STDOUTF")" - CHOWN=false assertCommandSuccess chown_cmd $id chown_file - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)" + CHOWN="false" assertCommandSuccess chown_cmd "$id" chown_file + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat "$STDOUTF")" - CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file + CHOWN=false LD_EXEC=false assertCommandFail chown_cmd "$id" chown_file } function test_mkdir(){ - MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir - assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)" + MKDIR="echo" assertCommandSuccess mkdir_cmd -p new_dir/new_dir + assertEquals "-p new_dir/new_dir" "$(cat "$STDOUTF")" MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir - assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)" + assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat "$STDOUTF")" MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir } function test_zgrep(){ - ZGREP=echo assertCommandSuccess zgrep_cmd new_file - assertEquals "new_file" "$(cat $STDOUTF)" + ZGREP="echo" assertCommandSuccess zgrep_cmd new_file + assertEquals "new_file" "$(cat "$STDOUTF")" - mkdir -p ${JUNEST_HOME}/usr/bin - touch ${JUNEST_HOME}/usr/bin/false - chmod +x ${JUNEST_HOME}/usr/bin/false + mkdir -p "${JUNEST_HOME}"/usr/bin + touch "${JUNEST_HOME}"/usr/bin/false + chmod +x "${JUNEST_HOME}"/usr/bin/false - echo -e "#!/bin/bash\necho zgrep" > ${JUNEST_HOME}/usr/bin/false + echo -e "#!/bin/bash\necho zgrep" > "${JUNEST_HOME}"/usr/bin/false ZGREP=false assertCommandSuccess zgrep_cmd new_file - assertEquals "zgrep" "$(cat $STDOUTF)" + assertEquals "zgrep" "$(cat "$STDOUTF")" - echo -e "#!/bin/bash\nexit 1" > ${JUNEST_HOME}/usr/bin/false + echo -e "#!/bin/bash\nexit 1" > "${JUNEST_HOME}"/usr/bin/false ZGREP=false assertCommandFail zgrep_cmd new_file } function test_unshare(){ assertCommandSuccess unshare_cmd new_program - assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE --user /bin/sh -c :\nld_exec ${JUNEST_HOME}/usr/bin/$UNSHARE new_program")" "$(cat "$STDOUTF")" LD_EXEC=ld_exec_mock_false assertCommandSuccess unshare_cmd new_program - assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh -c :\nunshare --user /bin/sh -c :\nunshare new_program")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "ld_exec ${JUNEST_HOME}/usr/bin/unshare_mock --user /bin/sh -c :\nunshare --user /bin/sh -c :\nunshare new_program")" "$(cat "$STDOUTF")" UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program } function test_bwrap(){ assertCommandSuccess bwrap_cmd new_program - assertEquals "$(echo -e "ld_exec $BWRAP --dev-bind / / /bin/sh -c :\nld_exec $BWRAP new_program")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "ld_exec $BWRAP --dev-bind / / /bin/sh -c :\nld_exec $BWRAP new_program")" "$(cat "$STDOUTF")" BWRAP=false LD_EXEC=false assertCommandFail bwrap_cmd new_program } function test_chroot(){ - CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root - assertEquals "root" "$(cat $STDOUTF)" + CLASSIC_CHROOT="echo" assertCommandSuccess chroot_cmd root + assertEquals "root" "$(cat "$STDOUTF")" CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root - assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat $STDOUTF)" + assertEquals "ld_exec $JUNEST_HOME/usr/bin/false root" "$(cat "$STDOUTF")" CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } @@ -170,34 +177,35 @@ function test_proot_cmd_seccomp(){ } PROOT=envv assertCommandSuccess proot_cmd cmd - assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" + assertEquals "" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" envv(){ env | grep "^PROOT_NO_SECCOMP" } + # shellcheck disable=SC2034 PROOT=envv assertCommandSuccess proot_cmd cmd # The variable PROOT_NO_SECCOMP will be produced # twice due to the fallback mechanism assertEquals "PROOT_NO_SECCOMP=1 -PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" +PROOT_NO_SECCOMP=1" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" } function test_copy_passwd_and_group(){ getent_cmd_mock() { - echo $@ + echo "$*" } GETENT=getent_cmd_mock assertCommandSuccess copy_passwd_and_group - assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)" - assertEquals "group" "$(cat $JUNEST_HOME/etc/group)" + assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat "$JUNEST_HOME"/etc/passwd)" + assertEquals "group" "$(cat "$JUNEST_HOME"/etc/group)" } function test_copy_passwd_and_group_fallback(){ cp_cmd_mock() { - echo $@ + echo "$*" } CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess copy_passwd_and_group - assertEquals "$(echo -e "-f /etc/passwd $JUNEST_HOME//etc/passwd\n-f /etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "-f /etc/passwd $JUNEST_HOME//etc/passwd\n-f /etc/group $JUNEST_HOME//etc/group")" "$(cat "$STDOUTF")" } function test_copy_passwd_and_group_failure(){ @@ -213,14 +221,14 @@ function test_nested_env_not_set_variable(){ } function test_check_same_arch_not_same(){ - echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + echo "JUNEST_ARCH=XXX" > "${JUNEST_HOME}"/etc/junest/info assertCommandFailOnStatus 104 check_same_arch } function test_check_same_arch(){ - echo "JUNEST_ARCH=$ARCH" > ${JUNEST_HOME}/etc/junest/info + echo "JUNEST_ARCH=$ARCH" > "${JUNEST_HOME}"/etc/junest/info assertCommandSuccess check_same_arch } -source $JUNEST_ROOT/tests/utils/shunit2 +source "$JUNEST_ROOT"/tests/utils/shunit2 diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index 123b4bd..086062f 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -1,8 +1,10 @@ #!/bin/bash -source "$(dirname $0)/../utils/utils.sh" +# shellcheck disable=SC1091 -JUNEST_BASE="$(dirname $0)/../.." -source $JUNEST_BASE/bin/junest -h &> /dev/null +source "$(dirname "$0")/../utils/utils.sh" + +JUNEST_BASE="$(dirname "$0")/../.." +source "$JUNEST_BASE"/bin/junest -h &> /dev/null # Disable the exiterr set +e @@ -37,42 +39,42 @@ function setUp(){ local backend_args="$2" local no_copy_files="$3" shift 3 - echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" + echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$*)" } function run_env_as_groot(){ local backend_command="$1" local backend_args="$2" local no_copy_files="$3" shift 3 - echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$@)" + echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$*)" } function run_env_as_chroot(){ local backend_command="$1" local backend_args="$2" local no_copy_files="$3" shift 3 - echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$@)" + echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$*)" } function run_env_as_proot_user(){ local backend_command="$1" local backend_args="$2" local no_copy_files="$3" shift 3 - echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$@)" + echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$*)" } function run_env_as_bwrap_fakeroot(){ local backend_command="$1" local backend_args="$2" local no_copy_files="$3" shift 3 - echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$@)" + echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$*)" } function run_env_as_bwrap_user(){ local backend_command="$1" local backend_args="$2" local no_copy_files="$3" shift 3 - echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$@)" + echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$*)" } function is_env_installed(){ return 0 @@ -84,25 +86,25 @@ function setUp(){ function test_help(){ assertCommandSuccess main -h - assertEquals "usage" "$(cat $STDOUTF)" + assertEquals "usage" "$(cat "$STDOUTF")" assertCommandSuccess main --help - assertEquals "usage" "$(cat $STDOUTF)" + assertEquals "usage" "$(cat "$STDOUTF")" } function test_version(){ assertCommandSuccess main -V - assertEquals "version" "$(cat $STDOUTF)" + assertEquals "version" "$(cat "$STDOUTF")" assertCommandSuccess main --version - assertEquals "version" "$(cat $STDOUTF)" + assertEquals "version" "$(cat "$STDOUTF")" } function test_build_image_env(){ assertCommandSuccess main b - assertEquals "build_image_env(false)" "$(cat $STDOUTF)" + assertEquals "build_image_env(false)" "$(cat "$STDOUTF")" assertCommandSuccess main build - assertEquals "build_image_env(false)" "$(cat $STDOUTF)" + assertEquals "build_image_env(false)" "$(cat "$STDOUTF")" assertCommandSuccess main b -n - assertEquals "build_image_env(true)" "$(cat $STDOUTF)" + assertEquals "build_image_env(true)" "$(cat "$STDOUTF")" assertCommandSuccess main build --disable-check - assertEquals "build_image_env(true)" "$(cat $STDOUTF)" + assertEquals "build_image_env(true)" "$(cat "$STDOUTF")" } function test_create_wrappers(){ @@ -111,26 +113,26 @@ function test_create_wrappers(){ echo "create_wrappers($force)" } assertCommandSuccess main create-bin-wrappers - assertEquals "create_wrappers(false)" "$(cat $STDOUTF)" + assertEquals "create_wrappers(false)" "$(cat "$STDOUTF")" assertCommandSuccess main create-bin-wrappers --force - assertEquals "create_wrappers(true)" "$(cat $STDOUTF)" + assertEquals "create_wrappers(true)" "$(cat "$STDOUTF")" } function test_delete_env(){ assertCommandSuccess main s -d - assertEquals "delete_env" "$(cat $STDOUTF)" + assertEquals "delete_env" "$(cat "$STDOUTF")" assertCommandSuccess main setup --delete - assertEquals "delete_env" "$(cat $STDOUTF)" + assertEquals "delete_env" "$(cat "$STDOUTF")" } function test_setup_env_from_file(){ is_env_installed(){ return 1 } assertCommandSuccess main s -i myimage - assertEquals "setup_env_from_file(myimage)" "$(cat $STDOUTF)" + assertEquals "setup_env_from_file(myimage)" "$(cat "$STDOUTF")" assertCommandSuccess main setup --from-file myimage - assertEquals "setup_env_from_file(myimage)" "$(cat $STDOUTF)" + assertEquals "setup_env_from_file(myimage)" "$(cat "$STDOUTF")" is_env_installed(){ return 0 @@ -143,13 +145,13 @@ function test_setup_env(){ return 1 } assertCommandSuccess main s - assertEquals "setup_env()" "$(cat $STDOUTF)" + assertEquals "setup_env()" "$(cat "$STDOUTF")" assertCommandSuccess main setup - assertEquals "setup_env()" "$(cat $STDOUTF)" + assertEquals "setup_env()" "$(cat "$STDOUTF")" assertCommandSuccess main s -a arm - assertEquals "setup_env(arm)" "$(cat $STDOUTF)" + assertEquals "setup_env(arm)" "$(cat "$STDOUTF")" assertCommandSuccess main setup --arch arm - assertEquals "setup_env(arm)" "$(cat $STDOUTF)" + assertEquals "setup_env(arm)" "$(cat "$STDOUTF")" is_env_installed(){ return 0 @@ -159,25 +161,25 @@ function test_setup_env(){ function test_run_env_as_proot_fakeroot(){ assertCommandSuccess main p -f - assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot --fakeroot - assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main p -f -n - assertEquals "run_env_as_proot_fakeroot(,,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,true,)" "$(cat "$STDOUTF")" assertCommandSuccess main p -f --backend-command blah - assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -f --backend-command blah - assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -f -b "-b arg" - assertEquals "run_env_as_proot_fakeroot(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -f -b "-b arg" -- command -kv - assertEquals "run_env_as_proot_fakeroot(,-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -f command --as - assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -f -- command --as - assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" is_env_installed(){ return 1 @@ -187,23 +189,23 @@ function test_run_env_as_proot_fakeroot(){ function test_run_env_as_user(){ assertCommandSuccess main proot - assertEquals "run_env_as_proot_user(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main p -n - assertEquals "run_env_as_proot_user(,,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,true,)" "$(cat "$STDOUTF")" assertCommandSuccess main p --backend-command blah - assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot --backend-command blah - assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -b "-b arg" - assertEquals "run_env_as_proot_user(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -b "-b arg" -- command -ll - assertEquals "run_env_as_proot_user(,-b arg,false,command -ll)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,-b arg,false,command -ll)" "$(cat "$STDOUTF")" assertCommandSuccess main proot command -ls - assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat "$STDOUTF")" assertCommandSuccess main proot -- command -ls - assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat $STDOUTF)" + assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat "$STDOUTF")" is_env_installed(){ return 1 @@ -213,21 +215,21 @@ function test_run_env_as_user(){ function test_run_env_as_groot(){ assertCommandSuccess main g - assertEquals "run_env_as_groot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main g -n - assertEquals "run_env_as_groot(,,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,true,)" "$(cat "$STDOUTF")" assertCommandSuccess main g -b "-b arg" - assertEquals "run_env_as_groot(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main g --backend-command blah - assertEquals "run_env_as_groot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main groot --backend-command blah - assertEquals "run_env_as_groot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main groot command - assertEquals "run_env_as_groot(,,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")" assertCommandSuccess main groot -- command - assertEquals "run_env_as_groot(,,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")" is_env_installed(){ return 1 @@ -237,19 +239,19 @@ function test_run_env_as_groot(){ function test_run_env_as_chroot(){ assertCommandSuccess main r - assertEquals "run_env_as_chroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main r -b "-b arg" - assertEquals "run_env_as_chroot(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main r --backend-command blah - assertEquals "run_env_as_chroot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main root --backend-command blah - assertEquals "run_env_as_chroot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main root command - assertEquals "run_env_as_chroot(,,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")" assertCommandSuccess main root -- command - assertEquals "run_env_as_chroot(,,false,command)" "$(cat $STDOUTF)" + assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")" is_env_installed(){ return 1 @@ -259,39 +261,39 @@ function test_run_env_as_chroot(){ function test_run_env_as_bwrap_fakeroot(){ assertCommandSuccess main n -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -n -f - assertEquals "run_env_as_bwrap_fakeroot(,,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,true,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -f -b "-b arg" - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -f -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -f command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -f -- command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -f --backend-command blah - assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -f --backend-command blah - assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -f -b "-b arg" - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -f -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" assertCommandSuccess main -f command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main -f -- command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" is_env_installed(){ return 1 @@ -301,39 +303,39 @@ function test_run_env_as_bwrap_fakeroot(){ function test_run_env_as_bwrap_user(){ assertCommandSuccess main n - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -n - assertEquals "run_env_as_bwrap_user(,,true,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,true,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -b "-b arg" - assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" assertCommandSuccess main ns command --as - assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main ns -- command --as - assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main ns --backend-command blah - assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main --backend-command blah - assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -b "-b arg" - assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,)" "$(cat "$STDOUTF")" assertCommandSuccess main -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" assertCommandSuccess main command --as - assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" assertCommandSuccess main -- command --as - assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat $STDOUTF)" + assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" is_env_installed(){ return 1 @@ -353,4 +355,4 @@ function test_invalid_option(){ assertCommandFail main s --no-option } -source $(dirname $0)/../utils/shunit2 +source "$(dirname "$0")"/../utils/shunit2 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 72b9035..373c1be 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -1,6 +1,7 @@ #!/bin/bash +# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) +JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -16,7 +17,7 @@ function oneTimeSetUp(){ ## Mock functions ## function init_mocks() { function bwrap_cmd(){ - echo "$BWRAP $@" + echo "$BWRAP $*" } } @@ -39,16 +40,16 @@ function tearDown(){ } function _test_copy_common_files() { - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat "${JUNEST_HOME}"/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat "${JUNEST_HOME}"/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat "${JUNEST_HOME}"/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat "${JUNEST_HOME}"/etc/resolv.conf)" } function _test_copy_remaining_files() { - [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" - [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" - [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat ${JUNEST_HOME}/etc/networks)" + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat "${JUNEST_HOME}"/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat "${JUNEST_HOME}"/etc/netgroup)" + [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat "${JUNEST_HOME}"/etc/networks)" [[ -e ${JUNEST_HOME}/etc/passwd ]] assertEquals 0 $? @@ -59,7 +60,7 @@ function _test_copy_remaining_files() { function test_is_user_namespace_enabled_no_config_file(){ CONFIG_PROC_FILE="blah" CONFIG_BOOT_FILE="blah" - assertCommandFailOnStatus $NOT_EXISTING_FILE _is_user_namespace_enabled + assertCommandFailOnStatus "$NOT_EXISTING_FILE" _is_user_namespace_enabled } function test_is_user_namespace_enabled_no_config(){ @@ -67,7 +68,7 @@ function test_is_user_namespace_enabled_no_config(){ gzip config CONFIG_PROC_FILE="config.gz" CONFIG_BOOT_FILE="blah" - assertCommandFailOnStatus $NO_CONFIG_FOUND _is_user_namespace_enabled + assertCommandFailOnStatus "$NO_CONFIG_FOUND" _is_user_namespace_enabled } function test_is_user_namespace_enabled_with_config(){ @@ -86,13 +87,15 @@ function test_is_user_namespace_enabled_with_userns_clone_file_disabled(){ CONFIG_BOOT_FILE="blah" PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" echo "0" > $PROC_USERNS_CLONE_FILE - assertCommandFailOnStatus $UNPRIVILEGED_USERNS_DISABLED _is_user_namespace_enabled + assertCommandFailOnStatus "$UNPRIVILEGED_USERNS_DISABLED" _is_user_namespace_enabled } function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ echo "CONFIG_USER_NS=y" > config gzip config + # shellcheck disable=SC2034 CONFIG_PROC_FILE="config.gz" + # shellcheck disable=SC2034 CONFIG_BOOT_FILE="blah" PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" echo "1" > $PROC_USERNS_CLONE_FILE @@ -101,21 +104,21 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mybwrap $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")" _test_copy_common_files } function test_run_env_as_bwrap_user() { assertCommandSuccess run_env_as_bwrap_user "" "" "false" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -123,7 +126,7 @@ function test_run_env_as_bwrap_user() { function test_run_env_as_bwrap_user_with_backend_command() { assertCommandSuccess run_env_as_bwrap_user "mybwrap" "" "false" - assertEquals "mybwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "mybwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -131,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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -157,7 +160,7 @@ function test_run_env_as_bwrap_fakeroot_no_copy() { function test_run_env_as_bwrap_user_no_copy() { assertCommandSuccess run_env_as_bwrap_user "" "" "true" "" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -183,14 +186,14 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat "$STDOUTF")" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args() { assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -198,14 +201,14 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" _test_copy_common_files } function test_run_env_as_bwrap_user_with_command() { assertCommandSuccess run_env_as_bwrap_user "" "" "false" "ls -la" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -213,14 +216,14 @@ 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 $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" _test_copy_common_files } function test_run_env_as_bwrap_user_with_backend_args_and_command() { assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" "ls -la" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)" + assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -233,9 +236,10 @@ function test_run_env_as_bwrap_fakeroot_nested_env(){ } function test_run_env_as_bwrap_user_nested_env(){ + # shellcheck disable=SC2034 JUNEST_ENV=1 assertCommandFailOnStatus 106 run_env_as_bwrap_user "" "" "false" "" unset JUNEST_ENV } -source $JUNEST_ROOT/tests/utils/shunit2 +source "$JUNEST_ROOT"/tests/utils/shunit2 diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index 9e152f9..2217150 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -1,6 +1,7 @@ #!/bin/bash +# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) +JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -30,16 +31,16 @@ function tearDown(){ } function _test_copy_common_files() { - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat "${JUNEST_HOME}"/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat "${JUNEST_HOME}"/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat "${JUNEST_HOME}"/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat "${JUNEST_HOME}"/etc/resolv.conf)" } function _test_copy_remaining_files() { - [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" - [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" - [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat ${JUNEST_HOME}/etc/networks)" + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat "${JUNEST_HOME}"/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat "${JUNEST_HOME}"/etc/netgroup)" + [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat "${JUNEST_HOME}"/etc/networks)" [[ -e ${JUNEST_HOME}/etc/passwd ]] assertEquals 0 $? @@ -49,14 +50,16 @@ function _test_copy_remaining_files() { function test_run_env_as_proot_user(){ _run_env_with_qemu() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -64,14 +67,16 @@ function test_run_env_as_proot_user(){ function test_run_env_as_proot_user_with_backend_command(){ _run_env_with_qemu() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" - assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -79,10 +84,12 @@ function test_run_env_as_proot_user_with_backend_command(){ function test_run_env_as_proot_user_no_copy(){ _run_env_with_qemu() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -114,28 +121,33 @@ function test_run_env_as_proot_user_nested_env(){ function test_run_env_as_proot_fakeroot(){ _run_env_with_qemu() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" - assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files } function test_run_env_as_proot_fakeroot_with_backend_command(){ _run_env_with_qemu() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + # shellcheck disable=SC2034 SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" - assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files } @@ -148,41 +160,51 @@ function test_run_env_as_proot_fakeroot_nested_env(){ function test_run_env_with_quotes(){ _run_env_with_qemu() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" - assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" + assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" } function test_run_env_with_proot_args(){ proot_cmd() { [ "$JUNEST_ENV" != "1" ] && return 1 - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } assertCommandSuccess _run_env_with_proot "" "--help" - assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)" + assertEquals "--help /bin/sh --login" "$(cat "$STDOUTF")" assertCommandSuccess _run_env_with_proot "" "--help" mycommand - assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)" + assertEquals "--help /bin/sh --login -c mycommand" "$(cat "$STDOUTF")" assertCommandFail _run_env_with_proot } function test_qemu() { - echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info + echo "JUNEST_ARCH=arm" > "${JUNEST_HOME}"/etc/junest/info rm_cmd() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } ln_cmd() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } _run_env_with_proot() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" "" - assertEquals "$(echo -e "-s $JUNEST_HOME/bin/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" + assertEquals "$(echo -e "-s $JUNEST_HOME/bin/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat "$STDOUTF")" } -source $JUNEST_ROOT/tests/utils/shunit2 +source "$JUNEST_ROOT"/tests/utils/shunit2 diff --git a/tests/unit-tests/test-setup.sh b/tests/unit-tests/test-setup.sh index a15dbca..d8c2456 100755 --- a/tests/unit-tests/test-setup.sh +++ b/tests/unit-tests/test-setup.sh @@ -1,6 +1,7 @@ #!/bin/bash +# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) +JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -26,24 +27,26 @@ function tearDown(){ } function test_is_env_installed(){ - rm -rf $JUNEST_HOME/* + rm -rf "${JUNEST_HOME:?}"/* assertCommandFail is_env_installed - touch $JUNEST_HOME/just_file + touch "$JUNEST_HOME"/just_file assertCommandSuccess is_env_installed } function test_setup_env(){ - rm -rf $JUNEST_HOME/* + rm -rf "${JUNEST_HOME:?}"/* wget_mock(){ # Proof that the setup is happening # inside $JUNEST_TEMPDIR - local cwd=${PWD#${JUNEST_TEMPDIR}} - local parent_dir=${PWD%${cwd}} + local cwd=${PWD#"${JUNEST_TEMPDIR}"} + local parent_dir=${PWD%"${cwd}"} assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file + tar -czvf "${CMD}-${ARCH}".tar.gz file } + # shellcheck disable=SC2034 WGET=wget_mock + # shellcheck disable=SC2119 setup_env 1> /dev/null assertTrue "[ -e $JUNEST_HOME/file ]" @@ -52,10 +55,10 @@ function test_setup_env(){ function test_setup_env_from_file(){ - rm -rf $JUNEST_HOME/* + rm -rf "${JUNEST_HOME:?}"/* touch file - tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null - assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz + tar -czvf "${CMD}-${ARCH}".tar.gz file 1> /dev/null + assertCommandSuccess setup_env_from_file "${CMD}-${ARCH}.tar.gz" assertTrue "[ -e $JUNEST_HOME/file ]" } @@ -64,10 +67,10 @@ function test_setup_env_from_file_not_existing_file(){ } function test_setup_env_from_file_with_absolute_path(){ - rm -rf $JUNEST_HOME/* + rm -rf "${JUNEST_HOME:?}"/* touch file - tar -czf ${CMD}-${ARCH}.tar.gz file - assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz + tar -czf "${CMD}-${ARCH}".tar.gz file + assertCommandSuccess setup_env_from_file "${CMD}-${ARCH}.tar.gz" assertTrue "[ -e $JUNEST_HOME/file ]" } @@ -78,4 +81,4 @@ function test_delete_env(){ assertCommandFail is_env_installed } -source $JUNEST_ROOT/tests/utils/shunit2 +source "$JUNEST_ROOT"/tests/utils/shunit2 diff --git a/tests/unit-tests/test-utils.sh b/tests/unit-tests/test-utils.sh index c0b1ebf..03e602a 100755 --- a/tests/unit-tests/test-utils.sh +++ b/tests/unit-tests/test-utils.sh @@ -1,10 +1,13 @@ #!/bin/bash -source "$(dirname $0)/../utils/utils.sh" +# shellcheck disable=SC1091 + +source "$(dirname "$0")/../utils/utils.sh" unset HOME -export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX) +export HOME +HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX) -source "$(dirname $0)/../../lib/utils/utils.sh" +source "$(dirname "$0")/../../lib/utils/utils.sh" # Disable the exiterr set +e @@ -20,37 +23,42 @@ function test_check_not_null(){ function test_echoerr(){ assertCommandSuccess echoerr "Test" - assertEquals "Test" "$(cat $STDERRF)" + assertEquals "Test" "$(cat "$STDERRF")" } function test_error(){ assertCommandSuccess error "Test" - local expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$expected" "$(cat $STDERRF)" + local expected + expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat "$STDERRF")" } function test_warn(){ assertCommandSuccess warn "Test" - local expected=$(echo -e "\033[1;33mTest\033[0m") - assertEquals "$expected" "$(cat $STDERRF)" + local expected + expected=$(echo -e "\033[1;33mTest\033[0m") + assertEquals "$expected" "$(cat "$STDERRF")" } function test_info(){ assertCommandSuccess info "Test" - local expected=$(echo -e "\033[1;36mTest\033[0m") - assertEquals "$expected" "$(cat $STDOUTF)" + local expected + expected=$(echo -e "\033[1;36mTest\033[0m") + assertEquals "$expected" "$(cat "$STDOUTF")" } function test_die(){ assertCommandFail die "Test" - local expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$expected" "$(cat $STDERRF)" + local expected + expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat "$STDERRF")" } function test_die_on_status(){ assertCommandFailOnStatus 222 die_on_status 222 "Test" - local expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$expected" "$(cat $STDERRF)" + local expected + expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat "$STDERRF")" } function test_ask_null_question(){ @@ -79,34 +87,12 @@ function test_ask_wrong_default_answer() { assertEquals 33 $? } -function test_check_and_trap_fail() { - trap echo EXIT - trap ls QUIT - assertCommandFailOnStatus 1 check_and_trap 'pwd' EXIT QUIT -} - -function test_check_and_trap() { - trap - EXIT QUIT - assertCommandSuccess check_and_trap 'echo' EXIT QUIT -} - -function test_check_and_force_trap_fail() { - trap echo EXIT - trap ls QUIT - assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT -} - -function test_check_and_force_trap() { - trap - EXIT QUIT - assertCommandSuccess check_and_force_trap 'echo' EXIT QUIT -} - function test_insert_quotes_on_spaces(){ assertCommandSuccess insert_quotes_on_spaces this is "a test" - assertEquals "this is \"a test\"" "$(cat $STDOUTF)" + assertEquals "this is \"a test\"" "$(cat "$STDOUTF")" assertCommandSuccess insert_quotes_on_spaces this is 'a test' - assertEquals "this is \"a test\"" "$(cat $STDOUTF)" + assertEquals "this is \"a test\"" "$(cat "$STDOUTF")" } function test_contains_element(){ @@ -116,4 +102,4 @@ function test_contains_element(){ assertCommandFailOnStatus 1 contains_element "blabla" "${array[@]}" } -source $(dirname $0)/../utils/shunit2 +source "$(dirname "$0")"/../utils/shunit2 diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index 9daf0f9..af7aae2 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -1,7 +1,9 @@ #!/bin/bash -source "$(dirname $0)/../utils/utils.sh" +# shellcheck disable=SC1091 -source "$(dirname $0)/../../lib/core/wrappers.sh" +source "$(dirname "$0")/../utils/utils.sh" + +source "$(dirname "$0")/../../lib/core/wrappers.sh" # Disable the exiterr set +e @@ -20,61 +22,61 @@ function tearDown(){ function test_create_wrappers_empty_bin(){ assertCommandSuccess create_wrappers - assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat "$STDOUTF")" assertTrue "bin_wrappers does not exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" } function test_create_wrappers_not_executable_file(){ - touch $JUNEST_HOME/usr/bin/myfile + touch "$JUNEST_HOME"/usr/bin/myfile assertCommandSuccess create_wrappers - assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat "$STDOUTF")" assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" } function test_create_wrappers_executable_file(){ - touch $JUNEST_HOME/usr/bin/myfile - chmod +x $JUNEST_HOME/usr/bin/myfile + touch "$JUNEST_HOME"/usr/bin/myfile + chmod +x "$JUNEST_HOME"/usr/bin/myfile assertCommandSuccess create_wrappers - assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat "$STDOUTF")" assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" } function test_create_wrappers_already_exist(){ - touch $JUNEST_HOME/usr/bin/myfile - chmod +x $JUNEST_HOME/usr/bin/myfile - mkdir -p $JUNEST_HOME/usr/bin_wrappers - echo "original" > $JUNEST_HOME/usr/bin_wrappers/myfile - chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile + touch "$JUNEST_HOME"/usr/bin/myfile + chmod +x "$JUNEST_HOME"/usr/bin/myfile + mkdir -p "$JUNEST_HOME"/usr/bin_wrappers + echo "original" > "$JUNEST_HOME"/usr/bin_wrappers/myfile + chmod +x "$JUNEST_HOME"/usr/bin_wrappers/myfile assertCommandSuccess create_wrappers false - assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat "$STDOUTF")" assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" - assertEquals "original" "$(cat $JUNEST_HOME/usr/bin_wrappers/myfile)" + assertEquals "original" "$(cat "$JUNEST_HOME"/usr/bin_wrappers/myfile)" } function test_create_wrappers_forced_already_exist(){ - echo "new" > $JUNEST_HOME/usr/bin/myfile - chmod +x $JUNEST_HOME/usr/bin/myfile - mkdir -p $JUNEST_HOME/usr/bin_wrappers - echo "original" > $JUNEST_HOME/usr/bin_wrappers/myfile - chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile + echo "new" > "$JUNEST_HOME"/usr/bin/myfile + chmod +x "$JUNEST_HOME"/usr/bin/myfile + mkdir -p "$JUNEST_HOME"/usr/bin_wrappers + echo "original" > "$JUNEST_HOME"/usr/bin_wrappers/myfile + chmod +x "$JUNEST_HOME"/usr/bin_wrappers/myfile assertCommandSuccess create_wrappers true - assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat "$STDOUTF")" assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" - assertNotEquals "original" "$(cat $JUNEST_HOME/usr/bin_wrappers/myfile)" + assertNotEquals "original" "$(cat "$JUNEST_HOME"/usr/bin_wrappers/myfile)" } function test_create_wrappers_executable_no_longer_exist(){ - mkdir -p $JUNEST_HOME/usr/bin_wrappers - touch $JUNEST_HOME/usr/bin_wrappers/myfile - chmod +x $JUNEST_HOME/usr/bin_wrappers/myfile + mkdir -p "$JUNEST_HOME"/usr/bin_wrappers + touch "$JUNEST_HOME"/usr/bin_wrappers/myfile + chmod +x "$JUNEST_HOME"/usr/bin_wrappers/myfile assertCommandSuccess create_wrappers - assertEquals "" "$(cat $STDOUTF)" + assertEquals "" "$(cat "$STDOUTF")" assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" } -source $(dirname $0)/../utils/shunit2 +source "$(dirname "$0")"/../utils/shunit2 diff --git a/tests/unit-tests/unit-tests.sh b/tests/unit-tests/unit-tests.sh index acf1bba..e90ed22 100755 --- a/tests/unit-tests/unit-tests.sh +++ b/tests/unit-tests/unit-tests.sh @@ -1,6 +1,7 @@ #!/bin/bash tests_succeded=true -for tst in $(ls $(dirname $0)/test* | grep -v $(basename $0)) +# shellcheck disable=SC2010 +for tst in $(ls "$(dirname "$0")"/test* | grep -v "$(basename "$0")") do $tst || tests_succeded=false done diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index 542af68..ab37bd9 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -1,26 +1,28 @@ +#!/usr/bin/env bash + OLD_CWD=${PWD} function cwdSetUp(){ ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) - cd $ORIGIN_CWD + cd "$ORIGIN_CWD" || return 1 } function cwdTearDown(){ - rm -rf $ORIGIN_CWD - cd $OLD_CWD + rm -rf "$ORIGIN_CWD" + cd "$OLD_CWD" || return 1 } function junestSetUp(){ JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) - mkdir -p ${JUNEST_HOME}/usr/bin - mkdir -p ${JUNEST_HOME}/etc/junest - echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info - mkdir -p ${JUNEST_HOME}/etc/ca-certificates + mkdir -p "${JUNEST_HOME}/usr/bin" + mkdir -p "${JUNEST_HOME}/etc/junest" + echo "JUNEST_ARCH=x86_64" > "${JUNEST_HOME}/etc/junest/info" + mkdir -p "${JUNEST_HOME}/etc/ca-certificates" } function junestTearDown(){ # the CA directories are read only and can be deleted only by changing the mod - [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates - rm -rf $JUNEST_HOME + [ -d "${JUNEST_HOME}/etc/ca-certificates" ] && chmod -R +w "${JUNEST_HOME}/etc/ca-certificates" + rm -rf "$JUNEST_HOME" unset JUNEST_HOME } @@ -32,15 +34,17 @@ function setUpUnitTests(){ } function assertCommandSuccess(){ + # shellcheck disable=SC2091 $(set -e - "$@" > $STDOUTF 2> $STDERRF + "$@" > "$STDOUTF" 2> "$STDERRF" ) assertTrue "The command $1 did not return 0 exit status" $? } function assertCommandFail(){ + # shellcheck disable=SC2091 $(set -e - "$@" > $STDOUTF 2> $STDERRF + "$@" > "$STDOUTF" 2> "$STDERRF" ) assertFalse "The command $1 returned 0 exit status" $? } @@ -50,8 +54,9 @@ function assertCommandFail(){ function assertCommandFailOnStatus(){ local status=$1 shift + # shellcheck disable=SC2091 $(set -e - "$@" > $STDOUTF 2> $STDERRF + "$@" > "$STDOUTF" 2> "$STDERRF" ) - assertEquals $status $? + assertEquals "$status" $? } From 21b5e3fabb4d5d28e82d1225f7eb415f026bc226 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 1 Mar 2022 00:43:02 +0100 Subject: [PATCH 273/326] 7.3.13 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 1cef271..e459e6b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.12 +7.3.13 From 0e6aa260ad59312ced486a5c76185765405deb70 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 23 Apr 2022 16:43:22 +0000 Subject: [PATCH 274/326] Default to ns mode (not fakeroot) for bin wrappers and add sudoj command This is related to #292 --- README.md | 19 ++++++++++++++----- bin/sudoj | 8 ++++++++ lib/checks/check_all.sh | 1 + lib/core/wrappers.sh | 2 +- 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100755 bin/sudoj diff --git a/README.md b/README.md index 458c1ac..da7248e 100644 --- a/README.md +++ b/README.md @@ -110,25 +110,34 @@ used, see the [Usage](#usage) section below. Run JuNest installed programs directly from host OS --------------------------------------- -Installed programs can be accessible directly from host without -entering directly into a JuNest session (no need to call `junest` command). +Program installed within JuNest can be accessible directly from host machine +without entering directly into a JuNest session +(no need to call `junest` command first). For instance, supposing the host OS is an Ubuntu distro you can directly run `pacman` by simply updating the `PATH` variable: ```sh export PATH="$PATH:~/.junest/usr/bin_wrappers" -pacman -S htop +sudoj pacman -S htop htop ``` -By default the wrappers use `"ns --fakeroot"` but you can change it via `JUNEST_ARGS` environment variable. +By default the wrappers use `ns` mode. To use the `ns --fakeroot` you can use the convenient command helper `sudoj`. +For more control on backend mode you can use the `JUNEST_ARGS` environment variable. For instance, if you want to run `iftop` with real root privileges: ``` -pacman -S iftop +sudoj pacman -S iftop sudo JUNEST_ARGS="groot" iftop ``` +Bin wrappers can be always recreated (e.g. in case for some reasons they get +corrupted) with: + +``` +junest create-bin-wrappers -f +``` + Install packages from AUR ------------------------- diff --git a/bin/sudoj b/bin/sudoj new file mode 100755 index 0000000..aa43e15 --- /dev/null +++ b/bin/sudoj @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# +# This file is part of JuNest (https://github.com/fsquillace/junest). +# + +export PATH="${PATH}:${JUNEST_HOME}/usr/bin_wrappers" + +JUNEST_ARGS="ns --fakeroot" "$@" diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index 394309c..2b39f9a 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -24,3 +24,4 @@ sudo -E "$JUNEST_SCRIPT" groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-te # Test the wrappers work "$JUNEST_SCRIPT" create-bin-wrappers --force "$JUNEST_HOME"/usr/bin_wrappers/pacman --help +"${JUNEST_BASE}/bin/sudoj" pacman -Syu diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index da5517f..13b206a 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -36,7 +36,7 @@ function create_wrappers() { cat < "${JUNEST_HOME}/usr/bin_wrappers/${file}" #!/usr/bin/env bash -JUNEST_ARGS=\${JUNEST_ARGS:-ns --fakeroot} +JUNEST_ARGS=\${JUNEST_ARGS:-ns} eval junest "\${JUNEST_ARGS}" -- ${file} "\$(printf "%q" "\$@")" EOF From 73b8bec8db34d1cfb51bf97934ac31a3909f0eaf Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 24 Apr 2022 19:42:10 +0000 Subject: [PATCH 275/326] Fix wrapper when passing multiple arguments and add unit tests This change come from the PR #289 --- lib/core/wrappers.sh | 6 +++--- tests/unit-tests/test-wrappers.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index 13b206a..d6c2f52 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -33,12 +33,12 @@ function create_wrappers() { # Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes # are not recognized normally unless using `eval`. More info here: # https://github.com/fsquillace/junest/issues/262 + # https://github.com/fsquillace/junest/pull/287 cat < "${JUNEST_HOME}/usr/bin_wrappers/${file}" #!/usr/bin/env bash -JUNEST_ARGS=\${JUNEST_ARGS:-ns} - -eval junest "\${JUNEST_ARGS}" -- ${file} "\$(printf "%q" "\$@")" +eval "junest_args_array=(\${JUNEST_ARGS:-ns})" +junest "\${junest_args_array[@]}" -- ${file} "\$@" EOF chmod +x "${JUNEST_HOME}/usr/bin_wrappers/${file}" done diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index af7aae2..ebd1eff 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -43,6 +43,35 @@ function test_create_wrappers_executable_file(){ assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" } +function test_create_wrappers_verify_content(){ + # Test for: + # https://github.com/fsquillace/junest/issues/262 + # https://github.com/fsquillace/junest/issues/292 + touch "$JUNEST_HOME"/usr/bin/myfile + chmod +x "$JUNEST_HOME"/usr/bin/myfile + export JUNEST_ARGS="ns --fakeroot -b '--bind /run /run2'" + assertCommandSuccess create_wrappers + assertEquals "" "$(cat "$STDOUTF")" + + # Mock junest command to capture the actual output generated from myfile script + junest(){ + for arg in "$@" + do + echo "$arg" + done + } + assertEquals "ns +--fakeroot +-b +--bind /run /run2 +-- +myfile +pacman +-Rsn +neovim +new package" "$(source "$JUNEST_HOME"/usr/bin_wrappers/myfile pacman -Rsn neovim 'new package')" +} + function test_create_wrappers_already_exist(){ touch "$JUNEST_HOME"/usr/bin/myfile chmod +x "$JUNEST_HOME"/usr/bin/myfile From df2fec0a363433bd939b7c7f3f7a18e488fc9e17 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 24 Apr 2022 20:14:12 +0000 Subject: [PATCH 276/326] 7.3.14 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e459e6b..af97984 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.13 +7.3.14 From a9f53042790b832dbb7a8b8d6930cc623dcba882 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 28 Jul 2022 00:07:15 +0200 Subject: [PATCH 277/326] #297 Create bin wrapper for symlinks --- lib/core/wrappers.sh | 7 +++++-- tests/unit-tests/test-wrappers.sh | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index d6c2f52..7e8b3a8 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -25,7 +25,10 @@ function create_wrappers() { cd "${JUNEST_HOME}/usr/bin" || return 1 for file in * do - [[ -x $file ]] || continue + [[ -d $file ]] && continue + # Symlinks outside junest appear as broken even though the are correct + # within a junest session. The following do not skip broken symlinks: + [[ -x $file || -L $file ]] || continue if [[ -e ${JUNEST_HOME}/usr/bin_wrappers/$file ]] && ! $force then continue @@ -47,7 +50,7 @@ EOF cd "${JUNEST_HOME}/usr/bin_wrappers" || return 1 for file in * do - [[ -e ${JUNEST_HOME}/usr/bin/$file ]] || rm -f "$file" + [[ -e ${JUNEST_HOME}/usr/bin/$file || -L ${JUNEST_HOME}/usr/bin/$file ]] || rm -f "$file" done } diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index ebd1eff..8944ee5 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -34,6 +34,22 @@ function test_create_wrappers_not_executable_file(){ assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" } +function test_create_wrappers_directory(){ + mkdir -p "$JUNEST_HOME"/usr/bin/mydir + assertCommandSuccess create_wrappers + assertEquals "" "$(cat "$STDOUTF")" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "mydir wrapper should not exist" "[ ! -e $JUNEST_HOME/usr/bin_wrappers/mydir ]" +} + +function test_create_wrappers_broken_link(){ + ln -s /opt/myapp/bin/cmd "$JUNEST_HOME"/usr/bin/cmd + assertCommandSuccess create_wrappers + assertEquals "" "$(cat "$STDOUTF")" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/bin_wrappers ]" + assertTrue "cmd wrapper should exist" "[ -x $JUNEST_HOME/usr/bin_wrappers/cmd ]" +} + function test_create_wrappers_executable_file(){ touch "$JUNEST_HOME"/usr/bin/myfile chmod +x "$JUNEST_HOME"/usr/bin/myfile From 799d3bdd426a42aaf024948c02f69287cbf71835 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 28 Jul 2022 00:23:48 +0200 Subject: [PATCH 278/326] Install keyring first during the build preparation --- lib/checks/check.sh | 3 --- lib/core/build.sh | 32 ++++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index f984d96..720e9e0 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -52,9 +52,6 @@ PACMAN_OPTIONS="--noconfirm --disable-download-timeout" # shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Syy -# Awk is required for pacman-key -# shellcheck disable=SC2086 -$SUDO pacman $PACMAN_OPTIONS -S gawk $SUDO pacman-key --init if [[ $(uname -m) == *"arm"* ]] diff --git a/lib/core/build.sh b/lib/core/build.sh index 48996f9..8406c97 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -24,7 +24,18 @@ function _install_pkg(){ function _prepare() { # ArchLinux System initialization - sudo pacman --noconfirm -Syu + sudo pacman --noconfirm -Syy + sudo pacman-key --init + if [[ $(uname -m) == *"arm"* ]] + then + sudo pacman -S --noconfirm archlinuxarm-keyring + sudo pacman-key --populate archlinuxarm + else + sudo pacman -S --noconfirm archlinux-keyring + sudo pacman-key --populate archlinux + fi + + sudo pacman --noconfirm -Su sudo pacman -S --noconfirm base-devel sudo pacman -S --noconfirm git arch-install-scripts } @@ -84,21 +95,22 @@ EOT sudo pacman --noconfirm --root "${maindir}"/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." - # gawk command is required for pacman-key - sudo pacman --noconfirm --root "${maindir}"/root -S gawk - # TODO check why the following did not fail! - sudo "${maindir}"/root/bin/groot --no-umount --avoid-bind -b /dev "${maindir}"/root bash -c ' + if [[ $(uname -m) == *"arm"* ]] + then + sudo pacman -S --noconfirm --root "${maindir}"/root archlinuxarm-keyring + else + sudo pacman -S --noconfirm --root "${maindir}"/root archlinux-keyring + fi + sudo mount --bind "${maindir}"/root "${maindir}"/root + sudo arch-chroot "${maindir}"/root bash -c ' set -e pacman-key --init; for keyring_file in /usr/share/pacman/keyrings/*.gpg; do keyring=$(basename $keyring_file | cut -f 1 -d "."); pacman-key --populate $keyring; - done; - [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye' - sudo umount --force --recursive --lazy "${maindir}"/root/dev - sudo umount --force --recursive "${maindir}"/root - sudo pacman --noconfirm --root "${maindir}"/root -Rsn gawk + done;' + sudo umount "${maindir}"/root sudo rm "${maindir}"/root/var/cache/pacman/pkg/* # This is needed on system with busybox tar command. From 77acbf5214ee84841bf7daedcf3dad5d88ce7798 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 5 Aug 2022 18:02:38 +0200 Subject: [PATCH 279/326] 7.3.15 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index af97984..31938fa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.14 +7.3.15 From 56761f6e630f0dd81eaf516a8b698bac11156c1a Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 15 Oct 2022 12:20:44 +0200 Subject: [PATCH 280/326] Change url --- .travis.yml | 5 ----- ci/deploy.sh | 12 +++++------- lib/core/common.sh | 4 ++-- lib/core/setup.sh | 2 +- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ad29e8..b819cbf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,11 +40,6 @@ archlinux: env: matrix: - TRAVIS_BASH_VERSION="4.0" - global: - # AWS_ACCESS_KEY_ID - - secure: "ZotyKKWH5ZrBXDdEnVmV22gbn86BBSiqDZn2d2jVAApgUQdDc3wa7/uYAZP1bts6oQ897nnkUSFHk3M3QAcIoPJerUITTU5D7yjKcFDejgHdpJ4t9XSajmpY9CgKftWapwliWG4wolAKwyAp5GnYqz4GGltHyGxbF/VzUNRF3lw=" - # AWS_SECRET_ACCESS_KEY - - secure: "AWixvJmhr6+rfF4cspMWMjkvLuOsdfNanLK5wrqkgx/0ezDGBBThH0qVhn5Mp1QFM6wVF+LRA6UESNnj0wNwByZHdM6LddkJWlWHb/qkVK+AO4RKUsXJWNyPyOkCNj/WEFpZHQKKUAlEtC8m8AmAcuoi90cr6ih0PXIePRyPFrM=" before_install: - ./ci/install-bash.sh "$TRAVIS_BASH_VERSION" diff --git a/ci/deploy.sh b/ci/deploy.sh index b3ba92c..0d95fa6 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -6,7 +6,8 @@ IMG_PATH=$1 set -ux -MAX_OLD_IMAGES=30 +MAX_OLD_IMAGES=5 +ENDPOINT="https://gateway.storjshare.io" # ARCH can be one of: x86, x86_64, arm HOST_ARCH=$(uname -m) @@ -32,16 +33,13 @@ then # The put is done via a temporary filename in order to prevent outage on the # production file for a longer period of time. img_name=$(basename "${IMG_PATH}") - cp "${IMG_PATH}" "${IMG_PATH}".temp - aws s3 cp "${IMG_PATH}".temp s3://junest-repo/junest/ - aws s3 mv s3://junest-repo/junest/"$img_name".temp s3://junest-repo/junest/"$img_name" + aws s3 --endpoint-url="$ENDPOINT" cp "${IMG_PATH}" s3://junest-repo/junest/ DATE=$(date +'%Y-%m-%d-%H-%M-%S') - - aws s3 cp "s3://junest-repo/junest/$img_name" "s3://junest-repo/junest/${img_name}.${DATE}" + aws s3 --endpoint-url="$ENDPOINT" cp "${IMG_PATH}" "s3://junest-repo/junest/${img_name}.${DATE}" # Cleanup old images - aws s3 ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} aws s3 rm "s3://junest-repo/junest/{}" + aws s3 --endpoint-url="$ENDPOINT" ls s3://junest-repo/junest/junest-${ARCH}.tar.gz. | awk '{print $4}' | head -n -${MAX_OLD_IMAGES} | xargs -I {} aws s3 --endpoint-url="$ENDPOINT" rm "s3://junest-repo/junest/{}" # Test the newly deployed image can be downloaded correctly junest setup diff --git a/lib/core/common.sh b/lib/core/common.sh index a75aff9..0362d69 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -53,7 +53,7 @@ else die "Unknown architecture ${HOST_ARCH}" fi -MAIN_REPO=https://dwa8bhj1f036z.cloudfront.net +MAIN_REPO=https://link.storjshare.io/s/jvb5tgarnjtt565fffa44spvyuga/junest-repo ENV_REPO=${MAIN_REPO}/${CMD} # shellcheck disable=SC2016 DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' @@ -74,7 +74,7 @@ BWRAP="${JUNEST_HOME}/usr/bin/bwrap" PROOT="${JUNEST_HOME}/usr/bin/proot-${ARCH}" GROOT="${JUNEST_HOME}/usr/bin/groot" CLASSIC_CHROOT=chroot -WGET="wget --no-check-certificate" +WGET="wget --content-disposition --no-check-certificate" CURL="curl -L -J -O -k" TAR="tar" CHOWN="chown" diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 749fd66..7138fc4 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -95,7 +95,7 @@ function setup_env(){ info "Downloading ${NAME}..." builtin cd "${maindir}" || return 1 local imagefile=${CMD}-${arch}.tar.gz - download_cmd "${ENV_REPO}/${imagefile}" + download_cmd "${ENV_REPO}/${imagefile}?download=1" info "Installing ${NAME}..." _setup_env "${maindir}/${imagefile}" From f0e82bf8bffc5c03e201879e373e80edf78a0db8 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 15 Oct 2022 12:50:44 +0200 Subject: [PATCH 281/326] 7.3.16 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 31938fa..e32eb5c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.15 +7.3.16 From e5f14c373562519923ea571d21b60e686535d24d Mon Sep 17 00:00:00 2001 From: Spencer Skylar Chan <54919210+schance995@users.noreply.github.com> Date: Sun, 30 Oct 2022 04:14:51 +0000 Subject: [PATCH 282/326] Extend $PATH in common.sh with system $PATH. This lets junest work on non-FHS systems such as GNU Guix. --- lib/core/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index 0362d69..4b2e7ff 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -27,7 +27,7 @@ JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} # The update of the variable PATH ensures that the executables are # found on different locations -PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:${HOME}/.local/bin +PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:${HOME}/.local/bin:"$PATH" # The executable uname is essential in order to get the architecture # of the host system, so a fallback mechanism cannot be used for it. From 2f6e137e7eaab2052a8421cba0e5640d4f28a523 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 5 Nov 2022 13:02:35 +0100 Subject: [PATCH 283/326] 7.3.17 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e32eb5c..9a62cf1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.16 +7.3.17 From 91f95ae4b593e70c06db644e5d54f3b1a0bb21f0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 18 Dec 2022 10:50:22 +0000 Subject: [PATCH 284/326] Change URL to CloudFlare provider --- ci/deploy.sh | 2 +- lib/core/common.sh | 1 + lib/core/setup.sh | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 0d95fa6..78fbd93 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -7,7 +7,7 @@ IMG_PATH=$1 set -ux MAX_OLD_IMAGES=5 -ENDPOINT="https://gateway.storjshare.io" +ENDPOINT="https://8da1bcd84e423c9b013b69fe1e8b4675.r2.cloudflarestorage.com" # ARCH can be one of: x86, x86_64, arm HOST_ARCH=$(uname -m) diff --git a/lib/core/common.sh b/lib/core/common.sh index 4b2e7ff..7062ecd 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -54,6 +54,7 @@ else fi MAIN_REPO=https://link.storjshare.io/s/jvb5tgarnjtt565fffa44spvyuga/junest-repo +MAIN_REPO=https://pub-a2af2344e8554f6c807bc3db355ae622.r2.dev ENV_REPO=${MAIN_REPO}/${CMD} # shellcheck disable=SC2016 DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 7138fc4..749fd66 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -95,7 +95,7 @@ function setup_env(){ info "Downloading ${NAME}..." builtin cd "${maindir}" || return 1 local imagefile=${CMD}-${arch}.tar.gz - download_cmd "${ENV_REPO}/${imagefile}?download=1" + download_cmd "${ENV_REPO}/${imagefile}" info "Installing ${NAME}..." _setup_env "${maindir}/${imagefile}" From 60c7d1c5d0c352c74b3339c867714766a1798294 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 18 Dec 2022 12:37:44 +0000 Subject: [PATCH 285/326] Update keyring --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index b819cbf..e024bbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,11 @@ archlinux: sudo sed -i '/^COMPRESSXZ/s/\xz/xz -T 2/' /etc/makepkg.conf sudo sed -i '$a CFLAGS="$CFLAGS -w"' /etc/makepkg.conf sudo sed -i '$a CXXFLAGS="$CXXFLAGS -w"' /etc/makepkg.conf + sudo pacman -Syy --noconfirm --disable-download-timeout + sudo pacman-key --init + sudo pacman -S --noconfirm --disable-download-timeout archlinux-keyring + sudo pacman-key --populate archlinux + sudo pacman -Su --noconfirm --disable-download-timeout script: # Here do not make any validation (-n) because it will be done later on in the Ubuntu host directly - ./bin/junest build -n From 30967bc15f53e9c3408b0712497628f9aa762010 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 18 Dec 2022 12:49:40 +0000 Subject: [PATCH 286/326] Remove -d option in pacstrap --- ci/deploy.sh | 2 +- lib/core/build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/deploy.sh b/ci/deploy.sh index 78fbd93..a45d0a1 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -28,7 +28,7 @@ fi if [[ "$TRAVIS_BRANCH" == "master" ]] then - export AWS_DEFAULT_REGION=eu-west-1 + export AWS_DEFAULT_REGION=auto # Upload image # The put is done via a temporary filename in order to prevent outage on the # production file for a longer period of time. diff --git a/lib/core/build.sh b/lib/core/build.sh index 8406c97..45f3631 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -62,7 +62,7 @@ function build_image_env(){ info "Installing pacman and its dependencies..." # All the essential executables (ln, mkdir, chown, etc) are in coreutils # bwrap command belongs to bubblewrap - sudo pacstrap -G -M -d "${maindir}"/root pacman coreutils bubblewrap + sudo pacstrap -G -M "${maindir}"/root pacman coreutils bubblewrap if [[ ${ARCH} != "arm" ]] then From c052e660eeb5d5002100617a210eb22f4da4b547 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 18 Dec 2022 13:43:00 +0000 Subject: [PATCH 287/326] 7.3.18 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9a62cf1..166696f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.17 +7.3.18 From fab5b0df2eead06cffad041cc6ac2c17a540b916 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 18 Dec 2022 20:40:41 +0000 Subject: [PATCH 288/326] Remove arch-travis and directly use docker --- .travis.yml | 36 ++---------------------------------- ci/build_image.sh | 15 +++++++++++++++ lib/checks/check.sh | 21 ++------------------- lib/core/build.sh | 16 ++-------------- lib/core/common.sh | 24 ++++++++++++++++++++++++ 5 files changed, 45 insertions(+), 67 deletions(-) create mode 100755 ci/build_image.sh diff --git a/.travis.yml b/.travis.yml index e024bbd..153b779 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,39 +9,6 @@ cache: services: - docker -archlinux: - mount: - - ~/.ccache:~/.ccache - - ~/.pkg-cache:/var/cache/pacman/pkg - packages: - # Pacman packages - - ccache - - git - - haveged - - before_install: - # 1.Override `package-cleanup.hook` to preserve cache for travis. - # 2.Enable ccache - # 3.Multithreaded build and compress - # 4.Suppress all gcc warnings - - | - sudo mkdir /etc/pacman.d/hooks/ - sudo ln -s /dev/null /etc/pacman.d/hooks/package-cleanup.hook - sudo sed -i '/^BUILDENV/s/\!ccache/ccache/' /etc/makepkg.conf - sudo sed -i '/#MAKEFLAGS=/c MAKEFLAGS="-j2"' /etc/makepkg.conf - sudo sed -i '/^COMPRESSXZ/s/\xz/xz -T 2/' /etc/makepkg.conf - sudo sed -i '$a CFLAGS="$CFLAGS -w"' /etc/makepkg.conf - sudo sed -i '$a CXXFLAGS="$CXXFLAGS -w"' /etc/makepkg.conf - sudo pacman -Syy --noconfirm --disable-download-timeout - sudo pacman-key --init - sudo pacman -S --noconfirm --disable-download-timeout archlinux-keyring - sudo pacman-key --populate archlinux - sudo pacman -Su --noconfirm --disable-download-timeout - script: - # Here do not make any validation (-n) because it will be done later on in the Ubuntu host directly - - ./bin/junest build -n - - env: matrix: - TRAVIS_BASH_VERSION="4.0" @@ -75,7 +42,8 @@ script: # Build and validation ####################### - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin - - "curl -s https://raw.githubusercontent.com/fsquillace/arch-travis/master/arch-travis.sh | bash" + - docker run --rm -v "$(pwd):/build" -v ~/.ccache:/home/travis/.ccache -v ~/.pkg-cache:/var/cache/pacman/pkg --privileged archlinux:latest bash /build/ci/build_image.sh + - "echo pacman pkg cache size: $(du -h ~/.pkg-cache|cut -f1) in $(ls ~/.pkg-cache|wc -l) files" - ls -l # Test the newly created JuNest image against Ubuntu host diff --git a/ci/build_image.sh b/ci/build_image.sh new file mode 100755 index 0000000..f9cda95 --- /dev/null +++ b/ci/build_image.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -ex + +pacman -Sy --noconfirm sudo + +# Create a travis user +echo "travis ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/travis +chmod 'u=r,g=r,o=' /etc/sudoers.d/travis +groupadd --gid "2000" "travis" +useradd --create-home --uid "2000" --gid "2000" --shell /usr/bin/false "travis" + +# Here do not make any validation (-n) because it will be done later on in the Ubuntu host directly +cd /build +runuser -u travis -- /build/bin/junest build -n diff --git a/lib/checks/check.sh b/lib/checks/check.sh index 720e9e0..e811f8a 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -47,26 +47,9 @@ info "Initial JuNest setup..." # otherwise it is not possible to exit from the session trap "[[ -e /etc/pacman.d/gnupg/S.gpg-agent ]] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" QUIT EXIT ABRT TERM INT +prepare_archlinux "$SUDO" + PACMAN_OPTIONS="--noconfirm --disable-download-timeout" - -# shellcheck disable=SC2086 -$SUDO pacman $PACMAN_OPTIONS -Syy - -$SUDO pacman-key --init - -if [[ $(uname -m) == *"arm"* ]] -then - # shellcheck disable=SC2086 - $SUDO pacman $PACMAN_OPTIONS -S archlinuxarm-keyring - $SUDO pacman-key --populate archlinuxarm -else - # shellcheck disable=SC2086 - $SUDO pacman $PACMAN_OPTIONS -S archlinux-keyring - $SUDO pacman-key --populate archlinux -fi - -# shellcheck disable=SC2086 -$SUDO pacman $PACMAN_OPTIONS -Su # shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S grep coreutils # shellcheck disable=SC2086 diff --git a/lib/core/build.sh b/lib/core/build.sh index 45f3631..09939d1 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -24,20 +24,8 @@ function _install_pkg(){ function _prepare() { # ArchLinux System initialization - sudo pacman --noconfirm -Syy - sudo pacman-key --init - if [[ $(uname -m) == *"arm"* ]] - then - sudo pacman -S --noconfirm archlinuxarm-keyring - sudo pacman-key --populate archlinuxarm - else - sudo pacman -S --noconfirm archlinux-keyring - sudo pacman-key --populate archlinux - fi - - sudo pacman --noconfirm -Su - sudo pacman -S --noconfirm base-devel - sudo pacman -S --noconfirm git arch-install-scripts + prepare_archlinux + sudo pacman -S --noconfirm git arch-install-scripts haveged } function build_image_env(){ diff --git a/lib/core/common.sh b/lib/core/common.sh index 7062ecd..d44303f 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -308,3 +308,27 @@ function copy_common_files() { copy_file /etc/resolv.conf return 0 } + +function prepare_archlinux() { + local sudo=${1:-sudo} + local pacman_options="--noconfirm --disable-download-timeout" + + # shellcheck disable=SC2086 + $sudo pacman $pacman_options -Syy + + $sudo pacman-key --init + + if [[ $(uname -m) == *"arm"* ]] + then + # shellcheck disable=SC2086 + $sudo pacman $pacman_options -S archlinuxarm-keyring + $sudo pacman-key --populate archlinuxarm + else + # shellcheck disable=SC2086 + $sudo pacman $pacman_options -S archlinux-keyring + $sudo pacman-key --populate archlinux + fi + + # shellcheck disable=SC2086 + $sudo pacman $pacman_options -Su +} From 1c16425b8854c8d3e56eb6153fbb62b06e99f905 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 19 Dec 2022 23:15:38 +0000 Subject: [PATCH 289/326] 7.3.19 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 166696f..c082dc6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.18 +7.3.19 From 76c1644c6334db6755d825714202e3364b6e4e4d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 31 Dec 2022 11:05:36 +0000 Subject: [PATCH 290/326] Add discord server link --- README.md | 2 +- lib/core/setup.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index da7248e..acea67f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The lightweight Arch Linux based distro that runs, without root privileges, upon |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.com/fsquillace/junest.png?branch=master)](https://app.travis-ci.com/github/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the gitter chat at https://gitter.im/fsquillace/junest](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/fsquillace/junest?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![RSS](https://img.shields.io/badge/RSS-News-orange.svg)](http://fsquillace.github.io/junest-site/feed.xml) | +| [![Build status](https://api.travis-ci.com/fsquillace/junest.png?branch=master)](https://app.travis-ci.com/github/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the Discord server at https://discord.gg/ttfBT7MKve](https://img.shields.io/badge/Discord-Server-blueviolet.svg)](https://discord.gg/ttfBT7MKve) | **Table of Contents** - [Description](#description) diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 749fd66..58c6122 100644 --- a/lib/core/setup.sh +++ b/lib/core/setup.sh @@ -61,6 +61,9 @@ function _setup_env(){ echo info "Remember to refresh the package databases from the server:" info " pacman -Syy" + echo + info "To install packages from AUR follow the wiki here:" + info "https://github.com/fsquillace/junest#install-packages-from-aur" } From 20f42f6cb7e5e65bbdab791c24c7d9f6eb3c3003 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 31 Dec 2022 11:17:45 +0000 Subject: [PATCH 291/326] 7.3.20 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c082dc6..185f9e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.19 +7.3.20 From 65c45517e15f4e0f3efa8245e8fec20c53c51b3e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Jan 2023 22:03:27 +0100 Subject: [PATCH 292/326] Bind /run/user directory --- lib/core/common.sh | 3 ++- lib/core/namespace.sh | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/core/common.sh b/lib/core/common.sh index d44303f..df79bec 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -84,6 +84,7 @@ RM="rm" MKDIR="mkdir" GETENT="getent" CP="cp" +ID="id" # Used for checking user namespace in config.gz file ZGREP="zgrep" UNSHARE="unshare" @@ -245,7 +246,7 @@ function check_same_arch() { function provide_common_bindings(){ RESULT="" local re='(.*):.*' - for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" + for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" "/run/user/$($ID -u)" do if [[ $bind =~ $re ]] then diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 2754dab..9471f31 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -11,7 +11,7 @@ # vim: ft=sh # shellcheck disable=SC2027 -COMMON_BWRAP_OPTION="--bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --bind /sys /sys --bind /proc /proc --dev-bind-try /dev /dev --unshare-user-try" +COMMON_BWRAP_OPTION="--bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp /tmp --bind /sys /sys --bind /proc /proc --dev-bind-try /dev /dev --bind-try "/run/user/$($ID -u)" "/run/user/$($ID -u)" --unshare-user-try" CONFIG_PROC_FILE="/proc/config.gz" CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" PROC_USERNS_CLONE_FILE="/proc/sys/kernel/unprivileged_userns_clone" From a9174267b39b1737ca17e7d8b91fe17ba7812b42 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Jan 2023 22:28:08 +0100 Subject: [PATCH 293/326] Add unit tests --- README.md | 2 +- tests/unit-tests/test-chroot.sh | 10 +++++----- tests/unit-tests/test-proot.sh | 20 ++++++++++---------- tests/utils/shunit2 | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index acea67f..ed326c0 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ In particular, it uses a special program called `GRoot`, a small and portable version of [arch-chroot](https://wiki.archlinux.org/index.php/Chroot) wrapper, that allows to bind mount directories specified by the user, such as -`/proc`, `/sys`, `/dev`, `/tmp` and `$HOME`, before +`/proc`, `/sys`, `/dev`, `/tmp`, `/run/user/` and `$HOME`, before executing any programs inside the JuNest sandbox. In case the mounting will not work, JuNest is even providing the possibility to run the environment directly via the pure `chroot` command. diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index f634b5b..703004d 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -41,22 +41,22 @@ function init_mocks() { function test_run_env_as_groot_cmd(){ assertCommandSuccess run_env_as_groot "" "" "false" pwd - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" + assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" } 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" "$(cat "$STDOUTF")" + assertEquals "chroot_cmd -b /run/user/$(id -u) -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" "$(cat "$STDOUTF")" + assertEquals "mychroot -b /run/user/$(id -u) -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(){ assertCommandSuccess run_env_as_groot "" "" "true" pwd - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" + assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -76,7 +76,7 @@ function test_run_env_as_groot_nested_env(){ function test_run_env_as_groot_cmd_with_backend_args(){ assertCommandSuccess run_env_as_groot "" "-n -b /home/blah" "false" pwd - assertEquals "chroot_cmd -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" + assertEquals "chroot_cmd -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -n -b /home/blah $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" } function test_run_env_as_chroot_cmd(){ diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index 2217150..dfc7498 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -55,11 +55,11 @@ function test_run_env_as_proot_user(){ echo $* } assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" + assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -72,11 +72,11 @@ function test_run_env_as_proot_user_with_backend_command(){ echo $* } assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + assertEquals "myproot -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" - assertEquals "myproot -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" + assertEquals "myproot -b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files _test_copy_remaining_files @@ -89,7 +89,7 @@ function test_run_env_as_proot_user_no_copy(){ echo $* } assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" [[ ! -e ${JUNEST_HOME}/etc/hosts ]] assertEquals 0 $? @@ -126,11 +126,11 @@ function test_run_env_as_proot_fakeroot(){ echo $* } assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + assertEquals "-0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_fakeroot "" "-k 3.10" "false" - assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" + assertEquals "-0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files } @@ -142,12 +142,12 @@ function test_run_env_as_proot_fakeroot_with_backend_command(){ echo $* } assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + assertEquals "myproot -0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" # shellcheck disable=SC2034 SH=("/usr/bin/echo") assertCommandSuccess run_env_as_proot_fakeroot "myproot" "-k 3.10" "false" - assertEquals "myproot -0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" + assertEquals "myproot -0 -b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" _test_copy_common_files } @@ -165,7 +165,7 @@ function test_run_env_with_quotes(){ echo $* } assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" - assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" + assertEquals "-b /run/user/$(id -u) -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat "$STDOUTF")" } function test_run_env_with_proot_args(){ diff --git a/tests/utils/shunit2 b/tests/utils/shunit2 index d6e7503..e4c719c 100644 --- a/tests/utils/shunit2 +++ b/tests/utils/shunit2 @@ -987,7 +987,7 @@ _shunit_extractTestFunctions() # extract the lines with test function names, strip of anything besides the # function name, and output everything on a single line. _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' - egrep "${_shunit_regex_}" "${_shunit_script_}" \ + grep -E "${_shunit_regex_}" "${_shunit_script_}" \ |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ |xargs From 24925838778593e44f4aa27daa194f6c2fa532fa Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 15 Jan 2023 22:28:41 +0100 Subject: [PATCH 294/326] 7.4.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 185f9e4..ba7f754 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.3.20 +7.4.0 From 0b34458fb516bf3e53571708a30a85fc54049b3a Mon Sep 17 00:00:00 2001 From: Cosmo Date: Mon, 30 Jan 2023 23:51:50 -0500 Subject: [PATCH 295/326] Fix deprecated find -perm syntax --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed326c0..d53a353 100644 --- a/README.md +++ b/README.md @@ -512,7 +512,7 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > have *suid* permission, you can list the commands from your JuNest environment > with the following command: - $> find /usr/bin -perm +4000 + $> find /usr/bin -perm /4000 ## No characters are visible on a graphic application ## From 632b416955b93eff2ba6275e582ec689b2b1d93d Mon Sep 17 00:00:00 2001 From: Cosmo Date: Tue, 31 Jan 2023 00:30:41 -0500 Subject: [PATCH 296/326] Fix grammar and improve style --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index ed326c0..9b75181 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ JuNest ====== -The lightweight Arch Linux based distro that runs, without root privileges, upon any Linux distro. +The lightweight Arch Linux based distro that runs, without root privileges, on top of any other Linux distro.

Date: Tue, 31 Jan 2023 22:09:43 +0100 Subject: [PATCH 297/326] 7.4.1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ba7f754..815da58 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.0 +7.4.1 From 95f97a62b74d1dc42e7747c7fb6453f8f59a3ccf Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 17 Feb 2023 18:26:13 +0100 Subject: [PATCH 298/326] #305: Add fakeroot variable to bypass chown commands --- lib/core/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/core/build.sh b/lib/core/build.sh index 09939d1..0f3d8b0 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -70,6 +70,8 @@ EOT echo "Generating the metadata info" sudo install -d -m 755 "${maindir}/root/etc/${CMD}" sudo bash -c "echo 'JUNEST_ARCH=$ARCH' > ${maindir}/root/etc/${CMD}/info" + # Related to: https://github.com/fsquillace/junest/issues/305 + sudo bash -c "echo 'export FAKEROOTDONTTRYCHOWN=true' > ${maindir}/root/etc/profile.d/junest.sh" info "Generating the locales..." # sed command is required for locale-gen but it is required by fakeroot From b976f767d5960df9ab39127a2482a5a9d96eb123 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Fri, 17 Feb 2023 18:40:19 +0100 Subject: [PATCH 299/326] Add checks for fakeroot chown --- lib/checks/check.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/checks/check.sh b/lib/checks/check.sh index e811f8a..789206e 100755 --- a/lib/checks/check.sh +++ b/lib/checks/check.sh @@ -54,12 +54,22 @@ PACMAN_OPTIONS="--noconfirm --disable-download-timeout" $SUDO pacman $PACMAN_OPTIONS -S grep coreutils # shellcheck disable=SC2086 # shellcheck disable=SC2046 -$SUDO pacman $PACMAN_OPTIONS -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) +$SUDO pacman $PACMAN_OPTIONS -Syu --ignore sudo base-devel info "Checking basic executables work..." $SUDO pacman -Qi pacman 1> /dev/null /usr/bin/groot --help 1> /dev/null +# Test FAKEROOTDONTTRYCHOWN is set to true by default +set +u +if [[ -z $FAKEROOTKEY ]] +then + fakeroot chown root /tmp +else + chown root /tmp +fi +set -u + repo_package1=tree echo "Checking ${repo_package1} package from official repo..." # shellcheck disable=SC2086 From 369cda8dc648b431234c8d6030ab2cac5246ea1d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Feb 2023 00:03:19 +0100 Subject: [PATCH 300/326] 7.4.2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 815da58..f8cb1fa 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.1 +7.4.2 From 4db85bcf1f247f316ed5f849d37908db5fcfd314 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Feb 2023 00:49:54 +0100 Subject: [PATCH 301/326] #318: Use multi-call wrapper --- lib/core/wrappers.sh | 24 +++++++++++++----------- tests/unit-tests/test-wrappers.sh | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index 7e8b3a8..1afbb2b 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -21,6 +21,17 @@ function create_wrappers() { local force=${1:-false} mkdir -p "${JUNEST_HOME}/usr/bin_wrappers" + # Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes + # are not recognized normally unless using `eval`. More info here: + # https://github.com/fsquillace/junest/issues/262 + # https://github.com/fsquillace/junest/pull/287 + cat < "${JUNEST_HOME}/usr/bin/junest_wrapper" +#!/usr/bin/env bash + +eval "junest_args_array=(\${JUNEST_ARGS:-ns})" +junest "\${junest_args_array[@]}" -- \$(basename \${0}) "\$@" +EOF + chmod +x "${JUNEST_HOME}/usr/bin/junest_wrapper" cd "${JUNEST_HOME}/usr/bin" || return 1 for file in * @@ -33,17 +44,8 @@ function create_wrappers() { then continue fi - # Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes - # are not recognized normally unless using `eval`. More info here: - # https://github.com/fsquillace/junest/issues/262 - # https://github.com/fsquillace/junest/pull/287 - cat < "${JUNEST_HOME}/usr/bin_wrappers/${file}" -#!/usr/bin/env bash - -eval "junest_args_array=(\${JUNEST_ARGS:-ns})" -junest "\${junest_args_array[@]}" -- ${file} "\$@" -EOF - chmod +x "${JUNEST_HOME}/usr/bin_wrappers/${file}" + rm -f "${JUNEST_HOME}/usr/bin_wrappers/$file" + ln -s "../bin/junest_wrapper" "${JUNEST_HOME}/usr/bin_wrappers/$file" done # Remove wrappers no longer needed diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index 8944ee5..c5a5857 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -81,7 +81,7 @@ function test_create_wrappers_verify_content(){ -b --bind /run /run2 -- -myfile +test-wrappers.sh pacman -Rsn neovim From ba0ddcc524b3a94e34dd8b2b747c882a8c16dd4e Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 18 Feb 2023 23:47:20 +0100 Subject: [PATCH 302/326] 7.4.3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index f8cb1fa..0f4a1d6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.2 +7.4.3 From 9b00c5c4c51c513b09ae32b97a0fbd8ca8590d45 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 30 Apr 2023 13:20:54 +0200 Subject: [PATCH 303/326] Reduce PATH when accessing to Junest session --- lib/core/chroot.sh | 3 ++- lib/core/namespace.sh | 6 ++++-- lib/core/proot.sh | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index c2237a9..c7f8abc 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -33,8 +33,9 @@ function _run_env_as_xroot(){ copy_common_files fi + # Resets PATH to avoid polluting with host related bin paths # shellcheck disable=SC2086 - JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" + PATH='' JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" } ####################################### diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 9471f31..bbda112 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -101,8 +101,9 @@ function run_env_as_bwrap_fakeroot(){ local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + # Fix PATH to /usr/bin to make sudo working and avoid polluting with host related bin paths # shellcheck disable=SC2086 - BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" + PATH="/usr/bin" BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 $backend_args sudo "${DEFAULT_SH[@]}" "${args[@]}" } @@ -150,8 +151,9 @@ function run_env_as_bwrap_user() { local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + # Resets PATH to avoid polluting with host related bin paths # shellcheck disable=SC2086 - BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}" + PATH='' BWRAP="${backend_command}" JUNEST_ENV=1 bwrap_cmd $COMMON_BWRAP_OPTION $backend_args "${DEFAULT_SH[@]}" "${args[@]}" } diff --git a/lib/core/proot.sh b/lib/core/proot.sh index 259c8b7..b6c1c8f 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -17,7 +17,8 @@ function _run_env_with_proot(){ local args=() [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - PROOT="${backend_command}" JUNEST_ENV=1 proot_cmd "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}" + # Resets PATH to avoid polluting with host related bin paths + PATH='' PROOT="${backend_command}" JUNEST_ENV=1 proot_cmd "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}" } function _run_env_with_qemu(){ From 296c9e47b4b98a8bdac048b5611b43f5ee4009c4 Mon Sep 17 00:00:00 2001 From: Escape0707 Date: Sat, 6 May 2023 00:55:50 +0900 Subject: [PATCH 304/326] Update README.md to accommodate that sudo-fake provides sudo Since junest/sudo-fake now provides sudo, users don't need to ignore core/sudo during the installation of base-devel. They only need to make sure not to install core/sudo manually. --- README.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 321feae..a6485d2 100644 --- a/README.md +++ b/README.md @@ -149,14 +149,11 @@ command. In `proot` mode, JuNest does no longer support the building of AUR pack first: ```sh -pacman -Syu --ignore sudo base-devel -:: sudo is in IgnorePkg/IgnoreGroup. Install anyway? [Y/n] n -... -... +pacman -S base-devel ``` -JuNest uses a modified version of `sudo`. That's why the original `sudo` -package **must be ignored** in the previous command. +JuNest uses a modified version of `sudo` provided by `junest/sudo-fake`. And the original `core/sudo` +package will be ignored **(and must not be installed)** during the installation of `base-devel`. Have fun! --------- @@ -387,9 +384,9 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > In order to install AUR packages you need to install the package group `base-devel` first > that contains all the essential packages for compiling from source code (such as gcc, make, patch, etc): - #> pacman -S --ignore sudo base-devel + #> pacman -S base-devel -> Remember to ignore `sudo` as it conflicts with `sudo-fake` package. +> Remember to not install `core/sudo` as it conflicts with `junest/sudo-fake` package. ## Can't set user and group as root From 874f52f0f8b61f47c7a7e10cbbeebb382f4f9b3b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 6 May 2023 00:46:09 +0200 Subject: [PATCH 305/326] Remove PATH setting for chroot mode --- lib/core/chroot.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index c7f8abc..c2237a9 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -33,9 +33,8 @@ function _run_env_as_xroot(){ copy_common_files fi - # Resets PATH to avoid polluting with host related bin paths # shellcheck disable=SC2086 - PATH='' JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" + JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" } ####################################### From ae365215fbaf2650429203d5a5ffa063369cfb5d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 6 May 2023 01:38:52 +0200 Subject: [PATCH 306/326] 7.4.4 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0f4a1d6..4e61aee 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.3 +7.4.4 From 39508ca8a9ddabfa2ebe1311831ec641a30bb121 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 7 May 2023 13:59:00 +0200 Subject: [PATCH 307/326] First commit --- bin/junest | 9 +++++++-- lib/core/wrappers.sh | 18 ++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/bin/junest b/bin/junest index d3435fe..7288e59 100755 --- a/bin/junest +++ b/bin/junest @@ -69,8 +69,11 @@ usage() { echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" echo -e " -n, --disable-check Disable the $NAME image check" echo - echo -e " create-bin-wrappers Create bin wrappers in $JUNEST_HOME/usr/bin_wrappers" + echo -e " create-bin-wrappers Create a bin wrappers directory according to --bin-path option" + echo -e " Default path is $JUNEST_HOME/usr/bin_wrappers" echo -e " -f, --force Create the wrapper files even if they already exist" + echo -e " -p, --bin-path The source directory where executable are located in JuNest" + echo -e " Default value is: /usr/bin" echo } @@ -215,10 +218,12 @@ function _parse_build_opts() { function _parse_create_wrappers_opts() { OPT_FORCE=false + OPT_BIN_PATH="" while [[ -n "$1" ]] do case "$1" in -f|--force) OPT_FORCE=true ; shift ;; + -p|--bin-path) shift ; OPT_BIN_PATH="$1" ; shift ;; *) die "Invalid option $1" ;; esac done @@ -276,7 +281,7 @@ function execute_operation() { fi if $ACT_CREATE_WRAPPERS; then - create_wrappers $OPT_FORCE + create_wrappers $OPT_FORCE "$OPT_BIN_PATH" exit fi diff --git a/lib/core/wrappers.sh b/lib/core/wrappers.sh index 1afbb2b..1fe955c 100644 --- a/lib/core/wrappers.sh +++ b/lib/core/wrappers.sh @@ -20,7 +20,9 @@ ####################################### function create_wrappers() { local force=${1:-false} - mkdir -p "${JUNEST_HOME}/usr/bin_wrappers" + local bin_path=${2:-/usr/bin} + bin_path=${bin_path%/} + mkdir -p "${JUNEST_HOME}${bin_path}_wrappers" # Arguments inside a variable (i.e. `JUNEST_ARGS`) separated by quotes # are not recognized normally unless using `eval`. More info here: # https://github.com/fsquillace/junest/issues/262 @@ -33,26 +35,26 @@ junest "\${junest_args_array[@]}" -- \$(basename \${0}) "\$@" EOF chmod +x "${JUNEST_HOME}/usr/bin/junest_wrapper" - cd "${JUNEST_HOME}/usr/bin" || return 1 + cd "${JUNEST_HOME}${bin_path}" || return 1 for file in * do [[ -d $file ]] && continue - # Symlinks outside junest appear as broken even though the are correct + # Symlinks outside junest appear as broken even though they are correct # within a junest session. The following do not skip broken symlinks: [[ -x $file || -L $file ]] || continue - if [[ -e ${JUNEST_HOME}/usr/bin_wrappers/$file ]] && ! $force + if [[ -e ${JUNEST_HOME}${bin_path}_wrappers/$file ]] && ! $force then continue fi - rm -f "${JUNEST_HOME}/usr/bin_wrappers/$file" - ln -s "../bin/junest_wrapper" "${JUNEST_HOME}/usr/bin_wrappers/$file" + rm -f "${JUNEST_HOME}${bin_path}_wrappers/$file" + ln -s "${JUNEST_HOME}/usr/bin/junest_wrapper" "${JUNEST_HOME}${bin_path}_wrappers/$file" done # Remove wrappers no longer needed - cd "${JUNEST_HOME}/usr/bin_wrappers" || return 1 + cd "${JUNEST_HOME}${bin_path}_wrappers" || return 1 for file in * do - [[ -e ${JUNEST_HOME}/usr/bin/$file || -L ${JUNEST_HOME}/usr/bin/$file ]] || rm -f "$file" + [[ -e ${JUNEST_HOME}${bin_path}/$file || -L ${JUNEST_HOME}${bin_path}/$file ]] || rm -f "$file" done } From c2dae9021d7bd4936d622a2984a8310984d2263d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 7 May 2023 14:15:55 +0200 Subject: [PATCH 308/326] Add integ test --- lib/checks/check_all.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh index 2b39f9a..13e9237 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -24,4 +24,8 @@ sudo -E "$JUNEST_SCRIPT" groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-te # Test the wrappers work "$JUNEST_SCRIPT" create-bin-wrappers --force "$JUNEST_HOME"/usr/bin_wrappers/pacman --help + +"$JUNEST_SCRIPT" create-bin-wrappers --force --bin-path /usr/bin/core_perl/ +"$JUNEST_HOME"/usr/bin/core_perl_wrappers/shasum --help + "${JUNEST_BASE}/bin/sudoj" pacman -Syu From 3742c16ce06bc8fbf6758a6f4ee796c3b2988084 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 7 May 2023 16:13:10 +0200 Subject: [PATCH 309/326] Add documentation and unit test --- README.md | 24 ++++++++++++++++++++---- tests/unit-tests/test-wrappers.sh | 11 +++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a6485d2..72ae100 100644 --- a/README.md +++ b/README.md @@ -110,9 +110,9 @@ used, see the [Usage](#usage) section below. Run JuNest installed programs directly from host OS --------------------------------------- -Program installed within JuNest can be accessible directly from host machine -without entering directly into a JuNest session -(no need to call `junest` command first). +Programs installed within JuNest can be accessible directly from host machine +without entering into a JuNest session +(namely, no need to call `junest` command first). For instance, supposing the host OS is an Ubuntu distro you can directly run `pacman` by simply updating the `PATH` variable: @@ -123,7 +123,7 @@ htop ``` By default the wrappers use `ns` mode. To use the `ns --fakeroot` you can use the convenient command helper `sudoj`. -For more control on backend mode you can use the `JUNEST_ARGS` environment variable. +For more control on backend modes you can use the `JUNEST_ARGS` environment variable too. For instance, if you want to run `iftop` with real root privileges: ``` @@ -138,6 +138,22 @@ corrupted) with: junest create-bin-wrappers -f ``` +Bin wrappers are automatically generated each time they get installed inside JuNest. +This only works for executables located in `/usr/bin` path. +For executables in other locations (say `/usr/mybinpath`) you can only create +wrappers manually by executing the command: + +``` +junest create-bin-wrappers --bin-path /usr/mybinpath +``` + +Obviously, to get access to the corresponding bin wrappers you will need to +update your `PATH` variable accordingly: + +``` +export PATH="$PATH:~/.junest/usr/mybinpath_wrappers" +``` + Install packages from AUR ------------------------- diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index c5a5857..eef1f38 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -124,4 +124,15 @@ function test_create_wrappers_executable_no_longer_exist(){ assertTrue "myfile wrapper should not exist" "[ ! -x $JUNEST_HOME/usr/bin_wrappers/myfile ]" } +function test_create_wrappers_custom_bin_path(){ + mkdir -p "$JUNEST_HOME"/usr/mybindir + touch "$JUNEST_HOME"/usr/mybindir/myfile + chmod +x "$JUNEST_HOME"/usr/mybindir/myfile + assertCommandSuccess create_wrappers false /usr/mybindir/ + assertEquals "" "$(cat "$STDOUTF")" + assertTrue "bin_wrappers should exist" "[ -e $JUNEST_HOME/usr/mybindir_wrappers ]" + assertTrue "myfile wrapper should exist" "[ -x $JUNEST_HOME/usr/mybindir_wrappers/myfile ]" +} + + source "$(dirname "$0")"/../utils/shunit2 From 507502dc1a5bbcdfa836a6d984cd4524958879cd Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 7 May 2023 16:27:17 +0200 Subject: [PATCH 310/326] 7.4.5 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4e61aee..e91f104 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.4 +7.4.5 From daa60b05e3cd4ebf75970ca19bb1a012339dfc8d Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 29 May 2023 11:47:18 +0200 Subject: [PATCH 311/326] Fix PATH when running trap --- VERSION | 2 +- bin/junest | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index e91f104..bd8293a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.5 +7.4.6 diff --git a/bin/junest b/bin/junest index 7288e59..356482d 100755 --- a/bin/junest +++ b/bin/junest @@ -305,7 +305,7 @@ function execute_operation() { fi # Call create_wrappers in case new bin files have been created - trap "create_wrappers" EXIT QUIT TERM + trap "PATH=$PATH create_wrappers" EXIT QUIT TERM $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } From 9a06d47f76bbe18cd0817ba6ddb5a780713a6d73 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Mon, 29 May 2023 12:00:15 +0200 Subject: [PATCH 312/326] Add shellcheck disable --- bin/junest | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/junest b/bin/junest index 356482d..f0d6abe 100755 --- a/bin/junest +++ b/bin/junest @@ -305,6 +305,7 @@ function execute_operation() { fi # Call create_wrappers in case new bin files have been created + # shellcheck disable=SC2064 trap "PATH=$PATH create_wrappers" EXIT QUIT TERM $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } From b3565e093d848eeb6c4f72ca97df25d200f0e0ad Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 31 May 2023 14:57:57 +0200 Subject: [PATCH 313/326] #328 Check if `user` file exist in `ns` directory --- lib/core/namespace.sh | 30 +++++++++++++++------------ tests/unit-tests/test-namespace.sh | 33 +++++++++++++----------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index bbda112..70763bd 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -15,8 +15,24 @@ COMMON_BWRAP_OPTION="--bind "$JUNEST_HOME" / --bind "$HOME" "$HOME" --bind /tmp CONFIG_PROC_FILE="/proc/config.gz" CONFIG_BOOT_FILE="/boot/config-$($UNAME -r)" PROC_USERNS_CLONE_FILE="/proc/sys/kernel/unprivileged_userns_clone" +PROC_USERNS_FILE="/proc/$$/ns/user" function _is_user_namespace_enabled() { + if [[ -L $PROC_USERNS_FILE ]] + then + return 0 + fi + + if [[ -e $PROC_USERNS_CLONE_FILE ]] + then + # `-q` option in zgrep may cause a gzip: stdout: Broken pipe + # Use redirect to /dev/null instead + if zgrep_cmd "1" "$PROC_USERNS_CLONE_FILE" > /dev/null + then + return 0 + fi + fi + local config_file="" if [[ -e $CONFIG_PROC_FILE ]] then @@ -35,19 +51,7 @@ function _is_user_namespace_enabled() { return "$NO_CONFIG_FOUND" fi - if [[ ! -e $PROC_USERNS_CLONE_FILE ]] - then - return 0 - fi - - # `-q` option in zgrep may cause a gzip: stdout: Broken pipe - # Use redirect to /dev/null instead - if ! zgrep_cmd "1" $PROC_USERNS_CLONE_FILE > /dev/null - then - return "$UNPRIVILEGED_USERNS_DISABLED" - fi - - return 0 + return "$UNPRIVILEGED_USERNS_DISABLED" } function _check_user_namespace() { diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 373c1be..781ca92 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -58,50 +58,45 @@ function _test_copy_remaining_files() { } function test_is_user_namespace_enabled_no_config_file(){ + PROC_USERNS_FILE="blah" + PROC_USERNS_CLONE_FILE="blah" CONFIG_PROC_FILE="blah" CONFIG_BOOT_FILE="blah" assertCommandFailOnStatus "$NOT_EXISTING_FILE" _is_user_namespace_enabled } function test_is_user_namespace_enabled_no_config(){ + PROC_USERNS_FILE="blah" + PROC_USERNS_CLONE_FILE="blah" touch config gzip config + # shellcheck disable=SC2034 CONFIG_PROC_FILE="config.gz" + # shellcheck disable=SC2034 CONFIG_BOOT_FILE="blah" assertCommandFailOnStatus "$NO_CONFIG_FOUND" _is_user_namespace_enabled } -function test_is_user_namespace_enabled_with_config(){ - echo "CONFIG_USER_NS=y" > config - gzip config - CONFIG_PROC_FILE="config.gz" - CONFIG_BOOT_FILE="blah" - PROC_USERNS_CLONE_FILE="not-existing-file" - assertCommandSuccess _is_user_namespace_enabled -} - function test_is_user_namespace_enabled_with_userns_clone_file_disabled(){ - echo "CONFIG_USER_NS=y" > config - gzip config - CONFIG_PROC_FILE="config.gz" - CONFIG_BOOT_FILE="blah" + PROC_USERNS_FILE="blah" PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" echo "0" > $PROC_USERNS_CLONE_FILE assertCommandFailOnStatus "$UNPRIVILEGED_USERNS_DISABLED" _is_user_namespace_enabled } function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ - echo "CONFIG_USER_NS=y" > config - gzip config - # shellcheck disable=SC2034 - CONFIG_PROC_FILE="config.gz" - # shellcheck disable=SC2034 - CONFIG_BOOT_FILE="blah" PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" echo "1" > $PROC_USERNS_CLONE_FILE assertCommandSuccess _is_user_namespace_enabled } +function test_is_user_namespace_enabled_with_proc_userns_file_existing(){ + PROC_USERNS_FILE="user" + ln -s . $PROC_USERNS_FILE + PROC_USERNS_CLONE_FILE="blah" + assertCommandSuccess _is_user_namespace_enabled +} + function test_run_env_as_bwrap_fakeroot() { assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false" assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")" From 2dd84efecbb6bda68b12cd567c41d01d3176f9d2 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Wed, 31 May 2023 15:07:39 +0200 Subject: [PATCH 314/326] 7.4.7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index bd8293a..25627bc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.6 +7.4.7 From d19d2f07b68e596706c7c576ca941e63809483c0 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 22 Jul 2023 16:26:21 +0200 Subject: [PATCH 315/326] Add buymeacoffee badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72ae100..e51e5be 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The lightweight Arch Linux based distro that runs, without root privileges, on t |Project Status|Donation|Communication| |:------------:|:------:|:-----------:| -| [![Build status](https://api.travis-ci.com/fsquillace/junest.png?branch=master)](https://app.travis-ci.com/github/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) | [![Join the Discord server at https://discord.gg/ttfBT7MKve](https://img.shields.io/badge/Discord-Server-blueviolet.svg)](https://discord.gg/ttfBT7MKve) | +| [![Build status](https://api.travis-ci.com/fsquillace/junest.png?branch=master)](https://app.travis-ci.com/github/fsquillace/junest) [![OpenHub](https://www.openhub.net/p/junest/widgets/project_thin_badge.gif)](https://www.openhub.net/p/junest) | [![Github Sponsors](https://img.shields.io/badge/GitHub-Sponsors-orange.svg)](https://github.com/sponsors/fsquillace) [![PayPal](https://img.shields.io/badge/PayPal-Donation-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8LEHQKBCYTACY) [![Buy me a coffee](https://www.buymeacoffee.com/assets/img/custom_images/yellow_img.png)](https://www.buymeacoffee.com/fsquillace) | [![Join the Discord server at https://discord.gg/ttfBT7MKve](https://img.shields.io/badge/Discord-Server-blueviolet.svg)](https://discord.gg/ttfBT7MKve) | **Table of Contents** - [Description](#description) From 6ae9f72dd5bd423bf5e6db8e62cf0e343a8a2bee Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 22 Jul 2023 16:34:44 +0200 Subject: [PATCH 316/326] Add Readme update --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e51e5be..7be58b1 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,9 @@ Setup environment ----------------- The first operation required is to install the JuNest environment in the -location of your choice (by default `~/.junest`, configurable via the environment variable `JUNEST_HOME`): +location of your choice via `JUNEST_HOME` environment variable +(it must contain an absolute path) which by +default is `~/.junest`: ```sh junest setup From e680325f5a815f58c8ef7e57a319c6cd64a497a2 Mon Sep 17 00:00:00 2001 From: Cosmo Date: Mon, 13 Nov 2023 15:29:05 -0500 Subject: [PATCH 317/326] Explain installation before quickstart/setup This should clear up some of the confusion that new users experience when discovering JuNest for the first time --- README.md | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 72ae100..49f3786 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,37 @@ This allows interaction between processes belonging to both host OS and JuNest. For example, you can install the `top` command in JuNest and use it to monitor processes belonging to the host OS. +Installation +============ + +## Dependencies ## +JuNest comes with a very short list of dependencies in order to be installed in most +of GNU/Linux distributions. +Before installing JuNest be sure that all dependencies are properly installed in your system: + +- [bash (>=4.0)](https://www.gnu.org/software/bash/) +- [GNU coreutils](https://www.gnu.org/software/coreutils/) + +## Installation from git repository ## +Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): + +```sh +git clone https://github.com/fsquillace/junest.git ~/.local/share/junest +export PATH=~/.local/share/junest/bin:$PATH +``` + +Optionally you want to use the wrappers to run commands +installed in JuNest directly from host: + +```sh +export PATH="$PATH:~/.junest/usr/bin_wrappers" +``` +Update your `~/.bashrc` or `~/.zshrc` to get always the wrappers available. + +### Installation using AUR (Arch Linux only) ### +If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/packages/junest-git/). +JuNest will be located in `/opt/junest/` + Quickstart ========== @@ -177,37 +208,6 @@ Have fun! If you are new on Arch Linux and you are not familiar with `pacman` package manager visit the [pacman rosetta page](https://wiki.archlinux.org/index.php/Pacman_Rosetta). -Installation -============ - -## Dependencies ## -JuNest comes with a very short list of dependencies in order to be installed in most -of GNU/Linux distributions. -Before installing JuNest be sure that all dependencies are properly installed in your system: - -- [bash (>=4.0)](https://www.gnu.org/software/bash/) -- [GNU coreutils](https://www.gnu.org/software/coreutils/) - -## Installation from git repository ## -Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): - -```sh -git clone https://github.com/fsquillace/junest.git ~/.local/share/junest -export PATH=~/.local/share/junest/bin:$PATH -``` - -Optionally you want to use the wrappers to run commands -installed in JuNest directly from host: - -```sh -export PATH="$PATH:~/.junest/usr/bin_wrappers" -``` -Update your `~/.bashrc` or `~/.zshrc` to get always the wrappers available. - -### Installation using AUR (Arch Linux only) ### -If you are using an Arch Linux system you can, alternatively, install JuNest from the [AUR repository](https://aur.archlinux.org/packages/junest-git/). -JuNest will be located in `/opt/junest/` - Usage ===== There are three different ways you can run JuNest depending on the backend program you decide to use. From c91e013cd4c473df120697e8130700d4d95c83ed Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 9 Jan 2024 15:51:33 +0100 Subject: [PATCH 318/326] Copy pacman.conf file if does not exist --- lib/core/build.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index 0f3d8b0..7a2ef9d 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -25,7 +25,8 @@ function _install_pkg(){ function _prepare() { # ArchLinux System initialization prepare_archlinux - sudo pacman -S --noconfirm git arch-install-scripts haveged + # curl is used to download pacman.conf file + sudo pacman -S --noconfirm git arch-install-scripts haveged curl } function build_image_env(){ @@ -59,12 +60,19 @@ function build_image_env(){ fi sudo mkdir -p "${maindir}"/root/run/lock - sudo tee -a "${maindir}"/root/etc/pacman.conf > /dev/null < Date: Tue, 9 Jan 2024 16:41:45 +0100 Subject: [PATCH 319/326] 7.4.8 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 25627bc..da8d653 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.7 +7.4.8 From fd449721375124ab9870970fb1e649b9d36da1dc Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 1 Aug 2024 19:51:21 +0200 Subject: [PATCH 320/326] Disable the checks and fix shellcheck --- .travis.yml | 4 +++- bin/junest | 3 +++ tests/unit-tests/test-chroot.sh | 3 +++ tests/unit-tests/test-common.sh | 8 ++++++++ tests/unit-tests/test-junest.sh | 25 +++++++++++++++++++++++++ tests/unit-tests/test-namespace.sh | 1 + tests/unit-tests/test-proot.sh | 10 ++++++++++ tests/unit-tests/test-setup.sh | 1 + tests/unit-tests/test-wrappers.sh | 1 + 9 files changed, 55 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 153b779..8efa537 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,7 +49,9 @@ script: # Test the newly created JuNest image against Ubuntu host - export JUNEST_HOME=~/.junest - junest setup -i junest-x86_64.tar.gz - - ${PWD}/lib/checks/check_all.sh + # TODO The check does not work at the moment: https://app.travis-ci.com/github/fsquillace/junest/builds/271706037 + # Disabling it in order to avoid having stale version of junest images. + # - ${PWD}/lib/checks/check_all.sh - yes | junest setup --delete diff --git a/bin/junest b/bin/junest index f0d6abe..4084fe0 100755 --- a/bin/junest +++ b/bin/junest @@ -250,6 +250,7 @@ function execute_operation() { $ACT_VERSION && version && return if $ACT_BUILD; then + # shellcheck disable=SC2086 build_image_env $OPT_DISABLE_CHECK return fi @@ -281,6 +282,7 @@ function execute_operation() { fi if $ACT_CREATE_WRAPPERS; then + # shellcheck disable=SC2086 create_wrappers $OPT_FORCE "$OPT_BIN_PATH" exit fi @@ -307,6 +309,7 @@ function execute_operation() { # Call create_wrappers in case new bin files have been created # shellcheck disable=SC2064 trap "PATH=$PATH create_wrappers" EXIT QUIT TERM + # shellcheck disable=SC2086 $run_env "$BACKEND_COMMAND" "${BACKEND_ARGS}" $OPT_NO_COPY_FILES "${ARGS[@]}" } diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 703004d..3739c58 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -29,12 +29,15 @@ function tearDown(){ function init_mocks() { chroot_cmd() { + # shellcheck disable=SC2317 [ "$JUNEST_ENV" != "1" ] && return 1 + # shellcheck disable=SC2317 echo "chroot_cmd $*" } # shellcheck disable=SC2034 GROOT=chroot_cmd mychroot() { + # shellcheck disable=SC2317 echo mychroot "$*" } } diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index d0a6c0b..89c1a1e 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -22,8 +22,10 @@ function oneTimeTearDown(){ function setUp(){ ld_exec_mock() { + # shellcheck disable=SC2317 echo "ld_exec $*" } + # shellcheck disable=SC2317 ld_exec_mock_false() { echo "ld_exec $*" return 1 @@ -32,11 +34,13 @@ function setUp(){ LD_EXEC=ld_exec_mock unshare_mock() { + # shellcheck disable=SC2317 echo "unshare $*" } # shellcheck disable=SC2034 UNSHARE=unshare_mock + # shellcheck disable=SC2317 bwrap_mock() { echo "bwrap $*" } @@ -173,6 +177,7 @@ function test_proot_cmd_compat(){ function test_proot_cmd_seccomp(){ envv(){ + # shellcheck disable=SC2317 env } PROOT=envv @@ -180,6 +185,7 @@ function test_proot_cmd_seccomp(){ assertEquals "" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" envv(){ + # shellcheck disable=SC2317 env | grep "^PROOT_NO_SECCOMP" } # shellcheck disable=SC2034 @@ -193,6 +199,7 @@ PROOT_NO_SECCOMP=1" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" function test_copy_passwd_and_group(){ getent_cmd_mock() { + # shellcheck disable=SC2317 echo "$*" } GETENT=getent_cmd_mock assertCommandSuccess copy_passwd_and_group @@ -202,6 +209,7 @@ function test_copy_passwd_and_group(){ function test_copy_passwd_and_group_fallback(){ cp_cmd_mock() { + # shellcheck disable=SC2317 echo "$*" } CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess copy_passwd_and_group diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh index 086062f..07a92b1 100755 --- a/tests/unit-tests/test-junest.sh +++ b/tests/unit-tests/test-junest.sh @@ -15,25 +15,32 @@ function oneTimeSetUp(){ function setUp(){ ## Mock functions ## + # shellcheck disable=SC2317 function usage(){ echo "usage" } + # shellcheck disable=SC2317 function version(){ echo "version" } + # shellcheck disable=SC2317 function build_image_env(){ local disable_check=$1 echo "build_image_env($disable_check)" } + # shellcheck disable=SC2317 function delete_env(){ echo "delete_env" } + # shellcheck disable=SC2317 function setup_env_from_file(){ echo "setup_env_from_file($1)" } + # shellcheck disable=SC2317 function setup_env(){ echo "setup_env($1)" } + # shellcheck disable=SC2317 function run_env_as_proot_fakeroot(){ local backend_command="$1" local backend_args="$2" @@ -41,6 +48,7 @@ function setUp(){ shift 3 echo "run_env_as_proot_fakeroot($backend_command,$backend_args,$no_copy_files,$*)" } + # shellcheck disable=SC2317 function run_env_as_groot(){ local backend_command="$1" local backend_args="$2" @@ -48,6 +56,7 @@ function setUp(){ shift 3 echo "run_env_as_groot($backend_command,$backend_args,$no_copy_files,$*)" } + # shellcheck disable=SC2317 function run_env_as_chroot(){ local backend_command="$1" local backend_args="$2" @@ -55,6 +64,7 @@ function setUp(){ shift 3 echo "run_env_as_chroot($backend_command,$backend_args,$no_copy_files,$*)" } + # shellcheck disable=SC2317 function run_env_as_proot_user(){ local backend_command="$1" local backend_args="$2" @@ -62,6 +72,7 @@ function setUp(){ shift 3 echo "run_env_as_proot_user($backend_command,$backend_args,$no_copy_files,$*)" } + # shellcheck disable=SC2317 function run_env_as_bwrap_fakeroot(){ local backend_command="$1" local backend_args="$2" @@ -69,6 +80,7 @@ function setUp(){ shift 3 echo "run_env_as_bwrap_fakeroot($backend_command,$backend_args,$no_copy_files,$*)" } + # shellcheck disable=SC2317 function run_env_as_bwrap_user(){ local backend_command="$1" local backend_args="$2" @@ -76,9 +88,11 @@ function setUp(){ shift 3 echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$*)" } + # shellcheck disable=SC2317 function is_env_installed(){ return 0 } + # shellcheck disable=SC2317 function create_wrappers(){ : } @@ -108,6 +122,7 @@ function test_build_image_env(){ } function test_create_wrappers(){ + # shellcheck disable=SC2317 function create_wrappers(){ local force=$1 echo "create_wrappers($force)" @@ -126,6 +141,7 @@ function test_delete_env(){ assertEquals "delete_env" "$(cat "$STDOUTF")" } function test_setup_env_from_file(){ + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -134,6 +150,7 @@ function test_setup_env_from_file(){ assertCommandSuccess main setup --from-file myimage assertEquals "setup_env_from_file(myimage)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 0 } @@ -141,6 +158,7 @@ function test_setup_env_from_file(){ } function test_setup_env(){ + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -153,6 +171,7 @@ function test_setup_env(){ assertCommandSuccess main setup --arch arm assertEquals "setup_env(arm)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 0 } @@ -181,6 +200,7 @@ function test_run_env_as_proot_fakeroot(){ assertCommandSuccess main proot -f -- command --as assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -207,6 +227,7 @@ function test_run_env_as_user(){ assertCommandSuccess main proot -- command -ls assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -231,6 +252,7 @@ function test_run_env_as_groot(){ assertCommandSuccess main groot -- command assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -253,6 +275,7 @@ function test_run_env_as_chroot(){ assertCommandSuccess main root -- command assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -295,6 +318,7 @@ function test_run_env_as_bwrap_fakeroot(){ assertCommandSuccess main -f -- command --as assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -337,6 +361,7 @@ function test_run_env_as_bwrap_user(){ assertCommandSuccess main -- command --as assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh index 781ca92..7a845aa 100755 --- a/tests/unit-tests/test-namespace.sh +++ b/tests/unit-tests/test-namespace.sh @@ -16,6 +16,7 @@ function oneTimeSetUp(){ ## Mock functions ## function init_mocks() { + # shellcheck disable=SC2317 function bwrap_cmd(){ echo "$BWRAP $*" } diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index dfc7498..0f4f11a 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -49,6 +49,7 @@ function _test_copy_remaining_files() { } function test_run_env_as_proot_user(){ + # shellcheck disable=SC2317 _run_env_with_qemu() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 @@ -66,6 +67,7 @@ function test_run_env_as_proot_user(){ } function test_run_env_as_proot_user_with_backend_command(){ + # shellcheck disable=SC2317 _run_env_with_qemu() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 @@ -83,6 +85,7 @@ function test_run_env_as_proot_user_with_backend_command(){ } function test_run_env_as_proot_user_no_copy(){ + # shellcheck disable=SC2317 _run_env_with_qemu() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 @@ -120,6 +123,7 @@ function test_run_env_as_proot_user_nested_env(){ } function test_run_env_as_proot_fakeroot(){ + # shellcheck disable=SC2317 _run_env_with_qemu() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 @@ -136,6 +140,7 @@ function test_run_env_as_proot_fakeroot(){ } function test_run_env_as_proot_fakeroot_with_backend_command(){ + # shellcheck disable=SC2317 _run_env_with_qemu() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 @@ -159,6 +164,7 @@ function test_run_env_as_proot_fakeroot_nested_env(){ } function test_run_env_with_quotes(){ + # shellcheck disable=SC2317 _run_env_with_qemu() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 @@ -169,6 +175,7 @@ function test_run_env_with_quotes(){ } function test_run_env_with_proot_args(){ + # shellcheck disable=SC2317 proot_cmd() { [ "$JUNEST_ENV" != "1" ] && return 1 # shellcheck disable=SC2086 @@ -187,16 +194,19 @@ function test_run_env_with_proot_args(){ function test_qemu() { echo "JUNEST_ARCH=arm" > "${JUNEST_HOME}"/etc/junest/info + # shellcheck disable=SC2317 rm_cmd() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 echo $* } + # shellcheck disable=SC2317 ln_cmd() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 echo $* } + # shellcheck disable=SC2317 _run_env_with_proot() { # shellcheck disable=SC2086 # shellcheck disable=SC2048 diff --git a/tests/unit-tests/test-setup.sh b/tests/unit-tests/test-setup.sh index d8c2456..de2df75 100755 --- a/tests/unit-tests/test-setup.sh +++ b/tests/unit-tests/test-setup.sh @@ -35,6 +35,7 @@ function test_is_env_installed(){ function test_setup_env(){ rm -rf "${JUNEST_HOME:?}"/* + # shellcheck disable=SC2317 wget_mock(){ # Proof that the setup is happening # inside $JUNEST_TEMPDIR diff --git a/tests/unit-tests/test-wrappers.sh b/tests/unit-tests/test-wrappers.sh index eef1f38..ee9776f 100755 --- a/tests/unit-tests/test-wrappers.sh +++ b/tests/unit-tests/test-wrappers.sh @@ -70,6 +70,7 @@ function test_create_wrappers_verify_content(){ assertEquals "" "$(cat "$STDOUTF")" # Mock junest command to capture the actual output generated from myfile script + # shellcheck disable=SC2317 junest(){ for arg in "$@" do From e68c24dec630412b01f378ffe242f79a5586a38b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Thu, 1 Aug 2024 20:29:07 +0200 Subject: [PATCH 321/326] 7.4.9 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index da8d653..14ebea1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.8 +7.4.9 From 7af01ba4811b03c4764727803a4c4c3d30e23c6c Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 8 Oct 2024 01:04:11 +0200 Subject: [PATCH 322/326] Fix pacman 7 usage during build --- lib/core/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/core/build.sh b/lib/core/build.sh index 7a2ef9d..cf23f67 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -65,6 +65,9 @@ function build_image_env(){ # https://app.travis-ci.com/github/fsquillace/junest/builds/268216346 [[ -e "${maindir}"/root/etc/pacman.conf ]] || sudo curl "https://gitlab.archlinux.org/archlinux/packaging/packages/pacman/-/raw/main/pacman.conf" -o "${maindir}/root/etc/pacman.conf" + # Pacman/pacstrap bug: https://gitlab.archlinux.org/archlinux/packaging/packages/arch-install-scripts/-/issues/3 + sudo sed -i '/^DownloadUser = alpm$/d' "${maindir}"/root/etc/pacman.conf + sudo tee -a "${maindir}"/root/etc/pacman.conf < Date: Tue, 8 Oct 2024 01:10:24 +0200 Subject: [PATCH 323/326] Do not remove gzip during build --- lib/core/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index cf23f67..9d985ea 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -87,13 +87,13 @@ EOT info "Generating the locales..." # sed command is required for locale-gen but it is required by fakeroot # and cannot be removed - # localedef (called by locale-gen) requires gzip + # localedef (called by locale-gen) requires gzip but it is supposed to be + # already installed as systemd already depends on it sudo pacman --noconfirm --root "${maindir}"/root -S sed gzip sudo ln -sf /usr/share/zoneinfo/posix/UTC "${maindir}"/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" sudo "${maindir}"/root/bin/groot "${maindir}"/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" - sudo pacman --noconfirm --root "${maindir}"/root -Rsn gzip info "Setting up the pacman keyring (this might take a while!)..." if [[ $(uname -m) == *"arm"* ]] From e2d9517a92093b6e5caddc5ab8c2254e76819134 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Tue, 8 Oct 2024 19:47:29 +0200 Subject: [PATCH 324/326] Test enabling back the check scripts --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8efa537..fab23ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,7 +51,7 @@ script: - junest setup -i junest-x86_64.tar.gz # TODO The check does not work at the moment: https://app.travis-ci.com/github/fsquillace/junest/builds/271706037 # Disabling it in order to avoid having stale version of junest images. - # - ${PWD}/lib/checks/check_all.sh + - ${PWD}/lib/checks/check_all.sh - yes | junest setup --delete From 0242749f8e39af96e5f1837e1ecfce3f4c146b07 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 12 Oct 2024 11:34:38 +0200 Subject: [PATCH 325/326] Replace yay with yay-git --- lib/core/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/core/build.sh b/lib/core/build.sh index 9d985ea..65a9474 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -76,7 +76,7 @@ Server = https://raw.githubusercontent.com/fsquillace/junest-repo/master/any EOT info "pacman.conf being used:" cat "${maindir}"/root/etc/pacman.conf - sudo pacman --noconfirm --config "${maindir}"/root/etc/pacman.conf --root "${maindir}"/root -Sy sudo-fake groot-git proot-static qemu-user-static-bin-alt yay + sudo pacman --noconfirm --config "${maindir}"/root/etc/pacman.conf --root "${maindir}"/root -Sy sudo-fake groot-git proot-static qemu-user-static-bin-alt yay-git echo "Generating the metadata info" sudo install -d -m 755 "${maindir}/root/etc/${CMD}" From 0037f96e159a143e37db978e537e3fb362ba3a5b Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sat, 12 Oct 2024 11:53:52 +0200 Subject: [PATCH 326/326] Add warning box for Ubuntu restriction --- README.md | 7 +++++++ VERSION | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a7001ce..1268f8b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ JuNest ====== + +> [!IMPORTANT] +> Starting from Ubuntu 23.10+, [unprivileged user namespaces has been restricted](https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces). +> If using JuNest within Ubuntu, you may need root privileges in order to enable it. +> Alternatively, you can access JuNest using the `proot` mode as described +> [below](#Proot-based). + The lightweight Arch Linux based distro that runs, without root privileges, on top of any other Linux distro.

diff --git a/VERSION b/VERSION index 14ebea1..ef13716 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.9 +7.4.10