#!/bin/sh -ef # # tiny init # # word splitting is safe by design # shellcheck disable=2068,2046,2086 # # false positive # shellcheck disable=2154,2163,1091 print() { printf "%b %s\n" "${2:-\033[1;37m>>\033[m}" "$1" shell } panic() { print "$1" "\033[1;31m!!\033[m" >&2 shell } shell() { # see https://busybox.net/FAQ.html#job_control setsid sh -c "exec sh <> /dev/${console:-tty1} 2>&1" || sh } findfs() { value=0; device= case "${1%%=*}" in /dev/*) device="$1" ;; UUID) device="/dev/disk/by-uuid/${1##*=}" ;; LABEL) device="/dev/disk/by-label/${1##*=}" ;; PARTUUID) device="/dev/disk/by-partuuid/${1##*=}" ;; esac # avoid race condition while [ ! -e "$device" ]; do [ "$value" = 30 ] && panic "failed to lookup partition" value=$(( value + 1 )); sleep 1 done } prepare_environment() { . /etc/config export \ SHELL=/bin/sh \ TERM=linux \ HOME=/root \ PATH=/bin:/sbin:/usr/bin:/usr/sbin \ PS1="# " \ LC_ALL=C \ LANG=C \ OLD_IFS="$IFS" # fix for ubase mount :> /etc/fstab mount -t proc -o nosuid,noexec,nodev proc /proc mount -t sysfs -o nosuid,noexec,nodev sys /sys mount -t devtmpfs -o nosuid,noexec,mode=0755 dev /dev ln -s /proc/self/fd /dev/fd ln -s /proc/self/fd/0 /dev/stdin ln -s /proc/self/fd/1 /dev/stdout ln -s /proc/self/fd/2 /dev/stderr trap 'panic "something went wrong"' EXIT # false positive # shellcheck disable=2015 [ "$modules" ] && modprobe -a "$modules" 2> /dev/null ||: } parse_cmdline() { read -r cmdline < /proc/cmdline for line in $cmdline; do case "$line" in debug | debug=1) set -x ;; rootfstype=*) root_type="$line" ;; rootflags=*) root_opts="$line" ;; ro | rw) rorw="-o $line" ;; *.*) # TODO implement backward compatibilty with dracut, mkinitcpio, etc : no operation ;; *=*) export "$line" ;; *) export "${line}=1" ;; esac; done } setup_devmgr() { [ "$break" = devmgr ] && print "break before setup device manager" case "$devmgr" in udev) udevd -d -N never udevadm trigger -c add -t subsystems udevadm trigger -c add -t devices udevadm settle ;; mdev) mdev -df 2> /dev/null & mdev_pid="$!" [ "$monolith" != 1 ] && { set -- $(find /sys -name modalias -type f -exec sort -u {} +) modprobe -a "$@" 2> /dev/null ||: } ;; mdevd) mdevd 2> /dev/null & mdevd_pid="$!" mdevd-coldplug ;; esac } unlock_luks() { [ "$break" = luks ] && print "break before unlock LUKS" { IFS=,; set -- $luks_opts; IFS="$OLD_IFS"; } for opt; do case "$opt" in discard | discard=1) luks_discard="--allow-discards" ;; header=*) luks_header="--${opt}" ;; name=*) luks_name="${opt##*=}" ;; key=*) luks_key="-d ${opt##*=}" ;; esac; done findfs "$luks_root" set -- \ "--disable-locks" \ "$luks_key" "$luks_header" \ "$luks_discard" "$device" \ "${luks_name:-luks-${device##*/}}" cryptsetup open $@ || panic "failed to unlock LUKS" } trigger_lvm() { [ "$break" = lvm ] && print "break before trigger LVM" { IFS=,; set -- $lvm_opts; IFS="$OLD_IFS"; } for opt; do case "$opt" in discard | discard=1) lvm_discard="--config=devices{issue_discards=1}" ;; config=0) :> /etc/lvm/lvm.conf ;; group=*) lvm_group="${opt##*=}" ;; name=*) lvm_name="/${opt##*=}" ;; tag=*) lvm_tag="@${opt##*=}" ;; esac; done set -- "--sysinit" "-qq" "-ay" "$lvm_discard" if [ "$lvm_group" ] && [ "$lvm_name" ]; then lvchange $@ "${lvm_group}${lvm_name}" elif [ "$lvm_group" ]; then vgchange $@ "$lvm_group" elif [ "$lvm_tag" ]; then lvchange $@ "$lvm_tag" else vgchange $@ fi } mount_root() { [ "$break" = root ] && print "break before mount root" findfs "$root" set -- \ "${root_type:+-t $root_type}" \ "${rorw:--o ro}${root_opts:+,$root_opts}" \ "$device" "/mnt/root" mount $@ || panic "failed to mount root" } cleanup() { [ "$break" = cleanup ] && print "break before cleanup" case "$devmgr" in udev) udevadm control -e ;; mdev) kill "$mdev_pid" ;; mdevd) kill "$mdevd_pid" ;; esac # temporary workaround until util-linux release a new version # see https://github.com/karelzak/util-linux/issues/997 for dir in dev sys proc; do mount -o move "$dir" "/mnt/root/${dir}" || mount --move "$dir" "/mnt/root/${dir}" done } boot_system() { [ "$break" = boot ] && print "break before boot system" set -- "/mnt/root" "${init:-/sbin/init}" exec switch_root $@ 2> /dev/null || panic "failed to boot system" } # int main() { prepare_environment parse_cmdline setup_devmgr # trigger lvm twice to handle both LUKS on LVM and LVM on LUKS [ "$lvm" = 1 ] && trigger_lvm [ "$luks" = 1 ] && unlock_luks [ "$lvm" = 1 ] && trigger_lvm mount_root cleanup boot_system }