Skip to content

Instantly share code, notes, and snippets.

@tai
Created April 28, 2021 03:26
Show Gist options
  • Select an option

  • Save tai/f0baa03b5d61609e2cb6fa601574b377 to your computer and use it in GitHub Desktop.

Select an option

Save tai/f0baa03b5d61609e2cb6fa601574b377 to your computer and use it in GitHub Desktop.
#!/bin/sh
usage() {
local p=${0##*/}
cat <<EOF 1>&2
$p - Run command in alternative environment
Usage: [VE_BACKEND=(proot|bwrap|unshare|chroot)] $p <env> cmd args...
Example:
$ eval \$(ve completion)
$ $p /n/hc xeyes
$ $p hc xeyes
$ VE_BACKEND=bwrap $p hc
NOTE:
- UTS hostname is kept same as host env to satisfy X auth.
- File owner/groups may be different from host env.
- Backend: proot is easier to use, but bwrap is more stable
EOF
exit 0
}
gencomp() {
local p=${0##*/}
cat <<EOF
_ve_helper() {
local cur="\${COMP_WORDS[COMP_CWORD]}";
if [ \${COMP_CWORD} -eq 1 ] ; then
COMPREPLY=(\$(compgen -W "\$(/bin/ls -1 /n)" "\$cur"));
else
COMPREPLY=(\$(compgen -o default -A file "\$cur"));
fi
};
complete -F _ve_helper $p
EOF
exit 0
}
do_mark() {
local key=$1
sudo mkdir -p $veroot/.ve/refs/$key
}
do_unmark() {
local key=$1
sudo rmdir -p --ignore-fail-on-non-empty $veroot/.ve/refs/$key
! test -d $veroot/.ve/refs
}
do_bind() {
local veroot=$1
test -e $veroot/proc/cpuinfo || sudo mount -t proc none $veroot/proc
test -e $veroot/sys/kernel || sudo mount -t sysfs none $veroot/sys
test -e $veroot/dev/usb || sudo mount -t devtmpfs none $veroot/dev
for i in c d f t; do
# skip if already mounted
test $(sudo stat -c %m $veroot/$i) = "$veroot/$i" && continue
$DEBUG sudo mount --rbind /$i $veroot/$i
done
}
do_unbind() {
local veroot=$1
for i in c d f t dev sys proc; do
# skip if already unmounted
test $(sudo stat -c %m $veroot/$i) = "$veroot/$i" || continue
$DEBUG sudo umount -lf $veroot/$i
done
}
do_unshare() {
local ve=$1 veroot=$2; shift 2
# prepare bind mounts
local key=$$
do_mark $key && do_bind $veroot
# NOTE:
# - Hostname is still parent hostname
# - May have an issue with file owner/groups
$DEBUG unshare -u -c -w $PWD -R $veroot "$@"
do_unmark $key && do_unbind $veroot
}
do_chroot() {
local ve=$1 veroot=$2; shift 2
# prepare bind mounts
local key=$$
do_mark $key && do_bind $veroot
# NOTE:
# - Hostname is still parent hostname
# - PWD is always /
$DEBUG sudo -E chroot --userspec=$USER $veroot "$@"
do_unmark $key && do_unbind $veroot
}
do_bwrap() {
local ve=$1 veroot=$2; shift 2
# NOTE:
# - May have an issue with file owner/groups
# - Hostname is still parent hostname - needed to satisfy X auth
$DEBUG bwrap --bind $veroot / --bind /c /c --bind /d /d --bind /f /f --bind /t /t \
--dev-bind /dev /dev --proc /proc --bind /sys /sys --chdir $PWD -- "$@"
}
do_proot() {
local ve=$1 veroot=$2; shift 2
# NOTE:
# - Hostname is still parent hostname - needed to satisfy X auth
local qemu=
if file -L $veroot/bin/sh | egrep -qv '(80386|x86-64)'; then
for i in $veroot/usr/bin/qemu-*-static; do
test -f $i && qemu="-q ${i##*/}"
done
fi
$DEBUG proot $qemu -r $veroot -b /c -b /d -b /f -b /t -b /dev -b /sys -b /proc "$@"
}
run() {
local ve=$1; shift
local veroot=$ve
# <env> can either be rootfs path or name
test -d "$veroot" || veroot="/n/$ve"
# Run a shell if no command is given
local fallback=
if [ $# -eq 0 ]; then
fallback="$SHELL -l"
fi
do_${VE_BACKEND:=proot} $ve $veroot "$@" $fallback
}
test "$1" = "completion" && gencomp
test $# -gt 0 || usage
run "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment