#!/bin/sh # # enter-chroot - Bind mount and chroot into installed system # rawnix.org - https://rawnix.org # # Usage: enter-chroot # enter-chroot /mnt set -e die() { echo "ERROR: $*" >&2; exit 1; } [ "$(id -u)" = 0 ] || die "Must root" [ -n "$1" ] || die "Usage: enter-chroot " [ -d "$1" ] || die "Directory not found: $1" MNT="${1%/}" [ -n "$MNT" ] || MNT="/" mountpoint -q "$MNT" || die "$MNT is not mounted" [ -x "$MNT/bin/bash" ] || die "No /bin/bash in $MNT — install the core group first" # ── Unmount on the way out ──────────────────────────────────── # Also on failure. Without a trap, a mount that fails partway # through the list leaves the earlier ones in place and $MNT busy, # with nothing to tell you which ones they were. cleanup() { umount "$MNT/sys/firmware/efi/efivars" 2>/dev/null || true umount "$MNT/dev/pts" 2>/dev/null || true umount "$MNT/dev/shm" 2>/dev/null || true umount "$MNT/sys" 2>/dev/null || true umount "$MNT/proc" 2>/dev/null || true umount "$MNT/run" 2>/dev/null || true umount "$MNT/tmp" 2>/dev/null || true umount "$MNT/dev" 2>/dev/null || true return 0 } trap cleanup EXIT INT TERM echo ">>> Mounting virtual filesystems..." mount --bind /dev "$MNT/dev" mount --bind /tmp "$MNT/tmp" mount --bind /run "$MNT/run" mount -t proc proc "$MNT/proc" mount -t sysfs none "$MNT/sys" mount -t devpts devpts "$MNT/dev/pts" -o noexec,nosuid,gid=tty,mode=0620 # `mount --bind` is not recursive, so /dev/shm does not come along # with /dev and anything using POSIX shared memory inside the # chroot fails with ENOENT. Mount it explicitly rather than # switching to --rbind, which would also drag in the host's devpts # and fight the line above. mount -t tmpfs -o mode=1777,nosuid,nodev tmpfs "$MNT/dev/shm" if [ -d /sys/firmware/efi ]; then if mount -t efivarfs efivarfs "$MNT/sys/firmware/efi/efivars" 2>/dev/null; then echo " + efivars" else echo " ! efivarfs unavailable - efibootmgr will not work" >&2 fi fi echo ">>> Entering chroot..." echo "" # -l, so /etc/profile is read. A non-login bash sources ~/.bashrc # and nothing else, which means PATH, PKG_CONFIG_PATH and the rest # of the target's /etc/profile do not apply and you silently get # the installer's environment instead of the installed system's. chroot "$MNT" /bin/bash -l echo "" echo ">>> Exited chroot. Unmounting..." cleanup trap - EXIT INT TERM echo ">>> Done."