#!/bin/sh set -eu USERNAME="${USERNAME:-$(id -u -n)}" UNSHARE_CMD="${UNSHARE_CMD:-unshare}" # make sure we're root if [ "$(id -u)" != 0 ]; then sucmd="su -c" if command -v doas >/dev/null; then sucmd="doas" elif command -v sudo >/dev/null; then sucmd="sudo" fi exec $sucmd \ env \ HOME="$HOME" \ USERNAME="$USERNAME" \ UNSHARE_CMD="$UNSHARE_CMD" \ WAYLAND_DISPLAY="$WAYLAND_DISPLAY" \ DISPLAY="$DISPLAY" \ XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \ DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" \ "$0" "$@" fi # and make sure we're in a separate mount namespace if [ "$(readlink /proc/$$/ns/mnt | cut -d: -f2)" = "$(readlink /proc/1/ns/mnt | cut -d: -f2)" ]; then exec $UNSHARE_CMD --keep-caps -m "$0" "$@" fi bindpoints="/etc/resolv.conf" command="" user="$USERNAME" while getopts "bde:u:c:" opt; do case $opt in 'b') bindpoints=" $bindpoints /var/cache/distfiles $HOME/aports $HOME/packages $HOME/.abuild " ;; 'd') bindpoints=" $bindpoints $XDG_RUNTIME_DIR /tmp " ;; 'e') bindpoints="$bindpoints $OPTARG" ;; 'u') user="$OPTARG" ;; 'c') command="$OPTARG" ;; *) echo "unknown $opt" ;; esac done shift $(( $OPTIND - 1 )) dest="$1" shift if [ ! -d "$dest" ]; then echo "no such directory: $dest" exit 1 fi if ! [ -x "$dest"/bin/sh -o -L "$dest"/bin/sh ]; then echo "$dest does not contain executable /bin/sh" exit 1 fi # do stupid path fixup export PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH" mount -t proc proc "$dest"/proc mount -t sysfs sysfs "$dest"/sys mount -t tmpfs tmpfs "$dest"/tmp # some mini kernels don't have devtmpfs if grep -q devtmpfs /proc/filesystems; then mount -t devtmpfs devtmpfs "$dest"/dev else mount -t tmpfs tmpfs "$dest"/dev if [ -x "$dest"/sbin/mdev -o -L "$dest"/sbin/mdev ]; then echo "devtmpfs not supported - running 'mdev -s' instead" chroot "$dest" /sbin/mdev -sv else echo "devtmpfs not supported - devices need to be created manually" fi fi mkdir -p "$dest"/dev/pts "$dest"/dev/shm mount -t devpts devpts "$dest"/dev/pts mount -t tmpfs tmpfs "$dest"/dev/shm # workaround for shitty android-based stuff if ! [ -f /etc/resolv.conf ]; then # remove /etc/resolv.conf from bindpoints bindpoints="${bindpoints#/etc/resolv.conf}" fi for bindpoint in $bindpoints; do if [ -f "$bindpoint" ]; then touch "$dest"/"$bindpoint" else mkdir -p "$dest"/"$bindpoint" fi mount -o bind "$bindpoint" "$dest"/"$bindpoint" done # if running on chromeos, fixup symlink exec # https://goo.gl/8xICW6 # https://github.com/dnschneid/crouton/commit/5cb7ad05 if [ -e "/run/chrome" ]; then if mount -n -t securityfs -o nodev,noexec,nosuid securityfs /sys/kernel/security; then policies=/sys/kernel/security/chromiumos/inode_security_policies if [ -d "$policies" ]; then for policy in "$policies/allow_"*; do printf "$(realpath "$dest")" > "$policy" done fi umount /sys/kernel/security fi fi mount -o bind "$dest" /mnt pivot_root /mnt /mnt/mnt if [ "$command" ]; then exec su $user -c "$command" elif [ "$#" -gt 0 ]; then exec su $user -c "$*" else exec login -p -f $user fi