147 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| #
 | |
| # Tiny init
 | |
| #
 | |
| # https://www.shellcheck.net/wiki/SC2154
 | |
| # 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
 | |
|         UUID)     device="/dev/disk/by-uuid/${device#*=}"     ;;
 | |
|         LABEL)    device="/dev/disk/by-label/${device#*=}"    ;;
 | |
|         PARTUUID) device="/dev/disk/by-partuuid/${device#*=}" ;;
 | |
|         /dev/*)            ;;
 | |
|         *)        return 0 ;;
 | |
|     esac
 | |
| 
 | |
|     # Race condition may occur if device manager is not yet initialized device.
 | |
|     # To fix this, we simply waiting until device is available. If device
 | |
|     # didn't appear in specified time, we panic.
 | |
|     while :; do
 | |
|         if [ -b "$device" ]; then
 | |
|             return 0
 | |
|         elif [ "$((count += 1))" = "${rootdelay:=30}" ]; then
 | |
|             break
 | |
|         else
 | |
|             sleep 1
 | |
|         fi
 | |
|     done
 | |
| 
 | |
|     panic "failed to lookup partition"
 | |
| }
 | |
| 
 | |
| run_hook()
 | |
| {
 | |
|     type="$1"
 | |
| 
 | |
|     # Run hooks if any exist.
 | |
|     #
 | |
|     # https://www.shellcheck.net/wiki/SC1090
 | |
|     # shellcheck disable=1090
 | |
|     for hook in $hooks; do
 | |
|         [ -f "/usr/share/tinyramfs/hooks/${hook}/${hook}.${type}" ] || continue
 | |
|            . "/usr/share/tinyramfs/hooks/${hook}/${hook}.${type}"
 | |
|     done
 | |
| }
 | |
| 
 | |
| prepare_environment()
 | |
| {
 | |
|     # https://www.shellcheck.net/wiki/SC1091
 | |
|     # 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="$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"
 | |
| 
 | |
|     # https://www.shellcheck.net/wiki/SC2086
 | |
|     # shellcheck disable=2086
 | |
|     mount \
 | |
|         -o "${rorw:-ro}${root_opts:+,$root_opts}" ${root_type:+-t $root_type} \
 | |
|         -- "$device" /mnt/root || 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
 | |
| 
 | |
|     # POSIX 'exec' has no '-c' flag to execute command with empty environment.
 | |
|     # Using 'env -i' instead to prevent leaking exported variables.
 | |
|     #
 | |
|     # Some implementations of 'switch_root' doesn't conform to POSIX utility
 | |
|     # guidelines and doesn't support '--'. This means that we can't guarantee
 | |
|     # safety of init_args.
 | |
|     # shellcheck disable=2086
 | |
|     exec \
 | |
|         env -i TERM=linux PATH=/bin:/sbin:/usr/bin:/usr/sbin \
 | |
|         switch_root /mnt/root "${init-/sbin/init}" $init_args ||
 | |
|         panic "failed to boot system"
 | |
| }
 | |
| 
 | |
| # Exit if command fails and disable globbing.
 | |
| set -ef
 | |
| 
 | |
| # Run emergency shell if init unexpectedly exiting due to error.
 | |
| trap panic EXIT
 | |
| 
 | |
| # TODO display fancy colored status info
 | |
| 
 | |
| prepare_environment
 | |
| parse_cmdline
 | |
| run_hook init
 | |
| mount_root
 | |
| run_hook init.late
 | |
| boot_system
 |