From e3f9cb6498d01082d19c193e29c70f4d897c7848 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Tue, 20 Dec 2022 16:45:17 +0800 Subject: [PATCH] arch-chroot: move resolve_link and chroot_add_resolv_link to common chroot_add_resolve_link is cleaned up to be simpler. (We shouldn't need the complex symlink handling logic for target) --- arch-chroot.in | 47 ---------------------------------------- common | 58 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 48 deletions(-) diff --git a/arch-chroot.in b/arch-chroot.in index 6b9039a..2d5fd14 100644 --- a/arch-chroot.in +++ b/arch-chroot.in @@ -30,53 +30,6 @@ itself to make it one, i.e. 'mount --bind chroot_dir chroot_dir'. 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 - 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 "$src" "$dest" --bind -} - if [[ -z $1 || $1 = @(-h|--help) ]]; then usage exit $(( $# ? 0 : 1 )) diff --git a/common b/common index c123c43..13f86cd 100644 --- a/common +++ b/common @@ -103,6 +103,35 @@ rev_array() { mapfile -t _arr < <(printf '%s\n' "${_arr[@]}" | tac) } +resolve_link() { + local link="$1" root="$2" target + + if [[ ! $root ]]; then + target="$(realpath -eq "$link")" + else + # This is tricky to do. We read from $link in a loop + # and prepend it with $root if it's not under it. + # This can't handle e.g. $root is /mnt and $link + # is /mnt/1 pointing to /mnt/2, which should actually + # be /mnt/mnt/2. Luckily these edge cases shouldn't + # bother most of the time. + + root="$(realpath -e "$root")" + target="$link" + while [[ -L "$target" ]]; do + target="$(readlink -m "$target")" + if [[ "$target" != "$root"/* ]]; then + target="$root/${target#/}" + fi + done + + # Normalize the path and make sure the resolved target exists + target="$(realpath -eq "$target")" + fi + + printf '%s' "$target" +} + chroot_add_mount() { mount "$@" && CHROOT_ACTIVE_MOUNTS+=("$2") } @@ -128,6 +157,27 @@ chroot_add_link() { ln -sf "$1" "$2" && CHROOT_ACTIVE_FILES+=("$2") } +chroot_add_resolv_conf() { + local src="$(resolve_link /etc/resolv.conf)" dest="$1/etc/resolv.conf" + + # If we don't have a source resolv.conf file, there's nothing useful we can do. + if [[ ! -f "$src" ]]; then + warning 'Cannot find a usable resolv.conf. DNS requests might fail in chroot' + return 0 + fi + + # If resolv.conf in the chroot is a symlink, we make a backup of it + # and create a plain file so we can bind mount to it. + # The backup is restore during chroot_teardown(). + + if [[ -L "$dest" ]]; then + mv "$dest" "$dest.orig" + fi + touch -a "$dest" + + chroot_add_mount "$src" "$dest" --bind +} + chroot_setup() { CHROOT_ACTIVE_MOUNTS=() [[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap' @@ -145,11 +195,17 @@ chroot_setup() { } chroot_teardown() { + local root="$1" + if (( ${#CHROOT_ACTIVE_MOUNTS[@]} )); then rev_array CHROOT_ACTIVE_MOUNTS umount "${CHROOT_ACTIVE_MOUNTS[@]}" fi unset CHROOT_ACTIVE_MOUNTS + + if [[ -L "$root"/etc/resolv.conf.orig ]]; then + mv "$root"/etc/resolv.conf.orig "$root"/etc/resolv.conf + fi } unshare_setup() { @@ -175,7 +231,7 @@ unshare_setup() { } unshare_teardown() { - chroot_teardown + chroot_teardown "$1" if (( ${#CHROOT_ACTIVE_LAZY[@]} )); then rev_array CHROOT_ACTIVE_LAZY