Add -i and -r options for groot command

This commit is contained in:
Filippo Squillace 2017-04-19 21:04:51 +01:00
parent 02650b754e
commit 03a29590de
5 changed files with 131 additions and 18 deletions

View file

@ -22,7 +22,8 @@ TOUCH=touch
CUT=cut
SORT=sort
UNIQ=uniq
GREP=grep
CAT=cat
READLINK=readlink
MOUNTS_FILE=/proc/self/mounts
NOT_EXISTING_FILE=103
@ -38,11 +39,18 @@ function chroot_teardown() {
# Remove all mounts starting from the most nested ones.
# Suffix the CHROOTDIR with / to avoid umounting directories not belonging
# to CHROOTDIR.
for mp in $($GREP "${CHROOTDIR%/}/" $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ)
local normalized_chrootdir="$($READLINK -f ${CHROOTDIR})/"
local final_res=0
for mp in $($CAT $MOUNTS_FILE | $CUT -f2 -d' ' | $SORT -r | $UNIQ)
do
$UMOUNT $mp
if [[ $mp =~ ^${normalized_chrootdir}.* ]]
then
$UMOUNT $mp || final_res=$?
fi
done
$UMOUNT ${CHROOTDIR%/}
return $final_res
}
function chroot_maybe_add_mount() {
@ -79,10 +87,32 @@ function chroot_setup() {
fi
create_node "${host_path}" "${CHROOTDIR}${guest_path}"
$MOUNT --rbind "${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"
@ -118,9 +148,19 @@ Options:
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
@ -135,16 +175,20 @@ version() {
}
function parse_arguments() {
OPT_BIND=false
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) OPT_BIND=true ; shift ; BINDINGS+=("$1") ; shift ;;
-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" ;;

View file

@ -73,7 +73,7 @@ function build_image_env(){
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/groot ${maindir}/root bash -c \
sudo ${maindir}/root/opt/junest/bin/groot -b /dev ${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/*

View file

@ -57,9 +57,9 @@ function _run_env_with_namespace(){
# will terminate too with its own mounted directories.
if [[ "$1" != "" ]]
then
JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT -n $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")"
JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}" "-c" "$(insert_quotes_on_spaces "${@}")"
else
JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT -n $bindings $backend_args "$JUNEST_HOME" "${SH[@]}"
JUNEST_ENV=1 unshare_cmd --mount --user --map-root-user $GROOT --no-umount --recursive $bindings $backend_args "$JUNEST_HOME" "${SH[@]}"
fi
}

View file

@ -89,14 +89,14 @@ 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)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind ${PWD}/file_src chrootdir/file_src)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\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
@ -111,7 +111,7 @@ 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)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\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
@ -119,7 +119,7 @@ function test_groot_with_multiple_bind(){
assertEquals 0 $?
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\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
@ -131,7 +131,7 @@ function test_groot_with_bind_and_command(){
assertEquals 0 $?
[[ -d chrootdir/dev ]]
assertEquals 0 $?
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(--rbind /tmp chrootdir/home/tmp)\nmount(--rbind /dev chrootdir/dev)\nchroot(chrootdir ls -la -h)")" "$(cat $STDOUTF)"
assertEquals "$(echo -e "check_and_trap(chroot_teardown QUIT EXIT ABRT KILL TERM INT)\nmountpoint(-q chrootdir)\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
@ -147,6 +147,23 @@ 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
@ -158,4 +175,56 @@ 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)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\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)\nmountpoint(-q chrootdir)\nmount(--bind chrootdir chrootdir)\nmount(tmp chrootdir/tmp -t tmpfs)\nmount(--bind /usr chrootdir/usr)\nchroot(chrootdir)")" "$(cat $STDOUTF)"
}
source $(dirname $0)/../utils/shunit2

View file

@ -80,7 +80,7 @@ function test_is_user_namespace_enabled_with_config(){
function test_run_env_with_namespace() {
assertCommandSuccess run_env_with_namespace "" ""
assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)"
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)"
_test_copy_common_files
_test_copy_remaining_files
@ -88,7 +88,7 @@ function test_run_env_with_namespace() {
function test_run_env_with_namespace_with_bindings() {
assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" ""
assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)"
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login" "$(cat $STDOUTF)"
_test_copy_common_files
_test_copy_remaining_files
@ -96,7 +96,7 @@ function test_run_env_with_namespace_with_bindings() {
function test_run_env_with_namespace_with_command() {
assertCommandSuccess run_env_with_namespace "" "ls -la"
assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)"
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)"
_test_copy_common_files
_test_copy_remaining_files
@ -104,7 +104,7 @@ function test_run_env_with_namespace_with_command() {
function test_run_env_with_namespace_with_bindings_and_command() {
assertCommandSuccess run_env_with_namespace "-b /usr -b /lib:/tmp/lib" "ls -la"
assertEquals "unshare --mount --user --map-root-user $GROOT -n -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)"
assertEquals "unshare --mount --user --map-root-user $GROOT --no-umount --recursive -b $HOME -b /tmp -b /proc -b /sys -b /dev -b /usr -b /lib:/tmp/lib $JUNEST_HOME /bin/sh --login -c \"ls -la\"" "$(cat $STDOUTF)"
_test_copy_common_files
_test_copy_remaining_files