#!/bin/sh # # tiny init # # false positive # shellcheck disable=2154 print() { printf "%b %s\n" "${2:-"\033[1;37m>>\033[m"}" "$1" } panic() { print "${1:-unexpected error occurred}" \ "\033[1;31m!!\033[m" >&2; sh } resolve_device() { count=0; device="$1" case "${device%%=*}" in /dev/*) ;; UUID) device="/dev/disk/by-uuid/${device#*=}" ;; LABEL) device="/dev/disk/by-label/${device#*=}" ;; PARTUUID) device="/dev/disk/by-partuuid/${device#*=}" ;; esac # prevent race condition # XXX what the hell happens here? # why this loop sometimes trigger panic if i remove '|| :' while [ ! -b "$device" ]; do sleep 1 [ "$((count += 1))" = 30 ] && { panic "failed to lookup partition" break } done || : } run_hook() { type="$1"; hksdir=/usr/share/tinyramfs/hooks # run hooks if any # false positive # shellcheck disable=1090 for hook in $hooks; do [ -f "${hksdir}/${hook}/${hook}.${type}" ] || continue . "${hksdir}/${hook}/${hook}.${type}" done } prepare_environment() { # false positive # shellcheck disable=1091 . /etc/tinyramfs/config export \ PATH=/bin TERM=linux SHELL=/bin/sh \ LANG=C LC_ALL=C PS1="# " HOME=/root 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 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 } parse_cmdline() { read -r cmdline < /proc/cmdline for line in $cmdline; do case "$line" in rootfstype=*) root_type="${line#*=}" ;; rootflags=*) root_opts="${line#*=}" ;; debug=1) set -x ;; ro | rw) rorw="-o $line" ;; --*) init_args="${cmdline#*-- }"; break ;; *=*) command export "$line" ;; *) command export "${line}=1" ;; esac 2> /dev/null || :; done } setup_devmgr() { [ "$break" = devmgr ] && { print "break before setup_devmgr()"; sh; } case "$devmgr" in udev) udevd -N never & devmgr_pid="$!" udevadm trigger -c add -t subsystems udevadm trigger -c add -t devices udevadm settle ;; mdev) mdev -s mdev -df & devmgr_pid="$!" find /sys/devices -name uevent | while read -r uevent; do printf add > "$uevent" done ;; mdevd) mdevd & devmgr_pid="$!" mdevd-coldplug ;; esac 2> /dev/null } mount_root() { [ "$break" = root ] && { print "break before mount_root()"; sh; } resolve_device "$root" set -- \ "${rorw:--o ro}${root_opts:+,$root_opts}" \ "${root_type:+-t $root_type}" "$device" "/mnt/root" # word splitting is safe by design # shellcheck disable=2068 mount $@ || panic "failed to mount root" } boot_system() { [ "$break" = boot ] && { print "break before boot_system()"; sh; } kill "$devmgr_pid" # 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 2> /dev/null set -- "/mnt/root" "${init:-/sbin/init}" "$init_args" # POSIX exec has no -c flag to execute command with empty environment # use 'env -i' to prevent leaking exported variables # word splitting is safe by design # shellcheck disable=2068 exec env -i TERM=linux PATH=/bin:/sbin:/usr/bin:/usr/sbin \ switch_root $@ || panic "failed to boot system" } # int main() { # enable exit on error and disable globbing # trap EXIT signal set -ef; trap panic EXIT prepare_environment parse_cmdline run_hook init.early # XXX may be moved to hooks soon setup_devmgr run_hook init mount_root boot_system }