diff options
| author | 2022-07-05 01:31:24 -0400 | |
|---|---|---|
| committer | 2022-07-05 01:31:24 -0400 | |
| commit | 22faa4b00068fc50c66614c4e4812273aa231d55 (patch) | |
| tree | e881c40b156e2e1c6d5c3bca72908c9b38277f64 /arch-chroot.in | |
| parent | f922fa446f9893e571bf038c5e2d2520837c9814 (diff) | |
New upstream version 25.upstream/25
Diffstat (limited to 'arch-chroot.in')
| -rw-r--r-- | arch-chroot.in | 103 |
1 files changed, 68 insertions, 35 deletions
diff --git a/arch-chroot.in b/arch-chroot.in index fd6140e..bcb38df 100644 --- a/arch-chroot.in +++ b/arch-chroot.in @@ -4,11 +4,15 @@ shopt -s extglob m4_include(common) +setup=chroot_setup +unshare="$root_unshare" + usage() { cat <<EOF -usage: ${0##*/} chroot-dir [command] +usage: ${0##*/} chroot-dir [command] [arguments...] -h Print this help message + -N Run in unshare mode as a regular user -u <user>[:group] Specify non-root user and optional group to use If 'command' is unspecified, ${0##*/} will launch /bin/bash. @@ -23,40 +27,63 @@ itself to make it a mountpoint, i.e. 'mount --bind /your/chroot /your/chroot'. EOF } +resolve_link() { + local target=$1 + local root=$2 + + # If a root was given, make sure it ends in a slash. + [[ -n $root && $root != */ ]] && root=$root/ + + while [[ -L $target ]]; do + target=$(readlink -m "$target") + # If a root was given, make sure the target is under it. + # Make sure to strip any leading slash from target first. + [[ -n $root && $target != $root* ]] && target=$root${target#/} + done + + printf %s "$target" +} + chroot_add_resolv_conf() { - local chrootdir=$1 resolv_conf=$1/etc/resolv.conf - - [[ -e /etc/resolv.conf ]] || return 0 - - # Handle resolv.conf as a symlink to somewhere else. - if [[ -L $chrootdir/etc/resolv.conf ]]; then - # readlink(1) should always give us *something* since we know at this point - # it's a symlink. For simplicity, ignore the case of nested symlinks. - resolv_conf=$(readlink "$chrootdir/etc/resolv.conf") - if [[ $resolv_conf = /* ]]; then - resolv_conf=$chrootdir$resolv_conf - else - resolv_conf=$chrootdir/etc/$resolv_conf - fi - - # ensure file exists to bind mount over - if [[ ! -f $resolv_conf ]]; then - install -Dm644 /dev/null "$resolv_conf" || return 1 - fi - elif [[ ! -e $chrootdir/etc/resolv.conf ]]; then - # The chroot might not have a resolv.conf. - return 0 + local chrootdir=$1 + local src=$(resolve_link /etc/resolv.conf) + local dest=$(resolve_link "$chrootdir/etc/resolv.conf" "$chrootdir") + + # If we don't have a source resolv.conf file, there's nothing useful we can do. + [[ -e $src ]] || return 0 + + if [[ ! -e $dest ]]; then + # There are two reasons the destination might not exist: + # + # 1. There may be no resolv.conf in the chroot. In this case, $dest won't exist, + # and it will be equal to $1/etc/resolv.conf. In this case, we'll just exit. + # The chroot environment must not be concerned with DNS resolution. + # + # 2. $1/etc/resolv.conf is (or resolves to) a broken link. The environment + # clearly intends to handle DNS resolution, but something's wrong. Maybe it + # normally creates the target at boot time. We'll (try to) take care of it by + # creating a dummy file at the target, so that we have something to bind to. + + # Case 1. + [[ $dest = $chrootdir/etc/resolv.conf ]] && return 0 + + # Case 2. + install -Dm644 /dev/null "$dest" || return 1 fi - chroot_add_mount /etc/resolv.conf "$resolv_conf" --bind + chroot_add_mount "$src" "$dest" --bind } -while getopts ':hu:' flag; do +while getopts ':hNu:' flag; do case $flag in h) usage exit 0 ;; + N) + setup=unshare_setup + unshare="$user_unshare" + ;; u) userspec=$OPTARG ;; @@ -70,21 +97,27 @@ while getopts ':hu:' flag; do done shift $(( OPTIND - 1 )) -(( EUID == 0 )) || die 'This script must be run with root privileges' (( $# )) || die 'No chroot directory specified' chrootdir=$1 shift -[[ -d $chrootdir ]] || die "Can't create chroot on non-directory %s" "$chrootdir" +arch-chroot() { + (( EUID == 0 )) || die 'This script must be run with root privileges' + + [[ -d $chrootdir ]] || die "Can't create chroot on non-directory %s" "$chrootdir" -if ! mountpoint -q "$chrootdir"; then - warning "$chrootdir is not a mountpoint. This may have undesirable side effects." -fi + $setup "$chrootdir" || die "failed to setup chroot %s" "$chrootdir" + chroot_add_resolv_conf "$chrootdir" || die "failed to setup resolv.conf" -chroot_setup "$chrootdir" || die "failed to setup chroot %s" "$chrootdir" -chroot_add_resolv_conf "$chrootdir" || die "failed to setup resolv.conf" + if ! mountpoint -q "$chrootdir"; then + warning "$chrootdir is not a mountpoint. This may have undesirable side effects." + fi -chroot_args=() -[[ $userspec ]] && chroot_args+=(--userspec "$userspec") + chroot_args=() + [[ $userspec ]] && chroot_args+=(--userspec "$userspec") + + SHELL=/bin/bash chroot "${chroot_args[@]}" -- "$chrootdir" "${args[@]}" +} -SHELL=/bin/bash unshare --fork --pid chroot "${chroot_args[@]}" -- "$chrootdir" "$@" +args=("$@") +$unshare bash -c "$(declare_all); arch-chroot" |
