#!/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" } panic() { print "${1:-unexpected error occurred}" \ "\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() { count=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 sleep 1; : $(( count += 1 )) [ "$count" = 30 ] && { panic "failed to lookup partition" break } done || : } prepare_environment() { . /etc/tinyramfs/config export \ LANG=C \ PS1="# " \ LC_ALL=C \ TERM=linux \ HOME=/root \ SHELL=/bin/sh \ OLD_IFS="$IFS" \ PATH=/bin:/sbin:/usr/bin:/usr/sbin # 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 tmpfs -o nosuid,nodev,mode=0755 run /run mount -t devtmpfs -o nosuid,noexec,mode=0755 dev /dev mkdir -p \ /run/cryptsetup \ /run/lock \ /run/lvm ln -s /proc/self/fd /dev/fd ln -s fd/0 /dev/stdin ln -s fd/1 /dev/stdout ln -s fd/2 /dev/stderr trap panic EXIT [ "$modules" ] || return 0 modprobe -a "$modules" } 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_devmgr()"; shell; } case "$devmgr" in udev) udevd -dN never udevadm trigger -c add -t subsystems udevadm trigger -c add -t devices udevadm settle ;; mdev) mdev -df 2> /dev/null & mdev_pid="$!" mdev -s [ "$monolith" = 1 ] && return 0 # TODO maybe replace sort using while-read loop # while-read can cause slowdown, so why i'm unsure 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()"; shell; } { 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 -- \ "$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()"; shell; } { 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" "-aay" "$lvm_discard" if [ "$lvm_group" ] && [ "$lvm_name" ]; then lvm lvchange $@ "${lvm_group}${lvm_name}" elif [ "$lvm_group" ]; then lvm vgchange $@ "$lvm_group" elif [ "$lvm_tag" ]; then lvm lvchange $@ "$lvm_tag" else lvm vgchange $@ fi } mount_root() { [ "$break" = root ] && { print "break before mount_root()"; shell; } 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()"; shell; } 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 /run /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()"; shell; } 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 }