Remove groot content

This commit is contained in:
Filippo Squillace 2020-03-24 21:18:25 +01:00
parent 6592bc9bd2
commit 348b73ce73
2 changed files with 0 additions and 490 deletions

242
bin/groot
View file

@ -1,242 +0,0 @@
#!/bin/bash
#
# This script is the simplified and portable version of arch-chroot
# (https://wiki.archlinux.org/index.php/Change_root#Using_arch-chroot)
#
set -e
# JUNEST_BASE can be overridden for testing purposes.
# There is no need for doing it for normal usage.
JUNEST_BASE="${JUNEST_BASE:-$(readlink -f $(dirname $(readlink -f "$0"))/..)}"
NAME='GRoot'
CMD='groot'
DESCRIPTION="I am $NAME!"
CHROOTCMD=${CHROOTCMD:-chroot}
SHELL="/bin/sh"
MOUNT=mount
UMOUNT=umount
MKDIR=mkdir
TOUCH=touch
CUT=cut
SORT=sort
UNIQ=uniq
CAT=cat
READLINK=readlink
MOUNTS_FILE=/proc/self/mounts
NOT_EXISTING_FILE=103
NOT_ABSOLUTE_PATH=111
NO_ROOT_PRIVILEGES=110
source "${JUNEST_BASE}/lib/utils/utils.sh"
################################ MAIN FUNCTIONS ###########################
function is_mountpoint() {
local mountpoint="$1"
for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ)
do
[[ $mp == $mountpoint ]] && return 0
done
return 1
}
function chroot_teardown() {
# Remove all mounts starting from the most nested ones.
# Suffix the CHROOTDIR with / to avoid umounting directories not belonging
# to CHROOTDIR.
local normalized_chrootdir="$($READLINK -f ${CHROOTDIR})/"
local final_res=0
for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ)
do
if [[ $mp =~ ^${normalized_chrootdir}.* ]] && is_mountpoint "$mp"
then
$UMOUNT $mp || final_res=$?
fi
done
$UMOUNT ${CHROOTDIR%/}
return $final_res
}
function chroot_maybe_add_mount() {
local cond=$1
shift
if eval "$cond"; then
$MOUNT "$@"
return
fi
return 1
}
function chroot_setup() {
$OPT_NO_UMOUNT || check_and_trap 'chroot_teardown' QUIT EXIT ABRT KILL TERM INT
if ! chroot_maybe_add_mount "! is_mountpoint '$CHROOTDIR'" --bind "$CHROOTDIR" "$CHROOTDIR"
then
warn "Failed mount of directories. $CHROOTDIR is already a mountpoint. Skipping it..."
return 0
fi
local re='(.*):(.*)'
for binds in ${BINDINGS[@]}
do
local host_path=""
local guest_path=""
if [[ $binds =~ $re ]]
then
local host_path="${BASH_REMATCH[1]}"
local guest_path="${BASH_REMATCH[2]}"
else
local host_path="$binds"
local guest_path="$binds"
fi
create_node "${host_path}" "${CHROOTDIR}${guest_path}"
mount_directory "${host_path}" "${guest_path}"
done
}
function mount_directory() {
local host_path=$($READLINK -f "$1")
local guest_path="$2"
if ! $OPT_AVOID_BIND
then
$MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}"
return 0
fi
case "$host_path" in
/proc) $MOUNT proc "${CHROOTDIR}${guest_path}" -t proc ;;
/sys) $MOUNT sys "${CHROOTDIR}${guest_path}" -t sysfs ;;
/dev) $MOUNT udev "${CHROOTDIR}${guest_path}" -t devtmpfs; $MOUNT devpts "${guest_path}/pts" -t devpts; $MOUNT shm "${guest_path}/shm" -t tmpfs ;;
/run) $MOUNT run "${CHROOTDIR}${guest_path}" -t tmpfs ;;
/tmp) $MOUNT tmp "${CHROOTDIR}${guest_path}" -t tmpfs ;;
*) $MOUNT $OPT_BIND "${host_path}" "${CHROOTDIR}${guest_path}" ;;
esac
return 0
}
function create_node() {
local src="$1"
local dst="$2"
if [[ ! -e $src ]]
then
die_on_status $NOT_EXISTING_FILE "${src} does not exist."
elif [[ $src != /* ]]
then
die_on_status $NOT_ABSOLUTE_PATH "${src} is not an absolute path."
elif [[ -f $src ]]
then
$TOUCH "$dst"
elif [[ -d $src ]]
then
$MKDIR -p "$dst"
fi
}
function usage() {
cat <<EOF
$NAME (v$(cat $JUNEST_BASE/VERSION)): $DESCRIPTION
Usage:
$CMD [options] [<chroot-dir> [command]]
Options:
-b, --bind <path>
Make the content of <path> accessible in the guest rootfs.
This option makes any file or directory of the host rootfs
accessible in the confined environment just as if it were part of
the guest rootfs. By default the host path is bound to the same
path in the guest rootfs but users can specify any other location
with the syntax: -b <host_path>:<guest_location>. This option can
be invoked multiple times and the paths specified must be absolutes.
-n, --no-umount
Do not umount after chroot session finished.
-r, --recursive
Use rbind instead of bind.
-i, --avoid-bind
Attempt to avoid mount --bind for common directories and use
proper mount fstype instead. Detected directories with
corresponding fstype are: /proc (proc), /sys (sysfs),
/dev (devtmpfs), /tmp (tmpfs), /run (tmpfs).
-h, --help Print this help message
-V, --version Show the $NAME version
If 'command' is unspecified, $CMD will launch $SHELL.
EOF
}
version() {
echo -e "$NAME $(cat $JUNEST_BASE/VERSION)"
}
function parse_arguments() {
BINDINGS=()
OPT_NO_UMOUNT=false
OPT_RECURSIVE=false
OPT_BIND="--bind"
OPT_AVOID_BIND=false
OPT_HELP=false
OPT_VERSION=false
for opt in "$@"
do
case "$1" in
-b|--bind) shift ; BINDINGS+=("$1") ; shift ;;
-n|--no-umount) OPT_NO_UMOUNT=true ; shift ;;
-r|--recursive) OPT_BIND="--rbind" ; shift ;;
-i|--avoid-bind) OPT_AVOID_BIND=true ; shift ;;
-h|--help) OPT_HELP=true ; shift ;;
-V|--version) OPT_VERSION=true ; shift ;;
-*) die "Invalid option $1" ;;
*) break ;;
esac
done
if [[ ! -z $1 ]]
then
CHROOTDIR="$1"
shift
fi
ARGS=()
for arg in "$@"
do
ARGS+=("$arg")
done
}
function is_user_root() {
(( EUID == 0 ))
}
function execute_operation() {
$OPT_HELP && usage && return
$OPT_VERSION && version && return
is_user_root || die_on_status $NO_ROOT_PRIVILEGES 'This script must be run with root privileges'
[[ -d $CHROOTDIR ]] || die_on_status $NOT_EXISTING_FILE "Can't create chroot on non-directory $CHROOTDIR"
chroot_setup "$CHROOTDIR" || die "Failed to setup chroot $CHROOTDIR"
$CHROOTCMD "$CHROOTDIR" "${ARGS[@]}"
}
function main() {
parse_arguments "$@"
execute_operation
}
main "$@"

View file

@ -1,248 +0,0 @@
#!/bin/bash
source "$(dirname $0)/../utils/utils.sh"
JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/../..)"
# Disable the exiterr
set +e
function oneTimeSetUp(){
setUpUnitTests
}
function setUp(){
# Attempt to source the files under test to revert variable overrides
source $JUNEST_BASE/bin/groot -h &> /dev/null
set +e
cwdSetUp
mkdir -p chrootdir
init_mocks
}
function tearDown(){
cwdTearDown
}
## Mock functions ##
function init_mocks() {
function usage(){
echo "usage"
}
function is_user_root() {
return 0
}
function chroot() {
echo "chroot($@)"
}
function mountpoint() {
echo "mountpoint($@)"
# As default suppose the mountpoint does not exist
return 1
}
function mountpoint_mock() {
echo "mountpoint($@)"
}
function mount() {
echo "mount($@)"
}
function umount() {
echo "umount($@)"
}
function check_and_trap() {
echo "check_and_trap($@)"
}
# As default suppose the mountpoint "chrootdir" does not exist
echo -e "1 /home/mychroot/dev\n" > ./mounts
MOUNTS_FILE=./mounts
}
function test_help(){
assertCommandSuccess main -h
assertEquals "usage" "$(cat $STDOUTF)"
assertCommandSuccess main --help
assertEquals "usage" "$(cat $STDOUTF)"
}
function test_version(){
assertCommandSuccess main -V
assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)"
assertCommandSuccess main --version
assertEquals "$NAME $(cat $JUNEST_BASE/VERSION)" "$(cat $STDOUTF)"
}
function test_groot_no_root(){
is_user_root() {
return 1
}
assertCommandFailOnStatus $NO_ROOT_PRIVILEGES main
}
function test_groot_no_directory(){
assertCommandFailOnStatus $NOT_EXISTING_FILE main no-directory
}
function test_groot_mountpoint_exist(){
echo -e "1 /home/mychroot/dev\n1 chrootdir\n" > ./mounts
MOUNTS_FILE=./mounts
assertCommandSuccess main chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_mountpoint_does_not_exist(){
assertCommandSuccess main chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind(){
assertCommandSuccess main -b /tmp chrootdir
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_file(){
touch file_src
assertCommandSuccess main -b ${PWD}/file_src:/file_src chrootdir
[[ -f chrootdir/file_src ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_not_existing_node(){
assertCommandFailOnStatus $NOT_EXISTING_FILE main -b ${PWD}/file_src:/file_src chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_not_absolute_path_node(){
touch file_src
assertCommandFailOnStatus $NOT_ABSOLUTE_PATH main -b file_src:/file_src chrootdir
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_guest_host(){
assertCommandSuccess main -b /tmp:/home/tmp chrootdir
[[ -d chrootdir/home/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_multiple_bind(){
assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir
[[ -d chrootdir/home/tmp ]]
assertEquals 0 $?
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_command(){
assertCommandSuccess main chrootdir ls -la -h
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_and_command(){
assertCommandSuccess main -b /tmp:/home/tmp -b /dev chrootdir ls -la -h
[[ -d chrootdir/home/tmp ]]
assertEquals 0 $?
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--bind /tmp chrootdir/home/tmp)\nmount(--bind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)"
}
function test_groot_with_bind_no_umount(){
assertCommandSuccess main -n chrootdir
assertEquals "$(echo -e "mount(--bind chrootdir chrootdir)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown(){
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev/shm)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown_umount_failure(){
function umount() {
echo "umount($@)"
[[ "$1" == "/home/mychroot/dev/shm" ]] && return 128
return 0
}
UMOUNT=umount
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandFailOnStatus 128 chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev/shm)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown_with_trailing_slash(){
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev/shm)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_chroot_teardown_mountpoint_failure(){
is_mountpoint() {
[[ $1 == "/home/mychroot/dev/shm" ]] && return 128
return 0
}
echo -e "1 /home/mychroot/dev\n1 /home/mychroot/proc/fs1\n1 /home/mychroot\n1 /home/mychroot-no/dev\n1 /home/mychroot/dev/shm\n1 /home/mychroot/proc\n" > ./mounts
MOUNTS_FILE=./mounts
CHROOTDIR=/home/mychroot assertCommandSuccess chroot_teardown
assertEquals "$(echo -e "umount(/home/mychroot/proc/fs1)
umount(/home/mychroot/proc)
umount(/home/mychroot/dev)
umount(/home/mychroot)")" "$(cat $STDOUTF)"
}
function test_groot_with_rbind(){
assertCommandSuccess main -r -b /tmp chrootdir
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_proc(){
assertCommandSuccess main -i -b /proc chrootdir
[[ -d chrootdir/proc ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(proc chrootdir/proc -t proc)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_dev(){
assertCommandSuccess main -i -b /dev chrootdir
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(udev chrootdir/dev -t devtmpfs)\nmount(devpts /dev/pts -t devpts)\nmount(shm /dev/shm -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_sys(){
assertCommandSuccess main -i -b /sys chrootdir
[[ -d chrootdir/sys ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(sys chrootdir/sys -t sysfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_run(){
assertCommandSuccess main -i -b /run chrootdir
[[ -d chrootdir/run ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(run chrootdir/run -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_tmp(){
assertCommandSuccess main -i -b /tmp chrootdir
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
function test_groot_with_avoid_bind_combined(){
assertCommandSuccess main -i -b /tmp -b /usr chrootdir
cat $STDERRF
[[ -d chrootdir/tmp ]]
assertEquals 0 $?
[[ -d chrootdir/usr ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
source $(dirname $0)/../utils/shunit2