diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 8efae1f..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: fsquillace -custom: https://github.com/fsquillace/junest/blob/master/README.md#donating diff --git a/.gitignore b/.gitignore index b47a408..1377554 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ *.swp -*pkg.tar.* -*.tar.gz -*.SRCINFO diff --git a/.travis.yml b/.travis.yml index fab23ba..a1b6078 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,62 +1,25 @@ +language: bash + sudo: required -os: linux - -cache: - directories: - - ~/.ccache - - ~/.pkg-cache - -services: -- docker env: - matrix: - TRAVIS_BASH_VERSION="4.0" before_install: - - ./ci/install-bash.sh "$TRAVIS_BASH_VERSION" - - sudo apt-get update - - sudo apt-get -y install awscli + - ./tests/integ-tests/install-bash.sh "$TRAVIS_BASH_VERSION" install: - PATH=$PWD/bin:$PATH + - junest -- echo "Installing JuNest (\$(uname -m))" + - JUNEST_HOME=~/.junest-arm junest -a arm -- echo "Installing JuNest (\$(uname -m))" + # TODO: Remember to enable x86 tests when fixed + #- JUNEST_HOME=~/.junest-x86 junest -a x86 -- echo "Installing JuNest (\$(uname -m))" 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 - - -after_success: - ####################### - # Deploy and validation - ####################### - - ./ci/deploy.sh ./junest-x86_64.tar.gz + - bash ./tests/checkstyle/checkstyle.sh + - junest --check ./bin/junest + - yes | junest --delete + - JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests + - yes | JUNEST_HOME=~/.junest-arm junest --delete diff --git a/README.md b/README.md index 1268f8b..98f0c9e 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ JuNest ====== - -> [!IMPORTANT] -> Starting from Ubuntu 23.10+, [unprivileged user namespaces has been restricted](https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces). -> If using JuNest within Ubuntu, you may need root privileges in order to enable it. -> Alternatively, you can access JuNest using the `proot` mode as described -> [below](#Proot-based). - -The lightweight Arch Linux based distro that runs, without root privileges, on top of any other Linux distro. +The Arch Linux based distro that runs upon any Linux distros without root access.

