future-install-scripts/common

329 lines
8.4 KiB
Plaintext
Raw Normal View History

# generated from util-linux source: libmount/src/utils.c
declare -A pseudofs_types=([anon_inodefs]=1
[autofs]=1
[bdev]=1
2018-12-11 20:25:20 +08:00
[bpf]=1
[binfmt_misc]=1
[cgroup]=1
2017-06-29 20:22:09 +08:00
[cgroup2]=1
[configfs]=1
[cpuset]=1
[debugfs]=1
[devfs]=1
[devpts]=1
[devtmpfs]=1
[dlmfs]=1
2018-12-11 20:25:20 +08:00
[efivarfs]=1
[fuse.gvfs-fuse-daemon]=1
[fusectl]=1
[hugetlbfs]=1
[mqueue]=1
[nfsd]=1
[none]=1
[pipefs]=1
[proc]=1
[pstore]=1
[ramfs]=1
[rootfs]=1
[rpc_pipefs]=1
[securityfs]=1
[sockfs]=1
[spufs]=1
[sysfs]=1
[tmpfs]=1)
# generated from: pkgfile -vbr '/fsck\..+' | awk -F. '{ print $NF }' | sort
declare -A fsck_types=([cramfs]=1
[exfat]=1
[ext2]=1
[ext3]=1
[ext4]=1
[ext4dev]=1
[f2fs]=1
[jfs]=1
[minix]=1
[msdos]=1
[reiserfs]=1
[vfat]=1
[xfs]=1)
2012-06-18 03:17:10 +08:00
out() { printf "$1 $2\n" "${@:3}"; }
2012-06-26 10:33:38 +08:00
error() { out "==> ERROR:" "$@"; } >&2
warning() { out "==> WARNING:" "$@"; } >&2
2012-06-18 03:17:10 +08:00
msg() { out "==>" "$@"; }
msg2() { out " ->" "$@";}
die() { error "$@"; exit 1; }
ignore_error() {
"$@" 2>/dev/null
return 0
}
2012-06-18 03:17:10 +08:00
in_array() {
local i
for i in "${@:2}"; do
[[ $1 = "$i" ]] && return 0
2012-06-18 03:17:10 +08:00
done
return 1
2012-06-18 03:17:10 +08:00
}
chroot_add_mount() {
mount "$@" && CHROOT_ACTIVE_MOUNTS=("$2" "${CHROOT_ACTIVE_MOUNTS[@]}")
}
chroot_maybe_add_mount() {
local cond=$1; shift
if eval "$cond"; then
chroot_add_mount "$@"
fi
}
chroot_setup() {
CHROOT_ACTIVE_MOUNTS=()
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'chroot_teardown' EXIT
chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
chroot_add_mount sys "$1/sys" -t sysfs -o nosuid,noexec,nodev,ro &&
ignore_error chroot_maybe_add_mount "[[ -d '$1/sys/firmware/efi/efivars' ]]" \
efivarfs "$1/sys/firmware/efi/efivars" -t efivarfs -o nosuid,noexec,nodev &&
chroot_add_mount udev "$1/dev" -t devtmpfs -o mode=0755,nosuid &&
chroot_add_mount devpts "$1/dev/pts" -t devpts -o mode=0620,gid=5,nosuid,noexec &&
chroot_add_mount shm "$1/dev/shm" -t tmpfs -o mode=1777,nosuid,nodev &&
chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 &&
chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid
2012-06-18 03:17:10 +08:00
}
chroot_teardown() {
if (( ${#CHROOT_ACTIVE_MOUNTS[@]} )); then
umount "${CHROOT_ACTIVE_MOUNTS[@]}"
fi
unset CHROOT_ACTIVE_MOUNTS
2012-06-18 03:17:10 +08:00
}
Add unshare mode to pacstrap This adds an "unshare" mode to pacstrap. This mode lets a regular user create a new arch root filesystem. We use -N because both -U and -u are taken in pacstrap and arch-chroot, respectively. There are two major changes to pacstrap: we need to run many commands in under unshare, and the setup process for mounts is different. Because unshare starts a new shell, it is difficult to run many commands in sequence. To get around this, we create a function for the rest of the commands we wish to run, and then declare all functions and variables in the unshare'd shell. This is pretty convenient. An alternative method would be to generate the shell script as a HERE document, and pipe it to bash. Because unshare starts a new shell, we can only communicate using stdin/out and any command line arguments. And we need to defer some setup until after we are root. To get around this, we create a function for the rest of the commands we wish to run, and then declare all functions and variables in the unshare'd shell. I also considered having a separate helper script which would contain the contents of pacstrap(). But I think this would be confusing, because the logic would then live in a separate file (instead of just a separate function). That method is also tricky because every variable has to be passed in through the command-line arguments. One last method would be to generate a script on the fly (e.g. using a HERE doc). I think that method could work as well. The primary difference to the setup process is that we need to mount filesystems in a different manner: - We bind-mount the root directory. This is so commands which want to determine how much free space there is (or otherwise work with mounts) expect a mount on /. We unmount it with --lazy, since otherwise sys will cause an error (see below). - proc can be mounted multiple times and is mounted in the same way - sys cannot be mounted again, but we can recursively bind-mount it. When mounted this way, we can't unmount it until the mount namespace is deleted (likely because sys has a number of sub-mounts), so we have to use --lazy when unmounting it. - dev can be bind-mounted, but this results in errors because some packages try and modify files in /dev if they exist. Since we don't have permission to do that on the host system, this fails. Instead, we just bind-mount a minimal set of files. - run is not bind-mounted, but is instead created as a new tmpfs. According to aea51ba ("Bind mount /run from host into new root"), the reason this was done was to avoid lengthy timeouts when scanning for lvm devices. Because unshare does not (and cannot) use lvm devices, we don't need to bind-mount. - tmp is created as usual. Closes: #8
2021-10-18 05:13:31 +08:00
chroot_add_mount_lazy() {
mount "$@" && CHROOT_ACTIVE_LAZY=("$2" "${CHROOT_ACTIVE_LAZY[@]}")
}
chroot_bind_device() {
touch "$2" && CHROOT_ACTIVE_FILES=("$2" "${CHROOT_ACTIVE_FILES[@]}")
chroot_add_mount $1 "$2" --bind
}
chroot_add_link() {
ln -sf "$1" "$2" && CHROOT_ACTIVE_FILES=("$2" "${CHROOT_ACTIVE_FILES[@]}")
}
unshare_setup() {
CHROOT_ACTIVE_MOUNTS=()
CHROOT_ACTIVE_LAZY=()
CHROOT_ACTIVE_FILES=()
[[ $(trap -p EXIT) ]] && die '(BUG): attempting to overwrite existing EXIT trap'
trap 'unshare_teardown' EXIT
chroot_add_mount_lazy "$1" "$1" --bind &&
chroot_add_mount proc "$1/proc" -t proc -o nosuid,noexec,nodev &&
chroot_add_mount_lazy /sys "$1/sys" --rbind &&
chroot_add_link "$1/proc/self/fd" "$1/dev/fd" &&
chroot_add_link "$1/proc/self/fd/0" "$1/dev/stdin" &&
chroot_add_link "$1/proc/self/fd/1" "$1/dev/stdout" &&
chroot_add_link "$1/proc/self/fd/2" "$1/dev/stderr" &&
chroot_bind_device /dev/full "$1/dev/full" &&
chroot_bind_device /dev/null "$1/dev/null" &&
chroot_bind_device /dev/random "$1/dev/random" &&
chroot_bind_device /dev/tty "$1/dev/tty" &&
chroot_bind_device /dev/urandom "$1/dev/urandom" &&
chroot_bind_device /dev/zero "$1/dev/zero" &&
chroot_add_mount run "$1/run" -t tmpfs -o nosuid,nodev,mode=0755 &&
chroot_add_mount tmp "$1/tmp" -t tmpfs -o mode=1777,strictatime,nodev,nosuid
}
unshare_teardown() {
chroot_teardown
if (( ${#CHROOT_ACTIVE_LAZY[@]} )); then
umount --lazy "${CHROOT_ACTIVE_LAZY[@]}"
fi
unset CHROOT_ACTIVE_LAZY
if (( ${#CHROOT_ACTIVE_FILES[@]} )); then
rm "${CHROOT_ACTIVE_FILES[@]}"
fi
unset CHROOT_ACTIVE_FILES
}
root_unshare="unshare --fork --pid"
user_unshare="$root_unshare --mount --map-auto --map-root-user --setuid 0 --setgid 0"
# This outputs code for declaring all variables to stdout. For example, if
# FOO=BAR, then running
# declare -p FOO
# will result in the output
# declare -- FOO="bar"
# This function may be used to re-declare all currently used variables and
# functions in a new shell.
declare_all() {
# Remove read-only variables to avoid warnings. Unfortunately, declare +r -p
# doesn't work like it looks like it should (declaring only read-write
# variables). However, declare -rp will print out read-only variables, which
# we can then use to remove those definitions.
declare -p | grep -Fvf <(declare -rp)
# Then declare functions
declare -pf
}
try_cast() (
_=$(( $1#$2 ))
) 2>/dev/null
valid_number_of_base() {
local base=$1 len=${#2} i=
for (( i = 0; i < len; i++ )); do
try_cast "$base" "${2:i:1}" || return 1
done
return 0
}
mangle() {
local i= chr= out=
local {a..f}= {A..F}=
for (( i = 0; i < ${#1}; i++ )); do
chr=${1:i:1}
case $chr in
[[:space:]\\])
printf -v chr '%03o' "'$chr"
out+=\\
;;
esac
2013-12-08 04:12:40 +08:00
out+=$chr
done
printf '%s' "$out"
}
unmangle() {
local i= chr= out= len=$(( ${#1} - 4 ))
local {a..f}= {A..F}=
for (( i = 0; i < len; i++ )); do
chr=${1:i:1}
case $chr in
\\)
if valid_number_of_base 8 "${1:i+1:3}" ||
valid_number_of_base 16 "${1:i+1:3}"; then
printf -v chr '%b' "${1:i:4}"
(( i += 3 ))
fi
2013-12-08 04:12:40 +08:00
;;
esac
2013-12-08 04:12:40 +08:00
out+=$chr
done
printf '%s' "$out${1:i}"
}
optstring_match_option() {
local candidate pat patterns
IFS=, read -ra patterns <<<"$1"
for pat in "${patterns[@]}"; do
if [[ $pat = *=* ]]; then
# "key=val" will only ever match "key=val"
candidate=$2
else
# "key" will match "key", but also "key=anyval"
candidate=${2%%=*}
fi
[[ $pat = "$candidate" ]] && return 0
done
return 1
}
optstring_remove_option() {
local o options_ remove=$2 IFS=,
read -ra options_ <<<"${!1}"
for o in "${!options_[@]}"; do
optstring_match_option "$remove" "${options_[o]}" && unset 'options_[o]'
done
declare -g "$1=${options_[*]}"
}
optstring_normalize() {
local o options_ norm IFS=,
read -ra options_ <<<"${!1}"
# remove empty fields
for o in "${options_[@]}"; do
[[ $o ]] && norm+=("$o")
done
# avoid empty strings, reset to "defaults"
declare -g "$1=${norm[*]:-defaults}"
}
optstring_append_option() {
if ! optstring_has_option "$1" "$2"; then
declare -g "$1=${!1},$2"
fi
optstring_normalize "$1"
}
optstring_prepend_option() {
local options_=$1
if ! optstring_has_option "$1" "$2"; then
declare -g "$1=$2,${!1}"
fi
optstring_normalize "$1"
}
optstring_get_option() {
local opts o
IFS=, read -ra opts <<<"${!1}"
for o in "${opts[@]}"; do
if optstring_match_option "$2" "$o"; then
declare -g "$o"
return 0
fi
done
return 1
}
optstring_has_option() {
local "${2%%=*}"
optstring_get_option "$1" "$2"
}
dm_name_for_devnode() {
read dm_name <"/sys/class/block/${1#/dev/}/dm/name"
if [[ $dm_name ]]; then
printf '/dev/mapper/%s' "$dm_name"
else
# don't leave the caller hanging, just print the original name
# along with the failure.
error 'Failed to resolve device mapper name for: %s' "$1"
fi
}
2012-06-18 03:17:10 +08:00
fstype_is_pseudofs() {
2012-12-17 01:35:38 +08:00
(( pseudofs_types["$1"] ))
2012-06-18 03:17:10 +08:00
}
fstype_has_fsck() {
(( fsck_types["$1"] ))
}