*: refactor

Documentation will be rewritten and added later.
This commit is contained in:
illiliti
2021-07-31 20:20:16 +03:00
parent 7bfc7fe315
commit a468c11a30
45 changed files with 618 additions and 2161 deletions

160
lib/common.sh Executable file
View 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
View 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
View 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