From 2a1649095d73a1e247c86ba7bc7e08478746aa48 Mon Sep 17 00:00:00 2001 From: j1nx Date: Sun, 23 Feb 2025 07:12:39 +0000 Subject: [PATCH] Another try for dracut-ng --- buildroot | 2 +- buildroot-external/configs/rpi4_64_defconfig | 1 + .../init-readonly-rootfs-overlay-boot.sh | 256 ++++++++++++++++++ .../99readonly-rootfs-overlay/module-setup.sh | 66 +++++ 4 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/init-readonly-rootfs-overlay-boot.sh create mode 100644 buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/module-setup.sh diff --git a/buildroot b/buildroot index 5385cac2..6c5d0339 160000 --- a/buildroot +++ b/buildroot @@ -1 +1 @@ -Subproject commit 5385cac22324ab3209ffe919c1c283989baf3951 +Subproject commit 6c5d033914dad097685b7a419ae8ec14ee870c8c diff --git a/buildroot-external/configs/rpi4_64_defconfig b/buildroot-external/configs/rpi4_64_defconfig index a7a92f0d..6f5ad8cb 100644 --- a/buildroot-external/configs/rpi4_64_defconfig +++ b/buildroot-external/configs/rpi4_64_defconfig @@ -175,6 +175,7 @@ BR2_PACKAGE_ALSA_LIB_PYTHON=y BR2_PACKAGE_ALSA_PLUGINS=y BR2_PACKAGE_LIBSAMPLERATE=y BR2_PACKAGE_LIBSNDFILE=y +BR2_PACKAGE_RNNOISE=y BR2_PACKAGE_LIBARCHIVE=y BR2_PACKAGE_LIBDEFLATE=y BR2_PACKAGE_LZO=y diff --git a/buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/init-readonly-rootfs-overlay-boot.sh b/buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/init-readonly-rootfs-overlay-boot.sh new file mode 100644 index 00000000..8011a9b1 --- /dev/null +++ b/buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/init-readonly-rootfs-overlay-boot.sh @@ -0,0 +1,256 @@ +#!/bin/bash + +PATH=/sbin:/bin:/usr/sbin:/usr/bin + +MOUNT="/bin/mount" + +PREINIT="" +INIT="/sbin/init" +ROOT_ROINIT="/sbin/init" + +ROOT_MOUNT="/mnt" +ROOT_RODEVICE="" +ROOT_RWDEVICE="" +ROOT_ROMOUNT="/media/rfs/ro" +ROOT_RWMOUNT="/media/rfs/rw" +ROOT_RWRESET="no" + +ROOT_ROFSTYPE="" +ROOT_ROMOUNTOPTIONS="bind" +ROOT_ROMOUNTOPTIONS_DEVICE="noatime,nodiratime" + +ROOT_RWFSTYPE="" +ROOT_RWMOUNTOPTIONS="rw,noatime,mode=755 tmpfs" +ROOT_RWMOUNTOPTIONS_DEVICE="rw,noatime,mode=755" + +early_setup() { + mkdir -p /proc + mkdir -p /sys + $MOUNT -t proc proc /proc + grep -w "/sys" /proc/mounts >/dev/null || $MOUNT -t sysfs sysfs /sys + grep -w "/dev" /proc/mounts >/dev/null || $MOUNT -t devtmpfs none /dev +} + +probe_fs() { + # Determine if we need to probe any modules to support the filesystem + if ! grep -w "$1" /proc/filesystems >/dev/null; then + modprobe "$optarg" 2> /dev/null || \ + log "Could not load $optarg module" + fi +} + +read_args() { + [ -z "${CMDLINE+x}" ] && CMDLINE=$(cat /proc/cmdline) + for arg in $CMDLINE; do + # Set optarg to option parameter, and '' if no parameter was + # given + optarg=$(expr "x$arg" : 'x[^=]*=\(.*\)' || echo '') + case $arg in + root=*) + ROOT_RODEVICE=$optarg ;; + rootfstype=*) + ROOT_ROFSTYPE="$optarg" + probe_fs "$optarg" ;; + rootinit=*) + ROOT_ROINIT=$optarg ;; + rootoptions=*) + ROOT_ROMOUNTOPTIONS_DEVICE="$optarg" ;; + rootrw=*) + ROOT_RWDEVICE=$optarg ;; + rootrwfstype=*) + ROOT_RWFSTYPE="$optarg" + probe_fs "$optarg" ;; + rootrwreset=*) + ROOT_RWRESET=$optarg ;; + rootrwoptions=*) + ROOT_RWMOUNTOPTIONS_DEVICE="$optarg" ;; + overlayfstype=*) + modprobe "$optarg" 2> /dev/null || \ + log "Could not load $optarg module";; + preinit=*) + PREINIT=$optarg ;; + init=*) + INIT=$optarg ;; + esac + done +} + +fatal() { + echo "rorootfs-overlay: $1" > "$CONSOLE" + echo > "$CONSOLE" + exec sh +} + +log() { + echo "rorootfs-overlay: $1" > "$CONSOLE" +} + +resolve_device() { + local dev=$1 + + if [ "$(echo $dev | cut -c1-5)" = "UUID=" ]; then + local uuid=$(echo $dev | cut -c6-) + new_dev="/dev/disk/by-uuid/$uuid" + elif [ "$(echo $dev | cut -c1-9)" = "PARTUUID=" ]; then + local partuuid=$(echo $dev | cut -c10-) + new_dev="/dev/disk/by-partuuid/$partuuid" + elif [ "$(echo $dev | cut -c1-10)" = "PARTLABEL=" ]; then + local partlabel=$(echo $dev | cut -c11-) + new_dev="/dev/disk/by-partlabel/$partlabel" + elif [ "$(echo $dev | cut -c1-6)" = "LABEL=" ]; then + local label=$(echo $dev | cut -c7-) + new_dev="/dev/disk/by-label/$label" + else + new_dev="$dev" + fi + + if [ "$new_dev" != "$dev" ] && [ ! -d /dev/disk ]; then + fatal "$dev device naming is not supported without udev" + fi + + echo "$new_dev" +} + +wait_for_device() { + local dev=$1 + + # Skip for e.g. `rootrw=ubi0:overlay` + echo "$dev" | grep -q ":" && return + + counter=0 + while [ ! -b "$dev" ]; do + sleep .100 + counter=$((counter + 1)) + if [ $counter -ge 50 ]; then + fatal "$dev is not availble" + exit + fi + done +} + +early_setup + +[ -z "${CONSOLE+x}" ] && CONSOLE="/dev/console" + +read_args + +mount_and_boot() { + mkdir -p $ROOT_MOUNT $ROOT_ROMOUNT $ROOT_RWMOUNT + + # Build mount options for read only root file system. + # If no read-only device was specified via kernel command line, use + # current root file system via bind mount. + ROOT_RODEVICE=$(resolve_device "$ROOT_RODEVICE") + wait_for_device "${ROOT_RODEVICE}" + ROOT_ROMOUNTPARAMS_BIND="-o ${ROOT_ROMOUNTOPTIONS} /" + if [ -n "${ROOT_RODEVICE}" ]; then + ROOT_ROMOUNTPARAMS="-o ${ROOT_ROMOUNTOPTIONS_DEVICE} $ROOT_RODEVICE" + if [ -n "${ROOT_ROFSTYPE}" ]; then + ROOT_ROMOUNTPARAMS="-t $ROOT_ROFSTYPE $ROOT_ROMOUNTPARAMS" + fi + else + ROOT_ROMOUNTPARAMS="$ROOT_ROMOUNTPARAMS_BIND" + fi + + # Mount root file system to new mount-point, if unsuccessful, try bind + # mounting current root file system. + # shellcheck disable=SC2086 + if ! $MOUNT $ROOT_ROMOUNTPARAMS "$ROOT_ROMOUNT" 2>/dev/null; then + log "Could not mount $ROOT_RODEVICE, bind mounting..." + if ! $MOUNT $ROOT_ROMOUNTPARAMS_BIND "$ROOT_ROMOUNT"; then + fatal "Could not mount read-only rootfs" + fi + fi + + # Remounting root file system as read only. + if ! $MOUNT -o remount,ro "$ROOT_ROMOUNT"; then + fatal "Could not remount read-only rootfs as read only" + fi + + # If future init is the same as current file, use $ROOT_ROINIT + # Tries to avoid loop to infinity if init is set to current file via + # kernel command line + if cmp -s "$0" "$INIT"; then + INIT="$ROOT_ROINIT" + fi + + # Build mount options for read write root file system. + # If a read-write device was specified via kernel command line, use + # it, otherwise default to tmpfs. + if [ -n "${ROOT_RWDEVICE}" ]; then + ROOT_RWDEVICE=$(resolve_device "$ROOT_RWDEVICE") + wait_for_device "${ROOT_RWDEVICE}" + ROOT_RWMOUNTPARAMS="-o $ROOT_RWMOUNTOPTIONS_DEVICE $ROOT_RWDEVICE" + if [ -n "${ROOT_RWFSTYPE}" ]; then + ROOT_RWMOUNTPARAMS="-t $ROOT_RWFSTYPE $ROOT_RWMOUNTPARAMS" + fi + else + ROOT_RWMOUNTPARAMS="-t tmpfs -o $ROOT_RWMOUNTOPTIONS" + fi + + # Mount read-write file system into initram root file system + # shellcheck disable=SC2086 + if ! $MOUNT $ROOT_RWMOUNTPARAMS $ROOT_RWMOUNT; then + fatal "Could not mount read-write rootfs" + fi + + # Reset read-write file system if specified + if [ "yes" = "$ROOT_RWRESET" ] && [ -n "${ROOT_RWMOUNT}" ]; then + rm -rf ${ROOT_RWMOUNT:?}/* + fi + + # Determine which unification file system to use + union_fs_type="" + if grep -w "overlay" /proc/filesystems >/dev/null; then + union_fs_type="overlay" + elif grep -w "aufs" /proc/filesystems >/dev/null; then + union_fs_type="aufs" + else + union_fs_type="" + fi + + # Create/Mount overlay root file system + case $union_fs_type in + "overlay") + mkdir -p $ROOT_RWMOUNT/upperdir $ROOT_RWMOUNT/work + $MOUNT -t overlay overlay \ + -o "$(printf "%s%s%s" \ + "lowerdir=$ROOT_ROMOUNT," \ + "upperdir=$ROOT_RWMOUNT/upperdir," \ + "workdir=$ROOT_RWMOUNT/work")" \ + $ROOT_MOUNT + ;; + "aufs") + $MOUNT -t aufs i\ + -o "dirs=$ROOT_RWMOUNT=rw:$ROOT_ROMOUNT=ro" \ + aufs $ROOT_MOUNT + ;; + "") + fatal "No overlay filesystem type available" + ;; + esac + + # Execute any preinit scripts + if [ -x "${PREINIT}" ]; then + ${PREINIT} + fi + + # Move read-only and read-write root file system into the overlay + # file system + mkdir -p $ROOT_MOUNT/$ROOT_ROMOUNT $ROOT_MOUNT/$ROOT_RWMOUNT + $MOUNT -n --move $ROOT_ROMOUNT ${ROOT_MOUNT}/$ROOT_ROMOUNT + $MOUNT -n --move $ROOT_RWMOUNT ${ROOT_MOUNT}/$ROOT_RWMOUNT + + $MOUNT -n --move /proc ${ROOT_MOUNT}/proc + $MOUNT -n --move /sys ${ROOT_MOUNT}/sys + $MOUNT -n --move /dev ${ROOT_MOUNT}/dev + + + cd $ROOT_MOUNT + + # switch to actual init in the overlay root file system + exec switch_root $ROOT_MOUNT "$INIT" || + fatal "Couldn't chroot, dropping to shell" +} + +mount_and_boot diff --git a/buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/module-setup.sh b/buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/module-setup.sh new file mode 100644 index 00000000..1c8bba54 --- /dev/null +++ b/buildroot-external/dracut/modules.d/99readonly-rootfs-overlay/module-setup.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh + +check() { + require_binaries busybox || return 1 + require_binaries cat || return 1 + require_binaries switch_root || return 1 + require_binaries cmp || return 1 + require_binaries expr || return 1 + require_binaries grep || return 1 + require_binaries mkdir || return 1 + require_binaries mount || return 1 + require_binaries modprobe || return 1 + require_binaries log || return 1 + return 0 +} + +depends() { + return 0 +} + +installkernel() { + return 0 +} + +install_busybox_links() { + dir="${1}" + linkname="${2}" + + (cd "${dracutsysrootdir?}${dir}" && + for x in *; do + if [ "$(readlink "${x}")" = "${linkname}" ]; then + ln -sf "${linkname}" "${initdir?}/${dir}/${x}" + fi + done + ) +} + +install() { + + inst_multiple mount umount cat cmp grep mkdir expr chroot + + # Install busybox binary + inst_multiple /bin/busybox + if [ -e "${dracutsysrootdir?}/lib64" ]; then + ln -sf lib "${initdir?}/lib64" + ln -sf lib "${initdir?}/usr/lib64" + fi + + if [ -e "${dracutsysrootdir?}/lib32" ]; then + ln -sf lib "${initdir?}/lib32" + ln -sf lib "${initdir?}/usr/lib32" + fi + + install_busybox_links "/bin" "busybox" + install_busybox_links "/sbin" "../bin/busybox" + if [ ! -L "${dracutsysrootdir?}/bin" ]; then + install_busybox_links "/usr/bin" "../../bin/busybox" + install_busybox_links "/usr/sbin" "../../bin/busybox" + fi + + # inst does not work for some reason. Use cp(1) instead. + #inst "$moddir/init-readonly-rootfs-overlay-boot.sh" "/init" + cp $moddir/init-readonly-rootfs-overlay-boot.sh $initdir/init +}