476 lines
14 KiB
Plaintext
Executable File
476 lines
14 KiB
Plaintext
Executable File
#!/bedrock/libexec/busybox sh
|
|
#
|
|
# init
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# version 2 as published by the Free Software Foundation.
|
|
#
|
|
# Copyright (c) 2014-2019 Daniel Thau <danthau@bedrocklinux.org>
|
|
#
|
|
# Bedrock Linux meta-init system
|
|
|
|
. /bedrock/share/common-code
|
|
# Remove typical runtime sanity checks, as crashing during init is going to
|
|
# just cause difficult to debug headaches for most users.
|
|
set +eu
|
|
trap '' EXIT
|
|
|
|
fatal_error() {
|
|
echo ""
|
|
printf "${color_alert}${*}${color_norm}\\n"
|
|
echo ""
|
|
echo "Starting emergency shell"
|
|
echo "Good luck"
|
|
echo ""
|
|
exec sh
|
|
}
|
|
|
|
setup_term() {
|
|
# Ensure plymouth is not running, as it will fight with us over control
|
|
# of the terminal.
|
|
/bedrock/libexec/plymouth-quit
|
|
|
|
# Plymouth will lock the terminal settings. This causes the following
|
|
# commands to fail if not unlocked.
|
|
/bedrock/libexec/manage_tty_lock unlock
|
|
|
|
# Ensure sane terminal settings. This is probably overkill.
|
|
reset
|
|
stty sane
|
|
stty cooked
|
|
reset
|
|
}
|
|
|
|
ensure_essential_environment() {
|
|
if ! [ -r /proc/mounts ] || ! grep -q "^\\w* /proc proc" /proc/mounts 2>&1 | head -n0; then
|
|
mkdir -p /proc
|
|
mount -t proc proc /proc
|
|
fi
|
|
mount -o remount,rw / 2>&1 | head -n0
|
|
if ! grep -q "^\\w* /sys sysfs" /proc/mounts; then
|
|
mkdir -p /sys
|
|
mount -t sysfs sysfs /sys
|
|
fi
|
|
if ! grep -q "^\\w* /dev devtmpfs" /proc/mounts; then
|
|
mkdir -p /dev
|
|
mount -t devtmpfs devtmpfs /dev
|
|
mdev -s
|
|
fi
|
|
if ! grep -q "^\\w* /dev/pts devpts" /proc/mounts; then
|
|
mkdir -p /dev/pts
|
|
mount -t devpts devpts /dev/pts
|
|
fi
|
|
if ! grep -q "^\\w* /run tmpfs" /proc/mounts; then
|
|
mkdir -p /run
|
|
mount -t tmpfs tmpfs /run
|
|
fi
|
|
|
|
# If the user runs a non-zstd-aware depmod with a zstd-based module
|
|
# set, it may clear modules.dep. If so, fix modules.dep.
|
|
if [ -e /lib/modules/$(uname -r)/modules.dep ] && \
|
|
[ "$(stat -c%s "/lib/modules/$(uname -r)/modules.dep")" -eq 0 ]; then
|
|
printf "Regenerating modules.dep... "
|
|
/sbin/depmod
|
|
echo "done"
|
|
fi
|
|
|
|
if ! grep -q "\\<fuse\\>" /proc/filesystems; then
|
|
/sbin/modprobe fuse
|
|
fi
|
|
|
|
if ! [ -e /dev/fuse ]; then
|
|
mkdir -p /dev
|
|
mknod -m 660 /dev/fuse c 10 229
|
|
fi
|
|
|
|
if ! grep -q "\\<binfmt_misc\\>" /proc/filesystems; then
|
|
/sbin/modprobe binfmt_misc >/dev/null 2>&1 || true
|
|
fi
|
|
|
|
# Systemd seems confused when an initrd-systemd launches Bedrock's init
|
|
# which launches userland-systemd. Kill /run/systemd to break the
|
|
# relationship so systemd thinks it is starting fresh.
|
|
if [ -d /run/systemd ]; then
|
|
rm -r /run/systemd
|
|
fi
|
|
|
|
# Some networking software make /etc/resolv.conf into a symlink. Other
|
|
# networking software seems confused by this. This can cause problems
|
|
# when switching init-providing strata (and thus their networking
|
|
# stacks) during a reboot. To avoid this, remove /etc/resolv.conf
|
|
# symlinks here. Network software should re-recreate this file as
|
|
# needed.
|
|
if [ -h /etc/resolv.conf ]; then
|
|
rm /etc/resolv.conf
|
|
fi
|
|
}
|
|
|
|
complete_hijack() {
|
|
step_init "6"
|
|
notice "Completing ${color_term}hijack install${color_norm}"
|
|
hijacked="$(deref hijacked)"
|
|
|
|
step "Moving ${color_strat}${hijacked}${color_norm} files to ${color_file}/bedrock/strata/${hijacked}${color_norm}"
|
|
mkdir -p "/bedrock/strata/${hijacked}"
|
|
set_attr "/bedrock/strata/${hijacked}" "stratum" "${hijacked}"
|
|
cd /
|
|
for item in *; do
|
|
case "${item}" in
|
|
"proc" | "sys" | "dev" | "run" | "boot" | bedrock*)
|
|
continue
|
|
;;
|
|
esac
|
|
mv "${item}" "/bedrock/strata/${hijacked}/${item}"
|
|
done
|
|
|
|
step "Moving ${color_strat}global${color_norm} items to ${color_file}/${color_norm}"
|
|
set_attr "/" "stratum" "bedrock"
|
|
for global in $(cfg_values "global" "share") $(cfg_values "global" "bind"); do
|
|
case "${global}" in
|
|
"/proc" | "/sys" | "/dev" | "/run" | "/boot" | /bedrock*)
|
|
continue
|
|
;;
|
|
esac
|
|
if [ -e "/bedrock/strata/${hijacked}${global}" ] ||
|
|
[ -h "/bedrock/strata/${hijacked}${global}" ]; then
|
|
mkdir -p "$(dirname "${global}")"
|
|
mv "/bedrock/strata/${hijacked}${global}" "${global}"
|
|
mkdir -p "/bedrock/strata/${hijacked}${global}"
|
|
else
|
|
mkdir -p "${global}"
|
|
fi
|
|
done
|
|
for global in $(cfg_values "global" "etc"); do
|
|
mkdir -p "$(dirname "/etc/${global}")"
|
|
if [ -e "/bedrock/strata/${hijacked}/etc/${global}" ] ||
|
|
[ -h "/bedrock/strata/${hijacked}/etc/${global}" ]; then
|
|
mv "/bedrock/strata/${hijacked}/etc/${global}" "/etc/${global}"
|
|
fi
|
|
done
|
|
|
|
step "Creating root files and directories"
|
|
for dir in /bin /dev /etc /lib/systemd /mnt /proc /root /run /sbin /sys /tmp /usr/bin /usr/sbin /usr/share/info /var; do
|
|
mkdir -p "${dir}"
|
|
done
|
|
ln -s ../bedrock/etc/bedrock-release /etc/bedrock-release
|
|
ln -s ../bedrock/etc/os-release /etc/os-release
|
|
ln -s /bedrock/libexec/kmod /sbin/depmod
|
|
ln -s /bedrock/libexec/kmod /sbin/insmod
|
|
ln -s /bedrock/libexec/kmod /sbin/lsmod
|
|
ln -s /bedrock/libexec/kmod /sbin/modinfo
|
|
ln -s /bedrock/libexec/kmod /sbin/modprobe
|
|
ln -s /bedrock/libexec/kmod /sbin/rmmod
|
|
ln -s /bedrock/strata/hijacked/usr/share/grub /usr/share/grub
|
|
/bedrock/libexec/busybox --install -s
|
|
touch /usr/share/info/.keepinfodir
|
|
mv "/bedrock/strata/${hijacked}/sbin/init" "/sbin/init"
|
|
|
|
step "Restoring ${color_term}hijacked${color_norm} init systems"
|
|
prefix="/bedrock/strata/${hijacked}"
|
|
for init in /bin/init /sbin/init /usr/bin/init /usr/sbin/init /lib/systemd/systemd /usr/lib/systemd/systemd; do
|
|
if [ -h "${prefix}${init}-bedrock-backup" ] || [ -e "${prefix}${init}-bedrock-backup" ]; then
|
|
mv "${prefix}${init}-bedrock-backup" "${prefix}${init}"
|
|
fi
|
|
done
|
|
|
|
step "Granting ${color_cmd}strat${color_norm} necessary capabilities"
|
|
/bedrock/libexec/setcap cap_sys_chroot=ep /bedrock/bin/strat
|
|
|
|
step "Completing ${color_term}hijack install${color_norm}"
|
|
rm /bedrock/complete-hijack-install
|
|
|
|
echo ""
|
|
}
|
|
|
|
complete_upgrade() {
|
|
# All crossfs builds prior to 0.7.8 became confused if bouncer changed
|
|
# out from under them. If upgrading such a version, bouncer was not
|
|
# upgraded in-place. Complete the upgrade now while crossfs is not
|
|
# running.
|
|
if [ -e /bedrock/libexec/bouncer-0.7.9 ]; then
|
|
mv /bedrock/libexec/bouncer-0.7.9 /bedrock/libexec/bouncer
|
|
fi
|
|
}
|
|
|
|
wait_for_keyboard() {
|
|
# Users with keyboards that take a while to initialize have reported
|
|
# surprise at the inability to type in the init selection menu.
|
|
# Vocally wait for a keyboard to be available to assuage these
|
|
# concerns.
|
|
|
|
for module in $(cfg_values "init" "modules"); do
|
|
/sbin/modprobe "${module}" 2>/dev/null
|
|
done
|
|
|
|
if /bedrock/libexec/keyboard_is_present; then
|
|
return
|
|
fi
|
|
|
|
printf "Waiting up to %s seconds for keyboard initialization..." "${init_timeout}"
|
|
start="$(date +%s)"
|
|
end="$((init_timeout + start))"
|
|
while [ "$(date +%s)" -lt "${end}" ] && ! /bedrock/libexec/keyboard_is_present; do
|
|
usleep 250000 # quarter second
|
|
done
|
|
|
|
printf "\r"
|
|
printf "Waiting up to %s seconds for keyboard initialization..." "${init_timeout}" | sed 's/./ /g'
|
|
printf "\r"
|
|
if ! /bedrock/libexec/keyboard_is_present; then
|
|
notice "${color_warn}WARNING: unable to detect keyboard${color_norm}"
|
|
fi
|
|
}
|
|
|
|
list_init_options() {
|
|
for stratum in $(list_strata); do
|
|
if [ "${stratum}" = "bedrock" ]; then
|
|
continue
|
|
fi
|
|
if ! has_attr "/bedrock/strata/${stratum}" "show_init"; then
|
|
continue
|
|
fi
|
|
for cmd in $(cfg_values "init" "paths"); do
|
|
sproc="/bedrock/strata/${stratum}/proc"
|
|
mkdir -p "${sproc}" 2>/dev/null || true
|
|
mount -t proc proc "${sproc}"
|
|
link="$(chroot "/bedrock/strata/${stratum}" "/proc/1/root/bedrock/libexec/busybox" realpath "${cmd}" 2>/dev/null)" || true
|
|
path="/bedrock/strata/${stratum}${link}"
|
|
if [ -n "${link:-}" ] && [ -x "${path}" ]; then
|
|
echo "${stratum} ${path} ${cmd} ${link}"
|
|
fi
|
|
umount "${sproc}"
|
|
done
|
|
done | awk '
|
|
{
|
|
if (!($2 in cmds)) {
|
|
cmds[$2] = $0
|
|
next
|
|
}
|
|
split($0, a)
|
|
if (a[3] == a[4] && $3 != $4) {
|
|
cmds[$2] = $0
|
|
}
|
|
}
|
|
END {
|
|
for (i in cmds) {
|
|
print cmds[i]
|
|
}
|
|
}
|
|
' | sort | uniq
|
|
}
|
|
|
|
pretty_print_options() {
|
|
i=0
|
|
IFS="
|
|
"
|
|
for option in $(list_init_options); do
|
|
i=$((i + 1))
|
|
stratum="$(echo "${option}" | cut -d" " -f1)"
|
|
path="$(echo "${option}" | cut -d" " -f2)"
|
|
cmd="$(echo "${option}" | cut -d" " -f3)"
|
|
link="$(echo "${option}" | cut -d" " -f4)"
|
|
if [ "${path}" = "${def_path}" ]; then
|
|
star="${color_glue}*${color_norm}"
|
|
else
|
|
star=" "
|
|
fi
|
|
if [ "${cmd}" != "${link}" ]; then
|
|
res="${color_glue} -> ${color_cmd}${link}"
|
|
else
|
|
res=""
|
|
fi
|
|
printf "${star}${color_sub}%2s${color_norm}. ${color_strat}${stratum}${color_glue}:${color_cmd}${cmd}${res}${color_norm}\\n" "${i}"
|
|
done
|
|
}
|
|
|
|
get_init_choice() {
|
|
echo "Select init number to use for this session" >&2
|
|
echo "See /bedrock/etc/bedrock.conf [init] to change default init and timeout" >&2
|
|
echo "" >&2
|
|
max="$(list_init_options | wc -l)"
|
|
|
|
wait_for_keyboard >&2
|
|
|
|
while true; do
|
|
pretty_print_options >&2
|
|
|
|
printf "\\nInit number: " >&2
|
|
|
|
if [ "${init_timeout}" -eq 0 ] && [ -n "${def_path}" ] && [ -x "${def_path}" ]; then
|
|
selected_num=0
|
|
elif [ "${init_timeout}" -gt 0 ] && [ -n "${def_path}" ] && [ -x "${def_path}" ]; then
|
|
printf "(${color_sub}${init_timeout}s${color_norm}): " >&2
|
|
read -r -t "${init_timeout}" selected_num
|
|
else
|
|
read -r selected_num
|
|
fi
|
|
if [ -z "${selected_num}" ]; then
|
|
selected_num=0
|
|
fi
|
|
if [ -n "${def_path}" ] && [ -x "${def_path}" ] && [ "${selected_num}" -eq 0 ]; then
|
|
echo "${def_stratum}:${def_cmd}"
|
|
return
|
|
elif echo "${selected_num}" | grep -q "[^0-9]"; then
|
|
true
|
|
elif [ "${selected_num}" -gt "${max}" ]; then
|
|
true
|
|
elif [ "${selected_num}" -gt 0 ]; then
|
|
list_init_options | awk -v"n=${selected_num}" 'NR==n {print $1":"$3}'
|
|
return
|
|
fi
|
|
printf "${color_alert}Unrecognized choice, try again.${color_norm}\\n" >&2
|
|
done
|
|
}
|
|
|
|
pivot() {
|
|
# Can only pivot_root with mount points. Ensure init_stratum root is a mount point.
|
|
mount --bind "/bedrock/strata/${init_stratum}" "/bedrock/strata/${init_stratum}"
|
|
# Ensure /bedrock is in the stratum so we can continue to utilize it post pivot
|
|
mkdir -p "/bedrock/strata/${init_stratum}/bedrock"
|
|
mount --bind "/bedrock" "/bedrock/strata/${init_stratum}/bedrock"
|
|
|
|
# Pivot
|
|
cd "/bedrock/strata/${init_stratum}"
|
|
pivot_root "." "bedrock/strata/${init_stratum}"
|
|
cd /
|
|
mount --move "/bedrock/strata/${init_stratum}" "/bedrock/strata/bedrock"
|
|
# `man 8 pivot_root` says to `chroot .` here, but in practice this was
|
|
# found to make mount points inaccessible, and no problems were found when
|
|
# skipping this step.
|
|
|
|
}
|
|
|
|
preenable() {
|
|
# Preemptively share key directories that are needed to enable
|
|
mkdir -p "/bedrock/strata/bedrock/proc"
|
|
mount --make-shared "/bedrock/strata/bedrock/proc"
|
|
mkdir -p "/proc"
|
|
mount --rbind "/bedrock/strata/bedrock/proc" "/proc"
|
|
|
|
mkdir -p "/bedrock/strata/bedrock/dev"
|
|
mount --make-shared "/bedrock/strata/bedrock/dev"
|
|
mkdir -p "/dev"
|
|
mount --rbind "/bedrock/strata/bedrock/dev" "/dev"
|
|
|
|
mkdir -p "/bedrock/strata/bedrock/sys"
|
|
mount --make-shared "/bedrock/strata/bedrock/sys"
|
|
mkdir -p "/sys"
|
|
mount --rbind "/bedrock/strata/bedrock/sys" "/sys"
|
|
|
|
mkdir -p "/bedrock/strata/bedrock/bedrock/run"
|
|
mount -t tmpfs bedrock_run "/bedrock/strata/bedrock/bedrock/run"
|
|
chmod go-w "/bedrock/strata/bedrock/bedrock"
|
|
chmod go-w "/bedrock/strata/bedrock/bedrock/run"
|
|
mkdir -p "/bedrock/run"
|
|
mount --rbind "/bedrock/strata/bedrock/bedrock/run" "/bedrock/run"
|
|
|
|
ensure_essential_environment
|
|
}
|
|
|
|
if [ "${$}" -ne 1 ]; then
|
|
exec "/sbin/init-bedrock-backup" "${@}"
|
|
fi
|
|
|
|
ensure_essential_environment
|
|
setup_term
|
|
clear
|
|
print_logo "$(cat /bedrock/etc/bedrock-release)"
|
|
|
|
if [ -e "/bedrock/complete-hijack-install" ]; then
|
|
complete_hijack
|
|
fi
|
|
|
|
complete_upgrade
|
|
|
|
init_timeout="$(cfg_values "init" "timeout")"
|
|
def_tuple="$(cfg_values "init" "default")"
|
|
def_stratum="$(deref "$(echo "${def_tuple}" | cut -d: -f1)")"
|
|
def_cmd="$(echo "${def_tuple}" | cut -d: -f2-)"
|
|
def_path=""
|
|
if [ -n "${def_tuple}" ] && [ -d "/bedrock/strata/${def_stratum}" ]; then
|
|
sproc="/bedrock/strata/${def_stratum}/proc"
|
|
mkdir -p "${sproc}" 2>/dev/null || true
|
|
mount -t proc proc "${sproc}"
|
|
if def_link="$(chroot "/bedrock/strata/${def_stratum}" "/proc/1/root/bedrock/libexec/busybox" realpath "${def_cmd}" 2>/dev/null)"; then
|
|
def_path="/bedrock/strata/${def_stratum}${def_link}"
|
|
fi
|
|
umount "${sproc}"
|
|
fi
|
|
if [ -n "${def_tuple}" ] && [ -z "${def_path:-}" ]; then
|
|
notice "${color_warn}WARNING: ${color_file}/bedrock/etc/bedrock.conf [init]/default ${color_warn}value does not describe a valid stratum:init pair.${color_norm}"
|
|
fi
|
|
if [ -z "${def_path:-}" ]; then
|
|
init_timeout="-1"
|
|
def_stratum=""
|
|
def_cmd=""
|
|
def_link=""
|
|
def_path=""
|
|
fi
|
|
|
|
if ! init_tuple="$(grep -q '\<bedrock_init=' /proc/cmdline && sed -e 's/^.*bedrock_init=//' -e 's/[ \t].*$//' /proc/cmdline)"; then
|
|
init_tuple="$(get_init_choice)"
|
|
fi
|
|
init_stratum="$(echo "${init_tuple}" | cut -d: -f1)"
|
|
init_cmd="$(echo "${init_tuple}" | cut -d: -f2-)"
|
|
|
|
echo ""
|
|
step_init "6"
|
|
|
|
step "Mounting ${color_file}fstab${color_norm}"
|
|
/bedrock/libexec/dmsetup mknodes
|
|
/bedrock/libexec/lvm vgscan --ignorelockingfailure
|
|
/bedrock/libexec/lvm vgchange -ay --ignorelockingfailure
|
|
mount -a
|
|
|
|
step "Pivoting to ${color_strat}${init_stratum}${color_norm}"
|
|
pivot
|
|
|
|
step "Preparing to enable"
|
|
preenable
|
|
|
|
step "Enabling ${color_term}strata${color_norm}"
|
|
|
|
notice "Enabling ${color_strat}bedrock${color_norm}"
|
|
# Cannot brl-enable bedrock or init stratum, and cannot brl-repair disabled
|
|
# strata. Thus, manually set up minimum required to mark strata as enabled
|
|
# then run brl-repair on bedrock and init strata.
|
|
mkdir -p /bedrock/strata/bedrock/bedrock/run/enabled_strata
|
|
touch /bedrock/strata/bedrock/bedrock/run/enabled_strata/bedrock
|
|
ln -s "/bedrock/strata/${init_stratum}" "/bedrock/strata/bedrock/bedrock/run/init-alias"
|
|
touch "/bedrock/strata/bedrock/bedrock/run/enabled_strata/${init_stratum}"
|
|
|
|
/bedrock/libexec/brl-repair --skip-crossfs "bedrock"
|
|
|
|
notice "Enabling ${color_strat}${init_stratum}${color_norm}"
|
|
/bedrock/libexec/brl-repair --skip-crossfs "${init_stratum}"
|
|
|
|
for stratum in $(list_strata); do
|
|
if is_bedrock "${stratum}" ||
|
|
is_init "${stratum}" ||
|
|
! has_attr "/bedrock/strata/${stratum}" "show_boot"; then
|
|
continue
|
|
fi
|
|
notice "Enabling ${color_strat}${stratum}${color_norm}"
|
|
/bedrock/libexec/brl-enable --skip-crossfs "${stratum}"
|
|
done
|
|
|
|
step "Applying configuration"
|
|
/bedrock/libexec/brl-apply --skip-repair
|
|
|
|
step "Handing control off to ${color_strat}${init_stratum}${color_glue}:${color_cmd}${init_cmd}${color_norm}"
|
|
|
|
if ! [ -x "${init_cmd}" ]; then
|
|
fatal_error "Specified (${init_cmd}) is not executable"
|
|
fi
|
|
|
|
# Shellcheck warns about `exec` usage. It is explicitly desired here.
|
|
#
|
|
# shellcheck disable=SC2093
|
|
exec "${init_cmd}" "${@}"
|
|
|
|
# We should never get here.
|
|
# If exec above succeeds, that takes over.
|
|
# If exec above fails, we get a kernel panic.
|
|
fatal_error "Unable to execute ${init_stratum}:${init_cmd}"
|