From 3341187cf6d6cade586460afe03e3994cf3b2d98 Mon Sep 17 00:00:00 2001 From: Filippo Squillace Date: Sun, 20 Oct 2019 16:15:31 +0200 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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"