]> git.wh0rd.org - home.git/commitdiff
custom-chroot: overhaul to clean up and add read-only chroot support
authorMike Frysinger <vapier@gentoo.org>
Sun, 7 Apr 2013 21:40:44 +0000 (17:40 -0400)
committerMike Frysinger <vapier@gentoo.org>
Sun, 7 Apr 2013 21:40:44 +0000 (17:40 -0400)
.bin/custom-chroot

index 878a8ff813a47c7d83790adacbac6de9d3cd4aba..a32a75fbe349acd83703f23754abdaa1cc6214b7 100755 (executable)
 #!/bin/bash -e
 
-[[ -w / ]] || exec sudo env HOME="$HOME" "$0" "$@"
+bootstrap() {
+       [[ -w / ]] || 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
+                       UNSHARE=true exec unshare -m -- "$0" "$@"
+               fi
+       else
+               mount_args='-n'
        fi
-else
-       mount_args='-n'
-fi
-unset UNSHARE
-
-mounts="proc sys tmp dev dev/pts usr/portage usr/portage/distfiles usr/local/src"
-
-chroot=${0%/*}
-case ${chroot} in
-       .) chroot=${PWD} ;;
-       ./*) chroot=${PWD}/${chroot#./} ;;
-esac
-cd "${chroot}"
-
-do_umount() {
-       local m 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 ;;
-       -m) mounts+=" $2"; shift ;;
-       -*) echo "unknown option $1"; exit 1 ;;
-       *)  break ;;
-       esac
-       shift
-done
-
 maybe_mount() {
        local src=/$1 dst=${chroot}/${2:-$1}
        [[ -d ${src} ]] || return 0
-       mkdir -p "${dst}"
+       if ! mkdir -p "${dst}" ; then
+               [[ -w ${chroot} ]] && exit 1 || return 0
+       fi
        grep -sq "${dst}" /proc/mounts || 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*) echo ppc;;
+       *64-bit*PowerPC*) echo ppc64;;
+       *32-bit*S/390*)   echo s390;;
+       *64-bit*S/390*)   echo s390x;;
        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
+               rm -f etc/mtab
+               ln -sf /proc/mounts etc/mtab
+       fi
+       local f
+       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
+               cp "${HOME}/${f}" "root/${f}"
+       done
+}
+
+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 <path>   Add path to mount list
+         -d <dir>    Use <dir> as chroot (defaults to ${0%/*})
+         -h          This help screen
+       EOF
+       exit
+}
+
+main() {
+       bootstrap "$@"
+
+       local mounts=( proc sys tmp dev dev/pts usr/portage usr/portage/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 ;;
+               -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
+
+       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
-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}" \
-       "$@"
+
+       unset LS_COLORS # format changes over time
+       [[ $# -eq 0 ]] && set -- env HOME=/root /bin/bash -l
+       exec \
+               ${setarch} \
+               chroot "${chroot}" \
+               "$@"
+}
+
+main "$@"