X-Git-Url: https://git.wh0rd.org/?a=blobdiff_plain;f=.bin%2Fcustom-chroot;h=08d76ada03bfa4aedf7429ab16893cb924858bdd;hb=8c29b1d8acfc9935f148a486227c8d2fdb05df37;hp=7c576bb0109d991863791249022402c655c458c0;hpb=f2ff891e6eb173ea0ffc4fed185af8ca1b2e15bd;p=home.git diff --git a/.bin/custom-chroot b/.bin/custom-chroot index 7c576bb..08d76ad 100755 --- a/.bin/custom-chroot +++ b/.bin/custom-chroot @@ -1,100 +1,181 @@ #!/bin/bash -e -[[ -w / ]] || exec sudo env HOME="$HOME" "$0" "$@" +bootstrap() { + [[ $(id -u) -eq 0 ]] || exec sudo env -uUNSHARE HOME="$HOME" "$0" "$@" -if [[ -z ${UNSHARE} ]] ; then - mount_args= - if type -P unshare >&/dev/null ; then - UNSHARE=true exec unshare -m -- "$0" "$@" + if [[ -z ${UNSHARE} ]] ; then + mount_args= + if type -P unshare >&/dev/null ; then + test_arg() { unshare "$@" -- true >&/dev/null && uargs+=( "$@" ) || :; } + uargs=( -m ) + test_arg -u + test_arg -i + test_arg -p -f --mount-proc + test_arg --propagation=private + UNSHARE=true exec unshare "${uargs[@]}" -- "$0" "$@" + fi + else + mount_args='-n' fi -else - mount_args='-n' -fi -unset UNSHARE - -mounts="proc sys dev dev/pts usr/portage usr/portage/distfiles" - -chroot=${0%/*} -case ${chroot} in - .) chroot=${PWD} ;; - ./*) chroot=${PWD}/${chroot#./} ;; -esac -cd "${chroot}" - -do_umount() { - mounts=$(mount | grep ${chroot} | awk '{print $3}' | tac) - for m in ${mounts} ; do - echo "unmounting $m" - umount $m - done - if [[ -z ${mounts} ]] ; then - echo "nothing mounted in ${chroot}" - fi - exit 0 + unset UNSHARE } -while [[ -n $1 ]] ; do - case $1 in - -u) do_umount ;; - -*) echo "unknown option $1"; exit 1 ;; - *) break ;; - esac -done +is_mounted() { + local dst=$1 + grep -sq "${dst}" /proc/mounts +} maybe_mount() { local src=/$1 dst=${chroot}/${2:-$1} [[ -d ${src} ]] || return 0 - mkdir -p "${dst}" - grep -sq "${dst}" /proc/mounts || mount ${mount_args} --bind "${src}" "${dst}" + if ! mkdir -p "${dst}" ; then + [[ -w ${chroot} ]] && exit 1 || return 0 + fi + is_mounted "${dst}" || mount ${mount_args} --bind "${src}" "${dst}" } -for m in ${mounts} ; do - maybe_mount ${m} -done get_type() { case $(file "$1") in - *x86-64*) echo x86_64;; - *"Intel 80386"*) echo i386;; - *32-bit*PowerPC*) echo ppc;; - *64-bit*PowerPC*) echo ppc64;; + *x86-64*) echo x86_64;; + *"Intel 80386"*) echo i386;; + *32-bit*PowerPC*MSB*) echo ppc;; + *64-bit*PowerPC*MSB*) echo ppc64;; + *32-bit*PowerPC*LSB*) echo ppcle;; + *64-bit*PowerPC*LSB*) echo ppc64le;; + *32-bit*S/390*) echo s390;; + *64-bit*S/390*) echo s390x;; + *64-bit*MIPS*) echo mips64;; + *32-bit*MIPS*N32*) echo mips64;; + *32-bit*MIPS*) echo mips;; + *32-bit*PA-RISC*) echo parisc;; + *64-bit*PA-RISC*) echo parisc64;; + *32-bit*SPARC*) echo sparc;; + *64-bit*SPARC*) echo sparc64;; esac } -bin_dst=$(get_type bin/bash) -setarch= -if [[ -n ${bin_dst} ]] && type -P setarch &>/dev/null ; then - setarch="setarch ${bin_dst}" -fi - -if [[ ! -L etc/mtab ]] ; then - rm -f etc/mtab - ln -sf /proc/mounts etc/mtab -fi -etc=" - hosts - locale.gen - localtime - resolv.conf -" -home=" - .inputrc - .gdbinit - .gitconfig - .nanorc -" -for f in \ - $(printf 'etc/%s ' ${etc}) \ -; do - if [ -e "/${f}" ] ; then - cp /${f} ${f} + +init_chroot() { + [[ -w . ]] || return 0 + + if [[ ! -L etc/mtab ]] ; then + ln -sfT /proc/mounts etc/mtab + fi + local f dst + local etc=( + hosts + locale.gen + localtime + resolv.conf + ) + local home=( + .inputrc + .gdbinit + .gitconfig + .nanorc + ) + for f in \ + $(printf 'etc/%s ' "${etc[@]}") \ + ; do + if [[ -e /${f} ]] ; then + cp "/${f}" "${f}" + fi + done + for f in "${home[@]}" ; do + df="root/${f}" + f="${HOME}/${f}" + if [[ -e ${f} ]] ; then + cp "${f}" "${df}" + fi + done + + if [[ ! -d root/.git ]] ; then + f="${HOME}/.profile.d/aliases.sh" + if [[ -e ${f} ]] ; then + cat "${f}" > root/.bash_profile + fi fi -done -for f in ${home} ; do - cp ~/${f} root/${f} -done - -unset LS_COLORS # format changes over time -[[ $# -eq 0 ]] && set -- env HOME=/root /bin/bash -l -exec \ - ${setarch} \ - chroot "${chroot}" \ - "$@" +} + +usage() { + cat <<-EOF + Usage: ${0##*/} [options] [program to run] + + Sets up common mount points and then chroots in and runs a program. + If no program is specified, then launch a login shell. + + Options: + -u Unmount all paths in the chroot + -m Add path to mount list + -d Use as chroot (defaults to ${0%/*}) + -h This help screen + EOF + exit +} + +main() { + bootstrap "$@" + + local mounts=( + proc sys tmp dev dev/shm run + usr/portage usr/portage/distfiles + var/db/repos/gentoo var/cache/distfiles + usr/local/src + ) + + local chroot=${0%/*} + case ${chroot} in + .) chroot=${PWD} ;; + ./*) chroot=${PWD}/${chroot#./} ;; + esac + + local cmd + while [[ -n $1 ]] ; do + case $1 in + -u) cmd='umount' ;; + -m) mounts+=( "$2" ); shift ;; + -d) chroot=$(realpath "$2"); shift ;; + --help|-h) usage ;; + -*) echo "${0##*/}: unknown option $1"; exit 1 ;; + *) break ;; + esac + shift + done + cd "${chroot}" + + case ${cmd} in + umount) exec "${0%/*}/umount-tree" -y "${chroot}" ;; + esac + + local m + for m in "${mounts[@]}" ; do + maybe_mount "${m}" + done + # Handle special mounts that we don't want to just bind mount. + if ! is_mounted "${chroot}/dev/pts" ; then + # Option order matters: on older kernels that don't recognize newinstance, + # parsing stops as soon as it hits that. + mount -t devpts devpts "${chroot}/dev/pts" \ + -o nosuid,noexec,mode=0620,gid=5,ptmxmode=0666,newinstance + fi + + init_chroot + + local setarch + if type -P setarch &>/dev/null ; then + local bin_dst=$(get_type bin/bash) + if [[ -n ${bin_dst} ]] ; then + setarch="setarch ${bin_dst}" + fi + fi + + # Doubtful these settings we want to leak into the chroot. + unset ROOT PORTAGE_CONFIGROOT LD_LIBRARY_PATH + unset LS_COLORS # format changes over time + [[ $# -eq 0 ]] && set -- env HOME=/root /bin/bash -l + exec \ + ${setarch} \ + chroot "${chroot}" \ + "$@" +} + +main "$@"