mirror of
https://github.com/fsquillace/junest.git
synced 2026-01-23 02:34:30 +00:00
Issue #174: 🎨 Change structure of core modules
This change separate different parts of the code into several categories: `chroot`, `proot`, `build`, `common`, `setup`. This should simplify the maintenance of the code and will help introducing the user namespace module in a easier way.
This commit is contained in:
parent
54a09245d2
commit
ddc7ede70a
20 changed files with 1189 additions and 1031 deletions
|
|
@ -17,7 +17,8 @@ install:
|
|||
|
||||
script:
|
||||
- bash --version
|
||||
- ./tests/unit-tests/unit-tests.sh
|
||||
- bash ./tests/unit-tests/unit-tests.sh
|
||||
- bash ./tests/checkstyle/checkstyle.sh
|
||||
- junest --check ./bin/junest
|
||||
- yes | junest --delete
|
||||
- JUNEST_HOME=~/.junest-arm junest --check ./bin/junest --skip-root-tests
|
||||
|
|
|
|||
14
bin/junest
14
bin/junest
|
|
@ -5,8 +5,12 @@
|
|||
|
||||
JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)"
|
||||
|
||||
source "${JUNEST_BASE}/lib/utils.sh"
|
||||
source "${JUNEST_BASE}/lib/core.sh"
|
||||
source "${JUNEST_BASE}/lib/utils/utils.sh"
|
||||
source "${JUNEST_BASE}/lib/core/common.sh"
|
||||
source "${JUNEST_BASE}/lib/core/build.sh"
|
||||
source "${JUNEST_BASE}/lib/core/setup.sh"
|
||||
source "${JUNEST_BASE}/lib/core/proot.sh"
|
||||
source "${JUNEST_BASE}/lib/core/chroot.sh"
|
||||
|
||||
###################################
|
||||
### General functions ###
|
||||
|
|
@ -19,7 +23,7 @@ usage() {
|
|||
echo
|
||||
echo -e "Setup options:"
|
||||
echo -e "-i, --setup-from-file <image> Setup the $NAME image in ${JUNEST_HOME}"
|
||||
echo -e "-a, --arch <arch> $NAME architecture to download (x86_64, x86, arm)."
|
||||
echo -e "-a, --arch <arch> $NAME architecture to download (x86_64, x86, arm)"
|
||||
echo -e " Defaults to the host architecture ($ARCH)"
|
||||
echo -e "-d, --delete Delete $NAME from ${JUNEST_HOME}"
|
||||
echo
|
||||
|
|
@ -32,8 +36,8 @@ usage() {
|
|||
echo -e "-b, --build-image Build a $NAME image (must run in ArchLinux)"
|
||||
echo -e "-n, --disable-validation Disable the $NAME image validation"
|
||||
echo -e "-c, --check <${CMD}_script> Validate the env located in ${JUNEST_HOME}"
|
||||
echo -e " using ${CMD}_script. This will alterate the environment."
|
||||
echo -e "-s, --skip-root-tests Skip the root tests during the validation process."
|
||||
echo -e " using ${CMD}_script. This will alterate the environment"
|
||||
echo -e "-s, --skip-root-tests Skip the root tests during the validation process"
|
||||
echo
|
||||
echo -e "General options:"
|
||||
echo -e "-h, --help Show this help message"
|
||||
|
|
|
|||
639
lib/core.sh
639
lib/core.sh
|
|
@ -1,639 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This module contains all core functionalities for JuNest.
|
||||
#
|
||||
# Dependencies:
|
||||
# - lib/utils.sh
|
||||
#
|
||||
# vim: ft=sh
|
||||
|
||||
set -e
|
||||
|
||||
NAME='JuNest'
|
||||
CMD='junest'
|
||||
DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access'
|
||||
|
||||
NOT_AVAILABLE_ARCH=102
|
||||
NOT_EXISTING_FILE=103
|
||||
ARCHITECTURE_MISMATCH=104
|
||||
ROOT_ACCESS_ERROR=105
|
||||
NESTED_ENVIRONMENT=106
|
||||
VARIABLE_NOT_SET=107
|
||||
|
||||
if [ "$JUNEST_ENV" == "1" ]
|
||||
then
|
||||
die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed"
|
||||
elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ]
|
||||
then
|
||||
die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set"
|
||||
fi
|
||||
|
||||
[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD}
|
||||
[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest
|
||||
if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ]
|
||||
then
|
||||
JUNEST_TEMPDIR=/tmp
|
||||
fi
|
||||
|
||||
# The update of the variable PATH ensures that the executables are
|
||||
# found on different locations
|
||||
PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH
|
||||
|
||||
# The executable uname is essential in order to get the architecture
|
||||
# of the host system, so a fallback mechanism cannot be used for it.
|
||||
UNAME=uname
|
||||
|
||||
ARCH_LIST=('x86_64' 'x86' 'arm')
|
||||
HOST_ARCH=$($UNAME -m)
|
||||
if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ]
|
||||
then
|
||||
ARCH="x86"
|
||||
LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2"
|
||||
elif [ $HOST_ARCH == "x86_64" ]
|
||||
then
|
||||
ARCH="x86_64"
|
||||
LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2"
|
||||
elif [[ $HOST_ARCH =~ .*(arm).* ]]
|
||||
then
|
||||
ARCH="arm"
|
||||
LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3"
|
||||
else
|
||||
die "Unknown architecture ${HOST_ARCH}"
|
||||
fi
|
||||
|
||||
MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030
|
||||
ENV_REPO=${MAIN_REPO}/${CMD}
|
||||
DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch'
|
||||
|
||||
ORIGIN_WD=$(pwd)
|
||||
|
||||
################################ EXECUTABLES ##################################
|
||||
# This section contains all the executables needed for JuNest to run properly.
|
||||
# They are based on a fallback mechanism that tries to use the executable in
|
||||
# different locations in the host OS.
|
||||
|
||||
# List of executables that are run inside JuNest:
|
||||
SH=("/bin/sh" "--login")
|
||||
|
||||
# List of executables that are run in the host OS:
|
||||
PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}"
|
||||
CHROOT=${JUNEST_BASE}/bin/jchroot
|
||||
CLASSIC_CHROOT="chroot"
|
||||
WGET="wget --no-check-certificate"
|
||||
CURL="curl -L -J -O -k"
|
||||
TAR=tar
|
||||
CHOWN="chown"
|
||||
LN=ln
|
||||
RM=rm
|
||||
MKDIR=mkdir
|
||||
GETENT=getent
|
||||
CP=cp
|
||||
|
||||
LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib"
|
||||
|
||||
# The following functions attempt first to run the executable in the host OS.
|
||||
# As a last hope they try to run the same executable available in the JuNest
|
||||
# image.
|
||||
|
||||
function ln_cmd(){
|
||||
$LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@
|
||||
}
|
||||
|
||||
function getent_cmd(){
|
||||
$GETENT $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT $@
|
||||
}
|
||||
|
||||
function cp_cmd(){
|
||||
$CP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP $@
|
||||
}
|
||||
|
||||
function rm_cmd(){
|
||||
$RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@
|
||||
}
|
||||
|
||||
function chown_cmd(){
|
||||
$CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@
|
||||
}
|
||||
|
||||
function mkdir_cmd(){
|
||||
$MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@
|
||||
}
|
||||
|
||||
function proot_cmd(){
|
||||
local proot_args="$1"
|
||||
shift
|
||||
if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":"
|
||||
then
|
||||
${PROOT} ${proot_args} "${@}"
|
||||
elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":"
|
||||
then
|
||||
PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}"
|
||||
else
|
||||
die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\""
|
||||
fi
|
||||
}
|
||||
|
||||
function download_cmd(){
|
||||
$WGET $@ || $CURL $@
|
||||
}
|
||||
|
||||
function chroot_cmd(){
|
||||
$CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@"
|
||||
}
|
||||
|
||||
################################# MAIN FUNCTIONS ##############################
|
||||
|
||||
#######################################
|
||||
# Check if the JuNest system is installed in JUNEST_HOME.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : Contains the JuNest home directory.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0 : If JuNest is installed
|
||||
# 1 : If JuNest is not installed
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function is_env_installed(){
|
||||
[ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
function _cleanup_build_directory(){
|
||||
local maindir=$1
|
||||
check_not_null "$maindir"
|
||||
builtin cd $ORIGIN_WD
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
rm_cmd -fr "$maindir"
|
||||
}
|
||||
|
||||
|
||||
function _prepare_build_directory(){
|
||||
local maindir=$1
|
||||
check_not_null "$maindir"
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
|
||||
}
|
||||
|
||||
|
||||
function _setup_env(){
|
||||
local imagepath=$1
|
||||
check_not_null "$imagepath"
|
||||
|
||||
is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME"
|
||||
|
||||
mkdir_cmd -p "${JUNEST_HOME}"
|
||||
$TAR -zxpf ${imagepath} -C ${JUNEST_HOME}
|
||||
info "The default mirror URL is ${DEFAULT_MIRROR}."
|
||||
info "Remember to refresh the package databases from the server:"
|
||||
info " pacman -Syy"
|
||||
info "${NAME} installed successfully"
|
||||
}
|
||||
|
||||
|
||||
#######################################
|
||||
# Setup JuNest.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
|
||||
# to be installed.
|
||||
# ARCH (RO) : The host architecture.
|
||||
# JUNEST_TEMPDIR (RO) : The JuNest temporary directory for building
|
||||
# the JuNest system from the image.
|
||||
# ENV_REPO (RO) : URL of the site containing JuNest images.
|
||||
# NAME (RO) : The JuNest name.
|
||||
# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
|
||||
# Arguments:
|
||||
# arch ($1?) : The JuNest architecture image to download.
|
||||
# Defaults to the host architecture
|
||||
# Returns:
|
||||
# $NOT_AVAILABLE_ARCH : If the architecture is not one of the available ones.
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function setup_env(){
|
||||
local arch=${1:-$ARCH}
|
||||
contains_element $arch "${ARCH_LIST[@]}" || \
|
||||
die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}"
|
||||
|
||||
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
|
||||
_prepare_build_directory $maindir
|
||||
|
||||
info "Downloading ${NAME}..."
|
||||
builtin cd ${maindir}
|
||||
local imagefile=${CMD}-${arch}.tar.gz
|
||||
download_cmd ${ENV_REPO}/${imagefile}
|
||||
|
||||
info "Installing ${NAME}..."
|
||||
_setup_env ${maindir}/${imagefile}
|
||||
|
||||
_cleanup_build_directory ${maindir}
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Setup JuNest from file.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
|
||||
# to be installed.
|
||||
# NAME (RO) : The JuNest name.
|
||||
# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
|
||||
# Arguments:
|
||||
# imagefile ($1) : The JuNest image file.
|
||||
# Returns:
|
||||
# $NOT_EXISTING_FILE : If the image file does not exist.
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function setup_env_from_file(){
|
||||
local imagefile=$1
|
||||
check_not_null "$imagefile"
|
||||
[ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist"
|
||||
|
||||
info "Installing ${NAME} from ${imagefile}..."
|
||||
_setup_env ${imagefile}
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Run JuNest as real root.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# UID (RO) : The user ID.
|
||||
# SUDO_USER (RO) : The sudo user ID.
|
||||
# SUDO_GID (RO) : The sudo group ID.
|
||||
# SH (RO) : Contains the default command to run in JuNest.
|
||||
# Arguments:
|
||||
# cmd ($@?) : The command to run inside JuNest environment.
|
||||
# Default command is defined by SH variable.
|
||||
# Returns:
|
||||
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
|
||||
# Output:
|
||||
# - : The command output.
|
||||
#######################################
|
||||
function run_env_as_root(){
|
||||
source ${JUNEST_HOME}/etc/junest/info
|
||||
[ "$JUNEST_ARCH" != "$ARCH" ] && \
|
||||
die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH"
|
||||
|
||||
local uid=$UID
|
||||
# SUDO_USER is more reliable compared to SUDO_UID
|
||||
[ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID
|
||||
|
||||
local main_cmd="${SH[@]}"
|
||||
[ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")"
|
||||
|
||||
# With chown the ownership of the files is assigned to the real user
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT
|
||||
|
||||
JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}"
|
||||
}
|
||||
|
||||
function _run_env_with_proot(){
|
||||
local proot_args="$1"
|
||||
shift
|
||||
|
||||
if [ "$1" != "" ]
|
||||
then
|
||||
JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")"
|
||||
else
|
||||
JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
function _run_env_with_qemu(){
|
||||
local proot_args="$1"
|
||||
source ${JUNEST_HOME}/etc/junest/info
|
||||
|
||||
if [ "$JUNEST_ARCH" != "$ARCH" ]
|
||||
then
|
||||
local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH"
|
||||
local qemu_symlink="/tmp/${qemu_bin}-$RANDOM"
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT
|
||||
|
||||
warn "Emulating $NAME via QEMU..."
|
||||
[ -e ${qemu_symlink} ] || \
|
||||
ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink}
|
||||
proot_args="-q ${qemu_symlink} $proot_args"
|
||||
fi
|
||||
shift
|
||||
_run_env_with_proot "$proot_args" "${@}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Run JuNest as fakeroot.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# EUID (RO) : The user ID.
|
||||
# SH (RO) : Contains the default command to run in JuNest.
|
||||
# Arguments:
|
||||
# cmd ($@?) : The command to run inside JuNest environment.
|
||||
# Default command is defined by SH variable.
|
||||
# Returns:
|
||||
# $ROOT_ACCESS_ERROR : If the user is the real root.
|
||||
# Output:
|
||||
# - : The command output.
|
||||
#######################################
|
||||
function run_env_as_fakeroot(){
|
||||
(( EUID == 0 )) && \
|
||||
die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead."
|
||||
|
||||
_copy_common_files
|
||||
|
||||
_provide_common_bindings
|
||||
local bindings=${RESULT}
|
||||
unset RESULT
|
||||
|
||||
# An alternative is via -S option:
|
||||
#_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}"
|
||||
_run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Run JuNest as normal user.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# EUID (RO) : The user ID.
|
||||
# SH (RO) : Contains the default command to run in JuNest.
|
||||
# Arguments:
|
||||
# cmd ($@?) : The command to run inside JuNest environment.
|
||||
# Default command is defined by SH variable.
|
||||
# Returns:
|
||||
# $ROOT_ACCESS_ERROR : If the user is the real root.
|
||||
# Output:
|
||||
# - : The command output.
|
||||
#######################################
|
||||
function run_env_as_user(){
|
||||
(( EUID == 0 )) && \
|
||||
die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead."
|
||||
|
||||
# Files to bind are visible in `proot --help`.
|
||||
# This function excludes /etc/mtab file so that
|
||||
# it will not give conflicts with the related
|
||||
# symlink in the Arch Linux image.
|
||||
_copy_common_files
|
||||
_copy_file /etc/hosts.equiv
|
||||
_copy_file /etc/netgroup
|
||||
_copy_file /etc/networks
|
||||
# No need for localtime as it is setup during the image build
|
||||
#_copy_file /etc/localtime
|
||||
_copy_passwd_and_group
|
||||
|
||||
_provide_common_bindings
|
||||
local bindings=${RESULT}
|
||||
unset RESULT
|
||||
|
||||
_run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Provide the proot common binding options for both normal user and fakeroot.
|
||||
# The list of bindings can be found in `proot --help`. This function excludes
|
||||
# /etc/mtab file so that it will not give conflicts with the related
|
||||
# symlink in the image.
|
||||
#
|
||||
# Globals:
|
||||
# HOME (RO) : The home directory.
|
||||
# RESULT (WO) : Contains the binding options.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function _provide_common_bindings(){
|
||||
RESULT=""
|
||||
local re='(.*):.*'
|
||||
for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME"
|
||||
do
|
||||
if [[ $bind =~ $re ]]
|
||||
then
|
||||
[ -e "${BASH_REMATCH[1]}" ] && RESULT="-b $bind $RESULT"
|
||||
else
|
||||
[ -e "$bind" ] && RESULT="-b $bind $RESULT"
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Build passwd and group files using getent command.
|
||||
# If getent fails the function fallbacks by copying the content from /etc/passwd
|
||||
# and /etc/group.
|
||||
#
|
||||
# The generated passwd and group will be stored in $JUNEST_HOME/etc/junest.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function _copy_passwd_and_group(){
|
||||
# Enumeration of users/groups is disabled/limited depending on how nsswitch.conf
|
||||
# is configured.
|
||||
# Try to at least get the current user via `getent passwd $USER` since it uses
|
||||
# a more reliable and faster system call (getpwnam(3)).
|
||||
if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \
|
||||
! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd
|
||||
then
|
||||
warn "getent command failed or does not exist. Binding directly from /etc/passwd."
|
||||
_copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd
|
||||
fi
|
||||
|
||||
if ! getent_cmd group > ${JUNEST_HOME}/etc/group
|
||||
then
|
||||
warn "getent command failed or does not exist. Binding directly from /etc/group."
|
||||
_copy_file /etc/group ${JUNEST_HOME}/etc/group
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function _copy_file() {
|
||||
local file="${1}"
|
||||
[[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file"
|
||||
return 0
|
||||
}
|
||||
|
||||
function _copy_common_files() {
|
||||
_copy_file /etc/host.conf
|
||||
_copy_file /etc/hosts
|
||||
_copy_file /etc/nsswitch.conf
|
||||
_copy_file /etc/resolv.conf
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Remove an existing JuNest system.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory to remove.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function delete_env(){
|
||||
! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return
|
||||
if mountpoint -q ${JUNEST_HOME}
|
||||
then
|
||||
info "There are mounted directories inside ${JUNEST_HOME}"
|
||||
if ! umount --force ${JUNEST_HOME}
|
||||
then
|
||||
error "Cannot umount directories in ${JUNEST_HOME}"
|
||||
die "Try to delete ${NAME} using root permissions"
|
||||
fi
|
||||
fi
|
||||
# the CA directories are read only and can be deleted only by changing the mod
|
||||
chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
|
||||
if rm_cmd -rf ${JUNEST_HOME}/*
|
||||
then
|
||||
info "${NAME} deleted in ${JUNEST_HOME}"
|
||||
else
|
||||
error "Error: Cannot delete ${NAME} in ${JUNEST_HOME}"
|
||||
fi
|
||||
}
|
||||
|
||||
function _check_package(){
|
||||
if ! pacman -Qq $1 > /dev/null
|
||||
then
|
||||
die "Package $1 must be installed"
|
||||
fi
|
||||
}
|
||||
|
||||
function _install_from_aur(){
|
||||
local maindir=$1
|
||||
local pkgname=$2
|
||||
local installname=$3
|
||||
mkdir -p ${maindir}/packages/${pkgname}
|
||||
builtin cd ${maindir}/packages/${pkgname}
|
||||
$CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}"
|
||||
[ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}"
|
||||
makepkg -sfc
|
||||
sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz
|
||||
}
|
||||
|
||||
function build_image_env(){
|
||||
umask 022
|
||||
|
||||
# The function must runs on ArchLinux with non-root privileges.
|
||||
(( EUID == 0 )) && \
|
||||
die "You cannot build with root privileges."
|
||||
|
||||
_check_package arch-install-scripts
|
||||
_check_package gcc
|
||||
_check_package package-query
|
||||
_check_package git
|
||||
|
||||
local disable_validation=$1
|
||||
local skip_root_tests=$2
|
||||
|
||||
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
|
||||
sudo mkdir -p ${maindir}/root
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
|
||||
info "Installing pacman and its dependencies..."
|
||||
# The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux
|
||||
# All the essential executables (ln, mkdir, chown, etc) are in coreutils
|
||||
# yaourt requires sed
|
||||
# localedef (called by locale-gen) requires gzip
|
||||
sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip
|
||||
sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist"
|
||||
sudo mkdir -p ${maindir}/root/run/lock
|
||||
|
||||
# AUR packages requires non-root user to be compiled. proot fakes the user to 10
|
||||
info "Compiling and installing yaourt..."
|
||||
_install_from_aur ${maindir} "package-query"
|
||||
_install_from_aur ${maindir} "yaourt"
|
||||
|
||||
info "Install ${NAME} script..."
|
||||
sudo pacman --noconfirm --root ${maindir}/root -S git
|
||||
_install_from_aur ${maindir} "${CMD}-git" "${CMD}.install"
|
||||
sudo pacman --noconfirm --root ${maindir}/root -Rsn git
|
||||
|
||||
info "Generating the locales..."
|
||||
# sed command is required for locale-gen
|
||||
sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime
|
||||
sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen"
|
||||
sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen
|
||||
sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf"
|
||||
|
||||
info "Setting up the pacman keyring (this might take a while!)..."
|
||||
sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \
|
||||
"pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye"
|
||||
|
||||
sudo rm ${maindir}/root/var/cache/pacman/pkg/*
|
||||
|
||||
mkdir -p ${maindir}/output
|
||||
builtin cd ${maindir}/output
|
||||
local imagefile="${CMD}-${ARCH}.tar.gz"
|
||||
info "Compressing image to ${imagefile}..."
|
||||
sudo $TAR -zcpf ${imagefile} -C ${maindir}/root .
|
||||
|
||||
if ! $disable_validation
|
||||
then
|
||||
mkdir -p ${maindir}/root_test
|
||||
$TAR -zxpf ${imagefile} -C "${maindir}/root_test"
|
||||
check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests
|
||||
fi
|
||||
|
||||
sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD}
|
||||
|
||||
builtin cd ${ORIGIN_WD}
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
sudo rm -fr "$maindir"
|
||||
}
|
||||
|
||||
function check_env(){
|
||||
local testdir=$1
|
||||
local cmd=$2
|
||||
local skip_root_tests=$3
|
||||
info "Validating ${NAME} located in ${testdir} using the ${cmd} script..."
|
||||
echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy
|
||||
|
||||
# Check most basic executables work
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null
|
||||
|
||||
local repo_package=tree
|
||||
info "Installing ${repo_package} package from official repo using proot..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package}
|
||||
JUNEST_HOME=${testdir} ${cmd} tree
|
||||
JUNEST_HOME=${testdir} ${cmd} -f tree
|
||||
|
||||
local repo_package=iftop
|
||||
info "Installing ${repo_package} package from official repo using root..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package}
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5
|
||||
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel
|
||||
local aur_package=tcptraceroute
|
||||
info "Installing ${aur_package} package from AUR repo using proot..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package}
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost
|
||||
|
||||
info "Removing the previous packages..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop
|
||||
|
||||
}
|
||||
140
lib/core/build.sh
Normal file
140
lib/core/build.sh
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This module contains all build functionalities for JuNest.
|
||||
#
|
||||
# Dependencies:
|
||||
# - lib/utils/utils.sh
|
||||
# - lib/core/common.sh
|
||||
#
|
||||
# vim: ft=sh
|
||||
|
||||
function _check_package(){
|
||||
if ! pacman -Qq $1 > /dev/null
|
||||
then
|
||||
die "Package $1 must be installed"
|
||||
fi
|
||||
}
|
||||
|
||||
function _install_from_aur(){
|
||||
local maindir=$1
|
||||
local pkgname=$2
|
||||
local installname=$3
|
||||
mkdir -p ${maindir}/packages/${pkgname}
|
||||
builtin cd ${maindir}/packages/${pkgname}
|
||||
$CURL "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=${pkgname}"
|
||||
[ -z "${installname}" ] || $CURL "https://aur.archlinux.org/cgit/aur.git/plain/${installname}?h=${pkgname}"
|
||||
makepkg -sfc
|
||||
sudo pacman --noconfirm --root ${maindir}/root -U ${pkgname}*.pkg.tar.xz
|
||||
}
|
||||
|
||||
function build_image_env(){
|
||||
umask 022
|
||||
|
||||
# The function must runs on ArchLinux with non-root privileges.
|
||||
(( EUID == 0 )) && \
|
||||
die "You cannot build with root privileges."
|
||||
|
||||
_check_package arch-install-scripts
|
||||
_check_package gcc
|
||||
_check_package package-query
|
||||
_check_package git
|
||||
|
||||
local disable_validation=$1
|
||||
local skip_root_tests=$2
|
||||
|
||||
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
|
||||
sudo mkdir -p ${maindir}/root
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "sudo rm -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
|
||||
info "Installing pacman and its dependencies..."
|
||||
# The archlinux-keyring and libunistring are due to missing dependencies declaration in ARM archlinux
|
||||
# All the essential executables (ln, mkdir, chown, etc) are in coreutils
|
||||
# yaourt requires sed
|
||||
# localedef (called by locale-gen) requires gzip
|
||||
sudo pacstrap -G -M -d ${maindir}/root pacman coreutils libunistring archlinux-keyring sed gzip
|
||||
sudo bash -c "echo 'Server = $DEFAULT_MIRROR' >> ${maindir}/root/etc/pacman.d/mirrorlist"
|
||||
sudo mkdir -p ${maindir}/root/run/lock
|
||||
|
||||
# AUR packages requires non-root user to be compiled. proot fakes the user to 10
|
||||
info "Compiling and installing yaourt..."
|
||||
_install_from_aur ${maindir} "package-query"
|
||||
_install_from_aur ${maindir} "yaourt"
|
||||
|
||||
info "Install ${NAME} script..."
|
||||
sudo pacman --noconfirm --root ${maindir}/root -S git
|
||||
_install_from_aur ${maindir} "${CMD}-git" "${CMD}.install"
|
||||
sudo pacman --noconfirm --root ${maindir}/root -Rsn git
|
||||
|
||||
info "Generating the locales..."
|
||||
# sed command is required for locale-gen
|
||||
sudo ln -sf /usr/share/zoneinfo/posix/UTC ${maindir}/root/etc/localtime
|
||||
sudo bash -c "echo 'en_US.UTF-8 UTF-8' >> ${maindir}/root/etc/locale.gen"
|
||||
sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root locale-gen
|
||||
sudo bash -c "echo LANG=\"en_US.UTF-8\" >> ${maindir}/root/etc/locale.conf"
|
||||
|
||||
info "Setting up the pacman keyring (this might take a while!)..."
|
||||
sudo ${maindir}/root/opt/junest/bin/jchroot ${maindir}/root bash -c \
|
||||
"pacman-key --init; pacman-key --populate archlinux; [ -e /etc/pacman.d/gnupg/S.gpg-agent ] && gpg-connect-agent -S /etc/pacman.d/gnupg/S.gpg-agent killagent /bye"
|
||||
|
||||
sudo rm ${maindir}/root/var/cache/pacman/pkg/*
|
||||
|
||||
mkdir -p ${maindir}/output
|
||||
builtin cd ${maindir}/output
|
||||
local imagefile="${CMD}-${ARCH}.tar.gz"
|
||||
info "Compressing image to ${imagefile}..."
|
||||
sudo $TAR -zcpf ${imagefile} -C ${maindir}/root .
|
||||
|
||||
if ! $disable_validation
|
||||
then
|
||||
mkdir -p ${maindir}/root_test
|
||||
$TAR -zxpf ${imagefile} -C "${maindir}/root_test"
|
||||
check_env "${maindir}/root_test" "${maindir}/root_test/opt/${CMD}/bin/${CMD}" $skip_root_tests
|
||||
fi
|
||||
|
||||
sudo cp ${maindir}/output/${imagefile} ${ORIGIN_WD}
|
||||
|
||||
builtin cd ${ORIGIN_WD}
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
sudo rm -fr "$maindir"
|
||||
}
|
||||
|
||||
function check_env(){
|
||||
local testdir=$1
|
||||
local cmd=$2
|
||||
local skip_root_tests=$3
|
||||
info "Validating ${NAME} located in ${testdir} using the ${cmd} script..."
|
||||
echo "Server = ${DEFAULT_MIRROR}" >> ${testdir}/etc/pacman.d/mirrorlist
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Syy
|
||||
|
||||
# Check most basic executables work
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r pacman -Qi pacman 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -- pacman -Qi pacman 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- pacman -Qi pacman 1> /dev/null
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r yogurt -V 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -- yogurt -V 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -V 1> /dev/null
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r /opt/proot/proot-$ARCH --help 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -- /opt/proot/proot-$ARCH --help 1> /dev/null
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- /opt/proot/proot-$ARCH --help 1> /dev/null
|
||||
|
||||
local repo_package=tree
|
||||
info "Installing ${repo_package} package from official repo using proot..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package}
|
||||
JUNEST_HOME=${testdir} ${cmd} tree
|
||||
JUNEST_HOME=${testdir} ${cmd} -f tree
|
||||
|
||||
local repo_package=iftop
|
||||
info "Installing ${repo_package} package from official repo using root..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S ${repo_package}
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r iftop -t -s 5
|
||||
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -S base-devel
|
||||
local aur_package=tcptraceroute
|
||||
info "Installing ${aur_package} package from AUR repo using proot..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f -- yogurt -A --noconfirm -S ${aur_package}
|
||||
$skip_root_tests || JUNEST_HOME=${testdir} sudo -E ${cmd} -r tcptraceroute localhost
|
||||
|
||||
info "Removing the previous packages..."
|
||||
JUNEST_HOME=${testdir} ${cmd} -f pacman --noconfirm -Rsn tcptraceroute tree iftop
|
||||
|
||||
}
|
||||
45
lib/core/chroot.sh
Normal file
45
lib/core/chroot.sh
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This module contains all chroot functionalities for JuNest.
|
||||
#
|
||||
# Dependencies:
|
||||
# - lib/utils/utils.sh
|
||||
# - lib/core/common.sh
|
||||
#
|
||||
# vim: ft=sh
|
||||
|
||||
#######################################
|
||||
# Run JuNest as real root.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# UID (RO) : The user ID.
|
||||
# SUDO_USER (RO) : The sudo user ID.
|
||||
# SUDO_GID (RO) : The sudo group ID.
|
||||
# SH (RO) : Contains the default command to run in JuNest.
|
||||
# Arguments:
|
||||
# cmd ($@?) : The command to run inside JuNest environment.
|
||||
# Default command is defined by SH variable.
|
||||
# Returns:
|
||||
# $ARCHITECTURE_MISMATCH : If host and JuNest architecture are different.
|
||||
# Output:
|
||||
# - : The command output.
|
||||
#######################################
|
||||
function run_env_as_root(){
|
||||
source ${JUNEST_HOME}/etc/junest/info
|
||||
[ "$JUNEST_ARCH" != "$ARCH" ] && \
|
||||
die_on_status $ARCHITECTURE_MISMATCH "The host system architecture is not correct: $ARCH != $JUNEST_ARCH"
|
||||
|
||||
local uid=$UID
|
||||
# SUDO_USER is more reliable compared to SUDO_UID
|
||||
[ -z $SUDO_USER ] || uid=$SUDO_USER:$SUDO_GID
|
||||
|
||||
local main_cmd="${SH[@]}"
|
||||
[ "$1" != "" ] && main_cmd="$(insert_quotes_on_spaces "$@")"
|
||||
|
||||
# With chown the ownership of the files is assigned to the real user
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "[ -z $uid ] || chown_cmd -R ${uid} ${JUNEST_HOME};" EXIT QUIT ABRT KILL TERM INT
|
||||
|
||||
JUNEST_ENV=1 chroot_cmd "$JUNEST_HOME" "${SH[@]}" "-c" "${main_cmd}"
|
||||
}
|
||||
226
lib/core/common.sh
Normal file
226
lib/core/common.sh
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This module contains all common functionalities for JuNest.
|
||||
#
|
||||
# Dependencies:
|
||||
# - lib/utils/utils.sh
|
||||
#
|
||||
# vim: ft=sh
|
||||
|
||||
set -e
|
||||
|
||||
NAME='JuNest'
|
||||
CMD='junest'
|
||||
DESCRIPTION='The Arch Linux based distro that runs upon any Linux distros without root access'
|
||||
|
||||
NOT_AVAILABLE_ARCH=102
|
||||
NOT_EXISTING_FILE=103
|
||||
ARCHITECTURE_MISMATCH=104
|
||||
ROOT_ACCESS_ERROR=105
|
||||
NESTED_ENVIRONMENT=106
|
||||
VARIABLE_NOT_SET=107
|
||||
|
||||
if [ "$JUNEST_ENV" == "1" ]
|
||||
then
|
||||
die_on_status $NESTED_ENVIRONMENT "Error: Nested ${NAME} environments are not allowed"
|
||||
elif [ ! -z $JUNEST_ENV ] && [ "$JUNEST_ENV" != "0" ]
|
||||
then
|
||||
die_on_status $VARIABLE_NOT_SET "The variable JUNEST_ENV is not properly set"
|
||||
fi
|
||||
|
||||
[ -z ${JUNEST_HOME} ] && JUNEST_HOME=~/.${CMD}
|
||||
[ -z ${JUNEST_BASE} ] && JUNEST_BASE=${JUNEST_HOME}/opt/junest
|
||||
if [ -z ${JUNEST_TEMPDIR} ] || [ ! -d ${JUNEST_TEMPDIR} ]
|
||||
then
|
||||
JUNEST_TEMPDIR=/tmp
|
||||
fi
|
||||
|
||||
# The update of the variable PATH ensures that the executables are
|
||||
# found on different locations
|
||||
PATH=/usr/bin:/bin:/usr/sbin:/sbin:$PATH
|
||||
|
||||
# The executable uname is essential in order to get the architecture
|
||||
# of the host system, so a fallback mechanism cannot be used for it.
|
||||
UNAME=uname
|
||||
|
||||
ARCH_LIST=('x86_64' 'x86' 'arm')
|
||||
HOST_ARCH=$($UNAME -m)
|
||||
if [ $HOST_ARCH == "i686" ] || [ $HOST_ARCH == "i386" ]
|
||||
then
|
||||
ARCH="x86"
|
||||
LD_LIB="${JUNEST_HOME}/lib/ld-linux.so.2"
|
||||
elif [ $HOST_ARCH == "x86_64" ]
|
||||
then
|
||||
ARCH="x86_64"
|
||||
LD_LIB="${JUNEST_HOME}/lib64/ld-linux-x86-64.so.2"
|
||||
elif [[ $HOST_ARCH =~ .*(arm).* ]]
|
||||
then
|
||||
ARCH="arm"
|
||||
LD_LIB="${JUNEST_HOME}/lib/ld-linux-armhf.so.3"
|
||||
else
|
||||
die "Unknown architecture ${HOST_ARCH}"
|
||||
fi
|
||||
|
||||
MAIN_REPO=https://dl.dropboxusercontent.com/u/42449030
|
||||
ENV_REPO=${MAIN_REPO}/${CMD}
|
||||
DEFAULT_MIRROR='https://mirrors.kernel.org/archlinux/$repo/os/$arch'
|
||||
|
||||
ORIGIN_WD=$(pwd)
|
||||
|
||||
################## EXECUTABLES ################
|
||||
|
||||
# This section contains all the executables needed for JuNest to run properly.
|
||||
# They are based on a fallback mechanism that tries to use the executable in
|
||||
# different locations in the host OS.
|
||||
|
||||
# List of executables that are run inside JuNest:
|
||||
SH=("/bin/sh" "--login")
|
||||
|
||||
# List of executables that are run in the host OS:
|
||||
PROOT="${JUNEST_HOME}/opt/proot/proot-${ARCH}"
|
||||
CHROOT=${JUNEST_BASE}/bin/jchroot
|
||||
CLASSIC_CHROOT="chroot"
|
||||
WGET="wget --no-check-certificate"
|
||||
CURL="curl -L -J -O -k"
|
||||
TAR=tar
|
||||
CHOWN="chown"
|
||||
LN=ln
|
||||
RM=rm
|
||||
MKDIR=mkdir
|
||||
GETENT=getent
|
||||
CP=cp
|
||||
|
||||
LD_EXEC="$LD_LIB --library-path ${JUNEST_HOME}/usr/lib:${JUNEST_HOME}/lib"
|
||||
|
||||
# The following functions attempt first to run the executable in the host OS.
|
||||
# As a last hope they try to run the same executable available in the JuNest
|
||||
# image.
|
||||
|
||||
function ln_cmd(){
|
||||
$LN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$LN $@
|
||||
}
|
||||
|
||||
function getent_cmd(){
|
||||
$GETENT $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$GETENT $@
|
||||
}
|
||||
|
||||
function cp_cmd(){
|
||||
$CP $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CP $@
|
||||
}
|
||||
|
||||
function rm_cmd(){
|
||||
$RM $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$RM $@
|
||||
}
|
||||
|
||||
function chown_cmd(){
|
||||
$CHOWN $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$CHOWN $@
|
||||
}
|
||||
|
||||
function mkdir_cmd(){
|
||||
$MKDIR $@ || $LD_EXEC ${JUNEST_HOME}/usr/bin/$MKDIR $@
|
||||
}
|
||||
|
||||
function proot_cmd(){
|
||||
local proot_args="$1"
|
||||
shift
|
||||
if ${PROOT} ${proot_args} "${SH[@]}" "-c" ":"
|
||||
then
|
||||
${PROOT} ${proot_args} "${@}"
|
||||
elif PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${SH[@]}" "-c" ":"
|
||||
then
|
||||
PROOT_NO_SECCOMP=1 ${PROOT} ${proot_args} "${@}"
|
||||
else
|
||||
die "Error: Check if the ${CMD} arguments are correct and if the kernel is too old use the option ${CMD} -p \"-k 3.10\""
|
||||
fi
|
||||
}
|
||||
|
||||
function download_cmd(){
|
||||
$WGET $@ || $CURL $@
|
||||
}
|
||||
|
||||
function chroot_cmd(){
|
||||
$CHROOT "$@" || $CLASSIC_CHROOT "$@" || $LD_EXEC ${JUNEST_HOME}/usr/bin/chroot "$@"
|
||||
}
|
||||
|
||||
############## COMMON FUNCTIONS ###############
|
||||
|
||||
#######################################
|
||||
# Provide the proot common binding options for both normal user and fakeroot.
|
||||
# The list of bindings can be found in `proot --help`. This function excludes
|
||||
# /etc/mtab file so that it will not give conflicts with the related
|
||||
# symlink in the image.
|
||||
#
|
||||
# Globals:
|
||||
# HOME (RO) : The home directory.
|
||||
# RESULT (WO) : Contains the binding options.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function _provide_common_bindings(){
|
||||
RESULT=""
|
||||
local re='(.*):.*'
|
||||
for bind in "/dev" "/sys" "/proc" "/tmp" "$HOME"
|
||||
do
|
||||
if [[ $bind =~ $re ]]
|
||||
then
|
||||
[ -e "${BASH_REMATCH[1]}" ] && RESULT="-b $bind $RESULT"
|
||||
else
|
||||
[ -e "$bind" ] && RESULT="-b $bind $RESULT"
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Build passwd and group files using getent command.
|
||||
# If getent fails the function fallbacks by copying the content from /etc/passwd
|
||||
# and /etc/group.
|
||||
#
|
||||
# The generated passwd and group will be stored in $JUNEST_HOME/etc/junest.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function _copy_passwd_and_group(){
|
||||
# Enumeration of users/groups is disabled/limited depending on how nsswitch.conf
|
||||
# is configured.
|
||||
# Try to at least get the current user via `getent passwd $USER` since it uses
|
||||
# a more reliable and faster system call (getpwnam(3)).
|
||||
if ! getent_cmd passwd > ${JUNEST_HOME}/etc/passwd || \
|
||||
! getent_cmd passwd ${USER} >> ${JUNEST_HOME}/etc/passwd
|
||||
then
|
||||
warn "getent command failed or does not exist. Binding directly from /etc/passwd."
|
||||
_copy_file /etc/passwd ${JUNEST_HOME}/etc/passwd
|
||||
fi
|
||||
|
||||
if ! getent_cmd group > ${JUNEST_HOME}/etc/group
|
||||
then
|
||||
warn "getent command failed or does not exist. Binding directly from /etc/group."
|
||||
_copy_file /etc/group ${JUNEST_HOME}/etc/group
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function _copy_file() {
|
||||
local file="${1}"
|
||||
[[ -r "$file" ]] && cp_cmd "$file" "${JUNEST_HOME}/$file"
|
||||
return 0
|
||||
}
|
||||
|
||||
function _copy_common_files() {
|
||||
_copy_file /etc/host.conf
|
||||
_copy_file /etc/hosts
|
||||
_copy_file /etc/nsswitch.conf
|
||||
_copy_file /etc/resolv.conf
|
||||
return 0
|
||||
}
|
||||
109
lib/core/proot.sh
Normal file
109
lib/core/proot.sh
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This module contains all proot functionalities for JuNest.
|
||||
#
|
||||
# Dependencies:
|
||||
# - lib/utils/utils.sh
|
||||
# - lib/core/common.sh
|
||||
#
|
||||
# vim: ft=sh
|
||||
|
||||
function _run_env_with_proot(){
|
||||
local proot_args="$1"
|
||||
shift
|
||||
|
||||
if [ "$1" != "" ]
|
||||
then
|
||||
JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")"
|
||||
else
|
||||
JUNEST_ENV=1 proot_cmd "${proot_args}" "${SH[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
function _run_env_with_qemu(){
|
||||
local proot_args="$1"
|
||||
source ${JUNEST_HOME}/etc/junest/info
|
||||
|
||||
if [ "$JUNEST_ARCH" != "$ARCH" ]
|
||||
then
|
||||
local qemu_bin="qemu-$JUNEST_ARCH-static-$ARCH"
|
||||
local qemu_symlink="/tmp/${qemu_bin}-$RANDOM"
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "[ -e ${qemu_symlink} ] && rm_cmd -f ${qemu_symlink}" EXIT QUIT ABRT KILL TERM INT
|
||||
|
||||
warn "Emulating $NAME via QEMU..."
|
||||
[ -e ${qemu_symlink} ] || \
|
||||
ln_cmd -s ${JUNEST_HOME}/opt/qemu/${qemu_bin} ${qemu_symlink}
|
||||
proot_args="-q ${qemu_symlink} $proot_args"
|
||||
fi
|
||||
shift
|
||||
_run_env_with_proot "$proot_args" "${@}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Run JuNest as fakeroot.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# EUID (RO) : The user ID.
|
||||
# SH (RO) : Contains the default command to run in JuNest.
|
||||
# Arguments:
|
||||
# cmd ($@?) : The command to run inside JuNest environment.
|
||||
# Default command is defined by SH variable.
|
||||
# Returns:
|
||||
# $ROOT_ACCESS_ERROR : If the user is the real root.
|
||||
# Output:
|
||||
# - : The command output.
|
||||
#######################################
|
||||
function run_env_as_fakeroot(){
|
||||
(( EUID == 0 )) && \
|
||||
die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead."
|
||||
|
||||
_copy_common_files
|
||||
|
||||
_provide_common_bindings
|
||||
local bindings=${RESULT}
|
||||
unset RESULT
|
||||
|
||||
# An alternative is via -S option:
|
||||
#_run_env_with_qemu "-S ${JUNEST_HOME} $1" "${@:2}"
|
||||
_run_env_with_qemu "-0 ${bindings} -r ${JUNEST_HOME} $1" "${@:2}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Run JuNest as normal user.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory.
|
||||
# EUID (RO) : The user ID.
|
||||
# SH (RO) : Contains the default command to run in JuNest.
|
||||
# Arguments:
|
||||
# cmd ($@?) : The command to run inside JuNest environment.
|
||||
# Default command is defined by SH variable.
|
||||
# Returns:
|
||||
# $ROOT_ACCESS_ERROR : If the user is the real root.
|
||||
# Output:
|
||||
# - : The command output.
|
||||
#######################################
|
||||
function run_env_as_user(){
|
||||
(( EUID == 0 )) && \
|
||||
die_on_status $ROOT_ACCESS_ERROR "You cannot access with root privileges. Use --root option instead."
|
||||
|
||||
# Files to bind are visible in `proot --help`.
|
||||
# This function excludes /etc/mtab file so that
|
||||
# it will not give conflicts with the related
|
||||
# symlink in the Arch Linux image.
|
||||
_copy_common_files
|
||||
_copy_file /etc/hosts.equiv
|
||||
_copy_file /etc/netgroup
|
||||
_copy_file /etc/networks
|
||||
# No need for localtime as it is setup during the image build
|
||||
#_copy_file /etc/localtime
|
||||
_copy_passwd_and_group
|
||||
|
||||
_provide_common_bindings
|
||||
local bindings=${RESULT}
|
||||
unset RESULT
|
||||
|
||||
_run_env_with_qemu "${bindings} -r ${JUNEST_HOME} $1" "${@:2}"
|
||||
}
|
||||
157
lib/core/setup.sh
Normal file
157
lib/core/setup.sh
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# This module contains all setup functionalities for JuNest.
|
||||
#
|
||||
# Dependencies:
|
||||
# - lib/utils/utils.sh
|
||||
# - lib/core/common.sh
|
||||
#
|
||||
# vim: ft=sh
|
||||
|
||||
#######################################
|
||||
# Check if the JuNest system is installed in JUNEST_HOME.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : Contains the JuNest home directory.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0 : If JuNest is installed
|
||||
# 1 : If JuNest is not installed
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function is_env_installed(){
|
||||
[ -d "$JUNEST_HOME" ] && [ "$(ls -A $JUNEST_HOME)" ] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
function _cleanup_build_directory(){
|
||||
local maindir=$1
|
||||
check_not_null "$maindir"
|
||||
builtin cd $ORIGIN_WD
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
rm_cmd -fr "$maindir"
|
||||
}
|
||||
|
||||
|
||||
function _prepare_build_directory(){
|
||||
local maindir=$1
|
||||
check_not_null "$maindir"
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "rm_cmd -rf ${maindir}; die \"Error occurred when installing ${NAME}\"" EXIT QUIT ABRT KILL TERM INT
|
||||
}
|
||||
|
||||
|
||||
function _setup_env(){
|
||||
local imagepath=$1
|
||||
check_not_null "$imagepath"
|
||||
|
||||
is_env_installed && die "Error: ${NAME} has been already installed in $JUNEST_HOME"
|
||||
|
||||
mkdir_cmd -p "${JUNEST_HOME}"
|
||||
$TAR -zxpf ${imagepath} -C ${JUNEST_HOME}
|
||||
info "The default mirror URL is ${DEFAULT_MIRROR}."
|
||||
info "Remember to refresh the package databases from the server:"
|
||||
info " pacman -Syy"
|
||||
info "${NAME} installed successfully"
|
||||
}
|
||||
|
||||
|
||||
#######################################
|
||||
# Setup JuNest.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
|
||||
# to be installed.
|
||||
# ARCH (RO) : The host architecture.
|
||||
# JUNEST_TEMPDIR (RO) : The JuNest temporary directory for building
|
||||
# the JuNest system from the image.
|
||||
# ENV_REPO (RO) : URL of the site containing JuNest images.
|
||||
# NAME (RO) : The JuNest name.
|
||||
# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
|
||||
# Arguments:
|
||||
# arch ($1?) : The JuNest architecture image to download.
|
||||
# Defaults to the host architecture
|
||||
# Returns:
|
||||
# $NOT_AVAILABLE_ARCH : If the architecture is not one of the available ones.
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function setup_env(){
|
||||
local arch=${1:-$ARCH}
|
||||
contains_element $arch "${ARCH_LIST[@]}" || \
|
||||
die_on_status $NOT_AVAILABLE_ARCH "The architecture is not one of: ${ARCH_LIST[@]}"
|
||||
|
||||
local maindir=$(TMPDIR=$JUNEST_TEMPDIR mktemp -d -t ${CMD}.XXXXXXXXXX)
|
||||
_prepare_build_directory $maindir
|
||||
|
||||
info "Downloading ${NAME}..."
|
||||
builtin cd ${maindir}
|
||||
local imagefile=${CMD}-${arch}.tar.gz
|
||||
download_cmd ${ENV_REPO}/${imagefile}
|
||||
|
||||
info "Installing ${NAME}..."
|
||||
_setup_env ${maindir}/${imagefile}
|
||||
|
||||
_cleanup_build_directory ${maindir}
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Setup JuNest from file.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory in which JuNest needs
|
||||
# to be installed.
|
||||
# NAME (RO) : The JuNest name.
|
||||
# DEFAULT_MIRROR (RO) : Arch Linux URL mirror.
|
||||
# Arguments:
|
||||
# imagefile ($1) : The JuNest image file.
|
||||
# Returns:
|
||||
# $NOT_EXISTING_FILE : If the image file does not exist.
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function setup_env_from_file(){
|
||||
local imagefile=$1
|
||||
check_not_null "$imagefile"
|
||||
[ ! -e ${imagefile} ] && die_on_status $NOT_EXISTING_FILE "Error: The ${NAME} image file ${imagefile} does not exist"
|
||||
|
||||
info "Installing ${NAME} from ${imagefile}..."
|
||||
_setup_env ${imagefile}
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Remove an existing JuNest system.
|
||||
#
|
||||
# Globals:
|
||||
# JUNEST_HOME (RO) : The JuNest home directory to remove.
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# None
|
||||
# Output:
|
||||
# None
|
||||
#######################################
|
||||
function delete_env(){
|
||||
! ask "Are you sure to delete ${NAME} located in ${JUNEST_HOME}" "N" && return
|
||||
if mountpoint -q ${JUNEST_HOME}
|
||||
then
|
||||
info "There are mounted directories inside ${JUNEST_HOME}"
|
||||
if ! umount --force ${JUNEST_HOME}
|
||||
then
|
||||
error "Cannot umount directories in ${JUNEST_HOME}"
|
||||
die "Try to delete ${NAME} using root permissions"
|
||||
fi
|
||||
fi
|
||||
# the CA directories are read only and can be deleted only by changing the mod
|
||||
chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
|
||||
if rm_cmd -rf ${JUNEST_HOME}/*
|
||||
then
|
||||
info "${NAME} deleted in ${JUNEST_HOME}"
|
||||
else
|
||||
error "Error: Cannot delete ${NAME} in ${JUNEST_HOME}"
|
||||
fi
|
||||
}
|
||||
|
||||
21
tests/checkstyle/checkstyle.sh
Executable file
21
tests/checkstyle/checkstyle.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source "$(dirname $0)/../utils/utils.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
||||
function oneTimeSetUp(){
|
||||
setUpUnitTests
|
||||
}
|
||||
|
||||
function test_check_no_tabs(){
|
||||
assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../bin/*
|
||||
assertEquals "" "$(cat $STDOUTF)"
|
||||
assertEquals "" "$(cat $STDERRF)"
|
||||
assertCommandFailOnStatus 1 grep -R "$(printf '\t')" $(dirname $0)/../../lib/*
|
||||
assertEquals "" "$(cat $STDOUTF)"
|
||||
assertEquals "" "$(cat $STDERRF)"
|
||||
}
|
||||
|
||||
source $(dirname $0)/../utils/shunit2
|
||||
52
tests/unit-tests/test-chroot.sh
Executable file
52
tests/unit-tests/test-chroot.sh
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
|
||||
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
|
||||
|
||||
source "$JUNEST_ROOT/tests/utils/utils.sh"
|
||||
|
||||
source "$JUNEST_ROOT/lib/utils/utils.sh"
|
||||
source "$JUNEST_ROOT/lib/core/common.sh"
|
||||
source "$JUNEST_ROOT/lib/core/chroot.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
||||
function oneTimeSetUp(){
|
||||
setUpUnitTests
|
||||
}
|
||||
|
||||
function setUp(){
|
||||
cwdSetUp
|
||||
junestSetUp
|
||||
}
|
||||
|
||||
function tearDown(){
|
||||
junestTearDown
|
||||
cwdTearDown
|
||||
}
|
||||
|
||||
function test_run_env_as_root_different_arch(){
|
||||
echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info
|
||||
assertCommandFailOnStatus 104 run_env_as_root pwd
|
||||
}
|
||||
|
||||
function _test_run_env_as_root() {
|
||||
chroot_cmd() {
|
||||
[ "$JUNEST_ENV" != "1" ] && return 1
|
||||
echo $@
|
||||
}
|
||||
|
||||
assertCommandSuccess run_env_as_root $@
|
||||
}
|
||||
|
||||
function test_run_env_as_root_cmd(){
|
||||
_test_run_env_as_root pwd
|
||||
assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_run_env_as_classic_root_no_cmd(){
|
||||
_test_run_env_as_root
|
||||
assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
source $JUNEST_ROOT/tests/utils/shunit2
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#!/bin/bash
|
||||
source "$(dirname $0)/utils.sh"
|
||||
source "$(dirname $0)/../utils/utils.sh"
|
||||
|
||||
source $(dirname $0)/../../bin/junest -h &> /dev/null
|
||||
|
||||
|
|
@ -178,4 +178,4 @@ function test_check_cli(){
|
|||
assertCommandFail cli -d args
|
||||
}
|
||||
|
||||
source $(dirname $0)/shunit2
|
||||
source $(dirname $0)/../utils/shunit2
|
||||
|
|
|
|||
171
tests/unit-tests/test-common.sh
Executable file
171
tests/unit-tests/test-common.sh
Executable file
|
|
@ -0,0 +1,171 @@
|
|||
#!/bin/bash
|
||||
|
||||
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
|
||||
|
||||
source "$JUNEST_ROOT/tests/utils/utils.sh"
|
||||
|
||||
source "$JUNEST_ROOT/lib/utils/utils.sh"
|
||||
source "$JUNEST_ROOT/lib/core/common.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
||||
function oneTimeSetUp(){
|
||||
setUpUnitTests
|
||||
junestSetUp
|
||||
}
|
||||
|
||||
function oneTimeTearDown(){
|
||||
junestTearDown
|
||||
}
|
||||
|
||||
function setUp(){
|
||||
ld_exec() {
|
||||
echo "ld_exec $@"
|
||||
}
|
||||
LD_EXEC=ld_exec
|
||||
}
|
||||
|
||||
function test_ln(){
|
||||
LN=echo assertCommandSuccess ln_cmd -s ln_file new_file
|
||||
assertEquals "-s ln_file new_file" "$(cat $STDOUTF)"
|
||||
|
||||
LN=false assertCommandSuccess ln_cmd -s ln_file new_file
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)"
|
||||
|
||||
LN=false LD_EXEC=false assertCommandFail ln_cmd
|
||||
}
|
||||
|
||||
function test_getent(){
|
||||
GETENT=echo assertCommandSuccess getent_cmd passwd
|
||||
assertEquals "passwd" "$(cat $STDOUTF)"
|
||||
|
||||
GETENT=false assertCommandSuccess getent_cmd passwd
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)"
|
||||
|
||||
GETENT=false LD_EXEC=false assertCommandFail getent_cmd
|
||||
}
|
||||
|
||||
function test_cp(){
|
||||
CP=echo assertCommandSuccess cp_cmd passwd
|
||||
assertEquals "passwd" "$(cat $STDOUTF)"
|
||||
|
||||
CP=false assertCommandSuccess cp_cmd passwd
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)"
|
||||
|
||||
CP=false LD_EXEC=false assertCommandFail cp_cmd
|
||||
}
|
||||
|
||||
function test_download(){
|
||||
WGET=/bin/true
|
||||
CURL=/bin/false
|
||||
assertCommandSuccess download_cmd
|
||||
|
||||
WGET=/bin/false
|
||||
CURL=/bin/true
|
||||
assertCommandSuccess download_cmd
|
||||
|
||||
WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd
|
||||
}
|
||||
|
||||
function test_rm(){
|
||||
RM=echo assertCommandSuccess rm_cmd rm_file
|
||||
assertEquals "rm_file" "$(cat $STDOUTF)"
|
||||
|
||||
RM=false assertCommandSuccess rm_cmd rm_file
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)"
|
||||
|
||||
RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file
|
||||
}
|
||||
|
||||
function test_chown(){
|
||||
local id=$(id -u)
|
||||
|
||||
CHOWN=echo assertCommandSuccess chown_cmd $id chown_file
|
||||
assertEquals "$id chown_file" "$(cat $STDOUTF)"
|
||||
|
||||
CHOWN=false assertCommandSuccess chown_cmd $id chown_file
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)"
|
||||
|
||||
CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file
|
||||
}
|
||||
|
||||
function test_mkdir(){
|
||||
MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir
|
||||
assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)"
|
||||
|
||||
MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)"
|
||||
|
||||
MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir
|
||||
}
|
||||
|
||||
function test_chroot(){
|
||||
CHROOT=echo assertCommandSuccess chroot_cmd root
|
||||
assertEquals "root" "$(cat $STDOUTF)"
|
||||
|
||||
CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root
|
||||
assertEquals "root" "$(cat $STDOUTF)"
|
||||
|
||||
CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root
|
||||
assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)"
|
||||
|
||||
CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root
|
||||
}
|
||||
|
||||
function test_proot_cmd_compat(){
|
||||
PROOT="/bin/true" assertCommandSuccess proot_cmd "" ""
|
||||
|
||||
PROOT="/bin/false" assertCommandFail proot_cmd --helps
|
||||
}
|
||||
|
||||
function test_proot_cmd_seccomp(){
|
||||
envv(){
|
||||
env
|
||||
}
|
||||
PROOT=envv
|
||||
assertCommandSuccess proot_cmd cmd
|
||||
assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
|
||||
|
||||
envv(){
|
||||
env | grep "^PROOT_NO_SECCOMP"
|
||||
}
|
||||
PROOT=envv
|
||||
local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP")
|
||||
assertCommandSuccess proot_cmd cmd
|
||||
# The variable PROOT_NO_SECCOMP will be produced
|
||||
# twice due to the fallback mechanism
|
||||
assertEquals "PROOT_NO_SECCOMP=1
|
||||
PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
|
||||
}
|
||||
|
||||
function test_copy_passwd_and_group(){
|
||||
getent_cmd_mock() {
|
||||
echo $@
|
||||
}
|
||||
GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group
|
||||
assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)"
|
||||
assertEquals "group" "$(cat $JUNEST_HOME/etc/group)"
|
||||
}
|
||||
|
||||
function test_copy_passwd_and_group_fallback(){
|
||||
cp_cmd_mock() {
|
||||
echo $@
|
||||
}
|
||||
CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group
|
||||
assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_copy_passwd_and_group_failure(){
|
||||
CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group
|
||||
}
|
||||
|
||||
function test_nested_env(){
|
||||
JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh"
|
||||
}
|
||||
|
||||
function test_nested_env_not_set_variable(){
|
||||
JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils/utils.sh; source $JUNEST_ROOT/lib/core/common.sh"
|
||||
}
|
||||
|
||||
source $JUNEST_ROOT/tests/utils/shunit2
|
||||
|
|
@ -1,349 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
|
||||
|
||||
source "$JUNEST_ROOT/tests/unit-tests/utils.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
||||
function oneTimeSetUp(){
|
||||
SKIP_ROOT_TESTS=${SKIP_ROOT_TESTS:-0}
|
||||
setUpUnitTests
|
||||
}
|
||||
|
||||
function setUp(){
|
||||
ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX)
|
||||
cd $ORIGIN_CWD
|
||||
JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX)
|
||||
mkdir -p ${JUNEST_HOME}/etc/junest
|
||||
echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info
|
||||
mkdir -p ${JUNEST_HOME}/etc/ca-certificates
|
||||
JUNEST_TEMPDIR=$(TMPDIR=/tmp mktemp -d -t junest-temp.XXXXXXXXXX)
|
||||
source "$JUNEST_ROOT/lib/utils.sh"
|
||||
source "$JUNEST_ROOT/lib/core.sh"
|
||||
|
||||
set +e
|
||||
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "rm -rf ${JUNEST_HOME}; rm -rf ${JUNEST_TEMPDIR}" EXIT QUIT ABRT KILL TERM INT
|
||||
|
||||
ld_exec() {
|
||||
echo "ld_exec $@"
|
||||
}
|
||||
LD_EXEC=ld_exec
|
||||
}
|
||||
|
||||
|
||||
function tearDown(){
|
||||
# the CA directories are read only and can be deleted only by changing the mod
|
||||
[ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
|
||||
rm -rf $JUNEST_HOME
|
||||
rm -rf $JUNEST_TEMPDIR
|
||||
rm -rf $ORIGIN_CWD
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
}
|
||||
|
||||
|
||||
function test_ln(){
|
||||
LN=echo assertCommandSuccess ln_cmd -s ln_file new_file
|
||||
assertEquals "-s ln_file new_file" "$(cat $STDOUTF)"
|
||||
|
||||
LN=false assertCommandSuccess ln_cmd -s ln_file new_file
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -s ln_file new_file" "$(cat $STDOUTF)"
|
||||
|
||||
LN=false LD_EXEC=false assertCommandFail ln_cmd
|
||||
}
|
||||
|
||||
function test_getent(){
|
||||
GETENT=echo assertCommandSuccess getent_cmd passwd
|
||||
assertEquals "passwd" "$(cat $STDOUTF)"
|
||||
|
||||
GETENT=false assertCommandSuccess getent_cmd passwd
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)"
|
||||
|
||||
GETENT=false LD_EXEC=false assertCommandFail getent_cmd
|
||||
}
|
||||
|
||||
function test_cp(){
|
||||
CP=echo assertCommandSuccess cp_cmd passwd
|
||||
assertEquals "passwd" "$(cat $STDOUTF)"
|
||||
|
||||
CP=false assertCommandSuccess cp_cmd passwd
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false passwd" "$(cat $STDOUTF)"
|
||||
|
||||
CP=false LD_EXEC=false assertCommandFail cp_cmd
|
||||
}
|
||||
|
||||
function test_download(){
|
||||
WGET=/bin/true
|
||||
CURL=/bin/false
|
||||
assertCommandSuccess download_cmd
|
||||
|
||||
WGET=/bin/false
|
||||
CURL=/bin/true
|
||||
assertCommandSuccess download_cmd
|
||||
|
||||
WGET=/bin/false CURL=/bin/false assertCommandFail download_cmd
|
||||
}
|
||||
|
||||
function test_rm(){
|
||||
RM=echo assertCommandSuccess rm_cmd rm_file
|
||||
assertEquals "rm_file" "$(cat $STDOUTF)"
|
||||
|
||||
RM=false assertCommandSuccess rm_cmd rm_file
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false rm_file" "$(cat $STDOUTF)"
|
||||
|
||||
RM=false LD_EXEC=false assertCommandFail rm_cmd rm_file
|
||||
}
|
||||
|
||||
function test_chown(){
|
||||
local id=$(id -u)
|
||||
|
||||
CHOWN=echo assertCommandSuccess chown_cmd $id chown_file
|
||||
assertEquals "$id chown_file" "$(cat $STDOUTF)"
|
||||
|
||||
CHOWN=false assertCommandSuccess chown_cmd $id chown_file
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false $id chown_file" "$(cat $STDOUTF)"
|
||||
|
||||
CHOWN=false LD_EXEC=false assertCommandFail chown_cmd $id chown_file
|
||||
}
|
||||
|
||||
function test_mkdir(){
|
||||
MKDIR=echo assertCommandSuccess mkdir_cmd -p new_dir/new_dir
|
||||
assertEquals "-p new_dir/new_dir" "$(cat $STDOUTF)"
|
||||
|
||||
MKDIR=false assertCommandSuccess mkdir_cmd -p new_dir/new_dir
|
||||
assertEquals "ld_exec ${JUNEST_HOME}/usr/bin/false -p new_dir/new_dir" "$(cat $STDOUTF)"
|
||||
|
||||
MKDIR=false LD_EXEC=false assertCommandFail mkdir_cmd -p new_dir/new_dir
|
||||
}
|
||||
|
||||
function test_chroot(){
|
||||
CHROOT=echo assertCommandSuccess chroot_cmd root
|
||||
assertEquals "root" "$(cat $STDOUTF)"
|
||||
|
||||
CHROOT=false CLASSIC_CHROOT=echo assertCommandSuccess chroot_cmd root
|
||||
assertEquals "root" "$(cat $STDOUTF)"
|
||||
|
||||
CHROOT=false CLASSIC_CHROOT=false assertCommandSuccess chroot_cmd root
|
||||
assertEquals "ld_exec $JUNEST_HOME/usr/bin/chroot root" "$(cat $STDOUTF)"
|
||||
|
||||
CHROOT=false CLASSIC_CHROOT=false LD_EXEC=false assertCommandFail chroot_cmd root
|
||||
}
|
||||
|
||||
function test_proot_cmd_compat(){
|
||||
PROOT="/bin/true" assertCommandSuccess proot_cmd "" ""
|
||||
|
||||
PROOT="/bin/false" assertCommandFail proot_cmd --helps
|
||||
}
|
||||
|
||||
function test_proot_cmd_seccomp(){
|
||||
envv(){
|
||||
env
|
||||
}
|
||||
PROOT=envv
|
||||
assertCommandSuccess proot_cmd cmd
|
||||
assertEquals "" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
|
||||
|
||||
envv(){
|
||||
env | grep "^PROOT_NO_SECCOMP"
|
||||
}
|
||||
PROOT=envv
|
||||
local output=$(proot_cmd | grep "^PROOT_NO_SECCOMP")
|
||||
assertCommandSuccess proot_cmd cmd
|
||||
# The variable PROOT_NO_SECCOMP will be produced
|
||||
# twice due to the fallback mechanism
|
||||
assertEquals "PROOT_NO_SECCOMP=1
|
||||
PROOT_NO_SECCOMP=1" "$(cat $STDOUTF | grep "^PROOT_NO_SECCOMP")"
|
||||
}
|
||||
|
||||
function test_is_env_installed(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
assertCommandFail is_env_installed
|
||||
touch $JUNEST_HOME/just_file
|
||||
assertCommandSuccess is_env_installed
|
||||
}
|
||||
|
||||
function test_setup_env(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
wget_mock(){
|
||||
# Proof that the setup is happening
|
||||
# inside $JUNEST_TEMPDIR
|
||||
local cwd=${PWD#${JUNEST_TEMPDIR}}
|
||||
local parent_dir=${PWD%${cwd}}
|
||||
assertEquals "$JUNEST_TEMPDIR" "${parent_dir}"
|
||||
touch file
|
||||
tar -czvf ${CMD}-${ARCH}.tar.gz file
|
||||
}
|
||||
WGET=wget_mock
|
||||
setup_env 1> /dev/null
|
||||
assertTrue "[ -e $JUNEST_HOME/file ]"
|
||||
|
||||
assertCommandFailOnStatus 102 setup_env "noarch"
|
||||
}
|
||||
|
||||
|
||||
function test_setup_env_from_file(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
touch file
|
||||
tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
|
||||
assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz
|
||||
assertTrue "[ -e $JUNEST_HOME/file ]"
|
||||
}
|
||||
|
||||
function test_setup_env_from_file_not_existing_file(){
|
||||
assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz
|
||||
}
|
||||
|
||||
function test_setup_env_from_file_with_absolute_path(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
touch file
|
||||
tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
|
||||
assertCommandSuccess setup_env_from_file ${ORIGIN_WD}/${CMD}-${ARCH}.tar.gz
|
||||
assertTrue "[ -e $JUNEST_HOME/file ]"
|
||||
}
|
||||
|
||||
function test_run_env_as_root_different_arch(){
|
||||
echo "JUNEST_ARCH=XXX" > ${JUNEST_HOME}/etc/junest/info
|
||||
assertCommandFailOnStatus 104 run_env_as_root pwd
|
||||
}
|
||||
|
||||
function _test_run_env_as_root() {
|
||||
chroot_cmd() {
|
||||
[ "$JUNEST_ENV" != "1" ] && return 1
|
||||
echo $@
|
||||
}
|
||||
|
||||
assertCommandSuccess run_env_as_root $@
|
||||
}
|
||||
|
||||
function test_run_env_as_root_cmd(){
|
||||
_test_run_env_as_root pwd
|
||||
assertEquals "$JUNEST_HOME /bin/sh --login -c pwd" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_run_env_as_classic_root_no_cmd(){
|
||||
_test_run_env_as_root
|
||||
assertEquals "$JUNEST_HOME /bin/sh --login -c /bin/sh --login" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_run_env_as_user(){
|
||||
_run_env_with_qemu() {
|
||||
echo $@
|
||||
}
|
||||
assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
|
||||
assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
|
||||
|
||||
SH=("/usr/bin/echo")
|
||||
assertCommandSuccess run_env_as_user "-k 3.10"
|
||||
assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
|
||||
|
||||
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)"
|
||||
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)"
|
||||
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)"
|
||||
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)"
|
||||
|
||||
[[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)"
|
||||
[[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)"
|
||||
|
||||
[[ -e /etc/passwd ]]
|
||||
assertEquals 0 $?
|
||||
[[ -e /etc/group ]]
|
||||
assertEquals 0 $?
|
||||
|
||||
}
|
||||
|
||||
function test_copy_passwd_and_group(){
|
||||
getent_cmd_mock() {
|
||||
echo $@
|
||||
}
|
||||
GETENT=getent_cmd_mock assertCommandSuccess _copy_passwd_and_group
|
||||
assertEquals "$(echo -e "passwd\npasswd $USER")" "$(cat $JUNEST_HOME/etc/passwd)"
|
||||
assertEquals "group" "$(cat $JUNEST_HOME/etc/group)"
|
||||
}
|
||||
|
||||
function test_copy_passwd_and_group_fallback(){
|
||||
cp_cmd_mock() {
|
||||
echo $@
|
||||
}
|
||||
CP=cp_cmd_mock GETENT=false LD_EXEC=false assertCommandSuccess _copy_passwd_and_group
|
||||
assertEquals "$(echo -e "/etc/passwd $JUNEST_HOME//etc/passwd\n/etc/group $JUNEST_HOME//etc/group")" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_copy_passwd_and_group_failure(){
|
||||
CP=false GETENT=false LD_EXEC=false assertCommandFailOnStatus 1 _copy_passwd_and_group
|
||||
}
|
||||
|
||||
function test_run_env_as_fakeroot(){
|
||||
_run_env_with_qemu() {
|
||||
echo $@
|
||||
}
|
||||
assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
|
||||
assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
|
||||
|
||||
SH=("/usr/bin/echo")
|
||||
assertCommandSuccess run_env_as_fakeroot "-k 3.10"
|
||||
assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
|
||||
|
||||
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)"
|
||||
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)"
|
||||
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)"
|
||||
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)"
|
||||
}
|
||||
|
||||
function test_run_env_with_quotes(){
|
||||
_run_env_with_qemu() {
|
||||
echo $@
|
||||
}
|
||||
assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2"
|
||||
assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_run_env_with_proot_args(){
|
||||
proot_cmd() {
|
||||
[ "$JUNEST_ENV" != "1" ] && return 1
|
||||
echo $@
|
||||
}
|
||||
|
||||
assertCommandSuccess _run_env_with_proot --help
|
||||
assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)"
|
||||
|
||||
assertCommandSuccess _run_env_with_proot --help mycommand
|
||||
assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)"
|
||||
|
||||
assertCommandFail _run_env_with_proot
|
||||
}
|
||||
|
||||
function test_delete_env(){
|
||||
echo "N" | delete_env 1> /dev/null
|
||||
assertCommandSuccess is_env_installed
|
||||
echo "Y" | delete_env 1> /dev/null
|
||||
assertCommandFail is_env_installed
|
||||
}
|
||||
|
||||
function test_nested_env(){
|
||||
JUNEST_ENV=1 assertCommandFailOnStatus 106 bash -c "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh"
|
||||
}
|
||||
|
||||
function test_nested_env_not_set_variable(){
|
||||
JUNEST_ENV=aaa assertCommandFailOnStatus 107 bash -c "source $JUNEST_ROOT/lib/utils.sh; source $JUNEST_ROOT/lib/core.sh"
|
||||
}
|
||||
|
||||
function test_qemu() {
|
||||
echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info
|
||||
rm_cmd() {
|
||||
echo $@
|
||||
}
|
||||
ln_cmd() {
|
||||
echo $@
|
||||
}
|
||||
_run_env_with_proot() {
|
||||
echo $@
|
||||
}
|
||||
|
||||
RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu ""
|
||||
assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
source $JUNEST_ROOT/tests/unit-tests/shunit2
|
||||
114
tests/unit-tests/test-proot.sh
Executable file
114
tests/unit-tests/test-proot.sh
Executable file
|
|
@ -0,0 +1,114 @@
|
|||
#!/bin/bash
|
||||
|
||||
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
|
||||
|
||||
source "$JUNEST_ROOT/tests/utils/utils.sh"
|
||||
|
||||
source "$JUNEST_ROOT/lib/utils/utils.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
||||
function oneTimeSetUp(){
|
||||
setUpUnitTests
|
||||
}
|
||||
|
||||
function setUp(){
|
||||
cwdSetUp
|
||||
junestSetUp
|
||||
|
||||
# Attempt to source the files under test to revert variable
|
||||
# overrides (i.e. SH variable)
|
||||
source "$JUNEST_ROOT/lib/core/common.sh"
|
||||
source "$JUNEST_ROOT/lib/core/proot.sh"
|
||||
set +e
|
||||
}
|
||||
|
||||
function tearDown(){
|
||||
junestTearDown
|
||||
cwdTearDown
|
||||
}
|
||||
|
||||
function test_run_env_as_user(){
|
||||
_run_env_with_qemu() {
|
||||
echo $@
|
||||
}
|
||||
assertCommandSuccess run_env_as_user "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
|
||||
assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
|
||||
|
||||
SH=("/usr/bin/echo")
|
||||
assertCommandSuccess run_env_as_user "-k 3.10"
|
||||
assertEquals "-b $HOME -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
|
||||
|
||||
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)"
|
||||
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)"
|
||||
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)"
|
||||
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)"
|
||||
|
||||
[[ -e /etc/hosts.equiv ]] && assertEquals "$(cat /etc/hosts.equiv)" "$(cat ${JUNEST_HOME}/etc/hosts.equiv)"
|
||||
[[ -e /etc/netgroup ]] && assertEquals "$(cat /etc/netgroup)" "$(cat ${JUNEST_HOME}/etc/netgroup)"
|
||||
|
||||
[[ -e /etc/passwd ]]
|
||||
assertEquals 0 $?
|
||||
[[ -e /etc/group ]]
|
||||
assertEquals 0 $?
|
||||
|
||||
}
|
||||
|
||||
function test_run_env_as_fakeroot(){
|
||||
_run_env_with_qemu() {
|
||||
echo $@
|
||||
}
|
||||
assertCommandSuccess run_env_as_fakeroot "-k 3.10" "/usr/bin/mkdir" "-v" "/newdir2"
|
||||
assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
|
||||
|
||||
SH=("/usr/bin/echo")
|
||||
assertCommandSuccess run_env_as_fakeroot "-k 3.10"
|
||||
assertEquals "-0 -b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10" "$(cat $STDOUTF)"
|
||||
|
||||
[[ -e /etc/hosts ]] && assertEquals "$(cat /etc/hosts)" "$(cat ${JUNEST_HOME}/etc/hosts)"
|
||||
[[ -e /etc/host.conf ]] && assertEquals "$(cat /etc/host.conf)" "$(cat ${JUNEST_HOME}/etc/host.conf)"
|
||||
[[ -e /etc/nsswitch.conf ]] && assertEquals "$(cat /etc/nsswitch.conf)" "$(cat ${JUNEST_HOME}/etc/nsswitch.conf)"
|
||||
[[ -e /etc/resolv.conf ]] && assertEquals "$(cat /etc/resolv.conf)" "$(cat ${JUNEST_HOME}/etc/resolv.conf)"
|
||||
}
|
||||
|
||||
function test_run_env_with_quotes(){
|
||||
_run_env_with_qemu() {
|
||||
echo $@
|
||||
}
|
||||
assertCommandSuccess run_env_as_user "-k 3.10" "bash" "-c" "/usr/bin/mkdir -v /newdir2"
|
||||
assertEquals "-b ${HOME} -b /tmp -b /proc -b /sys -b /dev -r ${JUNEST_HOME} -k 3.10 bash -c /usr/bin/mkdir -v /newdir2" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
function test_run_env_with_proot_args(){
|
||||
proot_cmd() {
|
||||
[ "$JUNEST_ENV" != "1" ] && return 1
|
||||
echo $@
|
||||
}
|
||||
|
||||
assertCommandSuccess _run_env_with_proot --help
|
||||
assertEquals "--help /bin/sh --login" "$(cat $STDOUTF)"
|
||||
|
||||
assertCommandSuccess _run_env_with_proot --help mycommand
|
||||
assertEquals "--help /bin/sh --login -c mycommand" "$(cat $STDOUTF)"
|
||||
|
||||
assertCommandFail _run_env_with_proot
|
||||
}
|
||||
|
||||
function test_qemu() {
|
||||
echo "JUNEST_ARCH=arm" > ${JUNEST_HOME}/etc/junest/info
|
||||
rm_cmd() {
|
||||
echo $@
|
||||
}
|
||||
ln_cmd() {
|
||||
echo $@
|
||||
}
|
||||
_run_env_with_proot() {
|
||||
echo $@
|
||||
}
|
||||
|
||||
RANDOM=100 ARCH=x86_64 assertCommandSuccess _run_env_with_qemu ""
|
||||
assertEquals "$(echo -e "-s $JUNEST_HOME/opt/qemu/qemu-arm-static-x86_64 /tmp/qemu-arm-static-x86_64-100\n-q /tmp/qemu-arm-static-x86_64-100")" "$(cat $STDOUTF)"
|
||||
}
|
||||
|
||||
source $JUNEST_ROOT/tests/utils/shunit2
|
||||
81
tests/unit-tests/test-setup.sh
Executable file
81
tests/unit-tests/test-setup.sh
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#!/bin/bash
|
||||
|
||||
JUNEST_ROOT=$(readlink -f $(dirname $0)/../..)
|
||||
|
||||
source "$JUNEST_ROOT/tests/utils/utils.sh"
|
||||
|
||||
source "$JUNEST_ROOT/lib/utils/utils.sh"
|
||||
source "$JUNEST_ROOT/lib/core/common.sh"
|
||||
source "$JUNEST_ROOT/lib/core/setup.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
||||
function oneTimeSetUp(){
|
||||
setUpUnitTests
|
||||
}
|
||||
|
||||
function setUp(){
|
||||
cwdSetUp
|
||||
junestSetUp
|
||||
}
|
||||
|
||||
function tearDown(){
|
||||
junestTearDown
|
||||
cwdTearDown
|
||||
}
|
||||
|
||||
function test_is_env_installed(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
assertCommandFail is_env_installed
|
||||
touch $JUNEST_HOME/just_file
|
||||
assertCommandSuccess is_env_installed
|
||||
}
|
||||
|
||||
function test_setup_env(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
wget_mock(){
|
||||
# Proof that the setup is happening
|
||||
# inside $JUNEST_TEMPDIR
|
||||
local cwd=${PWD#${JUNEST_TEMPDIR}}
|
||||
local parent_dir=${PWD%${cwd}}
|
||||
assertEquals "$JUNEST_TEMPDIR" "${parent_dir}"
|
||||
touch file
|
||||
tar -czvf ${CMD}-${ARCH}.tar.gz file
|
||||
}
|
||||
WGET=wget_mock
|
||||
setup_env 1> /dev/null
|
||||
assertTrue "[ -e $JUNEST_HOME/file ]"
|
||||
|
||||
assertCommandFailOnStatus 102 setup_env "noarch"
|
||||
}
|
||||
|
||||
|
||||
function test_setup_env_from_file(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
touch file
|
||||
tar -czvf ${CMD}-${ARCH}.tar.gz file 1> /dev/null
|
||||
assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz
|
||||
assertTrue "[ -e $JUNEST_HOME/file ]"
|
||||
}
|
||||
|
||||
function test_setup_env_from_file_not_existing_file(){
|
||||
assertCommandFailOnStatus 103 setup_env_from_file noexist.tar.gz
|
||||
}
|
||||
|
||||
function test_setup_env_from_file_with_absolute_path(){
|
||||
rm -rf $JUNEST_HOME/*
|
||||
touch file
|
||||
tar -czf ${CMD}-${ARCH}.tar.gz file
|
||||
assertCommandSuccess setup_env_from_file ${CMD}-${ARCH}.tar.gz
|
||||
assertTrue "[ -e $JUNEST_HOME/file ]"
|
||||
}
|
||||
|
||||
function test_delete_env(){
|
||||
echo "N" | delete_env 1> /dev/null
|
||||
assertCommandSuccess is_env_installed
|
||||
echo "Y" | delete_env 1> /dev/null
|
||||
assertCommandFail is_env_installed
|
||||
}
|
||||
|
||||
source $JUNEST_ROOT/tests/utils/shunit2
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#!/bin/bash
|
||||
source "$(dirname $0)/utils.sh"
|
||||
source "$(dirname $0)/../utils/utils.sh"
|
||||
|
||||
unset HOME
|
||||
export HOME=$(TMPDIR=/tmp mktemp -d -t pearl-user-home.XXXXXXX)
|
||||
|
||||
source "$(dirname $0)/../../lib/utils.sh"
|
||||
source "$(dirname $0)/../../lib/utils/utils.sh"
|
||||
|
||||
# Disable the exiterr
|
||||
set +e
|
||||
|
|
@ -94,4 +94,4 @@ function test_contains_element(){
|
|||
assertCommandFailOnStatus 1 contains_element "blabla" "${array[@]}"
|
||||
}
|
||||
|
||||
source $(dirname $0)/shunit2
|
||||
source $(dirname $0)/../utils/shunit2
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
|
||||
function setUpUnitTests(){
|
||||
OUTPUT_DIR="${SHUNIT_TMPDIR}/output"
|
||||
mkdir "${OUTPUT_DIR}"
|
||||
STDOUTF="${OUTPUT_DIR}/stdout"
|
||||
STDERRF="${OUTPUT_DIR}/stderr"
|
||||
}
|
||||
|
||||
function assertCommandSuccess(){
|
||||
$(set -e
|
||||
"$@" > $STDOUTF 2> $STDERRF
|
||||
)
|
||||
assertTrue "The command $1 did not return 0 exit status" $?
|
||||
}
|
||||
|
||||
function assertCommandFail(){
|
||||
$(set -e
|
||||
"$@" > $STDOUTF 2> $STDERRF
|
||||
)
|
||||
assertFalse "The command $1 returned 0 exit status" $?
|
||||
}
|
||||
|
||||
# $1: expected exit status
|
||||
# $2-: The command under test
|
||||
function assertCommandFailOnStatus(){
|
||||
local status=$1
|
||||
shift
|
||||
$(set -e
|
||||
"$@" > $STDOUTF 2> $STDERRF
|
||||
)
|
||||
assertEquals $status $?
|
||||
}
|
||||
57
tests/utils/utils.sh
Normal file
57
tests/utils/utils.sh
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
function cwdSetUp(){
|
||||
ORIGIN_CWD=$(TMPDIR=/tmp mktemp -d -t junest-cwd.XXXXXXXXXX)
|
||||
cd $ORIGIN_CWD
|
||||
}
|
||||
|
||||
function cwdTearDown(){
|
||||
rm -rf $ORIGIN_CWD
|
||||
}
|
||||
|
||||
function junestSetUp(){
|
||||
JUNEST_HOME=$(TMPDIR=/tmp mktemp -d -t junest-home.XXXXXXXXXX)
|
||||
mkdir -p ${JUNEST_HOME}/etc/junest
|
||||
echo "JUNEST_ARCH=x86_64" > ${JUNEST_HOME}/etc/junest/info
|
||||
mkdir -p ${JUNEST_HOME}/etc/ca-certificates
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
trap "rm -rf ${JUNEST_HOME}" EXIT QUIT ABRT KILL TERM INT
|
||||
}
|
||||
|
||||
function junestTearDown(){
|
||||
# the CA directories are read only and can be deleted only by changing the mod
|
||||
[ -d ${JUNEST_HOME}/etc/ca-certificates ] && chmod -R +w ${JUNEST_HOME}/etc/ca-certificates
|
||||
rm -rf $JUNEST_HOME
|
||||
trap - QUIT EXIT ABRT KILL TERM INT
|
||||
unset JUNEST_HOME
|
||||
}
|
||||
|
||||
function setUpUnitTests(){
|
||||
OUTPUT_DIR="${SHUNIT_TMPDIR}/output"
|
||||
mkdir "${OUTPUT_DIR}"
|
||||
STDOUTF="${OUTPUT_DIR}/stdout"
|
||||
STDERRF="${OUTPUT_DIR}/stderr"
|
||||
}
|
||||
|
||||
function assertCommandSuccess(){
|
||||
$(set -e
|
||||
"$@" > $STDOUTF 2> $STDERRF
|
||||
)
|
||||
assertTrue "The command $1 did not return 0 exit status" $?
|
||||
}
|
||||
|
||||
function assertCommandFail(){
|
||||
$(set -e
|
||||
"$@" > $STDOUTF 2> $STDERRF
|
||||
)
|
||||
assertFalse "The command $1 returned 0 exit status" $?
|
||||
}
|
||||
|
||||
# $1: expected exit status
|
||||
# $2-: The command under test
|
||||
function assertCommandFailOnStatus(){
|
||||
local status=$1
|
||||
shift
|
||||
$(set -e
|
||||
"$@" > $STDOUTF 2> $STDERRF
|
||||
)
|
||||
assertEquals $status $?
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue