From 0bbf3c3e71e613801583222ae782fae866ecd5d8 Mon Sep 17 00:00:00 2001 From: Aaron Ball Date: Sat, 4 Mar 2023 22:03:20 -0700 Subject: Refactor to support udev block device loading Previously block device aliases did not load correctly, so the direct `/dev/nvme*` path for example was required as `/dev/disk/by-*` was not available at all for mounting by partlabel or uuid. This adds the udevadm and udevd binaries so the /dev/disk directory tree can be populated during init, allowing for block device aliases. This also does some cleanup and organization to improve the over code quality. --- init | 63 +++++++++++++++++++++---------------------------------------- mkinitramfs | 21 +++++++++++++++------ 2 files changed, 37 insertions(+), 47 deletions(-) diff --git a/init b/init index 36dde80..7babfd2 100755 --- a/init +++ b/init @@ -121,7 +121,7 @@ parse_cmdline() { # setup_encrypted() { local path="${1}" - local name="$(echo ${path} | tr / _)" + local name="${path//\//_}" # Decrypted block dev path is /dev/mapper/${name} cryptsetup luksOpen ${path} ${name} @@ -144,35 +144,18 @@ setup_encrypted() { } -# -# Waits up to a threshold (in seconds) for the specified path to appear as a -# block device. A check for device presence occurs once per second. -# -# If the device appears within the threshold time, the function returns early -# with error code 0 (all is well - no need to wait more). -# -# If the block device fails to appear within the threshold time, the function -# returns code 2 (not found) -# -# @param dev Path to the device to wait for -# @param timeout Maximum time (in seconds) to wait for the device to appear -# -wait_dev() { - local dev=${1} - local timeout=${2} - - local wait=0 - - while [ ${wait} -lt ${timeout} ]; do - # If the path exists as a block device, exit the wait loop - [ -b "${dev}" ] && return 0 - # Increment the wait counter - wait=$(( wait + 1 )) - # Wait another second for the device to appear - sleep 1 - done +udev_populate() { + # Start udevd if not already running + pidof -s udevd > /dev/null || /sbin/udevd --daemon - return 2 + /sbin/udevadm trigger --type=subsystems --action=add + /sbin/udevadm trigger --type=devices --action=add --subsystem-match=block + /sbin/udevadm trigger --type=devices --action=add --subsystem-match=input + /sbin/udevadm settle + + # Shut down udevd once devices are populated so main init can handle udevd to + # finish booting + kill $(pidof udevd) } @@ -182,30 +165,27 @@ wait_dev() { # main() { # Mount the /proc and /sys filesystems. - mount -t tmpfs none /run - mount -t sysfs -o nodev,noexec,nosuid sysfs /sys - mount -t proc -o nodev,noexec,nosuid proc /proc - mount -t devtmpfs none /dev - mount -t devpts devpts /dev/pts - mount -t tmpfs shm /dev/shm + mount -t tmpfs -o mode=0755,nousid,nodev none /run + mount -t sysfs -o nodev,noexec,nosuid sysfs /sys + mount -t proc -o nodev,noexec,nosuid proc /proc + mount -t tmpfs shm /dev/shm + mount -t devtmpfs -o exec,nosuid,noatime dev /dev + mount -t devpts devpts /dev/pts local fakeroot='/mnt/root' if [ ! -d "${fakeroot}" ]; then - log INFO "Fake root location ${fakeroot} does not exist. Creating." - mkdir ${fakeroot} + log INFO "Fake root location ${fakeroot} does not exist. Cannot boot." fi parse_cmdline "$(cat /proc/cmdline)" # display fanciful boot image screen_init + udev_populate log INFO "Root device: ${ROOTDEV}" - log INFO "Waiting up to 10 seconds for root device to appear." - wait_dev "${ROOTDEV}" 10 - # Drop to maintenance shell if root device does not exist. if [ "$?" -ne 0 ]; then log ERROR "ERROR: Root device ${ROOTDEV} does not exist or can not be accessed." @@ -215,7 +195,8 @@ main() { fi # Modprobe atkbd to ensure user can type password - for i in dm-crypt i8042 atkbd; do + # dm-crypt + for i in i8042 atkbd; do printf 'Loading required module [%s]\n' "${i}" modprobe "${i}" || printf 'Failed loading %s\n' "${i}" done diff --git a/mkinitramfs b/mkinitramfs index 52e0165..5d35386 100755 --- a/mkinitramfs +++ b/mkinitramfs @@ -36,7 +36,7 @@ function resolve_bins { local args=${@} for i in ${args[@]}; do - local path=$(which ${i} 2>/dev/null) + local path=$(type -p ${i} 2>/dev/null) if [[ $? -gt 0 ]]; then echo "Could not find binary ${i}. Is it installed?" @@ -114,7 +114,7 @@ function mkcpio { # # Sets up cache dir for later writing to an archive (via cpio). -# Performs simple operations like creating a basic directory structure, +# Performs simple operations like creating a basic directory structure, # # @param cache Path to the cache directory. Will be created if not exists # @@ -203,10 +203,15 @@ function main { fi # List of binaries to exist in the new initramfs - resolve_bins \ - bash cat echo ls cryptsetup chmod chown mount sleep umount clear cut \ - grep less tr which blkid partprobe reboot shutdown switch_root modprobe \ - rmmod + # Standard shell binaries + resolve_bins bash cat pidof ps ls clear cut grep less blkid switch_root kill + # Module management + resolve_bins udevadm udevd modprobe rmmod + # For encrypted and block device support + resolve_bins partprobe dmsetup mount umount cryptsetup + + # For debugging + #resolve_bins sleep mkdir chmod chown tr # Set up the archive source dir. cache_dir_setup ${cache} @@ -218,6 +223,10 @@ function main { install -v -D /usr/lib/libgcc_s.so "${cache}/usr/lib/libgcc_s.so" install -v -D /usr/lib/libgcc_s.so.1 "${cache}/usr/lib/libgcc_s.so.1" + # Install udev rules for block devices + mkdir -p "${cache}/lib/udev" + cp -rv /lib/udev/rules.d "${cache}/lib/udev/rules.d" + # Copy binary and dependencies to cache dir for bin in ${fqbins[@]}; do # Copy the binary of interest -- cgit v1.2.3