aboutsummaryrefslogtreecommitdiffstats
path: root/arch-chroot.in
diff options
context:
space:
mode:
Diffstat (limited to 'arch-chroot.in')
-rw-r--r--arch-chroot.in103
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"