From 1f2ba1eff87d6329cca99d479ec8dec5c6badc7b Mon Sep 17 00:00:00 2001 From: Pete Anderson Date: Tue, 5 Jun 2018 17:57:02 -0400 Subject: [PATCH] add_resolve_conf: recursive host + target symlinks --- arch-chroot.in | 65 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/arch-chroot.in b/arch-chroot.in index bfb83a3..0f292e4 100644 --- a/arch-chroot.in +++ b/arch-chroot.in @@ -16,32 +16,51 @@ If 'command' is unspecified, ${0##*/} will launch /bin/bash. 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 -- 2.17.1