=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 -========== - -Setup environment ------------------ - -The first operation required is to install the JuNest environment in the -location of your choice via `JUNEST_HOME` environment variable -(it must contain an absolute path) which by -default is `~/.junest`: - -```sh -junest setup -``` - -The script will download the image from the repository and will place it to the default directory `~/.junest`. - -Access to environment ---------------------- - -JuNest uses the Linux namespaces (aka `ns`) as the default backend program. To access via `ns` just type: - -```sh -junest -``` - -You can use the command `sudo` to acquire fakeroot privileges and -install/remove packages. - -Alternatively, you can access fakeroot privileges without using `sudo` all the -time with the `-f` (or `--fakeroot`) option: - -```sh -junest -f -``` - -Another execution mode is via [Proot](https://wiki.archlinux.org/index.php/Proot): - -```sh -junest proot [-f] -``` - -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! ---------- - -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). - -Usage -===== -There are three different ways you can run JuNest depending on the backend program you decide to use. - -Linux namespaces based ----------------------- -The [Linux namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html) -represents the default backend program for JuNest. -The requirements for having Linux namespaces working are: - -1. Kernel starting from Linux 3.8 allows unprivileged processes to create -user and mount namespaces. -1. The Linux kernel distro must have the user namespace enabled. - -In the last years, the majority of GNU/Linux distros have the user namespace -enabled by default. This means that you do not need to have root privileges to -access to the JuNest environment via this method. -This -[wiki](https://github.com/fsquillace/junest/wiki/Linux-distros-with-user-namespace-enabled-by-default) -provides the state of the user namespace on several GNU/Linux distros. - -In order to run JuNest via Linux namespaces: - -- As normal user - Allow to make basic operations or install/remove packages -with `sudo` command: `junest ns` or `junest` -- As fakeroot - Allow to install/remove packages: `junest ns -f` or `junest -f` - -This mode is based on the fantastic -[`bubblewrap`](https://github.com/containers/bubblewrap) command. - -PRoot based ------------ -[Proot](https://wiki.archlinux.org/index.php/Proot) represents a portable -solution which allows unprivileged users to execute programs inside a sandbox -and works well in most of GNU/Linux distros available. - -In order to run JuNest via Proot: - -- As normal user - Allow to make basic operations: `junest 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 +The minimum recommended Linux kernel of the host OS is 2.6.32 on x86 (32-bit +and 64 bit) and ARM architectures. It is still possible to run JuNest on lower 2.6.x host OS kernels but errors may appear, and some applications may crash. For further information, read the [Troubleshooting](#troubleshooting) section below. -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`, 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`, `/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. -In order to run JuNest via `chroot` solutions: +## Method one (Recommended) ## +Just clone the JuNest repo somewhere (for example in ~/.local/share/junest): -- As root via `GRoot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): `junest groot` + git clone git://github.com/fsquillace/junest ~/.local/share/junest + export PATH=~/.local/share/junest/bin:$PATH -- As root via `chroot` - Allow to have fully root privileges inside JuNest environment (you need to be root for executing this): `junest root` +### 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/): -Execution modes comparison table ----------------- -The following table shows the capabilities that each backend program is able to perform: + yogurt -S junest-git + export PATH=/opt/junest/bin:$PATH -| | 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 | YES | Normal user and `fakeroot` | -| **Chroot** | NO | YES | YES | YES | YES | YES | `root` only | +## Method two ## +Alternatively, another installation method would be to directly download the JuNest image and place it to the default directory ~/.junest: + + ARCH= + mkdir ~/.junest + curl https://dl.dropboxusercontent.com/u/42449030/junest/junest-${ARCH}.tar.gz | tar -xz -C ~/.junest + export PATH=~/.junest/opt/junest/bin:$PATH Advanced usage ============== + ## Build image ## You can build a new JuNest image from scratch by running the following command: -```sh -junest build [-n] -``` + junest -b [-n] The script will create a directory containing all the essentials -files in order to make JuNest working properly (such as `pacman` and `proot`). -The option `-n` will skip the final validation tests if they are not needed. +files in order to make JuNest working properly (such as pacman, yogurt and proot). +The option **-n** will skip the final validation tests if they are not needed. Remember that the script to build the image must run in an Arch Linux OS with -arch-install-scripts and the base-devel packages installed. -To change the build directory just use the `JUNEST_TEMPDIR` (by default /tmp). +arch-install-scripts, package-query, git and the base-devel packages installed. +To change the build directory just use the *JUNEST_TEMPDIR* (by default /tmp). -After creating the image `junest-x86_64.tar.gz` you can install it by running: +After creating the image junest-x86\_64.tar.gz you can install it by running: -```sh -junest setup -i junest-x86_64.tar.gz -``` + junest -i junest-x86_64.tar.gz For more details, you can also take a look at [junest-builder](https://github.com/fsquillace/junest-builder) @@ -327,36 +131,22 @@ Related wiki page: ## Run JuNest using a different architecture via QEMU ## The following command will download the ARM JuNest image and will run QEMU in -case the host OS runs on `x86_64` architecture: +case the host OS runs on either x86\_64 or x86 architectures: -```sh -$> export JUNEST_HOME=~/.junest-arm -$> junest setup -a arm -$> junest proot -- uname -m -armv7l -``` + $> JUNEST_HOME=~/.junest-arm junest -a arm -- uname -m + armv7l ## Bind directories ## -To bind a host directory to a guest location: +To bind a host directory to a guest location, you can use proot arguments: -```sh -junest -b "--bind /home/user/mydata /mnt/mydata" -``` + junest -p "-b /mnt/mydata:/home/user/mydata" -Or using proot arguments: +Check out the proot options with: -```sh -junest proot -b "-b /mnt/mydata:/home/user/mydata" -``` - -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 -junest [u|g|p] -b "--help" -``` + junest -p "--help" ## Systemd integration ## + Although JuNest has not been designed to be a complete container, it is even possible to virtualize the process tree thanks to the [systemd container](https://wiki.archlinux.org/index.php/Systemd-nspawn). The JuNest containter allows to run services inside the container that can be @@ -366,9 +156,7 @@ and the container can only be executed using root privileges. To boot a JuNest container: -```sh -sudo systemd-nspawn -bD ~/.junest -``` + sudo systemd-nspawn -bD ~/.junest Related wiki page: @@ -377,17 +165,30 @@ 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 +jchroot, a small and portable version of +[arch-chroot](https://wiki.archlinux.org/index.php/Chroot) which is an +enhanced chroot for privileged users that mounts the primary directories +(i.e. /proc, /sys, /dev and /run) before executing any programs inside +the sandbox. + +## Automatic fallback to classic chroot ## +If jchroot fails for some reasons in the host system (i.e. it is not able to +mount one of the directories), +JuNest automatically tries to fallback to the classic chroot. + ## Automatic fallback for all the dependent host OS executables ## -JuNest attempts first to run the executables in the host OS located in different -positions (`/usr/bin`, `/bin`, `/usr/sbin` and `/sbin`). +JuNest attempt first to run the executables in the host OS located in different +positions (/usr/bin, /bin, /usr/sbin and /sbin). As a fallback it tries to run the same executable if it is available in the JuNest -environment. +image. ## Automatic building of the JuNest images ## -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. +The JuNest images are built every week so that you can always get the most +updated package versions. ## Static QEMU binaries ## There are static QEMU binaries included in JuNest image that allows to run JuNest @@ -397,35 +198,18 @@ directory. Troubleshooting =============== -For Arch Linux related FAQs take a look at the [General troubleshooting page](https://wiki.archlinux.org/index.php/General_troubleshooting). - ## Cannot use AUR repository ## -> **Q**: Why do I get the following error when I try to install a package? +> **Q**: Why do I get the following error when I try to install a package with yogurt? Cannot find the gzip binary required for compressing man and info pages. > **A**: JuNest comes with a very basic number of packages. -> In order to install 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): +> In order to install packages using yogurt you may need to install the package group **base-devel** +> that contains all the essential packages for compiling source code (such as gcc, make, patch, etc): #> pacman -S base-devel -> Remember to not install `core/sudo` as it conflicts with `junest/sudo-fake` package. - -## Can't set user and group as root - -> **Q**: In ns mode when installing package I get the following error: - - warning: warning given when extracting /usr/file... (Can't set user=0/group=0 for - /usr/file...) - -> **A**: This is because as fakeroot is not possible to set the owner/group of -> files as root. The package will still be installed correctly even though this -> message is showed. - -## Could not change the root directory in pacman - ## No servers configured for repository ## > **Q**: Why I cannot install packages? @@ -461,8 +245,6 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht $> pkgfile getop core/util-linux -> Alternatively, you can use directly `pacman` command only. Take a look [here](https://wiki.archlinux.org/index.php/General_troubleshooting#Message:_%22error_while_loading_shared_libraries%22). - ## Kernel too old ## > **Q**: Why do I get the error: "FATAL: kernel too old"? @@ -477,7 +259,7 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > on to PRoot when *-p* is prepended. For example, to fake a kernel version of > 3.10, issue the following command: - $> junest proot -b "-k 3.10" + $> junest -p "-k 3.10" > As Arch Linux ships binaries for kernel version 2.6.32, the above error is > not unique to the precompiled package from JuNest. It will also appear when @@ -534,7 +316,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 ## @@ -563,32 +345,6 @@ For Arch Linux related FAQs take a look at the [General troubleshooting page](ht > since JuNest will try to preserve the JuNest environment by assigning ownership > of the files to the real user. -## Unprivileged user namespace disable at kernel compile time or kernel too old ## - -> **Q**: Why do I get this warning when I run JuNest via Linux namespaces? - - $> junest ns - Unprivileged user namespace is disabled at kernel compile time or kernel too old (<3.8). Proceeding anyway... - -> **A**: This means that JuNest detected that the host OS either -> does not have a newer kernel version or the unprivileged user namespace -> is not enabled at kernel compile time. -> JuNest does not stop the execution of the program but it attempts to run it -> anyway. Try to use Proot as backend program in case is not possible to invoke namespaces. - -## Unprivileged user namespace disabled - -> **Q**: Why do I get this warning when I run JuNest via Linux namespaces? - - $> junest ns - Unprivileged user namespace disabled. Root permissions are required to enable it: sudo sysctl kernel.unprivileged_userns_clone=1 - -> **A**: This means that JuNest detected that the host OS either -> does not have a newer Linux version or the user namespace is not enabled. -> JuNest does not stop the execution of the program but it attempts to run it -> anyway. If you have root permissions try to enable it, otherwise try to use -> Proot as backend program. - More documentation ================== There are additional tutorials in the @@ -596,21 +352,13 @@ There are additional tutorials in the Contributing ============ -Contributions are welcome! You could help improving JuNest in the following ways: +You could help improving JuNest in the following ways: - [Reporting Bugs](CONTRIBUTING.md#reporting-bugs) - [Suggesting Enhancements](CONTRIBUTING.md#suggesting-enhancements) - [Writing Code](CONTRIBUTING.md#your-first-code-contribution) -Donating -======== -To sustain the project please consider funding by donations through -the [GitHub Sponsors page](https://github.com/sponsors/fsquillace/). +Author +====== +Filippo Squillace -Authors -======= -JuNest was originally created in late 2014 by [Filippo Squillace (feel.sqoox@gmail.com)](https://github.com/fsquillace). - -Here is a list of [**really appreciated contributors**](https://github.com/fsquillace/junest/graphs/contributors)! - -[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/0)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/0)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/1)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/1)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/2)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/2)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/3)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/3)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/4)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/4)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/5)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/5)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/6)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/6)[![](https://sourcerer.io/fame/fsquillace/fsquillace/junest/images/7)](https://sourcerer.io/fame/fsquillace/fsquillace/junest/links/7) diff --git a/VERSION b/VERSION index ef13716..723bfc6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.4.10 +5.6.11 diff --git a/bin/jchroot b/bin/jchroot new file mode 100755 index 0000000..8eaa8d4 --- /dev/null +++ b/bin/jchroot @@ -0,0 +1,98 @@ +#!/bin/bash +# +# This script is the simplified and portable version of arch-chroot +# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot) +# + +set -e + +JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)" + +source "${JUNEST_BASE}/lib/utils.sh" + +################################ MAIN FUNCTIONS ########################### + +chroot_add_mount() { + mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}") +} + +chroot_maybe_add_mount() { + local cond=$1; shift + if eval "$cond"; then + chroot_add_mount "$@" + fi +} + +chroot_setup() { + CHROOT_ACTIVE_MOUNTS=() + [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' + trap 'chroot_teardown' EXIT + + chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind && + chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev && + chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro && + chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid && + chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec && + chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev && + chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 && + chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,atime,nodev,nosuid && + mkdir -p "$1/$HOME" && + chroot_add_mount $HOME "$1/$HOME" --bind + + mkdir -p "$1/run/lock" +} + +chroot_teardown() { + umount "${CHROOT_ACTIVE_MOUNTS[@]}" + unset CHROOT_ACTIVE_MOUNTS +} + +usage() { + cat < Setup the $NAME image in ${JUNEST_HOME}" + echo -e "-a, --arch $NAME architecture to download (x86_64, x86, arm)" + echo -e " Defaults to the host architecture ($ARCH)" + echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}" echo - echo -e "Actions and options:" - echo -e " s[etup] Setup $NAME in ${JUNEST_HOME} either from repo or from file" - echo -e " -i, --from-file Setup the $NAME image in ${JUNEST_HOME}" - echo -e " -a, --arch $NAME architecture to download (x86_64, arm)" - echo -e " Defaults to the host architecture ($ARCH)" - echo -e " -d, --delete Delete $NAME from ${JUNEST_HOME}" + echo -e "Access options:" + echo -e "-f, --fakeroot Run $NAME with fakeroot privileges" + echo -e "-r, --root Run $NAME with root privileges" + echo -e "-p, --proot-args Proot arguments (use $CMD -p \"--help\" to check out the proot options)" echo - echo -e " n[s] Access via Linux Namespaces using BubbleWrap (Default action)" - echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" - echo -e " --backend-command Bwrap command to use" - echo -e " -b, --backend-args Arguments for bwrap backend program" - echo -e " ($CMD ns -b \"--help\" to check out the bwrap options)" - echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" - echo - echo -e " p[root] Access via PRoot" - echo -e " -f, --fakeroot Run $NAME with fakeroot privileges" - echo -e " --backend-command PRoot command to use" - echo -e " -b, --backend-args Arguments for PRoot backend program" - echo -e " ($CMD proot -b \"--help\" to check out the PRoot options)" - echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" - echo - echo -e " g[root] Access with root privileges via GRoot" - echo -e " --backend-command GRoot command to use" - echo -e " -b, --backend-args Arguments for GRoot backend program" - echo -e " ($CMD groot -b \"--help\" to check out the GRoot options)" - echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" - echo - echo -e " r[oot] Access with root privileges via classic chroot" - echo -e " --backend-command Chroot command to use" - echo -e " -b, --backend-args Arguments for chroot backend program" - echo -e " ($CMD root -b \"--help\" to check out the chroot options)" - echo -e " -n, --no-copy-files Do not copy common etc files into $NAME environment" - echo - echo -e " b[uild] Build a $NAME image (must run in ArchLinux)" - echo -e " -n, --disable-check Disable the $NAME image check" - echo - echo -e " 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 -e "Building options:" + echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)" + echo -e "-n, --disable-validation Disable the $NAME image validation" + echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}" + echo -e " using ${CMD}_script. This will alterate the environment" + echo -e "-s, --skip-root-tests Skip the root tests during the validation process" echo + echo -e "General options:" + echo -e "-h, --help Show this help message" + echo -e "-v, --version Show the $NAME version" } version() { - echo -e "$NAME $(cat "$JUNEST_BASE"/VERSION)" + echo -e "$NAME $(cat $JUNEST_BASE/VERSION)" } +check_cli(){ + if $OPT_BUILD_IMAGE + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK + then + die "The build image option must be used exclusively" + fi + fi + if $OPT_SKIP_ROOT_TEST + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT + then + die "The skip root tests option must be used with either build image or check options" + fi + fi + if $OPT_CHECK + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_BUILD_IMAGE + then + die "The validation image option must be used exclusively" + fi + fi + if $OPT_DISABLE_VALIDATION + then + if $OPT_DELETE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_CHECK + then + die "The disable validation option must be used with the build image option only" + fi + fi + if $OPT_DELETE + then + if $OPT_BUILD_IMAGE || $OPT_HELP || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + then + die "The $NAME delete option must be used exclusively" + fi + fi + if $OPT_HELP + then + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_VERSION || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + then + die "The $NAME help option must be used exclusively" + fi + fi + if $OPT_VERSION + then + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ + $OPT_FAKEROOT || $OPT_ROOT || $OPT_DISABLE_VALIDATION || $OPT_CHECK + then + die "The $NAME version option must be used exclusively" + fi + fi + if $OPT_FAKEROOT && $OPT_ROOT + then + die "You must access to $NAME with either fakeroot or root permissions" + fi + if $OPT_PROOT_ARGS || $OPT_ARCH + then + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || \ + $OPT_ROOT || $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK + then + die "Invalid syntax: Proot and arch args are not allowed with the other options" + fi + fi + if [ "$ARGS" != "" ] + then + if $OPT_BUILD_IMAGE || $OPT_DELETE || $OPT_HELP || $OPT_SETUP_FROM_FILE || \ + $OPT_VERSION || $OPT_DISABLE_VALIDATION || $OPT_CHECK + then + die "No arguments are needed. For the CLI syntax run: $CMD --help" + fi + fi + + return 0 +} + + function parse_arguments(){ - # Actions - ACT_SETUP=false - ACT_BUILD=false - ACT_CREATE_WRAPPERS=false - ACT_NAMESPACE=false - ACT_PROOT=false - ACT_GROOT=false - ACT_ROOT=false - ACT_HELP=false - ACT_VERSION=false - - 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 ;; - r|root) ACT_ROOT=true ; shift ;; - -h|--help) ACT_HELP=true ; shift ;; - -V|--version) ACT_VERSION=true ; shift ;; - *) ACT_NAMESPACE=true ;; - esac - - if $ACT_SETUP - then - _parse_setup_opts "$@" - elif $ACT_BUILD - then - _parse_build_opts "$@" - elif $ACT_CREATE_WRAPPERS - then - _parse_create_wrappers_opts "$@" - elif $ACT_NAMESPACE - then - _parse_ns_opts "$@" - elif $ACT_PROOT - then - _parse_proot_opts "$@" - elif $ACT_GROOT - then - _parse_root_opts "$@" - elif $ACT_ROOT - then - _parse_root_opts "$@" - fi -} - -function _parse_root_opts() { - # Options: - BACKEND_ARGS="" - OPT_NO_COPY_FILES=false - BACKEND_COMMAND="" - - while [[ -n "$1" ]] - do - case "$1" in - -b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;; - -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; - --backend-command) shift; BACKEND_COMMAND="$1"; shift ;; - --) shift ; break ;; - -*) die "Invalid option $1" ;; - *) break ;; - esac - done - - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done -} - -function _parse_ns_opts() { - # Options: - OPT_FAKEROOT=false - BACKEND_ARGS="" - OPT_NO_COPY_FILES=false - BACKEND_COMMAND="" - - while [[ -n "$1" ]] - do - case "$1" in - -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;; - -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; - --backend-command) shift; BACKEND_COMMAND="$1"; shift ;; - --) shift ; break ;; - -*) die "Invalid option $1" ;; - *) break ;; - esac - done - - ARGS=() - for arg in "$@" - do - ARGS+=("$arg") - done -} - -function _parse_proot_opts() { - # Options: - OPT_FAKEROOT=false - BACKEND_ARGS="" - OPT_NO_COPY_FILES=false - BACKEND_COMMAND="" - - while [[ -n "$1" ]] - do - case "$1" in - -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; - -b|--backend-args) shift ; BACKEND_ARGS=$1; shift ;; - -n|--no-copy-files) OPT_NO_COPY_FILES=true ; shift ;; - --backend-command) shift; BACKEND_COMMAND="$1"; shift ;; - --) shift ; break ;; - -*) die "Invalid option $1" ;; - *) break ;; - esac - done - - ARGS=("$@") -} - -function _parse_build_opts() { - OPT_DISABLE_CHECK=false - while [[ -n "$1" ]] - do - case "$1" in - -n|--disable-check) OPT_DISABLE_CHECK=true ; shift ;; - *) die "Invalid option $1" ;; - esac - 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 + OPT_SETUP_FROM_FILE=false IMAGE_FILE="" + OPT_FAKEROOT=false + OPT_ROOT=false + OPT_PROOT_ARGS=false + PROOT_ARGS="" + OPT_ARCH=false ARCH_ARG="" + OPT_BUILD_IMAGE=false + OPT_DISABLE_VALIDATION=false + OPT_CHECK=false + CHECK_ARG="" + OPT_SKIP_ROOT_TEST=false OPT_DELETE=false - while [[ -n "$1" ]] + OPT_HELP=false + OPT_VERSION=false + for opt in "$@" do case "$1" in - -i|--from-file) OPT_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; - -a|--arch) shift ; ARCH_ARG=$1; shift ;; + -i|--setup-from-file) OPT_SETUP_FROM_FILE=true ; shift ; IMAGE_FILE=$1 ; shift ;; + -f|--fakeroot) OPT_FAKEROOT=true ; shift ;; + -r|--root) OPT_ROOT=true ; shift ;; + -p|--proot-args) OPT_PROOT_ARGS=true ; shift ; PROOT_ARGS=$1; shift ;; + -a|--arch) OPT_ARCH=true ; shift ; ARCH_ARG=$1; shift ;; + -b|--build-image) OPT_BUILD_IMAGE=true ; shift ;; + -n|--disable-validation) OPT_DISABLE_VALIDATION=true ; shift ;; + -c|--check) OPT_CHECK=true ; shift ; CHECK_ARG=$1; shift ;; + -s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;; -d|--delete) OPT_DELETE=true ; shift ;; - *) die "Invalid option $1" ;; + -h|--help) OPT_HELP=true ; shift ;; + -v|--version) OPT_VERSION=true ; shift ;; + --) shift ; break ;; + -*) die "Invalid option $1" ;; + *) break ;; esac done + + ARGS=() + for arg in "$@" + do + ARGS+=("$arg") + done } -function execute_operation() { - $ACT_HELP && usage && return - $ACT_VERSION && version && return +function execute_operation(){ + $OPT_HELP && usage && return + $OPT_VERSION && version && return - if $ACT_BUILD; then - # shellcheck disable=SC2086 - build_image_env $OPT_DISABLE_CHECK + if $OPT_BUILD_IMAGE; then + build_image_env $OPT_DISABLE_VALIDATION $OPT_SKIP_ROOT_TEST + return + elif $OPT_DELETE; then + delete_env + return + elif $OPT_CHECK; then + check_env "${JUNEST_HOME}" "${CHECK_ARG}" $OPT_SKIP_ROOT_TEST return fi - if $ACT_SETUP; then - if $OPT_DELETE; then - delete_env - else - if is_env_installed - then - die "Error: The image cannot be installed since $JUNEST_HOME is not empty." - fi - - if $OPT_FROM_FILE; then - setup_env_from_file "$IMAGE_FILE" - else - setup_env "$ARCH_ARG" - fi - create_wrappers - fi - - return - fi - - if ! is_env_installed then - 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 - run_env=run_env_as_bwrap_fakeroot + if $OPT_SETUP_FROM_FILE; then + setup_env_from_file $IMAGE_FILE else - run_env=run_env_as_bwrap_user + setup_env $ARCH_ARG + unset ARCH_ARG fi - elif $ACT_PROOT; then - if $OPT_FAKEROOT; then - run_env=run_env_as_proot_fakeroot - else - run_env=run_env_as_proot_user - fi - elif $ACT_GROOT; then - run_env=run_env_as_groot - elif $ACT_ROOT; then - run_env=run_env_as_chroot + elif $OPT_SETUP_FROM_FILE; then + die "Error: The image cannot be installed since $JUNEST_HOME is not empty." 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[@]}" + [ -z "${ARCH_ARG}" ] || \ + die "The option --arch cannot be specified since JuNest has already been downloaded in $JUNEST_HOME" + + if $OPT_FAKEROOT; then + run_env_as_fakeroot "${PROOT_ARGS}" "${ARGS[@]}" + elif $OPT_ROOT; then + run_env_as_root "${ARGS[@]}" + else + run_env_as_user "${PROOT_ARGS}" "${ARGS[@]}" + fi } -function main() { +function cli() { parse_arguments "$@" + check_cli execute_operation } -main "$@" +cli "$@" # vim: set ts=4 sw=4 noet: diff --git a/bin/sudoj b/bin/sudoj deleted file mode 100755 index aa43e15..0000000 --- a/bin/sudoj +++ /dev/null @@ -1,8 +0,0 @@ -#!/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 deleted file mode 100755 index f9cda95..0000000 --- a/ci/build_image.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/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 deleted file mode 100755 index a45d0a1..0000000 --- a/ci/deploy.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/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 deleted file mode 100755 index b766123..0000000 --- a/ci/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/lib/checks/check.sh b/lib/checks/check.sh deleted file mode 100755 index 789206e..0000000 --- a/lib/checks/check.sh +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bash -# shellcheck disable=SC1091 -# -# This modules is used for: -# - Running checks against the building JuNest image -# - Integration tests on JuNest script against different execution modes (i.e. -f, -u, -r modes) -# -# Dependencies: -# - None -# -# vim: ft=sh - -set -ex - - -RUN_ROOT_TESTS=false -SKIP_AUR_TESTS=false -USE_SUDO=false -while [[ -n "$1" ]] -do - case "$1" in - --run-root-tests) RUN_ROOT_TESTS=true ; shift ;; - --skip-aur-tests) SKIP_AUR_TESTS=true ; shift ;; - --use-sudo) USE_SUDO=true ; shift ;; - *) die "Invalid option $1" ;; - esac -done - -set -u - -SUDO="" -[[ -n $USE_SUDO ]] && SUDO="sudo" - -JUNEST_HOME=${JUNEST_HOME:-$HOME/.junest} - -# JUNEST_BASE can be overridden for testing purposes. -# There is no need for doing it for normal usage. -JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/../..)}" - -source "${JUNEST_BASE}/lib/utils/utils.sh" -source "${JUNEST_BASE}/lib/core/common.sh" - -info "Validating JuNest located in ${JUNEST_HOME}..." - -info "Initial JuNest setup..." -# 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 TERM INT - -prepare_archlinux "$SUDO" - -PACMAN_OPTIONS="--noconfirm --disable-download-timeout" -# shellcheck disable=SC2086 -$SUDO pacman $PACMAN_OPTIONS -S grep coreutils -# 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/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} -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 -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 - -exit 0 diff --git a/lib/checks/check_all.sh b/lib/checks/check_all.sh deleted file mode 100755 index 13e9237..0000000 --- a/lib/checks/check_all.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash -# Multiple tests against different execution modes - -set -ex - -# JUNEST_BASE can be overridden for testing purposes. -# There is no need for doing it for normal usage. -JUNEST_BASE="${JUNEST_BASE:-$(readlink -f "$(dirname "$(readlink -f "$0")")"/../..)}" - -JUNEST_SCRIPT=${JUNEST_SCRIPT:-${JUNEST_BASE}/bin/junest} - -CHECK_SCRIPT=${JUNEST_BASE}/lib/checks/check.sh - -$JUNEST_SCRIPT proot --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests -$JUNEST_SCRIPT proot -- "$CHECK_SCRIPT" --skip-aur-tests --use-sudo -# Test the backend command option -$JUNEST_SCRIPT proot --backend-command "$JUNEST_HOME/usr/bin/proot-x86_64" -- exit -$JUNEST_SCRIPT ns --fakeroot -- "$CHECK_SCRIPT" --skip-aur-tests -$JUNEST_SCRIPT ns -- "$CHECK_SCRIPT" --use-sudo -# Test the backend command option -$JUNEST_SCRIPT ns --backend-command "$JUNEST_HOME/usr/bin/bwrap" -- exit -sudo -E "$JUNEST_SCRIPT" groot -- "$CHECK_SCRIPT" --run-root-tests --skip-aur-tests - -# Test the wrappers work -"$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 65a9474..017ccad 100644 --- a/lib/core/build.sh +++ b/lib/core/build.sh @@ -8,134 +8,133 @@ # # vim: ft=sh -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}" || return 1 - makepkg -sfcd - makepkg --printsrcinfo > "${pkgbuilddir}"/.SRCINFO - sudo pacman --noconfirm --root "${maindir}"/root -U ./*.pkg.tar.* +function _check_package(){ + if ! pacman -Qq $1 > /dev/null + then + die "Package $1 must be installed" + fi } -function _prepare() { - # ArchLinux System initialization - prepare_archlinux - # curl is used to download pacman.conf file - sudo pacman -S --noconfirm git arch-install-scripts haveged curl +function _install_from_aur(){ + local maindir=$1 + local pkgname=$2 + local installname=$3 + mkdir -p ${maindir}/packages/${pkgname} + builtin cd ${maindir}/packages/${pkgname} + $CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}" + [ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}" + makepkg -sfc + sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz } function build_image_env(){ - set -x umask 022 # The function must runs on ArchLinux with non-root privileges. - # This is because installing AUR packages can be done by normal users only. (( EUID == 0 )) && \ die "You cannot build with root privileges." - _prepare + _check_package arch-install-scripts + _check_package gcc + _check_package package-query + _check_package git local disable_validation=$1 + local skip_root_tests=$2 - local maindir - 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 + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + sudo mkdir -p ${maindir}/root + trap - QUIT EXIT ABRT KILL TERM INT + trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT info "Installing pacman and its dependencies..." + # The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux # All the essential executables (ln, mkdir, chown, etc) are in coreutils - # bwrap command belongs to bubblewrap - sudo pacstrap -G -M "${maindir}"/root pacman coreutils bubblewrap + # yaourt requires sed + # localedef (called by locale-gen) requires gzip + sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip + sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist" + sudo mkdir -p ${maindir}/root/run/lock - 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 + # AUR packages requires non-root user to be compiled. proot fakes the user to 10 + info "Compiling and installing yaourt..." + _install_from_aur ${maindir} "package-query" + _install_from_aur ${maindir} "yaourt" - # 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" - - # 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 "Install ${NAME} script..." + sudo pacman --noconfirm --root ${maindir}/root -S git + _install_from_aur ${maindir} "${CMD}-git" "${CMD}.install" + sudo pacman --noconfirm --root ${maindir}/root -Rsn git info "Generating the locales..." - # sed command is required for locale-gen but it is required by fakeroot - # and cannot be removed - # 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 + # sed command is required for locale-gen + sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen" - sudo "${maindir}"/root/bin/groot "${maindir}"/root locale-gen + sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf" info "Setting up the pacman keyring (this might take a while!)..." - 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;' - sudo umount "${maindir}"/root + sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \ + "pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye" - sudo rm "${maindir}"/root/var/cache/pacman/pkg/* - # 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 rm ${maindir}/root/var/cache/pacman/pkg/* - mkdir -p "${maindir}"/output - builtin cd "${maindir}"/output || return 1 + mkdir -p ${maindir}/output + builtin cd ${maindir}/output local imagefile="${CMD}-${ARCH}.tar.gz" info "Compressing image to ${imagefile}..." - sudo "$TAR" -zcpf "${imagefile}" -C "${maindir}"/root . + 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" + check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests fi - sudo cp "${maindir}"/output/"${imagefile}" "${ORIGIN_WD}" + sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD} - builtin cd "${ORIGIN_WD}" || return 1 + builtin cd ${ORIGIN_WD} trap - QUIT EXIT ABRT KILL TERM INT sudo rm -fr "$maindir" - - set +x +} + +function check_env(){ + local testdir=$1 + local cmd=$2 + local skip_root_tests=$3 + info "Validating ${NAME} located in ${testdir} using the ${cmd} script..." + echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy + + # Check most basic executables work + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null + JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null + + local repo_package=tree + info "Installing ${repo_package} package from official repo using proot..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} + JUNEST_HOME=${testdir} ${cmd} tree + JUNEST_HOME=${testdir} ${cmd} -f tree + + local repo_package=iftop + info "Installing ${repo_package} package from official repo using root..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package} + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5 + + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel + local aur_package=tcptraceroute + info "Installing ${aur_package} package from AUR repo using proot..." + JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package} + $skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost + + info "Removing the previous packages..." + JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop + } diff --git a/lib/core/chroot.sh b/lib/core/chroot.sh index c2237a9..ff8465d 100644 --- a/lib/core/chroot.sh +++ b/lib/core/chroot.sh @@ -8,97 +8,38 @@ # # vim: ft=sh -function _run_env_as_xroot(){ - local cmd=$1 - local backend_args="$2" - local no_copy_files="$3" - shift 3 - - check_same_arch +####################################### +# Run JuNest as real root. +# +# Globals: +# JUNEST_HOME (RO) : The JuNest home directory. +# UID (RO) : The user ID. +# SUDO_USER (RO) : The sudo user ID. +# SUDO_GID (RO) : The sudo group ID. +# SH (RO) : Contains the default command to run in JuNest. +# Arguments: +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. +# Returns: +# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. +# Output: +# - : The command output. +####################################### +function run_env_as_root(){ + source ${JUNEST_HOME}/etc/junest/info + [ "$JUNEST_ARCH" != "$ARCH" ] && \ + die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" local uid=$UID # SUDO_USER is more reliable compared to SUDO_UID - [[ -z $SUDO_USER ]] || uid=$SUDO_USER:$SUDO_GID + [ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID - local args=() - [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") + local main_cmd="${SH[@]}" + [ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")" # With chown the ownership of the files is assigned to the real user trap - QUIT EXIT ABRT KILL TERM INT - # shellcheck disable=SC2064 - trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT TERM INT + trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT - if ! $no_copy_files - then - copy_common_files - fi - - # shellcheck disable=SC2086 - JUNEST_ENV=1 $cmd $backend_args "$JUNEST_HOME" "${DEFAULT_SH[@]}" "${args[@]}" -} - -####################################### -# Run JuNest as real root via GRoot command. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# UID (RO) : The user ID. -# SUDO_USER (RO) : The sudo user ID. -# SUDO_GID (RO) : The sudo group ID. -# 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 DEFAULT_SH variable. -# Returns: -# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Output: -# - : The command output. -####################################### -function run_env_as_groot(){ - check_nested_env - - local backend_command="${1:-$GROOT}" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - - provide_common_bindings - local bindings=${RESULT} - unset RESULT - - _run_env_as_xroot "$backend_command $bindings" "$backend_args" "$no_copy_files" "$@" -} - -####################################### -# Run JuNest as real root via chroot command. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# UID (RO) : The user ID. -# SUDO_USER (RO) : The sudo user ID. -# SUDO_GID (RO) : The sudo group ID. -# 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 DEFAULT_SH variable. -# Returns: -# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Output: -# - : The command output. -####################################### -function run_env_as_chroot(){ - check_nested_env - - local backend_command="${1:-chroot_cmd}" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - - _run_env_as_xroot "$backend_command" "$backend_args" "$no_copy_files" "$@" + JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}" } diff --git a/lib/core/common.sh b/lib/core/common.sh index df79bec..d317933 100644 --- a/lib/core/common.sh +++ b/lib/core/common.sh @@ -1,6 +1,4 @@ #!/usr/bin/env bash -# shellcheck disable=SC2034 -# shellcheck disable=SC1091 # # This module contains all common functionalities for JuNest. # @@ -9,6 +7,8 @@ # # vim: ft=sh +set -e + NAME='JuNest' CMD='junest' DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access' @@ -19,33 +19,41 @@ ARCHITECTURE_MISMATCH=104 ROOT_ACCESS_ERROR=105 NESTED_ENVIRONMENT=106 VARIABLE_NOT_SET=107 -NO_CONFIG_FOUND=108 -UNPRIVILEGED_USERNS_DISABLED=109 -JUNEST_HOME=${JUNEST_HOME:-~/.${CMD}} -JUNEST_TEMPDIR=${JUNEST_TEMPDIR:-/tmp} +if [ "$JUNEST_ENV" == "1" ] +then + die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" +elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ] +then + die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" +fi + +[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD} +[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest +if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ] +then + JUNEST_TEMPDIR=/tmp +fi # The update of the variable PATH ensures that the executables are # found on different locations -PATH=/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:${HOME}/.local/bin:"$PATH" +PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH # The executable uname is essential in order to get the architecture # of the host system, so a fallback mechanism cannot be used for it. -UNAME="uname" +UNAME=uname ARCH_LIST=('x86_64' 'x86' 'arm') HOST_ARCH=$($UNAME -m) -# To check all available architectures look here: -# https://wiki.archlinux.org/index.php/PKGBUILD#arch -if [[ $HOST_ARCH == "i686" ]] || [[ $HOST_ARCH == "i386" ]] +if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ] then ARCH="x86" LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2" -elif [[ $HOST_ARCH == "x86_64" ]] +elif [ $HOST_ARCH == "x86_64" ] then ARCH="x86_64" LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2" -elif [[ $HOST_ARCH =~ .*(arm).* ]] || [[ $HOST_ARCH == "aarch64" ]] +elif [[ $HOST_ARCH =~ .*(arm).* ]] then ARCH="arm" LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3" @@ -53,11 +61,9 @@ else die "Unknown architecture ${HOST_ARCH}" fi -MAIN_REPO=https://link.storjshare.io/s/jvb5tgarnjtt565fffa44spvyuga/junest-repo -MAIN_REPO=https://pub-a2af2344e8554f6c807bc3db355ae622.r2.dev +MAIN_REPO=https://s3-eu-west-1.amazonaws.com/${CMD}-repo ENV_REPO=${MAIN_REPO}/${CMD} -# shellcheck disable=SC2016 -DEFAULT_MIRROR='https://mirror.rackspace.com/archlinux/$repo/os/$arch' +DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch' ORIGIN_WD=$(pwd) @@ -68,26 +74,21 @@ ORIGIN_WD=$(pwd) # different locations in the host OS. # List of executables that are run inside JuNest: -DEFAULT_SH=("/bin/sh" "--login") +SH=("/bin/sh" "--login") # List of executables that are run in the host OS: -BWRAP="${JUNEST_HOME}/usr/bin/bwrap" -PROOT="${JUNEST_HOME}/usr/bin/proot-${ARCH}" -GROOT="${JUNEST_HOME}/usr/bin/groot" -CLASSIC_CHROOT=chroot -WGET="wget --content-disposition --no-check-certificate" +PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}" +CHROOT=${JUNEST_BASE}/bin/jchroot +CLASSIC_CHROOT="chroot" +WGET="wget --no-check-certificate" CURL="curl -L -J -O -k" -TAR="tar" +TAR=tar CHOWN="chown" -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" +LN=ln +RM=rm +MKDIR=mkdir +GETENT=getent +CP=cp LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib" @@ -96,137 +97,53 @@ 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 "$@" -} - -function zgrep_cmd(){ - # No need for LD_EXEC as zgrep is a POSIX shell script - $ZGREP "$@" || "${JUNEST_HOME}"/usr/bin/$ZGREP "$@" -} - -function download_cmd(){ - $WGET "$@" || $CURL "$@" -} - -function chroot_cmd(){ - $CLASSIC_CHROOT "$@" || $LD_EXEC "${JUNEST_HOME}"/usr/bin/$CLASSIC_CHROOT "$@" -} - -function unshare_cmd(){ - # Most of the distros do not have the `unshare` command updated - # with --user option available. - # Hence, give priority to the `unshare` executable in JuNest image. - # Also, unshare provides an environment in which /bin/sh maps to dash shell, - # therefore it ignores all the remaining DEFAULT_SH arguments (i.e. --login) as - # they are not supported by dash. - if $LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" - then - $LD_EXEC "${JUNEST_HOME}"/usr/bin/$UNSHARE "${@}" - elif $UNSHARE --user "${DEFAULT_SH[0]}" "-c" ":" - then - $UNSHARE "$@" - else - die "Error: Something went wrong while executing unshare command. Exiting" - fi -} - -function bwrap_cmd(){ - if $LD_EXEC "$BWRAP" --dev-bind / / "${DEFAULT_SH[0]}" "-c" ":" - then - $LD_EXEC "$BWRAP" "${@}" - else - die "Error: Something went wrong while executing bwrap command. Exiting" - fi + $MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@ } function proot_cmd(){ local proot_args="$1" shift - # shellcheck disable=SC2086 - if ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":" + if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" then - # shellcheck disable=SC2086 ${PROOT} ${proot_args} "${@}" - elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${DEFAULT_SH[@]}" "-c" ":" + elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":" then - warn "Warn: Proot is not properly working. Disabling SECCOMP and expect the application to run slowly in particular when it uses syscalls intensively." - warn "Try to use Linux namespace instead as it is more reliable: junest ns" PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}" else - die "Error: Something went wrong with proot command. Exiting" + die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\"" fi } +function download_cmd(){ + $WGET $@ || $CURL $@ +} + +function chroot_cmd(){ + $CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@" +} + ############## COMMON FUNCTIONS ############### -####################################### -# Check if the executable is being running inside a JuNest environment. -# -# Globals: -# JUNEST_ENV (RO) : The boolean junest env check -# NESTED_ENVIRONMENT (RO) : The nest env exception -# VARIABLE_NOT_SET (RO) : The var not set exception -# NAME (RO) : The JuNest name -# Arguments: -# None -# Returns: -# VARIABLE_NOT_SET : If no JUNEST_ENV is not properly set -# NESTED_ENVIRONMENT : If the script is executed inside JuNest env -# Output: -# None -####################################### -function check_nested_env() { - if [[ $JUNEST_ENV == "1" ]] - then - die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed" - elif [[ -n $JUNEST_ENV ]] && [[ $JUNEST_ENV != "0" ]] - then - die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set" - fi -} - -####################################### -# Check if the architecture between Host OS and Guest OS is the same. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home path. -# ARCHITECTURE_MISMATCH (RO) : The arch mismatch exception -# ARCH (RO) : The host OS arch -# JUNEST_ARCH (RO) : The JuNest arch -# Arguments: -# None -# Returns: -# ARCHITECTURE_MISMATCH : If arch between host and guest is not the same -# Output: -# None -####################################### -function check_same_arch() { - source "${JUNEST_HOME}"/etc/junest/info - [ "$JUNEST_ARCH" != "$ARCH" ] && \ - die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH" - return 0 -} - ####################################### # Provide the proot common binding options for both normal user and fakeroot. # The list of bindings can be found in `proot --help`. This function excludes @@ -243,10 +160,10 @@ function check_same_arch() { # Output: # None ####################################### -function provide_common_bindings(){ +function _provide_common_bindings(){ RESULT="" local re='(.*):.*' - for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" "/run/user/$($ID -u)" + for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME" do if [[ $bind =~ $re ]] then @@ -274,62 +191,36 @@ function provide_common_bindings(){ # Output: # None ####################################### -function copy_passwd_and_group(){ +function _copy_passwd_and_group(){ # Enumeration of users/groups is disabled/limited depending on how nsswitch.conf # is configured. # Try to at least get the current user via `getent passwd $USER` since it uses # 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 + _copy_file /etc/passwd ${JUNEST_HOME}/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 + _copy_file /etc/group ${JUNEST_HOME}/etc/group fi return 0 } -function copy_file() { +function _copy_file() { local file="${1}" - # -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" + [[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file" return 0 } -function copy_common_files() { - copy_file /etc/host.conf - copy_file /etc/hosts - copy_file /etc/nsswitch.conf - copy_file /etc/resolv.conf +function _copy_common_files() { + _copy_file /etc/host.conf + _copy_file /etc/hosts + _copy_file /etc/nsswitch.conf + _copy_file /etc/resolv.conf return 0 } - -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 deleted file mode 100644 index 70763bd..0000000 --- a/lib/core/namespace.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env bash -# -# This module contains functionalities for accessing to JuNest via bubblewrap. -# -# https://github.com/containers/bubblewrap -# -# Dependencies: -# - lib/utils/utils.sh -# - lib/core/common.sh -# -# 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 - config_file=$CONFIG_PROC_FILE - elif [[ -e $CONFIG_BOOT_FILE ]] - then - config_file=$CONFIG_BOOT_FILE - else - return "$NOT_EXISTING_FILE" - fi - - # `-q` option in zgrep may cause a gzip: stdout: Broken pipe - # Use redirect to /dev/null instead - if ! zgrep_cmd "CONFIG_USER_NS=y" "$config_file" > /dev/null - then - return "$NO_CONFIG_FOUND" - fi - - 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" ;; - esac - set -e -} - - -####################################### -# Run JuNest as fakeroot via bwrap -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# DEFAULT_SH (RO) : Contains the default command to run in JuNest. -# BWRAP (RO): : The location of the bwrap binary. -# Arguments: -# backend_args ($1) : The arguments to pass to bwrap -# no_copy_files ($2?) : If false it will copy some files in /etc -# from host to JuNest environment. -# cmd ($3-?) : The command to run inside JuNest environment. -# 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. -# Output: -# - : The command output. -####################################### -function run_env_as_bwrap_fakeroot(){ - check_nested_env - - local backend_command="${1:-$BWRAP}" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - - _check_user_namespace - - check_same_arch - - if ! $no_copy_files - then - copy_common_files - fi - - 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[@]}" -} - - -####################################### -# Run JuNest as normal user via bwrap. -# -# Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# DEFAULT_SH (RO) : Contains the default command to run in JuNest. -# BWRAP (RO): : The location of the bwrap binary. -# Arguments: -# backend_args ($1) : The arguments to pass to bwrap -# no_copy_files ($2?) : If false it will copy some files in /etc -# from host to JuNest environment. -# cmd ($3-?) : The command to run inside JuNest environment. -# Default command is defined by DEFAULT_SH variable. -# Returns: -# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different. -# Output: -# - : The command output. -####################################### -function run_env_as_bwrap_user() { - check_nested_env - - local backend_command="${1:-$BWRAP}" - local backend_args="$2" - local no_copy_files="$3" - shift 3 - - _check_user_namespace - - check_same_arch - - if ! $no_copy_files - then - copy_common_files - copy_file /etc/hosts.equiv - copy_file /etc/netgroup - copy_file /etc/networks - # No need for localtime as it is setup during the image build - #copy_file /etc/localtime - copy_passwd_and_group - fi - - 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 b6c1c8f..39d901c 100644 --- a/lib/core/proot.sh +++ b/lib/core/proot.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash -# shellcheck disable=SC1091 # # This module contains all proot functionalities for JuNest. # @@ -10,81 +9,65 @@ # vim: ft=sh function _run_env_with_proot(){ - local backend_command="${1:-$PROOT}" - local backend_args="$2" - shift 2 + local proot_args="$1" + shift - local args=() - [[ "$1" != "" ]] && args=("-c" "$(insert_quotes_on_spaces "${@}")") - - # Resets PATH to avoid polluting with host related bin paths - PATH='' PROOT="${backend_command}" JUNEST_ENV=1 proot_cmd "${backend_args}" "${DEFAULT_SH[@]}" "${args[@]}" + if [ "$1" != "" ] + then + JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")" + else + JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" + fi } function _run_env_with_qemu(){ - local backend_command="$1" - local backend_args="$2" - shift 2 - - source "${JUNEST_HOME}"/etc/junest/info + local proot_args="$1" + source ${JUNEST_HOME}/etc/junest/info if [ "$JUNEST_ARCH" != "$ARCH" ] then local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH" local qemu_symlink="/tmp/${qemu_bin}-$RANDOM" trap - QUIT EXIT ABRT KILL TERM INT - # shellcheck disable=SC2064 - trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT TERM INT + trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT warn "Emulating $NAME via QEMU..." - [[ -e ${qemu_symlink} ]] || \ - ln_cmd -s "${JUNEST_HOME}/bin/${qemu_bin}" "${qemu_symlink}" - backend_args="-q ${qemu_symlink} $backend_args" + [ -e ${qemu_symlink} ] || \ + ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink} + proot_args="-q ${qemu_symlink} $proot_args" fi - - _run_env_with_proot "${backend_command}" "$backend_args" "${@}" + shift + _run_env_with_proot "$proot_args" "${@}" } ####################################### # Run JuNest as fakeroot. # # Globals: -# JUNEST_HOME (RO) : The JuNest home directory. -# EUID (RO) : The user ID. -# DEFAULT_SH (RO) : Contains the default command to run in JuNest. +# JUNEST_HOME (RO) : The JuNest home directory. +# EUID (RO) : The user ID. +# SH (RO) : Contains the default command to run in JuNest. # Arguments: -# 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 DEFAULT_SH variable. +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. # Returns: -# $ROOT_ACCESS_ERROR : If the user is the real root. +# $ROOT_ACCESS_ERROR : If the user is the real root. # Output: -# - : The command output. +# - : The command output. ####################################### -function run_env_as_proot_fakeroot(){ +function run_env_as_fakeroot(){ (( EUID == 0 )) && \ - die_on_status "$ROOT_ACCESS_ERROR" "You cannot access with root privileges. Use --groot option instead." - check_nested_env + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 + _copy_common_files - if ! $no_copy_files - then - copy_common_files - fi - - provide_common_bindings + _provide_common_bindings local bindings=${RESULT} unset RESULT # An alternative is via -S option: #_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}" - _run_env_with_qemu "$backend_command" "-0 ${bindings} -r ${JUNEST_HOME} $backend_args" "$@" + _run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}" } ####################################### @@ -93,46 +76,34 @@ function run_env_as_proot_fakeroot(){ # Globals: # JUNEST_HOME (RO) : The JuNest home directory. # EUID (RO) : The user ID. -# DEFAULT_SH (RO) : Contains the default command to run in JuNest. +# 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 DEFAULT_SH variable. +# cmd ($@?) : The command to run inside JuNest environment. +# Default command is defined by SH variable. # Returns: # $ROOT_ACCESS_ERROR : If the user is the real root. # Output: # - : The command output. ####################################### -function run_env_as_proot_user(){ +function run_env_as_user(){ (( EUID == 0 )) && \ - die_on_status "$ROOT_ACCESS_ERROR" "You cannot access with root privileges. Use --groot option instead." - check_nested_env + die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead." - local backend_command="$1" - local backend_args="$2" - local no_copy_files="$3" - shift 3 + # Files to bind are visible in `proot --help`. + # This function excludes /etc/mtab file so that + # it will not give conflicts with the related + # symlink in the Arch Linux image. + _copy_common_files + _copy_file /etc/hosts.equiv + _copy_file /etc/netgroup + _copy_file /etc/networks + # No need for localtime as it is setup during the image build + #_copy_file /etc/localtime + _copy_passwd_and_group - if ! $no_copy_files - then - # Files to bind are visible in `proot --help`. - # This function excludes /etc/mtab file so that - # it will not give conflicts with the related - # symlink in the Arch Linux image. - copy_common_files - copy_file /etc/hosts.equiv - copy_file /etc/netgroup - copy_file /etc/networks - # No need for localtime as it is setup during the image build - #copy_file /etc/localtime - copy_passwd_and_group - fi - - provide_common_bindings + _provide_common_bindings local bindings=${RESULT} unset RESULT - _run_env_with_qemu "$backend_command" "${bindings} -r ${JUNEST_HOME} $backend_args" "$@" + _run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}" } diff --git a/lib/core/setup.sh b/lib/core/setup.sh index 58c6122..f55780b 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" || return 1 + builtin cd $ORIGIN_WD trap - QUIT EXIT ABRT KILL TERM INT rm_cmd -fr "$maindir" } @@ -40,8 +40,7 @@ function _prepare_build_directory(){ local maindir=$1 check_not_null "$maindir" trap - QUIT EXIT ABRT KILL TERM INT - # shellcheck disable=SC2064 - trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT TERM INT + trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT } @@ -52,18 +51,11 @@ 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}" - info "${NAME} installed successfully!" - echo - 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 + $TAR -zxpf ${imagepath} -C ${JUNEST_HOME} + info "The default mirror URL is ${DEFAULT_MIRROR}." info "Remember to refresh the package databases from the server:" info " pacman -Syy" - echo - info "To install packages from AUR follow the wiki here:" - info "https://github.com/fsquillace/junest#install-packages-from-aur" + info "${NAME} installed successfully" } @@ -78,6 +70,7 @@ function _setup_env(){ # the JuNest system from the image. # ENV_REPO (RO) : URL of the site containing JuNest images. # NAME (RO) : The JuNest name. +# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. # Arguments: # arch ($1?) : The JuNest architecture image to download. # Defaults to the host architecture @@ -88,22 +81,21 @@ 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 - maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t "${CMD}".XXXXXXXXXX) - _prepare_build_directory "$maindir" + local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX) + _prepare_build_directory $maindir info "Downloading ${NAME}..." - builtin cd "${maindir}" || return 1 + builtin cd ${maindir} 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} } ####################################### @@ -113,6 +105,7 @@ function setup_env(){ # JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs # to be installed. # NAME (RO) : The JuNest name. +# DEFAULT_MIRROR (RO) : Arch Linux URL mirror. # Arguments: # imagefile ($1) : The JuNest image file. # Returns: @@ -123,10 +116,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} } ####################################### @@ -143,18 +136,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 deleted file mode 100644 index 1fe955c..0000000 --- a/lib/core/wrappers.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/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 5659568..840fbe9 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 [ -n "$default_answer" ] + if [ ! -z "$default_answer" ] then local answers="Y y N n" - [[ "$answers" =~ $default_answer ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; } + [[ "$answers" =~ "$default_answer" ]] || { error "The default answer: $default_answer is wrong."; return $WRONG_ANSWER; } fi local default="Y" @@ -156,13 +156,12 @@ function ask(){ local other="n" [ "$default" == "N" ] && other="y" - local prompt - prompt=$(info "$question (${default}/${other})> ") + local prompt=$(info "$question (${default}/${other})> ") local res="none" while [ "$res" != "Y" ] && [ "$res" != "N" ] && [ "$res" != "" ]; do - read -r -p "$prompt" res + read -p "$prompt" res res=$(echo "$res" | tr '[:lower:]' '[:upper:]') done @@ -175,27 +174,18 @@ function insert_quotes_on_spaces(){ # It inserts quotes between arguments. # Useful to preserve quotes on command # to be used inside sh -c/bash -c - local C="" + C='' whitespace="[[:space:]]" for i in "$@" do if [[ $i =~ $whitespace ]] then - temp_C="\"$i\"" + C="$C \"$i\"" else - temp_C="$i" + C="$C $i" fi - - # Handle edge case when C is empty to avoid adding an extra space - if [[ -z $C ]] - then - C="$temp_C" - else - C="$C $temp_C" - fi - done - echo "$C" + echo $C } contains_element () { diff --git a/tests/checkstyle/checkstyle.sh b/tests/checkstyle/checkstyle.sh index 4f71965..27cb82a 100755 --- a/tests/checkstyle/checkstyle.sh +++ b/tests/checkstyle/checkstyle.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash -# shellcheck disable=SC1091 -source "$(dirname "$0")/../utils/utils.sh" +source "$(dirname $0)/../utils/utils.sh" # Disable the exiterr set +e @@ -11,12 +10,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 new file mode 100755 index 0000000..575c9c5 --- /dev/null +++ b/tests/integ-tests/install-bash.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -ex + +VERSION=$1 + +cd /tmp +wget http://ftp.gnu.org/gnu/bash/bash-$VERSION.tar.gz + +tar -zxf bash-$VERSION.tar.gz +cd /tmp/bash-$VERSION* +./configure +make +sudo make install diff --git a/tests/unit-tests/test-chroot.sh b/tests/unit-tests/test-chroot.sh index 3739c58..04b22a7 100755 --- a/tests/unit-tests/test-chroot.sh +++ b/tests/unit-tests/test-chroot.sh @@ -1,7 +1,6 @@ #!/bin/bash -# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -19,7 +18,6 @@ function oneTimeSetUp(){ function setUp(){ cwdSetUp junestSetUp - init_mocks } function tearDown(){ @@ -27,99 +25,28 @@ function tearDown(){ cwdTearDown } -function init_mocks() { +function test_run_env_as_root_different_arch(){ + echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info + assertCommandFailOnStatus 104 run_env_as_root pwd +} + +function _test_run_env_as_root() { chroot_cmd() { - # shellcheck disable=SC2317 [ "$JUNEST_ENV" != "1" ] && return 1 - # shellcheck disable=SC2317 - echo "chroot_cmd $*" - } - # shellcheck disable=SC2034 - GROOT=chroot_cmd - mychroot() { - # shellcheck disable=SC2317 - echo mychroot "$*" + echo $@ } + + assertCommandSuccess run_env_as_root $@ } -function test_run_env_as_groot_cmd(){ - assertCommandSuccess run_env_as_groot "" "" "false" pwd - 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_root_cmd(){ + _test_run_env_as_root pwd + assertEquals "$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 /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_classic_root_no_cmd(){ + _test_run_env_as_root + assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)" } -function test_run_env_as_groot_with_backend_command(){ - assertCommandSuccess run_env_as_groot "mychroot" "" "false" "" - 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 /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 $? - [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] - assertEquals 0 $? -} - -function test_run_env_as_groot_nested_env(){ - JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_groot "" "" "false" "" - unset JUNEST_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 /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")" -} - -function test_run_env_as_chroot_no_cmd(){ - assertCommandSuccess run_env_as_chroot "" "" "false" "" - assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")" -} - -function test_run_env_as_chroot_with_backend_command(){ - assertCommandSuccess run_env_as_chroot "mychroot" "" "false" "" - assertEquals "mychroot $JUNEST_HOME /bin/sh --login" "$(cat "$STDOUTF")" -} - -function test_run_env_as_chroot_no_copy(){ - assertCommandSuccess run_env_as_chroot "" "" "true" pwd - assertEquals "chroot_cmd $JUNEST_HOME /bin/sh --login -c pwd" "$(cat "$STDOUTF")" - - [[ ! -e ${JUNEST_HOME}/etc/hosts ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] - assertEquals 0 $? -} - -function test_run_env_as_choot_nested_env(){ - JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_chroot "" "" "false" "" - unset JUNEST_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")" -} - -source "$JUNEST_ROOT"/tests/utils/shunit2 +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-cli.sh b/tests/unit-tests/test-cli.sh new file mode 100755 index 0000000..db23eea --- /dev/null +++ b/tests/unit-tests/test-cli.sh @@ -0,0 +1,181 @@ +#!/bin/bash +source "$(dirname $0)/../utils/utils.sh" + +source $(dirname $0)/../../bin/junest -h &> /dev/null + +# Disable the exiterr +set +e + +function oneTimeSetUp(){ + setUpUnitTests +} + +function setUp(){ + function is_env_installed(){ + return 0 + } +} + +## Mock functions ## +function usage(){ + echo "usage" +} +function version(){ + echo "version" +} +function build_image_env(){ + local disable_validation=$1 + local skip_root_tests=$2 + echo "build_image_env($disable_validation,$skip_root_tests)" +} +function check_env(){ + local env_home=$1 + local cmd_script=$2 + local skip_root_tests=$3 + echo "check_env($env_home,$cmd_script,$skip_root_tests)" +} +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_fakeroot(){ + local proot_args="$1" + shift + echo "run_env_as_fakeroot($proot_args,$@)" +} +function run_env_as_root(){ + echo "run_env_as_root $@" +} +function run_env_as_user(){ + local proot_args="$1" + shift + echo "run_env_as_user($proot_args,$@)" +} + +function test_help(){ + assertCommandSuccess cli -h + assertEquals "usage" "$(cat $STDOUTF)" + assertCommandSuccess cli --help + assertEquals "usage" "$(cat $STDOUTF)" +} +function test_version(){ + assertCommandSuccess cli -v + assertEquals "version" "$(cat $STDOUTF)" + assertCommandSuccess cli --version + assertEquals "version" "$(cat $STDOUTF)" +} +function test_build_image_env(){ + assertCommandSuccess cli -b + assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli --build-image + assertEquals "build_image_env(false,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli -b -s + assertEquals "build_image_env(false,true)" "$(cat $STDOUTF)" + assertCommandSuccess cli -b -n + assertEquals "build_image_env(true,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli -b -n -s + assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" + assertCommandSuccess cli --build-image --disable-validation --skip-root-tests + assertEquals "build_image_env(true,true)" "$(cat $STDOUTF)" +} +function test_check_env(){ + assertCommandSuccess cli -c myscript + assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli --check myscript + assertEquals "check_env(${JUNEST_HOME},myscript,false)" "$(cat $STDOUTF)" + assertCommandSuccess cli -c myscript -s + assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" + assertCommandSuccess cli --check myscript --skip-root-tests + assertEquals "check_env(${JUNEST_HOME},myscript,true)" "$(cat $STDOUTF)" +} +function test_delete_env(){ + assertCommandSuccess cli -d + assertEquals "delete_env" "$(cat $STDOUTF)" + assertCommandSuccess cli --delete + assertEquals "delete_env" "$(cat $STDOUTF)" +} +function test_setup_env_from_file(){ + is_env_installed(){ + return 1 + } + assertCommandSuccess cli -i myimage + assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess cli --setup-from-file myimage + assertEquals "$(echo -e "setup_env_from_file(myimage)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + + is_env_installed(){ + return 0 + } + assertCommandFail cli -i myimage +} + +function test_setup_env(){ + is_env_installed(){ + return 1 + } + assertCommandSuccess cli -a arm + assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess cli --arch arm + assertEquals "$(echo -e "setup_env(arm)\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + assertCommandSuccess cli + assertEquals "$(echo -e "setup_env()\nrun_env_as_user(,)")" "$(cat $STDOUTF)" + + is_env_installed(){ + return 0 + } + assertCommandFail cli -a arm +} +function test_run_env_as_fakeroot(){ + assertCommandSuccess cli -f + assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" + assertCommandSuccess cli --fakeroot + assertEquals "run_env_as_fakeroot(,)" "$(cat $STDOUTF)" + + assertCommandSuccess cli -f -p "-b arg" + assertEquals "run_env_as_fakeroot(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess cli -f -p "-b arg" -- command -kv + assertEquals "run_env_as_fakeroot(-b arg,command -kv)" "$(cat $STDOUTF)" + assertCommandSuccess cli -f command --as + assertEquals "run_env_as_fakeroot(,command --as)" "$(cat $STDOUTF)" + assertCommandFail cli -a "myarch" -f command --as +} +function test_run_env_as_user(){ + assertCommandSuccess cli + assertEquals "run_env_as_user(,)" "$(cat $STDOUTF)" + + assertCommandSuccess cli -p "-b arg" + assertEquals "run_env_as_user(-b arg,)" "$(cat $STDOUTF)" + assertCommandSuccess cli -p "-b arg" -- command -ll + assertEquals "run_env_as_user(-b arg,command -ll)" "$(cat $STDOUTF)" + assertCommandSuccess cli command -ls + assertEquals "run_env_as_user(,command -ls)" "$(cat $STDOUTF)" + + assertCommandFail cli -a "myarch" -- command -ls +} +function test_run_env_as_root(){ + assertCommandSuccess cli -r + assertEquals "run_env_as_root " "$(cat $STDOUTF)" + assertCommandSuccess cli -r command + assertEquals "run_env_as_root command" "$(cat $STDOUTF)" +} + +function test_check_cli(){ + assertCommandFail cli -b -h + assertCommandFail cli -b -c + assertCommandFail cli -d -s + assertCommandFail cli -n -v + assertCommandFail cli -d -r + assertCommandFail cli -h -f + assertCommandFail cli -v -i fsd + assertCommandFail cli -f -r + assertCommandFail cli -p args -v + assertCommandFail cli -a arch -v + assertCommandFail cli -d args +} + +source $(dirname $0)/../utils/shunit2 diff --git a/tests/unit-tests/test-common.sh b/tests/unit-tests/test-common.sh index 89c1a1e..ad871f5 100755 --- a/tests/unit-tests/test-common.sh +++ b/tests/unit-tests/test-common.sh @@ -1,7 +1,6 @@ #!/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,60 +20,38 @@ function oneTimeTearDown(){ } function setUp(){ - ld_exec_mock() { - # shellcheck disable=SC2317 - echo "ld_exec $*" + ld_exec() { + echo "ld_exec $@" } - # shellcheck disable=SC2317 - ld_exec_mock_false() { - echo "ld_exec $*" - return 1 - } - # shellcheck disable=SC2034 - LD_EXEC=ld_exec_mock - - unshare_mock() { - # shellcheck disable=SC2317 - echo "unshare $*" - } - # shellcheck disable=SC2034 - UNSHARE=unshare_mock - - # shellcheck disable=SC2317 - bwrap_mock() { - echo "bwrap $*" - } - # shellcheck disable=SC2034 - BWRAP=bwrap_mock - + LD_EXEC=ld_exec } function test_ln(){ - LN="echo" assertCommandSuccess ln_cmd -s ln_file new_file - assertEquals "-s ln_file new_file" "$(cat "$STDOUTF")" + LN=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 } @@ -84,9 +61,7 @@ function test_download(){ CURL=/bin/false assertCommandSuccess download_cmd - # shellcheck disable=SC2034 WGET=/bin/false - # shellcheck disable=SC2034 CURL=/bin/true assertCommandSuccess download_cmd @@ -94,79 +69,48 @@ 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=$(id -u) + local 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")" - - 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 - ZGREP=false assertCommandSuccess zgrep_cmd new_file - assertEquals "zgrep" "$(cat "$STDOUTF")" - - echo -e "#!/bin/bash\nexit 1" > "${JUNEST_HOME}"/usr/bin/false - ZGREP=false assertCommandFail zgrep_cmd new_file -} - -function test_unshare(){ - 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")" - - 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")" - - UNSHARE=false LD_EXEC=false assertCommandFail unshare_cmd new_program -} - -function test_bwrap(){ - assertCommandSuccess bwrap_cmd new_program - assertEquals "$(echo -e "ld_exec $BWRAP --dev-bind / / /bin/sh -c :\nld_exec $BWRAP new_program")" "$(cat "$STDOUTF")" - - BWRAP=false LD_EXEC=false assertCommandFail bwrap_cmd new_program -} - function test_chroot(){ - CLASSIC_CHROOT="echo" assertCommandSuccess chroot_cmd root - assertEquals "root" "$(cat "$STDOUTF")" + 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")" + CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root + assertEquals "root" "$(cat $STDOUTF)" - CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root + CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root + assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)" + + CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root } function test_proot_cmd_compat(){ @@ -177,66 +121,51 @@ function test_proot_cmd_compat(){ function test_proot_cmd_seccomp(){ envv(){ - # shellcheck disable=SC2317 env } PROOT=envv assertCommandSuccess proot_cmd cmd - assertEquals "" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" + assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" envv(){ - # shellcheck disable=SC2317 env | grep "^PROOT_NO_SECCOMP" } - # shellcheck disable=SC2034 PROOT=envv + local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP") assertCommandSuccess proot_cmd cmd # The variable PROOT_NO_SECCOMP will be produced # twice due to the fallback mechanism assertEquals "PROOT_NO_SECCOMP=1 -PROOT_NO_SECCOMP=1" "$(grep "^PROOT_NO_SECCOMP" "$STDOUTF")" +PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")" } function test_copy_passwd_and_group(){ getent_cmd_mock() { - # shellcheck disable=SC2317 - echo "$*" + echo $@ } - GETENT=getent_cmd_mock assertCommandSuccess copy_passwd_and_group - assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat "$JUNEST_HOME"/etc/passwd)" - assertEquals "group" "$(cat "$JUNEST_HOME"/etc/group)" + GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group + assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)" + assertEquals "group" "$(cat $JUNEST_HOME/etc/group)" } function test_copy_passwd_and_group_fallback(){ cp_cmd_mock() { - # shellcheck disable=SC2317 - echo "$*" + echo $@ } - CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess copy_passwd_and_group - assertEquals "$(echo -e "-f /etc/passwd $JUNEST_HOME//etc/passwd\n-f /etc/group $JUNEST_HOME//etc/group")" "$(cat "$STDOUTF")" + CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group + assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)" } function test_copy_passwd_and_group_failure(){ - CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 copy_passwd_and_group + CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group } function test_nested_env(){ - JUNEST_ENV=1 assertCommandFailOnStatus 106 check_nested_env + JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" } function test_nested_env_not_set_variable(){ - JUNEST_ENV=aaa assertCommandFailOnStatus 107 check_nested_env + JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh" } -function test_check_same_arch_not_same(){ - echo "JUNEST_ARCH=XXX" > "${JUNEST_HOME}"/etc/junest/info - assertCommandFailOnStatus 104 check_same_arch -} - -function test_check_same_arch(){ - echo "JUNEST_ARCH=$ARCH" > "${JUNEST_HOME}"/etc/junest/info - assertCommandSuccess check_same_arch -} - - -source "$JUNEST_ROOT"/tests/utils/shunit2 +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-junest.sh b/tests/unit-tests/test-junest.sh deleted file mode 100755 index 07a92b1..0000000 --- a/tests/unit-tests/test-junest.sh +++ /dev/null @@ -1,383 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 - -source "$(dirname "$0")/../utils/utils.sh" - -JUNEST_BASE="$(dirname "$0")/../.." -source "$JUNEST_BASE"/bin/junest -h &> /dev/null - -# Disable the exiterr -set +e - -function oneTimeSetUp(){ - setUpUnitTests -} - -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 - } - # shellcheck disable=SC2317 - function create_wrappers(){ - : - } -} - -function test_help(){ - assertCommandSuccess main -h - assertEquals "usage" "$(cat "$STDOUTF")" - assertCommandSuccess main --help - assertEquals "usage" "$(cat "$STDOUTF")" -} -function test_version(){ - assertCommandSuccess main -V - assertEquals "version" "$(cat "$STDOUTF")" - assertCommandSuccess main --version - assertEquals "version" "$(cat "$STDOUTF")" -} -function test_build_image_env(){ - assertCommandSuccess main b - assertEquals "build_image_env(false)" "$(cat "$STDOUTF")" - assertCommandSuccess main build - assertEquals "build_image_env(false)" "$(cat "$STDOUTF")" - assertCommandSuccess main b -n - assertEquals "build_image_env(true)" "$(cat "$STDOUTF")" - assertCommandSuccess main build --disable-check - 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")" - assertCommandSuccess main setup --delete - 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")" - assertCommandSuccess main setup --from-file myimage - assertEquals "setup_env_from_file(myimage)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 0 - } - assertCommandFail main setup -i myimage -} - -function test_setup_env(){ - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandSuccess main s - assertEquals "setup_env()" "$(cat "$STDOUTF")" - assertCommandSuccess main setup - assertEquals "setup_env()" "$(cat "$STDOUTF")" - assertCommandSuccess main s -a arm - assertEquals "setup_env(arm)" "$(cat "$STDOUTF")" - assertCommandSuccess main setup --arch arm - assertEquals "setup_env(arm)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 0 - } - assertCommandFail main setup -a arm -} - -function test_run_env_as_proot_fakeroot(){ - assertCommandSuccess main p -f - assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main proot --fakeroot - assertEquals "run_env_as_proot_fakeroot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main p -f -n - assertEquals "run_env_as_proot_fakeroot(,,true,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main p -f --backend-command blah - assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main proot -f --backend-command blah - assertEquals "run_env_as_proot_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main proot -f -b "-b arg" - assertEquals "run_env_as_proot_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main proot -f -b "-b arg" -- command -kv - 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")" - assertCommandSuccess main proot -f -- command --as - assertEquals "run_env_as_proot_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandFail main proot -f -} - -function test_run_env_as_user(){ - assertCommandSuccess main proot - assertEquals "run_env_as_proot_user(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main p -n - assertEquals "run_env_as_proot_user(,,true,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main p --backend-command blah - assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main proot --backend-command blah - assertEquals "run_env_as_proot_user(blah,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main proot -b "-b arg" - assertEquals "run_env_as_proot_user(,-b arg,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main proot -b "-b arg" -- command -ll - 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")" - assertCommandSuccess main proot -- command -ls - assertEquals "run_env_as_proot_user(,,false,command -ls)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandFail main proot -} - -function test_run_env_as_groot(){ - assertCommandSuccess main g - assertEquals "run_env_as_groot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main g -n - assertEquals "run_env_as_groot(,,true,)" "$(cat "$STDOUTF")" - assertCommandSuccess main g -b "-b arg" - assertEquals "run_env_as_groot(,-b arg,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main g --backend-command blah - assertEquals "run_env_as_groot(blah,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main groot --backend-command blah - assertEquals "run_env_as_groot(blah,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main groot command - assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")" - assertCommandSuccess main groot -- command - assertEquals "run_env_as_groot(,,false,command)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandFail main groot -} - -function test_run_env_as_chroot(){ - assertCommandSuccess main r - assertEquals "run_env_as_chroot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main r -b "-b arg" - assertEquals "run_env_as_chroot(,-b arg,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main r --backend-command blah - assertEquals "run_env_as_chroot(blah,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main root --backend-command blah - assertEquals "run_env_as_chroot(blah,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main root command - assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")" - assertCommandSuccess main root -- command - assertEquals "run_env_as_chroot(,,false,command)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandFail main root -f -} - -function test_run_env_as_bwrap_fakeroot(){ - assertCommandSuccess main n -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns -n -f - assertEquals "run_env_as_bwrap_fakeroot(,,true,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main ns -f -b "-b arg" - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns -f -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns -f command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns -f -- command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" - - assertCommandSuccess main ns -f --backend-command blah - assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main -f --backend-command blah - assertEquals "run_env_as_bwrap_fakeroot(blah,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main -f - assertEquals "run_env_as_bwrap_fakeroot(,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main -f -b "-b arg" - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main -f -b "-b arg" -- command -kv - assertEquals "run_env_as_bwrap_fakeroot(,-b arg,false,command -kv)" "$(cat "$STDOUTF")" - assertCommandSuccess main -f command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" - assertCommandSuccess main -f -- command --as - assertEquals "run_env_as_bwrap_fakeroot(,,false,command --as)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandFail main ns -f -} - -function test_run_env_as_bwrap_user(){ - assertCommandSuccess main n - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main ns -n - 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")" - assertCommandSuccess main ns -b "-b arg" -- command -kv - 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")" - assertCommandSuccess main ns -- command --as - assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" - - assertCommandSuccess main ns --backend-command blah - assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main --backend-command blah - assertEquals "run_env_as_bwrap_user(blah,,false,)" "$(cat "$STDOUTF")" - - assertCommandSuccess main - assertEquals "run_env_as_bwrap_user(,,false,)" "$(cat "$STDOUTF")" - assertCommandSuccess main - 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")" - assertCommandSuccess main -b "-b arg" -- command -kv - 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")" - assertCommandSuccess main -- command --as - assertEquals "run_env_as_bwrap_user(,,false,command --as)" "$(cat "$STDOUTF")" - - # shellcheck disable=SC2317 - is_env_installed(){ - return 1 - } - assertCommandFail main ns -} - -function test_invalid_option(){ - assertCommandFail main --no-option - assertCommandFail main n --no-option - assertCommandFail main g --no-option - assertCommandFail main r --no-option - - assertCommandFail main p --no-option - - assertCommandFail main b --no-option - assertCommandFail main s --no-option -} - -source "$(dirname "$0")"/../utils/shunit2 diff --git a/tests/unit-tests/test-namespace.sh b/tests/unit-tests/test-namespace.sh deleted file mode 100755 index 7a845aa..0000000 --- a/tests/unit-tests/test-namespace.sh +++ /dev/null @@ -1,241 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 - -JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) - -source "$JUNEST_ROOT/tests/utils/utils.sh" - -source "$JUNEST_ROOT/lib/utils/utils.sh" - -# Disable the exiterr -set +e - -function oneTimeSetUp(){ - setUpUnitTests -} - -## Mock functions ## -function init_mocks() { - # shellcheck disable=SC2317 - function bwrap_cmd(){ - echo "$BWRAP $*" - } -} - -function setUp(){ - cwdSetUp - junestSetUp - - # Attempt to source the files under test to revert variable - # overrides (i.e. SH variable) - source "$JUNEST_ROOT/lib/core/common.sh" - source "$JUNEST_ROOT/lib/core/namespace.sh" - set +e - - init_mocks -} - -function tearDown(){ - junestTearDown - cwdTearDown -} - -function _test_copy_common_files() { - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat "${JUNEST_HOME}"/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat "${JUNEST_HOME}"/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat "${JUNEST_HOME}"/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat "${JUNEST_HOME}"/etc/resolv.conf)" -} - -function _test_copy_remaining_files() { - [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat "${JUNEST_HOME}"/etc/hosts.equiv)" - [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat "${JUNEST_HOME}"/etc/netgroup)" - [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat "${JUNEST_HOME}"/etc/networks)" - - [[ -e ${JUNEST_HOME}/etc/passwd ]] - assertEquals 0 $? - [[ -e ${JUNEST_HOME}/etc/group ]] - assertEquals 0 $? -} - -function test_is_user_namespace_enabled_no_config_file(){ - PROC_USERNS_FILE="blah" - PROC_USERNS_CLONE_FILE="blah" - CONFIG_PROC_FILE="blah" - CONFIG_BOOT_FILE="blah" - assertCommandFailOnStatus "$NOT_EXISTING_FILE" _is_user_namespace_enabled -} - -function test_is_user_namespace_enabled_no_config(){ - PROC_USERNS_FILE="blah" - PROC_USERNS_CLONE_FILE="blah" - touch config - gzip config - # shellcheck disable=SC2034 - CONFIG_PROC_FILE="config.gz" - # shellcheck disable=SC2034 - CONFIG_BOOT_FILE="blah" - assertCommandFailOnStatus "$NO_CONFIG_FOUND" _is_user_namespace_enabled -} - -function test_is_user_namespace_enabled_with_userns_clone_file_disabled(){ - PROC_USERNS_FILE="blah" - PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" - echo "0" > $PROC_USERNS_CLONE_FILE - assertCommandFailOnStatus "$UNPRIVILEGED_USERNS_DISABLED" _is_user_namespace_enabled -} - -function test_is_user_namespace_enabled_with_userns_clone_file_enabled(){ - PROC_USERNS_CLONE_FILE="unprivileged_userns_clone" - echo "1" > $PROC_USERNS_CLONE_FILE - assertCommandSuccess _is_user_namespace_enabled -} - -function test_is_user_namespace_enabled_with_proc_userns_file_existing(){ - PROC_USERNS_FILE="user" - ln -s . $PROC_USERNS_FILE - PROC_USERNS_CLONE_FILE="blah" - assertCommandSuccess _is_user_namespace_enabled -} - -function test_run_env_as_bwrap_fakeroot() { - assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")" - - _test_copy_common_files -} - -function test_run_env_as_bwrap_fakeroot_with_backend_command() { - assertCommandSuccess run_env_as_bwrap_fakeroot "mybwrap" "" "false" - assertEquals "mybwrap $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login" "$(cat "$STDOUTF")" - - _test_copy_common_files -} - -function test_run_env_as_bwrap_user() { - assertCommandSuccess run_env_as_bwrap_user "" "" "false" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")" - - _test_copy_common_files - _test_copy_remaining_files -} - -function test_run_env_as_bwrap_user_with_backend_command() { - assertCommandSuccess run_env_as_bwrap_user "mybwrap" "" "false" - assertEquals "mybwrap $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")" - - _test_copy_common_files - _test_copy_remaining_files -} - -function test_run_env_as_bwrap_fakeroot_no_copy() { - assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "true" "" - 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 $? - [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] - assertEquals 0 $? - - [[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/netgroup ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/networks ]] - assertEquals 0 $? - - [[ ! -e ${JUNEST_HOME}/etc/passwd ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/group ]] - assertEquals 0 $? -} - -function test_run_env_as_bwrap_user_no_copy() { - assertCommandSuccess run_env_as_bwrap_user "" "" "true" "" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login" "$(cat "$STDOUTF")" - - [[ ! -e ${JUNEST_HOME}/etc/hosts ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] - assertEquals 0 $? - - [[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/netgroup ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/networks ]] - assertEquals 0 $? - - [[ ! -e ${JUNEST_HOME}/etc/passwd ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/group ]] - assertEquals 0 $? -} - -function test_run_env_as_bwrap_fakeroot_with_backend_args() { - assertCommandSuccess run_env_as_bwrap_fakeroot "" "--bind /usr /usr" "false" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login" "$(cat "$STDOUTF")" - - _test_copy_common_files -} - -function test_run_env_as_bwrap_user_with_backend_args() { - assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login" "$(cat "$STDOUTF")" - - _test_copy_common_files - _test_copy_remaining_files -} - -function test_run_env_as_bwrap_fakeroot_with_command() { - assertCommandSuccess run_env_as_bwrap_fakeroot "" "" "false" "ls -la" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 sudo /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" - - _test_copy_common_files -} - -function test_run_env_as_bwrap_user_with_command() { - assertCommandSuccess run_env_as_bwrap_user "" "" "false" "ls -la" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" - - _test_copy_common_files - _test_copy_remaining_files -} - -function test_run_env_as_bwrap_fakeroot_with_backend_args_and_command() { - assertCommandSuccess run_env_as_bwrap_fakeroot "" "--bind /usr /usr" "false" "ls -la" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --cap-add ALL --uid 0 --gid 0 --bind /usr /usr sudo /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" - - _test_copy_common_files -} - -function test_run_env_as_bwrap_user_with_backend_args_and_command() { - assertCommandSuccess run_env_as_bwrap_user "" "--bind /usr /usr" "false" "ls -la" - assertEquals "$BWRAP $COMMON_BWRAP_OPTION --bind /usr /usr /bin/sh --login -c \"ls -la\"" "$(cat "$STDOUTF")" - - _test_copy_common_files - _test_copy_remaining_files -} - -function test_run_env_as_bwrap_fakeroot_nested_env(){ - JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_bwrap_fakeroot "" "" "false" "" - unset JUNEST_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 diff --git a/tests/unit-tests/test-proot.sh b/tests/unit-tests/test-proot.sh index 0f4f11a..fdc83b2 100755 --- a/tests/unit-tests/test-proot.sh +++ b/tests/unit-tests/test-proot.sh @@ -1,7 +1,6 @@ #!/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,191 +29,86 @@ function tearDown(){ cwdTearDown } -function _test_copy_common_files() { - [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat "${JUNEST_HOME}"/etc/hosts)" - [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat "${JUNEST_HOME}"/etc/host.conf)" - [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat "${JUNEST_HOME}"/etc/nsswitch.conf)" - [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat "${JUNEST_HOME}"/etc/resolv.conf)" -} - -function _test_copy_remaining_files() { - [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat "${JUNEST_HOME}"/etc/hosts.equiv)" - [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat "${JUNEST_HOME}"/etc/netgroup)" - [[ -e /etc/networks ]] && assertEquals "$(cat /etc/networks)" "$(cat "${JUNEST_HOME}"/etc/networks)" - - [[ -e ${JUNEST_HOME}/etc/passwd ]] - assertEquals 0 $? - [[ -e ${JUNEST_HOME}/etc/group ]] - assertEquals 0 $? -} - -function test_run_env_as_proot_user(){ - # shellcheck disable=SC2317 +function test_run_env_as_user(){ _run_env_with_qemu() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + echo $@ } - assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - 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")" + assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" - assertEquals "-b /run/user/$(id -u) -b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat "$STDOUTF")" + assertCommandSuccess run_env_as_user "-k 3.10" + assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" + + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" + + [[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)" + [[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)" + + [[ -e /etc/passwd ]] + assertEquals 0 $? + [[ -e /etc/group ]] + assertEquals 0 $? - _test_copy_common_files - _test_copy_remaining_files } -function test_run_env_as_proot_user_with_backend_command(){ - # shellcheck disable=SC2317 +function test_run_env_as_fakeroot(){ _run_env_with_qemu() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + echo $@ } - assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" "/usr/bin/mkdir" "-v" "/newdir2" - 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")" + assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" SH=("/usr/bin/echo") - assertCommandSuccess run_env_as_proot_user "myproot" "-k 3.10" "false" - 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")" + assertCommandSuccess run_env_as_fakeroot "-k 3.10" + assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)" - _test_copy_common_files - _test_copy_remaining_files -} - -function test_run_env_as_proot_user_no_copy(){ - # shellcheck disable=SC2317 - _run_env_with_qemu() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* - } - assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "true" "/usr/bin/mkdir" "-v" "/newdir2" - 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 $? - [[ ! -e ${JUNEST_HOME}/etc/host.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/nsswitch.conf ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/resolv.conf ]] - assertEquals 0 $? - - [[ ! -e ${JUNEST_HOME}/etc/hosts.equiv ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/netgroup ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/networks ]] - assertEquals 0 $? - - [[ ! -e ${JUNEST_HOME}/etc/passwd ]] - assertEquals 0 $? - [[ ! -e ${JUNEST_HOME}/etc/group ]] - assertEquals 0 $? -} - -function test_run_env_as_proot_user_nested_env(){ - JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_proot_user "" "" "false" - unset JUNEST_ENV -} - -function test_run_env_as_proot_fakeroot(){ - # shellcheck disable=SC2317 - _run_env_with_qemu() { - # 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 /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 /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() { - # 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 /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 /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_nested_env(){ - JUNEST_ENV=1 - assertCommandFailOnStatus 106 run_env_as_proot_fakeroot "" "" "false" "" - unset JUNEST_ENV + [[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)" + [[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)" + [[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)" + [[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)" } function test_run_env_with_quotes(){ - # shellcheck disable=SC2317 _run_env_with_qemu() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + echo $@ } - assertCommandSuccess run_env_as_proot_user "" "-k 3.10" "false" "bash" "-c" "/usr/bin/mkdir -v /newdir2" - 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")" + assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2" + assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)" } function test_run_env_with_proot_args(){ - # shellcheck disable=SC2317 proot_cmd() { [ "$JUNEST_ENV" != "1" ] && return 1 - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + echo $@ } - assertCommandSuccess _run_env_with_proot "" "--help" - assertEquals "--help /bin/sh --login" "$(cat "$STDOUTF")" + assertCommandSuccess _run_env_with_proot --help + assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)" - assertCommandSuccess _run_env_with_proot "" "--help" mycommand - assertEquals "--help /bin/sh --login -c mycommand" "$(cat "$STDOUTF")" + assertCommandSuccess _run_env_with_proot --help mycommand + assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)" assertCommandFail _run_env_with_proot } function test_qemu() { - echo "JUNEST_ARCH=arm" > "${JUNEST_HOME}"/etc/junest/info - # shellcheck disable=SC2317 + echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info rm_cmd() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + echo $@ } - # shellcheck disable=SC2317 ln_cmd() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + echo $@ } - # shellcheck disable=SC2317 _run_env_with_proot() { - # shellcheck disable=SC2086 - # shellcheck disable=SC2048 - echo $* + 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")" + RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu "" + assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)" } -source "$JUNEST_ROOT"/tests/utils/shunit2 +source $JUNEST_ROOT/tests/utils/shunit2 diff --git a/tests/unit-tests/test-setup.sh b/tests/unit-tests/test-setup.sh index de2df75..a15dbca 100755 --- a/tests/unit-tests/test-setup.sh +++ b/tests/unit-tests/test-setup.sh @@ -1,7 +1,6 @@ #!/bin/bash -# shellcheck disable=SC1091 -JUNEST_ROOT=$(readlink -f "$(dirname "$0")"/../..) +JUNEST_ROOT=$(readlink -f $(dirname $0)/../..) source "$JUNEST_ROOT/tests/utils/utils.sh" @@ -27,27 +26,24 @@ 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:?}"/* - # shellcheck disable=SC2317 + rm -rf $JUNEST_HOME/* wget_mock(){ # Proof that the setup is happening # inside $JUNEST_TEMPDIR - local cwd=${PWD#"${JUNEST_TEMPDIR}"} - local parent_dir=${PWD%"${cwd}"} + local cwd=${PWD#${JUNEST_TEMPDIR}} + local parent_dir=${PWD%${cwd}} assertEquals "$JUNEST_TEMPDIR" "${parent_dir}" touch file - tar -czvf "${CMD}-${ARCH}".tar.gz file + tar -czvf ${CMD}-${ARCH}.tar.gz file } - # shellcheck disable=SC2034 WGET=wget_mock - # shellcheck disable=SC2119 setup_env 1> /dev/null assertTrue "[ -e $JUNEST_HOME/file ]" @@ -56,10 +52,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 ]" } @@ -68,10 +64,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 ]" } @@ -82,4 +78,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 03e602a..8a5a127 100755 --- a/tests/unit-tests/test-utils.sh +++ b/tests/unit-tests/test-utils.sh @@ -1,13 +1,10 @@ #!/bin/bash -# shellcheck disable=SC1091 - -source "$(dirname "$0")/../utils/utils.sh" +source "$(dirname $0)/../utils/utils.sh" unset HOME -export HOME -HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX) +export 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 @@ -23,42 +20,37 @@ 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 - expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$expected" "$(cat "$STDERRF")" + local expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" } function test_warn(){ assertCommandSuccess warn "Test" - local expected - expected=$(echo -e "\033[1;33mTest\033[0m") - assertEquals "$expected" "$(cat "$STDERRF")" + local expected=$(echo -e "\033[1;33mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" } function test_info(){ assertCommandSuccess info "Test" - local expected - expected=$(echo -e "\033[1;36mTest\033[0m") - assertEquals "$expected" "$(cat "$STDOUTF")" + local expected=$(echo -e "\033[1;36mTest\033[0m") + assertEquals "$expected" "$(cat $STDOUTF)" } function test_die(){ assertCommandFail die "Test" - local expected - expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$expected" "$(cat "$STDERRF")" + local expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" } function test_die_on_status(){ assertCommandFailOnStatus 222 die_on_status 222 "Test" - local expected - expected=$(echo -e "\033[1;31mTest\033[0m") - assertEquals "$expected" "$(cat "$STDERRF")" + local expected=$(echo -e "\033[1;31mTest\033[0m") + assertEquals "$expected" "$(cat $STDERRF)" } function test_ask_null_question(){ @@ -89,10 +81,10 @@ function test_ask_wrong_default_answer() { 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(){ @@ -102,4 +94,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 deleted file mode 100755 index ee9776f..0000000 --- a/tests/unit-tests/test-wrappers.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/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 e90ed22..acf1bba 100755 --- a/tests/unit-tests/unit-tests.sh +++ b/tests/unit-tests/unit-tests.sh @@ -1,7 +1,6 @@ #!/bin/bash tests_succeded=true -# shellcheck disable=SC2010 -for tst in $(ls "$(dirname "$0")"/test* | grep -v "$(basename "$0")") +for tst in $(ls $(dirname $0)/test* | grep -v $(basename $0)) do $tst || tests_succeded=false done diff --git a/tests/utils/shunit2 b/tests/utils/shunit2 index e4c719c..d6e7503 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_]* *\(\)' - grep -E "${_shunit_regex_}" "${_shunit_script_}" \ + egrep "${_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 ab37bd9..b96000c 100644 --- a/tests/utils/utils.sh +++ b/tests/utils/utils.sh @@ -1,28 +1,26 @@ -#!/usr/bin/env bash - -OLD_CWD=${PWD} function cwdSetUp(){ ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX) - cd "$ORIGIN_CWD" || return 1 + cd $ORIGIN_CWD } function cwdTearDown(){ - rm -rf "$ORIGIN_CWD" - cd "$OLD_CWD" || return 1 + rm -rf $ORIGIN_CWD } function junestSetUp(){ JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX) - mkdir -p "${JUNEST_HOME}/usr/bin" - mkdir -p "${JUNEST_HOME}/etc/junest" - echo "JUNEST_ARCH=x86_64" > "${JUNEST_HOME}/etc/junest/info" - mkdir -p "${JUNEST_HOME}/etc/ca-certificates" + mkdir -p ${JUNEST_HOME}/etc/junest + echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info + mkdir -p ${JUNEST_HOME}/etc/ca-certificates + trap - QUIT EXIT ABRT KILL TERM INT + trap "rm -rf ${JUNEST_HOME}" EXIT QUIT ABRT KILL TERM INT } function junestTearDown(){ # the CA directories are read only and can be deleted only by changing the mod - [ -d "${JUNEST_HOME}/etc/ca-certificates" ] && chmod -R +w "${JUNEST_HOME}/etc/ca-certificates" - rm -rf "$JUNEST_HOME" + [ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates + rm -rf $JUNEST_HOME + trap - QUIT EXIT ABRT KILL TERM INT unset JUNEST_HOME } @@ -34,17 +32,15 @@ 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" $? } @@ -54,9 +50,8 @@ function assertCommandFail(){ function assertCommandFailOnStatus(){ local status=$1 shift - # shellcheck disable=SC2091 $(set -e - "$@" > "$STDOUTF" 2> "$STDERRF" + "$@" > $STDOUTF 2> $STDERRF ) - assertEquals "$status" $? + assertEquals $status $? }