186 lines
4.5 KiB
Bash
Executable File
186 lines
4.5 KiB
Bash
Executable File
#!/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
|
|
proc)
|
|
command -v device-helper > /proc/sys/kernel/hotplug
|
|
|
|
# get ready for fork bomb. kek
|
|
find /sys/devices -name uevent |
|
|
|
|
while read -r uevent; do
|
|
printf add > "$uevent"
|
|
done
|
|
;;
|
|
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" || printf '\n' > /proc/sys/kernel/hotplug
|
|
} 2> /dev/null || :
|
|
|
|
# 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
|
|
}
|