Issue #174: Add new program GRoot and change version option for JuNest!

This replaces jchroot because GRoot can be also used in a user namespace environment.
This commit is contained in:
Filippo Squillace 2017-03-17 17:49:00 +00:00
parent 426b708d2d
commit 0f7fd33c53
13 changed files with 458 additions and 184 deletions

180
bin/groot Executable file
View file

@ -0,0 +1,180 @@
#!/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
MOUNTPOINT=mountpoint
MKDIR=mkdir
TOUCH=touch
NOT_EXISTING_FILE=103
NOT_ABSOLUTE_PATH=111
NO_ROOT_PRIVILEGES=110
source "${JUNEST_BASE}/lib/utils/utils.sh"
################################ MAIN FUNCTIONS ###########################
function chroot_add_mount() {
$MOUNT "$@" && CHROOT_ACTIVE_MOUNTS=("${@: -1}" "${CHROOT_ACTIVE_MOUNTS[@]}")
}
function chroot_teardown() {
$UMOUNT "${CHROOT_ACTIVE_MOUNTS[@]}"
unset CHROOT_ACTIVE_MOUNTS
}
function chroot_maybe_add_mount() {
local cond=$1
shift
if eval "$cond"; then
chroot_add_mount "$@"
return
fi
return 1
}
function chroot_setup() {
CHROOT_ACTIVE_MOUNTS=()
check_and_trap 'chroot_teardown' EXIT
if ! chroot_maybe_add_mount "! $MOUNTPOINT -q '$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}"
chroot_add_mount --rbind "${host_path}" "${CHROOTDIR}${guest_path}"
done
}
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.
-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() {
OPT_BIND=false
BINDINGS=()
OPT_HELP=false
OPT_VERSION=false
for opt in "$@"
do
case "$1" in
-b|--bind) OPT_BIND=true ; shift ; BINDINGS+=("$1") ; 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,98 +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="$(readlink -f $(dirname $(readlink -f "$0"))/..)"
source "${JUNEST_BASE}/lib/utils/utils.sh"
################################ MAIN FUNCTIONS ###########################
chroot_add_mount() {
mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}")
}
chroot_maybe_add_mount() {
local cond=$1; shift
if eval "$cond"; then
chroot_add_mount "$@"
fi
}
chroot_setup() {
CHROOT_ACTIVE_MOUNTS=()
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'chroot_teardown' EXIT
chroot_maybe_add_mount "! mountpoint -q '$1'" "$1" "$1" --bind &&
chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro &&
chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid &&
chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec &&
chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev &&
chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 &&
chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,atime,nodev,nosuid &&
mkdir -p "$1/$HOME" &&
chroot_add_mount $HOME "$1/$HOME" --bind
mkdir -p "$1/run/lock"
}
chroot_teardown() {
umount "${CHROOT_ACTIVE_MOUNTS[@]}"
unset CHROOT_ACTIVE_MOUNTS
}
usage() {
cat <<EOF
usage: ${0##*/} chroot-dir [command]
-h Print this help message
If 'command' is unspecified, ${0##*/} will launch /bin/sh.
EOF
}
chroot_add_resolv_conf() {
local chrootdir=$1 resolv_conf=$1/etc/resolv.conf
# Handle resolv.conf as a symlink to somewhere else.
if [[ -L $chrootdir/etc/resolv.conf ]]; then
# readlink(1) should always give us *something* since we know at this point
# it's a symlink. For simplicity, ignore the case of nested symlinks.
resolv_conf=$(readlink "$chrootdir/etc/resolv.conf")
if [[ $resolv_conf = /* ]]; then
resolv_conf=$chrootdir$resolv_conf
else
resolv_conf=$chrootdir/etc/$resolv_conf
fi
# ensure file exists to bind mount over
if [[ ! -f $resolv_conf ]]; then
install -Dm644 /dev/null "$resolv_conf" || return 1
fi
fi
chroot_add_mount /etc/resolv.conf "$resolv_conf" --bind
}
if [[ -z $1 || $1 == -h || $1 == --help ]]; then
usage
exit $(( $# ? 0 : 1 ))
fi
(( EUID == 0 )) || die 'This script must be run with root privileges'
chrootdir=$1
shift
[[ -d $chrootdir ]] || die "Can't create chroot on non-directory $chrootdir"
chroot_setup "$chrootdir" || die "failed to setup chroot $chrootdir"
chroot_add_resolv_conf "$chrootdir" || die "failed to setup resolv.conf"
SHELL="/bin/sh" chroot "$chrootdir" "$@"

View file

@ -3,7 +3,11 @@
# This file is part of JuNest (https://github.com/fsquillace/junest).
#
JUNEST_BASE="$(readlink -f $(dirname $(readlink -f "$0"))/..)"
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"))/..)}"
source "${JUNEST_BASE}/lib/utils/utils.sh"
source "${JUNEST_BASE}/lib/core/common.sh"
@ -32,10 +36,10 @@ usage() {
echo
echo -e "Access options:"
echo -e "-f, --fakeroot Run $NAME with fakeroot privileges"
echo -e "-r, --root Run $NAME with root privileges via jchroot"
echo -e "-p, --backend-args <args> Arguments for backend program (PRoot or jchroot)"
echo -e "-r, --root Run $NAME with root privileges via GRoot"
echo -e "-p, --backend-args <args> Arguments for backend program (PRoot or GRoot)"
echo -e " ($CMD -p \"--help\" to check out the PRoot options"
echo -e " $CMD -u -p \"--help\" to check out the jchroot options)"
echo -e " $CMD -u -p \"--help\" to check out the GRoot options)"
echo -e "-u, --user-namespace Use Linux User Namespace instead of PRoot"
echo
echo -e "Building options:"
@ -47,7 +51,7 @@ usage() {
echo
echo -e "General options:"
echo -e "-h, --help Show this help message"
echo -e "-v, --version Show the $NAME version"
echo -e "-V, --version Show the $NAME version"
}
version() {
@ -169,7 +173,7 @@ function parse_arguments(){
-s|--skip-root-tests) OPT_SKIP_ROOT_TEST=true ; shift ;;
-d|--delete) OPT_DELETE=true ; shift ;;
-h|--help) OPT_HELP=true ; shift ;;
-v|--version) OPT_VERSION=true ; shift ;;
-V|--version) OPT_VERSION=true ; shift ;;
--) shift ; break ;;
-*) die "Invalid option $1" ;;
*) break ;;
@ -231,11 +235,11 @@ function execute_operation(){
}
function cli() {
function main() {
parse_arguments "$@"
check_cli
execute_operation
}
cli "$@"
main "$@"
# vim: set ts=4 sw=4 noet: