135 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.3 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))" = "${rootdelay:=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
 | 
						|
}
 | 
						|
 | 
						|
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; }
 | 
						|
 | 
						|
    for dir in run dev sys proc; do
 | 
						|
        mount -o move "$dir" "/mnt/root/${dir}"
 | 
						|
    done
 | 
						|
 | 
						|
    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
 | 
						|
    mount_root
 | 
						|
    run_hook init.late
 | 
						|
    boot_system
 | 
						|
}
 |