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/.travis.yml b/.travis.yml index 025ddc7..fab23ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,30 +1,62 @@ -language: bash - sudo: required +os: linux + +cache: + directories: + - ~/.ccache + - ~/.pkg-cache + +services: +- docker env: + matrix: - TRAVIS_BASH_VERSION="4.0" 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 - - 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: + ####################### + # Unit Tests + ####################### - 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 + #- 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 + ####################### + - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin + - 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 - export JUNEST_HOME=~/.junest + - 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 - 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 + +after_success: + ####################### + # Deploy and validation + ####################### + - ./ci/deploy.sh ./junest-x86_64.tar.gz diff --git a/README.md b/README.md index fc9f320..1268f8b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ JuNest ====== -The lightweight Arch Linux based distro that runs upon any Linux distros without root access. + +> [!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.

=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 ========== @@ -70,7 +108,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 @@ -81,7 +121,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 +130,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,6 +147,69 @@ 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 JuNest installed programs directly from host OS +--------------------------------------- + +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: + +```sh +export PATH="$PATH:~/.junest/usr/bin_wrappers" +sudoj pacman -S htop +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 modes you can use the `JUNEST_ARGS` environment variable too. +For instance, if you want to run `iftop` with real root privileges: + +``` +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 +``` + +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 +------------------------- + +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 AUR, `base-devel` package group is required +first: + +```sh +pacman -S base-devel +``` + +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! --------- @@ -114,48 +217,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). -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 -============ - -## 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/) - -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): - - 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/packages/junest-git/). -After installing 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. @@ -189,9 +250,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. -One of the major drawbacks is the fact that Proot is not officially -supported anymore, therefore, Proot bugs may no longer be fixed. +solution which allows unprivileged users to execute programs inside a sandbox +and works well in most of GNU/Linux distros available. In order to run JuNest via Proot: @@ -199,13 +259,21 @@ 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 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 +`/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. @@ -223,7 +291,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 @@ -269,13 +337,19 @@ 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" ``` -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 +377,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 +384,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 @@ -350,9 +409,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 @@ -365,6 +424,8 @@ 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 + ## No servers configured for repository ## > **Q**: Why I cannot install packages? @@ -473,7 +534,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 ## diff --git a/VERSION b/VERSION index 0ee843c..ef13716 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.2.0 +7.4.10 diff --git a/bin/junest b/bin/junest index 17d32bc..4084fe0 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" @@ -17,13 +18,14 @@ 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" ################################### ### 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 @@ -67,16 +69,23 @@ 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 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 } version() { - echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" + echo -e "$NAME $(cat "$JUNEST_BASE"/VERSION)" } function parse_arguments(){ # Actions ACT_SETUP=false ACT_BUILD=false + ACT_CREATE_WRAPPERS=false ACT_NAMESPACE=false ACT_PROOT=false ACT_GROOT=false @@ -87,6 +96,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 ;; @@ -102,6 +112,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 "$@" @@ -189,11 +202,7 @@ function _parse_proot_opts() { esac done - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done + ARGS=("$@") } function _parse_build_opts() { @@ -207,17 +216,29 @@ function _parse_build_opts() { done } +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 +} + 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 @@ -229,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 @@ -243,10 +265,11 @@ 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 return @@ -258,6 +281,12 @@ 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 + # shellcheck disable=SC2086 + create_wrappers $OPT_FORCE "$OPT_BIN_PATH" + exit + fi + local run_env if $ACT_NAMESPACE; then if $OPT_FAKEROOT; then @@ -277,8 +306,11 @@ function execute_operation() { run_env=run_env_as_chroot fi + # 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[@]}" - } function main() { 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/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/ci/deploy.sh b/ci/deploy.sh new file mode 100755 index 0000000..a45d0a1 --- /dev/null +++ b/ci/deploy.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +set -e + +IMG_PATH=$1 + +set -ux + +MAX_OLD_IMAGES=5 +ENDPOINT="https://8da1bcd84e423c9b013b69fe1e8b4675.r2.cloudflarestorage.com" + +# 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=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. + img_name=$(basename "${IMG_PATH}") + aws s3 --endpoint-url="$ENDPOINT" cp "${IMG_PATH}" s3://junest-repo/junest/ + + DATE=$(date +'%Y-%m-%d-%H-%M-%S') + aws s3 --endpoint-url="$ENDPOINT" cp "${IMG_PATH}" "s3://junest-repo/junest/${img_name}.${DATE}" + + # Cleanup old images + 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 + junest -- echo "Installed JuNest (\$(uname -m))" + yes | junest setup --delete +fi diff --git a/ci/install-bash.sh b/ci/install-bash.sh new file mode 100755 index 0000000..b766123 --- /dev/null +++ b/ci/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/lib/checks/check.sh b/lib/checks/check.sh index 634044c..789206e 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 @@ -9,7 +10,7 @@ # # vim: ft=sh -set -e +set -ex RUN_ROOT_TESTS=false @@ -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,44 +45,49 @@ 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 + +prepare_archlinux "$SUDO" PACMAN_OPTIONS="--noconfirm --disable-download-timeout" - -$SUDO pacman $PACMAN_OPTIONS -Syy - -# Awk is required for pacman-key -$SUDO pacman $PACMAN_OPTIONS -S gawk -$SUDO pacman-key --init - -if [[ $(uname -m) == *"arm"* ]] -then - $SUDO pacman $PACMAN_OPTIONS -S archlinuxarm-keyring - $SUDO pacman-key --populate archlinuxarm -else - $SUDO pacman $PACMAN_OPTIONS -S archlinux-keyring - $SUDO pacman-key --populate archlinux -fi - -$SUDO pacman $PACMAN_OPTIONS -Su +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -S grep coreutils -$SUDO pacman $PACMAN_OPTIONS -S $(pacman -Sg base-devel | cut -d ' ' -f 2 | grep -v sudo) +# shellcheck disable=SC2086 +# shellcheck disable=SC2046 +$SUDO pacman $PACMAN_OPTIONS -Syu --ignore sudo base-devel 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 +# 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 $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} -$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 +# shellcheck disable=SC2086 $SUDO pacman $PACMAN_OPTIONS -Rsn ${repo_package2} if ! $SKIP_AUR_TESTS @@ -89,15 +95,8 @@ 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 -# 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/lib/checks/check_all.sh b/lib/checks/check_all.sh index 6e28ee5..13e9237 100755 --- a/lib/checks/check_all.sh +++ b/lib/checks/check_all.sh @@ -5,13 +5,27 @@ 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} + 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 -sudo -E $JUNEST_SCRIPT groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests +# 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 +"$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 diff --git a/lib/core/build.sh b/lib/core/build.sh index 9a224f0..65a9474 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -8,38 +8,29 @@ # # 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.xz -} - 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 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.xz + makepkg --printsrcinfo > "${pkgbuilddir}"/.SRCINFO + sudo pacman --noconfirm --root "${maindir}"/root -U ./*.pkg.tar.* } function _prepare() { # ArchLinux System initialization - sudo pacman --noconfirm -Syu - sudo pacman -S --noconfirm base-devel - sudo pacman -S --noconfirm git arch-install-scripts + prepare_archlinux + # curl is used to download pacman.conf file + sudo pacman -S --noconfirm git arch-install-scripts haveged curl } function build_image_env(){ + set -x umask 022 # The function must runs on ArchLinux with non-root privileges. @@ -51,80 +42,100 @@ 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 "${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 - _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" + # For some reasons, pacstrap does not create the pacman.conf file, + # I could not reproduce the issue locally though: + # 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" - info "Installing yay..." - sudo pacman --noconfirm -S go - _install_pkg_from_aur ${maindir} "yay" + # 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 < ${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 # 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 + # 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 "${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 ${maindir}/root/bin/groot -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 pacman --noconfirm --root ${maindir}/root -Rsn gawk + done;' + sudo umount "${maindir}"/root - 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" + + set +x } diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index 635137b..c2237a9 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -18,21 +18,23 @@ 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 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 - 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 - JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" + # shellcheck disable=SC2086 + JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" } ####################################### @@ -43,13 +45,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 +60,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 +80,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 +95,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 eb728e9..df79bec 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. # @@ -25,11 +27,11 @@ 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:"$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 +UNAME="uname" ARCH_LIST=('x86_64' 'x86' 'arm') HOST_ARCH=$($UNAME -m) @@ -51,9 +53,11 @@ else die "Unknown architecture ${HOST_ARCH}" fi -MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo +MAIN_REPO=https://link.storjshare.io/s/jvb5tgarnjtt565fffa44spvyuga/junest-repo +MAIN_REPO=https://pub-a2af2344e8554f6c807bc3db355ae622.r2.dev ENV_REPO=${MAIN_REPO}/${CMD} -DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' +# shellcheck disable=SC2016 +DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) @@ -64,25 +68,26 @@ 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" +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 +TAR="tar" CHOWN="chown" -LN=ln -RM=rm -MKDIR=mkdir -GETENT=getent -CP=cp +LN="ln" +RM="rm" +MKDIR="mkdir" +GETENT="getent" +CP="cp" +ID="id" # Used for checking user namespace in config.gz file -ZGREP=zgrep -UNSHARE=unshare -BWRAP=bwrap +ZGREP="zgrep" +UNSHARE="unshare" LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -91,32 +96,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 +129,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(){ @@ -132,12 +137,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" ":" + $LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE "${@}" + elif $UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" then $UNSHARE "$@" else @@ -146,9 +151,9 @@ function unshare_cmd(){ } function bwrap_cmd(){ - if $LD_EXEC ${JUNEST_HOME}/usr/bin/$BWRAP --dev-bind / / "${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 @@ -157,10 +162,12 @@ function bwrap_cmd(){ function proot_cmd(){ local proot_args="$1" shift - if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" + # 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} "${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" @@ -192,7 +199,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 +221,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 @@ -239,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 @@ -272,24 +279,26 @@ 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 ${JUNEST_HOME}/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 ${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 } @@ -300,3 +309,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 +} diff --git a/lib/core/namespace.sh b/lib/core/namespace.sh index 1307de0..70763bd 100644 --- a/lib/core/namespace.sh +++ b/lib/core/namespace.sh @@ -10,11 +10,29 @@ # # 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 --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" +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 @@ -23,66 +41,44 @@ function _is_user_namespace_enabled() { then config_file=$CONFIG_BOOT_FILE else - return $NOT_EXISTING_FILE + 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 + 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 + return "$UNPRIVILEGED_USERNS_DISABLED" } 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 } -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. +# 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 # 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 +88,7 @@ function _run_env_with_bwrap(){ function run_env_as_bwrap_fakeroot(){ check_nested_env - local backend_command="$1" + local backend_command="${1:-$BWRAP}" local backend_args="$2" local no_copy_files="$3" shift 3 @@ -106,7 +102,12 @@ function run_env_as_bwrap_fakeroot(){ copy_common_files fi - _run_env_with_bwrap "$backend_command" "--uid 0 $backend_args" "$@" + 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 + 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[@]}" } @@ -115,13 +116,14 @@ 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. +# 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 # 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 +132,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}" local backend_args="$2" local no_copy_files="$3" shift 3 @@ -150,7 +152,12 @@ 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 "${@}")") + + # Resets PATH to avoid polluting with host related bin paths + # shellcheck disable=SC2086 + 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 bce8295..b6c1c8f 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. # @@ -9,18 +10,15 @@ # vim: ft=sh function _run_env_with_proot(){ - local backend_command="$1" + local backend_command="${1:-$PROOT}" 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 + # 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(){ @@ -28,18 +26,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 @@ -52,13 +51,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: @@ -66,7 +65,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" @@ -94,13 +93,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: @@ -108,7 +107,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 532f2a2..58c6122 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,12 +52,18 @@ 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 "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" + echo + info "To install packages from AUR follow the wiki here:" + info "https://github.com/fsquillace/junest#install-packages-from-aur" } @@ -81,21 +88,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}" } ####################################### @@ -115,10 +123,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}" } ####################################### @@ -135,18 +143,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/core/wrappers.sh b/lib/core/wrappers.sh new file mode 100644 index 0000000..1fe955c --- /dev/null +++ b/lib/core/wrappers.sh @@ -0,0 +1,60 @@ +#!/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} + 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 + # 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}${bin_path}" || return 1 + for file in * + do + [[ -d $file ]] && continue + # 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}${bin_path}_wrappers/$file ]] && ! $force + then + continue + fi + 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}${bin_path}_wrappers" || return 1 + for file in * + do + [[ -e ${JUNEST_HOME}${bin_path}/$file || -L ${JUNEST_HOME}${bin_path}/$file ]] || rm -f "$file" + done + +} 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/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 95d34de..0000000 --- a/pkgs/proot-static/PKGBUILD +++ /dev/null @@ -1,52 +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_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" - 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 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: 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/integ-tests/install-bash.sh b/tests/integ-tests/install-bash.sh deleted file mode 100755 index 575c9c5..0000000 --- a/tests/integ-tests/install-bash.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/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/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 4556671..3739c58 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" @@ -28,33 +29,37 @@ function tearDown(){ function init_mocks() { chroot_cmd() { + # shellcheck disable=SC2317 [ "$JUNEST_ENV" != "1" ] && return 1 - echo "chroot_cmd $@" + # shellcheck disable=SC2317 + echo "chroot_cmd $*" } + # shellcheck disable=SC2034 GROOT=chroot_cmd mychroot() { - echo mychroot $@ + # shellcheck disable=SC2317 + 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 /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 -c /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 -c /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 $? @@ -74,27 +79,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 /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(){ 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 -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(){ 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 +119,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 dd77077..89c1a1e 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,59 @@ function oneTimeTearDown(){ function setUp(){ ld_exec_mock() { - echo "ld_exec $@" + # shellcheck disable=SC2317 + echo "ld_exec $*" } + # shellcheck disable=SC2317 ld_exec_mock_false() { - echo "ld_exec $@" + echo "ld_exec $*" return 1 } + # shellcheck disable=SC2034 LD_EXEC=ld_exec_mock unshare_mock() { - echo "unshare $@" + # shellcheck disable=SC2317 + echo "unshare $*" } + # shellcheck disable=SC2034 UNSHARE=unshare_mock + # shellcheck disable=SC2317 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 +84,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 +94,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 ${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 } 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 } @@ -166,38 +177,43 @@ function test_proot_cmd_compat(){ function test_proot_cmd_seccomp(){ envv(){ + # shellcheck disable=SC2317 env } PROOT=envv assertCommandSuccess proot_cmd cmd - assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" + assertEquals "" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" envv(){ + # shellcheck disable=SC2317 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 $@ + # shellcheck disable=SC2317 + 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 $@ + # shellcheck disable=SC2317 + 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(){ @@ -213,14 +229,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 e3c7ee1..07a92b1 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 @@ -12,112 +14,143 @@ 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" + local no_copy_files="$3" + 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" + local no_copy_files="$3" + 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" + local no_copy_files="$3" + 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" + local no_copy_files="$3" + 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" + local no_copy_files="$3" + 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" + local no_copy_files="$3" + shift 3 + echo "run_env_as_bwrap_user($backend_command,$backend_args,$no_copy_files,$*)" + } + # shellcheck disable=SC2317 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 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,$@)" + # shellcheck disable=SC2317 + function create_wrappers(){ + : + } } 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(){ + # shellcheck disable=SC2317 + 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)" + 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(){ + # shellcheck disable=SC2317 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 0 } @@ -125,18 +158,20 @@ function test_setup_env_from_file(){ } function test_setup_env(){ + # shellcheck disable=SC2317 is_env_installed(){ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 0 } @@ -145,26 +180,27 @@ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -173,24 +209,25 @@ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -199,22 +236,23 @@ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -223,20 +261,21 @@ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -245,40 +284,41 @@ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -287,40 +327,41 @@ 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")" + # shellcheck disable=SC2317 is_env_installed(){ return 1 } @@ -339,4 +380,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 9efbad3..7a845aa 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" @@ -15,11 +16,9 @@ function oneTimeSetUp(){ ## Mock functions ## function init_mocks() { + # shellcheck disable=SC2317 function bwrap_cmd(){ - echo "bwrap $@" - } - function mybwrap(){ - echo "mybwrap $@" + echo "$BWRAP $*" } } @@ -42,16 +41,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 $? @@ -60,65 +59,62 @@ 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 + 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 + assertCommandFailOnStatus "$NO_CONFIG_FOUND" _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 + 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 } +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 --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 $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 --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 $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 --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 +122,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 +130,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 $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 +156,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 +182,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 --bind /usr /usr /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 --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 +197,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 /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 --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 +212,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 --bind /usr /usr /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 --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 @@ -236,9 +232,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..0f4f11a 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 $? @@ -48,41 +49,50 @@ function _test_copy_remaining_files() { } function test_run_env_as_proot_user(){ + # shellcheck disable=SC2317 _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 /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 } function test_run_env_as_proot_user_with_backend_command(){ + # shellcheck disable=SC2317 _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 /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 } function test_run_env_as_proot_user_no_copy(){ + # shellcheck disable=SC2317 _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 /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 $? @@ -113,29 +123,36 @@ function test_run_env_as_proot_user_nested_env(){ } function test_run_env_as_proot_fakeroot(){ + # shellcheck disable=SC2317 _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 /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 } function test_run_env_as_proot_fakeroot_with_backend_command(){ + # shellcheck disable=SC2317 _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 /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 } @@ -147,42 +164,57 @@ function test_run_env_as_proot_fakeroot_nested_env(){ } function test_run_env_with_quotes(){ + # shellcheck disable=SC2317 _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 /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(){ + # shellcheck disable=SC2317 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 + # shellcheck disable=SC2317 rm_cmd() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } + # shellcheck disable=SC2317 ln_cmd() { - echo $@ + # shellcheck disable=SC2086 + # shellcheck disable=SC2048 + echo $* } + # shellcheck disable=SC2317 _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..de2df75 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,27 @@ 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:?}"/* + # shellcheck disable=SC2317 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 +56,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 +68,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 +82,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 new file mode 100755 index 0000000..ee9776f --- /dev/null +++ b/tests/unit-tests/test-wrappers.sh @@ -0,0 +1,139 @@ +#!/bin/bash +# shellcheck disable=SC1091 + +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_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 + 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_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 + # shellcheck disable=SC2317 + junest(){ + for arg in "$@" + do + echo "$arg" + done + } + assertEquals "ns +--fakeroot +-b +--bind /run /run2 +-- +test-wrappers.sh +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 + 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")" + 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)" +} + +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(){ + 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 ]" +} + +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 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/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 diff --git a/tests/utils/utils.sh b/tests/utils/utils.sh index ed7cb8c..ab37bd9 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -1,25 +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}/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 } @@ -31,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" $? } @@ -49,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" $? }