*: refactor
Documentation will be rewritten and added later.
This commit is contained in:
160
lib/common.sh
Executable file
160
lib/common.sh
Executable file
@ -0,0 +1,160 @@
|
||||
# vim: set ft=sh:
|
||||
# shellcheck shell=sh
|
||||
#
|
||||
# https://shellcheck.net/wiki/SC2154
|
||||
# shellcheck disable=2154
|
||||
|
||||
print()
|
||||
{
|
||||
printf "%s %s\n" "${2:-">>"}" "$1"
|
||||
}
|
||||
|
||||
panic()
|
||||
{
|
||||
print "${1:-unexpected error occurred}" '!>' >&2
|
||||
|
||||
if [ "$$" = 1 ]; then
|
||||
sh
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# random()
|
||||
# {
|
||||
# _sum=$(cksum < /proc/uptime)
|
||||
# printf '%s' "${sum% *}"
|
||||
# }
|
||||
|
||||
# TODO ensure correctness
|
||||
copy_file()
|
||||
(
|
||||
file=$1; dest=$2
|
||||
|
||||
[ -e "${tmpdir}/${dest}" ] && return
|
||||
|
||||
while [ -h "$file" ]; do
|
||||
mkdir -p "${tmpdir}/${file%/*}"
|
||||
cp -P "$file" "${tmpdir}/${file}"
|
||||
cd -P "${file%/*}" || exit
|
||||
|
||||
symlink=$(ls -ld "$file")
|
||||
symlink=${symlink##* -> }
|
||||
|
||||
case $symlink in
|
||||
/*) file=$symlink ;;
|
||||
*) file="${PWD}/${symlink##*/}" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -h "${tmpdir}/${dest}" ] && dest=$file
|
||||
|
||||
mkdir -p "${tmpdir}/${dest%/*}"
|
||||
cp "$file" "${tmpdir}/${dest}"
|
||||
|
||||
[ "$3" ] && chmod "$3" "${tmpdir}/${dest}"
|
||||
|
||||
# https://shellcheck.net/wiki/SC2015
|
||||
# shellcheck disable=2015
|
||||
[ "$4" ] && strip "${tmpdir}/${dest}" > /dev/null 2>&1 || :
|
||||
)
|
||||
|
||||
copy_exec()
|
||||
{
|
||||
_bin=$(command -v "$1")
|
||||
|
||||
case $_bin in /*) ;;
|
||||
'')
|
||||
panic "unable to find command: $1"
|
||||
;;
|
||||
*)
|
||||
# https://shellcheck.net/wiki/SC2086
|
||||
# shellcheck disable=2086
|
||||
{ IFS=:; set -- $PATH; unset IFS; }
|
||||
|
||||
for _dir; do
|
||||
__bin="${_dir}/${_bin}"
|
||||
|
||||
[ -x "$__bin" ] && break
|
||||
done
|
||||
|
||||
# https://shellcheck.net/wiki/SC2015
|
||||
# shellcheck disable=2015
|
||||
[ -x "$__bin" ] && _bin=$__bin || panic "unable to find command: $_bin"
|
||||
;;
|
||||
esac
|
||||
|
||||
copy_file "$_bin" "/bin/${_bin##*/}" 0755 1
|
||||
|
||||
# TODO copy libs to the directory of interpreter.
|
||||
ldd "$_bin" 2> /dev/null |
|
||||
|
||||
while read -r _lib || [ "$_lib" ]; do
|
||||
_lib=${_lib#* => }
|
||||
_lib=${_lib% *}
|
||||
|
||||
[ -e "$_lib" ] && copy_file "$_lib" "$_lib" 0755 1
|
||||
done
|
||||
}
|
||||
|
||||
copy_kmod()
|
||||
{
|
||||
modprobe -S "$kernel" -D "$1" 2> /dev/null |
|
||||
|
||||
while read -r _ _mod || [ "$_mod" ]; do
|
||||
case $_mod in /*) copy_file "$_mod" "$_mod" 0644; esac
|
||||
done
|
||||
}
|
||||
|
||||
# TODO allow full path to hook
|
||||
copy_hook()
|
||||
{
|
||||
for _dir in "${local+./hook}" /etc/tinyramfs/hook.d /lib/tinyramfs/hook.d; do
|
||||
_hook="${_dir}/${1}/${1}"
|
||||
[ -f "$_hook" ] && break
|
||||
done
|
||||
|
||||
[ -f "$_hook" ] || panic "unable to find hook: $1"
|
||||
|
||||
for _ext in init init.late; do
|
||||
[ -f "${_hook}.${_ext}" ] || continue
|
||||
|
||||
print "copying hook: ${1}.${_ext}"
|
||||
|
||||
copy_file "${_hook}.${_ext}" "/lib/tinyramfs/hook.d/${1}/${1}.${_ext}" 0644
|
||||
done
|
||||
|
||||
print "evaluating hook: $1"
|
||||
|
||||
# https://shellcheck.net/wiki/SC1090
|
||||
# shellcheck disable=1090
|
||||
. "$_hook"
|
||||
}
|
||||
|
||||
resolve_device()
|
||||
{
|
||||
device=$1; _count=${2:-30}
|
||||
|
||||
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 ;;
|
||||
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
|
||||
elif [ "$((_count -= 1))" = 0 ]; then
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
|
||||
panic "failed to lookup partition: $device"
|
||||
}
|
45
lib/helper.sh
Executable file
45
lib/helper.sh
Executable file
@ -0,0 +1,45 @@
|
||||
#!/bin/sh -f
|
||||
#
|
||||
# Load modules via $MODALIAS.
|
||||
# Create /dev/disk/by-* and /dev/mapper/* symlinks.
|
||||
|
||||
create_symlink()
|
||||
{
|
||||
typ=$1; sym=$2
|
||||
|
||||
sym=${sym%\"}
|
||||
sym=${sym#\"}
|
||||
sym="/dev/disk/by-${typ}/${sym}"
|
||||
|
||||
mkdir -p "${sym%/*}"
|
||||
ln -s "../../${dev_name}" "$sym"
|
||||
}
|
||||
|
||||
exec > /dev/null 2>&1
|
||||
|
||||
[ "$MODALIAS" ] && modprobe "$MODALIAS"
|
||||
[ "$SUBSYSTEM" = block ] && [ -b "/dev/${dev_name=${DEVPATH##*/}}" ] || exit 1
|
||||
|
||||
read -r dm_name < "/sys/block/${dev_name}/dm/name" && {
|
||||
mkdir -p /dev/mapper
|
||||
ln -sf "../${dev_name}" "/dev/mapper/${dm_name:?}"
|
||||
}
|
||||
|
||||
command -v blkid || exit 0
|
||||
|
||||
# Race condition may occur if uevent arrives faster(isn't that a kernel bug!?)
|
||||
# than the kernel initializes device. This prevents blkid to fetch data from
|
||||
# device. To fix this, we simply waiting until blkid is succeeded.
|
||||
while ! _blkid=$(blkid "/dev/${dev_name}"); do
|
||||
if [ "$((count += 1))" = 10 ]; then
|
||||
exit 1
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
|
||||
for line in $_blkid; do case ${line%%=*} in
|
||||
UUID) create_symlink uuid "${line#*=}" ;;
|
||||
LABEL) create_symlink label "${line#*=}" ;;
|
||||
PARTUUID) create_symlink partuuid "${line#*=}" ;;
|
||||
esac; done
|
118
lib/init.sh
Executable file
118
lib/init.sh
Executable file
@ -0,0 +1,118 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# https://shellcheck.net/wiki/SC2154
|
||||
# https://shellcheck.net/wiki/SC2034
|
||||
# shellcheck disable=2154,2034
|
||||
|
||||
init_base()
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
eval_hooks()
|
||||
{
|
||||
_type=$1
|
||||
|
||||
# https://shellcheck.net/wiki/SC2086
|
||||
# shellcheck disable=2086
|
||||
{ IFS=,; set -- $hooks; unset IFS; }
|
||||
|
||||
for _hook; do
|
||||
[ -f "/lib/tinyramfs/hook.d/${_hook}/${_hook}.${_type}" ] || continue
|
||||
[ "$rdbreak" = "$_hook" ] && panic "break before: ${_hook}.${_type}"
|
||||
|
||||
# https://shellcheck.net/wiki/SC1090
|
||||
# shellcheck disable=1090
|
||||
. "/lib/tinyramfs/hook.d/${_hook}/${_hook}.${_type}"
|
||||
done
|
||||
}
|
||||
|
||||
parse_cmdline()
|
||||
{
|
||||
# XXX /proc/cmdline can contain multiline data?
|
||||
read -r cmdline < /proc/cmdline
|
||||
|
||||
# https://kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
|
||||
# ... parameters with '=' go into init's environment ...
|
||||
for _param in $cmdline; do case $_param in
|
||||
rdpanic) trap - EXIT ;;
|
||||
rddebug) set -x ;;
|
||||
|
||||
# Maintain backward compatibility with kernel parameters.
|
||||
ro | rw) rorw=$_param ;;
|
||||
rootwait) root_wait=-1 ;;
|
||||
--) init_args=${_param##*--}; break ;;
|
||||
rootfstype=*) root_type=${_param#*=} ;;
|
||||
rootflags=*) root_opts=${_param#*=} ;;
|
||||
rootdelay=*) root_wait=${_param#*=} ;;
|
||||
esac; done
|
||||
}
|
||||
|
||||
mount_root()
|
||||
{
|
||||
[ "$rdbreak" = root ] && panic 'break before: mount_root()'
|
||||
|
||||
resolve_device "$root" "$root_wait"
|
||||
|
||||
# https://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 rootfs: $device"
|
||||
}
|
||||
|
||||
boot_system()
|
||||
{
|
||||
[ "$rdbreak" = boot ] && panic 'break before: boot_system()'
|
||||
|
||||
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.
|
||||
# Use '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 safety of init_args
|
||||
# isn't guaranteed.
|
||||
#
|
||||
# https://shellcheck.net/wiki/SC2086
|
||||
# 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"
|
||||
}
|
||||
|
||||
# TODO add `quiet` support
|
||||
|
||||
# -e: Exit if command return status greater than 0
|
||||
# -f: Disable globbing *?[]
|
||||
set -ef
|
||||
|
||||
# Run emergency shell if init unexpectedly exiting due to error.
|
||||
# TODO prompt to continue
|
||||
trap panic EXIT
|
||||
|
||||
# https://shellcheck.net/wiki/SC1091
|
||||
# shellcheck disable=1091
|
||||
. /lib/tinyramfs/common.sh
|
||||
|
||||
# https://shellcheck.net/wiki/SC1091
|
||||
# shellcheck disable=1091
|
||||
. /etc/tinyramfs/config
|
||||
|
||||
init_base
|
||||
parse_cmdline
|
||||
eval_hooks init
|
||||
mount_root
|
||||
eval_hooks init.late
|
||||
boot_system
|
Reference in New Issue
Block a user