├── bound ├── conf │ ├── make.conf.user │ ├── bashrc.user │ └── make.conf ├── make_typical_binds.sh ├── README └── make_typical_confs.sh ├── chrootiez_config ├── scripts ├── run_from_chroot ├── run_chroot.sh └── run_chroot_unshared.sh └── HOWTO /bound/conf/make.conf.user: -------------------------------------------------------------------------------- 1 | PORTAGE_USERNAME=root 2 | PORTAGE_GRPNAME=root 3 | -------------------------------------------------------------------------------- /bound/make_typical_binds.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ln -s "$(portageq envvar PORTDIR)" portage 4 | ln -s "$(portageq envvar DISTDIR)" distfiles 5 | -------------------------------------------------------------------------------- /bound/README: -------------------------------------------------------------------------------- 1 | Every subdir in this directory is bound to chroot with 2 | mount --bind 3 | command. 4 | 5 | It is handy to place some overlays here and things like 6 | /usr/portage 7 | /usr/portage/distifes 8 | and so on. 9 | 10 | -------------------------------------------------------------------------------- /bound/conf/bashrc.user: -------------------------------------------------------------------------------- 1 | # in unprivileved user namespaces chown does not work 2 | # as user namespace allow you to map single UID (usually root) 3 | # anything else is bound to fail. 4 | # Thus just include it in bashrc in such environments: 5 | # $ echo 'source /bound/conf/bashrc.user' >> /etc/portage/bashrc 6 | chown() { :; } 7 | fowners() { :; } 8 | -------------------------------------------------------------------------------- /chrootiez_config: -------------------------------------------------------------------------------- 1 | ### privileged example (enabled by default): 2 | CHROOTIEZ_UNSHARE_EXTRA_OPTS="--ipc --mount --pid --uts --fork" 3 | CHROOTIEZ_DEVPTS=newinstance 4 | 5 | ### unprivileged example: 6 | #CHROOTIEZ_UNSHARE_EXTRA_OPTS="--ipc --mount --pid --uts --fork --user --map-root-user" 7 | #CHROOTIEZ_DEVPTS=newinstance 8 | #CHROOTIEZ_DEVPTS_GID=0 9 | -------------------------------------------------------------------------------- /bound/make_typical_confs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | makeopts=auto 4 | 5 | for a; do 6 | case "$a" in 7 | --makeopts=*) 8 | makeopts=${a#--makeopts=} 9 | ;; 10 | *) 11 | die "unknown option: $a" 12 | ;; 13 | esac 14 | done 15 | 16 | if [ "${makeopts}" = auto ]; then 17 | makeopts=$(expr `nproc` + 1) 18 | fi 19 | 20 | cat >conf/make.conf.local <> /etc/portage/make.conf 27 | #optionally 28 | echo 'ACCEPT_KEYWORDS="~$ARCH"' >> /etc/portage/make.conf 29 | 30 | eselect profile set 1 31 | 32 | # for unprivileged container: 33 | echo 'source /bound/conf/bashrc.user' >> /etc/portage/bashrc 34 | # for unprivileged --map-root-user container: 35 | echo 'source /bound/conf/make.conf.user' >> /etc/portage/make.conf 36 | 37 | # Done! 38 | -------------------------------------------------------------------------------- /scripts/run_chroot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | script_base=gentoo-chrootiez 4 | cfg="$script_base"/chrootiez_config 5 | 6 | if [ -f "${cfg}" ]; then 7 | . "${cfg}" 8 | # used only locally 9 | #export CHROOTIEZ_UNSHARE_EXTRA_OPTS 10 | 11 | # used in child mount 12 | export CHROOTIEZ_DEVPTS 13 | export CHROOTIEZ_DEVPTS_GID 14 | else 15 | echo "HINT from '${0}': you can create '${cfg}'" 16 | echo ' which recognizes the following variables:' 17 | echo ' CHROOTIEZ_UNSHARE_EXTRA_OPTS - arguments passed to' 18 | echo " 'unshare' before 'chroot'; very handy to unshare" 19 | echo ' everything including network.' 20 | echo ' CHROOTIEZ_DEVPTS={newinstance|host|none} - mounts new devpts instance' 21 | echo " 'newinstance' requires kernel support of CONFIG_DEVPTS_MULTIPLE_INSTANCES=y." 22 | echo ' WARNING: setting this variable without kernel support' 23 | echo ' will break ptys on your host system (xterm, screen will stop working).' 24 | echo " To fix the damage run: 'mount -oremount /dev/pts'" 25 | echo ' CHROOTIEZ_DEVPTS_GID=5 - override default group for newly mounted /dev/pts' 26 | echo ' Use CHROOTIEZ_DEVPTS_GID=0 for unprivileged namespaces as it is the' 27 | echo ' only group our current user can be owner of.' 28 | echo ' Example:' 29 | echo ' CHROOTIEZ_UNSHARE_EXTRA_OPTS="--ipc --mount --pid --uts --fork --user --map-root-user"' 30 | echo ' CHROOTIEZ_DEVPTS=newinstance' 31 | echo ' CHROOTIEZ_DEVPTS_GID=0' 32 | fi 33 | 34 | exec unshare $CHROOTIEZ_UNSHARE_EXTRA_OPTS --mount \ 35 | "$script_base"/scripts/run_chroot_unshared.sh "$@" 36 | 37 | # won't work anyways 38 | unset CHROOTIEZ_DEVPTS 39 | unset CHROOTIEZ_DEVPTS_GID 40 | echo "WARNING: unshare not found, only chroot facility will be used" 41 | exec "$script_base"/scripts/run_chroot_unshared.sh "$@" 42 | -------------------------------------------------------------------------------- /scripts/run_chroot_unshared.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | script_name=$0 4 | script_base=gentoo-chrootiez 5 | 6 | die() { echo "$script_name: ERROR: $@"; exit 1; } 7 | warn() { echo "$script_name: WARN: $@"; } 8 | info() { echo "$script_name: INFO: $@"; } 9 | 10 | [ $(id -u) = 0 ] || die "Sorry, I need root privileges to 'mount --bind' and 'chroot'" 11 | [ -n "$1" -a -n "$2" ] || die "usage: $0 <32 | 64 | as-is> [command to run]" 12 | 13 | chroot_name="$1"; shift 14 | chroot_bits="$1"; shift 15 | 16 | chroots_base=$(pwd) 17 | chroot_path=$chroots_base/$chroot_name 18 | 19 | mkdir -vp "$chroot_path"/bound 20 | 21 | cp /etc/resolv.conf "$chroot_path"/etc/resolv.conf 22 | cp /etc/hosts "$chroot_path"/etc/hosts 23 | cp /etc/localtime "$chroot_path"/etc/localtime 24 | cp "$chroots_base"/$script_base/scripts/run_from_chroot "$chroot_path"/run_from_chroot 25 | 26 | # unshare whole mount namespace 27 | mount --make-rprivate / 28 | 29 | # pass through our current (pseudo)terminal as current console 30 | touch "$chroot_path"/dev/console 31 | mount --bind "$(tty)" "$chroot_path"/dev/console 32 | 33 | # pass through other basic /dev/* as-is 34 | for f in full null random tty urandom zero; do 35 | touch "$chroot_path"/dev/"${f}" 36 | mount --bind /dev/"${f}" "$chroot_path"/dev/"${f}" 37 | done 38 | 39 | for d in "$chroots_base"/$script_base/bound/* 40 | do 41 | if [ -d "$d" ]; then 42 | base_d=$(basename "$d") 43 | dest_d=$chroot_path/bound/$base_d 44 | 45 | mkdir -p "$dest_d" 46 | mount --bind "$d" "$dest_d" 47 | fi 48 | done 49 | 50 | mkdir -vp "$chroot_path"/dev/pts 51 | mkdir -vp "$chroot_path"/dev/shm 52 | 53 | mount -t proc proc "$chroot_path"/proc 54 | mount -t sysfs sysfs "$chroot_path"/sys 55 | 56 | # See linux/Documentation/filesystems/devpts.txt on 57 | # semantics on /dev/pts in each mode. 58 | case "${CHROOTIEZ_DEVPTS}" in 59 | newinstance) 60 | mount -t devpts devpts -onewinstance,ptmxmode=0666,mode=620,gid=${CHROOTIEZ_DEVPTS_GID:-5} "$chroot_path"/dev/pts 61 | # don't use the default one 62 | rm "$chroot_path"/dev/ptmx 63 | ln -fs pts/ptmx "$chroot_path"/dev/ptmx 64 | ;; 65 | host) 66 | mount --bind /dev/pts "$chroot_path"/dev/pts 67 | if [ -L "$chroot_path"/dev/ptmx ]; then 68 | # restore from possible previous newinstance setup 69 | warn "restoring '$chroot_path/dev/ptmx' to defaults:" 70 | rm -v "$chroot_path"/dev/ptmx 71 | mknod -m666 "$chroot_path"/dev/ptmx c 5 2 72 | ls -l "$chroot_path"/dev/ptmx 73 | fi 74 | ;; 75 | none) 76 | ;; 77 | *) 78 | echo "CHROOTIEZ_DEVPTS has unknown '${CHROOTIEZ_DEVPTS}' value, assuming 'none'" 79 | ;; 80 | esac 81 | mount -t tmpfs tmpfs "$chroot_path"/dev/shm 82 | 83 | 84 | setarch_wrapper= 85 | case "$chroot_bits" in 86 | 32|64) setarch_wrapper=linux$chroot_bits ;; 87 | esac 88 | info "entering chroot ..." 89 | $setarch_wrapper chroot "$chroot_path" /run_from_chroot "$@" 90 | result=$? 91 | # for daemons you might like to use: 92 | #>$chroots_base/$chroot_name.log 2>&1 93 | info "... exited from chroot" 94 | 95 | for d in /dev/shm /dev/pts /sys /proc 96 | do 97 | umount $chroot_path"/$d" 98 | done 99 | 100 | # TODO: save actually mounted list and iterate thru 101 | # it in reverse order 102 | for d in "$chroots_base"/$script_base/bound/* 103 | do 104 | if [ -d "$d" ]; then 105 | base_d=$(basename "$d") 106 | dest_d=$chroot_path/bound/$base_d 107 | 108 | umount "$dest_d" 109 | fi 110 | done 111 | 112 | exit "${result}" 113 | --------------------------------------------------------------------------------