diff options
Diffstat (limited to 'meta/recipes-core/initrdscripts/initramfs-framework')
9 files changed, 265 insertions, 10 deletions
diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/exec b/meta/recipes-core/initrdscripts/initramfs-framework/exec new file mode 100644 index 0000000000..a8e2432bb6 --- /dev/null +++ b/meta/recipes-core/initrdscripts/initramfs-framework/exec @@ -0,0 +1,29 @@ +#!/bin/sh +# Copyright (C) 2017 O.S. Systems Software LTDA. +# Licensed on MIT + +EXEC_DIR=/exec.d # place to look for modules + +exec_enabled() { + return 0 +} + +exec_run() { + if [ ! -d $EXEC_DIR ]; then + msg "No contents to exec in $EXEC_DIR. Starting shell ..." + sh + fi + + # Load and run modules + for m in $EXEC_DIR/*; do + # Skip backup files + if [ "`echo $m | sed -e 's/\~$//'`" != "$m" ]; then + continue + fi + + debug "Starting $m" + + # process module + ./$m + done +} diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/finish b/meta/recipes-core/initrdscripts/initramfs-framework/finish index 717383ebac..ac0de9f996 100755 --- a/meta/recipes-core/initrdscripts/initramfs-framework/finish +++ b/meta/recipes-core/initrdscripts/initramfs-framework/finish @@ -12,8 +12,29 @@ finish_run() { fatal "ERROR: There's no '/dev' on rootfs." fi + # Unmount anything that was automounted by busybox via mdev-mount.sh. + # We're about to switch_root, and leaving anything mounted will prevent + # the next rootfs from modifying the block device. Ignore ROOT_DISK, + # if it was set by setup-live, because it'll be mounted over loopback + # to ROOTFS_DIR. + local dev + for dev in /run/media/*; do + if mountpoint -q "${dev}" && [ "${dev##*/}" != "${ROOT_DISK}" ]; then + umount -f "${dev}" || debug "Failed to unmount ${dev}" + fi + done + info "Switching root to '$ROOTFS_DIR'..." + debug "Moving basic mounts onto rootfs" + for dir in `awk '/\/dev.* \/run\/media/{print $2}' /proc/mounts`; do + # Parse any OCT or HEX encoded chars such as spaces + # in the mount points to actual ASCII chars + dir=`printf $dir` + mkdir -p "${ROOTFS_DIR}/media/${dir##*/}" + mount -n --move "$dir" "${ROOTFS_DIR}/media/${dir##*/}" + done + debug "Moving /dev, /proc and /sys onto rootfs..." mount --move /dev $ROOTFS_DIR/dev mount --move /proc $ROOTFS_DIR/proc diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/init b/meta/recipes-core/initrdscripts/initramfs-framework/init index 37527a840a..567694aff7 100755 --- a/meta/recipes-core/initrdscripts/initramfs-framework/init +++ b/meta/recipes-core/initrdscripts/initramfs-framework/init @@ -72,6 +72,7 @@ ROOTFS_DIR="/rootfs" # where to do the switch root MODULE_PRE_HOOKS="" # functions to call before running each module MODULE_POST_HOOKS="" # functions to call after running each module MODULES_DIR=/init.d # place to look for modules +EFI_DIR=/sys/firmware/efi # place to store device firmware information # make mount stop complaining about missing /etc/fstab touch /etc/fstab @@ -81,14 +82,31 @@ mkdir -p /proc /sys /run/lock /var/lock mount -t proc proc /proc mount -t sysfs sysfs /sys +if [ -d $EFI_DIR ];then + mount -t efivarfs none /sys/firmware/efi/efivars +fi + # populate bootparam environment for p in `cat /proc/cmdline`; do + if [ -n "$quoted" ]; then + value="$value $p" + if [ "`echo $p | sed -e 's/\"$//'`" != "$p" ]; then + eval "bootparam_${quoted}=${value}" + unset quoted + fi + continue + fi + opt=`echo $p | cut -d'=' -f1` - opt=`echo $opt | tr '.-' '__'` + opt=`echo $opt | sed -e 'y/.-/__/'` if [ "`echo $p | cut -d'=' -f1`" = "$p" ]; then eval "bootparam_${opt}=true" else value="`echo $p | cut -d'=' -f2-`" + if [ "`echo $value | sed -e 's/^\"//'`" != "$value" ]; then + quoted=${opt} + continue + fi eval "bootparam_${opt}=\"${value}\"" fi done diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/lvm b/meta/recipes-core/initrdscripts/initramfs-framework/lvm new file mode 100644 index 0000000000..7deeccb9a2 --- /dev/null +++ b/meta/recipes-core/initrdscripts/initramfs-framework/lvm @@ -0,0 +1,13 @@ +#!/bin/sh + +lvm_enabled() { + if ! lvscan |grep -i -w "inactive" &>/dev/null;then + return 1 + fi + return 0 +} + +lvm_run() { + lvm pvscan --cache --activate ay + udevadm trigger --action=add +} diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/nfsrootfs b/meta/recipes-core/initrdscripts/initramfs-framework/nfsrootfs new file mode 100644 index 0000000000..e67ee4c25d --- /dev/null +++ b/meta/recipes-core/initrdscripts/initramfs-framework/nfsrootfs @@ -0,0 +1,48 @@ +#!/bin/sh + +nfsrootfs_enabled() { + if [ ${bootparam_root} != "/dev/nfs" ] || [ -z ${bootparam_nfsroot} ]; then + return 1 + fi + return 0 +} + +nfsrootfs_run() { + local nfs_opts + local location + local flags + local server_ip + + nfs_opts="" + if [ "${bootparam_nfsroot#*,}" != "${bootparam_nfsroot}" ]; then + nfs_opts="-o ${bootparam_nfsroot#*,}" + fi + + location="${bootparam_nfsroot%%,*}" + if [ "${location#*:}" = "${location}" ]; then + # server-ip not given. Get server ip from ip option + server_ip="" + if [ "${bootparam_ip#*:}" != "${bootparam_ip}" ]; then + server_ip=$(echo "$bootparam_ip" | cut -d: -f2) + fi + + if [ -z "$server_ip" ]; then + fatal "Server IP is not set. Update ip or nfsroot options." + fi + location=${server_ip}:${location} + fi + + flags="-o nolock" + if [ -n "$bootparam_ro" ] && ! echo "$bootparam_rootflags" | grep -w -q "ro"; then + if [ -n "$bootparam_rootflags" ]; then + bootparam_rootflags="$bootparam_rootflags," + fi + bootparam_rootflags="${bootparam_rootflags}ro" + fi + if [ -n "$bootparam_rootflags" ]; then + flags="$flags -o $bootparam_rootflags" + fi + + mount -t nfs ${flags} ${nfs_opts} ${location} ${ROOTFS_DIR} +} + diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/overlayroot b/meta/recipes-core/initrdscripts/initramfs-framework/overlayroot new file mode 100644 index 0000000000..0d41432878 --- /dev/null +++ b/meta/recipes-core/initrdscripts/initramfs-framework/overlayroot @@ -0,0 +1,118 @@ +#!/bin/sh + +# SPDX-License-Identifier: MIT +# +# Copyright 2022 (C), Microsoft Corporation + +# Simple initramfs module intended to mount a read-write (RW) +# overlayfs on top of /, keeping the original root filesystem +# as read-only (RO), free from modifications by the user. +# +# NOTE: The read-only IMAGE_FEATURE is not required for this to work +# +# This script is based on the overlay-etc.bbclass, which sets up +# an overlay on top of the /etc directory, but in this case allows +# accessing the original, unmodified rootfs at /rofs after boot. +# +# It relies on the initramfs-module-rootfs to mount the original +# root filesystem, and requires 'overlayrootrwdev=<foo>' to be passed as a +# kernel parameter, specifying the device/partition intended to +# use as RW. +# Mount options of the RW device can be tweaked with 'overlayrootfstype=' +# (defaults to 'ext4') and 'overlayrootfsflags=' ('defaults'). +# +# This module needs to be executed after the initramfs-module-rootfs +# since it relies on it to mount the filesystem at initramfs startup +# but before the finish module which normally switches root. +# After overlayroot is executed the usual boot flow continues from +# the real init process. +# +# If something goes wrong while running this module, the rootfs +# is still mounted RO (with no overlay) and the finish module is +# executed to continue booting normally. +# +# It also has a dependency on overlayfs being enabled in the +# running kernel via KERNEL_FEATURES (kmeta) or any other means. + + +PATH=/sbin:/bin:/usr/sbin:/usr/bin + +# We get OLDROOT from the rootfs module +OLDROOT="/rootfs" + +NEWROOT="${RWMOUNT}/root" +RWMOUNT="/overlay" +ROMOUNT="${RWMOUNT}/rofs" +UPPER_DIR="${RWMOUNT}/upper" +WORK_DIR="${RWMOUNT}/work" + +MODULES_DIR=/init.d + +# Something went wrong, make sure / is mounted as read only anyway. +exit_gracefully() { + echo $1 >/dev/console + echo >/dev/console + echo "OverlayRoot mounting failed, starting system as read-only" >/dev/console + echo >/dev/console + + # The following is borrowed from rootfs-postcommands.bbclass + # This basically looks at the real rootfs mounting options and + # replaces them with "ro" + + # Tweak the mount option and fs_passno for rootfs in fstab + if [ -f ${OLDROOT}/etc/fstab ]; then + sed -i -e '/^[#[:space:]]*\/dev\/root/{s/defaults/ro/;s/\([[:space:]]*[[:digit:]]\)\([[:space:]]*\)[[:digit:]]$/\1\20/}' ${OLDROOT}/etc/fstab + fi + + # Tweak the "mount -o remount,rw /" command in busybox-inittab inittab + if [ -f ${OLDROOT}/etc/inittab ]; then + sed -i 's|/bin/mount -o remount,rw /|/bin/mount -o remount,ro /|' ${OLDROOT}/etc/inittab + fi + + # Continue as if the overlayroot module didn't exist to continue booting + . $MODULES_DIR/99-finish + eval "finish_run" +} + +# migrate legacy parameter +if [ ! -z "$bootparam_rootrw" ]; then + bootparam_overlayrootrwdev="$bootparam_rootrw" +fi + +if [ -z "$bootparam_overlayrootrwdev" ]; then + exit_gracefully "overlayrootrwdev= kernel parameter doesn't exist and its required to mount the overlayfs" +fi + +mkdir -p ${RWMOUNT} + +# Mount RW device +if mount -n -t ${bootparam_overlayrootfstype:-ext4} -o ${bootparam_overlayrootfsflags:-defaults} ${bootparam_overlayrootrwdev} ${RWMOUNT} +then + # Set up overlay directories + mkdir -p ${UPPER_DIR} + mkdir -p ${WORK_DIR} + mkdir -p ${NEWROOT} + mkdir -p ${ROMOUNT} + + # Remount OLDROOT as read-only + mount -o bind ${OLDROOT} ${ROMOUNT} + mount -o remount,ro ${ROMOUNT} + + # Mount RW overlay + mount -t overlay overlay -o lowerdir=${ROMOUNT},upperdir=${UPPER_DIR},workdir=${WORK_DIR} ${NEWROOT} || exit_gracefully "initramfs-overlayroot: Mounting overlay failed" +else + exit_gracefully "initramfs-overlayroot: Mounting RW device failed" +fi + +# Set up filesystems on overlay +mkdir -p ${NEWROOT}/proc +mkdir -p ${NEWROOT}/dev +mkdir -p ${NEWROOT}/sys +mkdir -p ${NEWROOT}/rofs + +mount -n --move ${ROMOUNT} ${NEWROOT}/rofs +mount -n --move /proc ${NEWROOT}/proc +mount -n --move /sys ${NEWROOT}/sys +mount -n --move /dev ${NEWROOT}/dev + +exec chroot ${NEWROOT}/ ${bootparam_init:-/sbin/init} || exit_gracefully "Couldn't chroot into overlay" diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/rootfs b/meta/recipes-core/initrdscripts/initramfs-framework/rootfs index 14768f1cd4..e0efbe6ebe 100644 --- a/meta/recipes-core/initrdscripts/initramfs-framework/rootfs +++ b/meta/recipes-core/initrdscripts/initramfs-framework/rootfs @@ -13,7 +13,7 @@ rootfs_run() { C=0 delay=${bootparam_rootdelay:-1} timeout=${bootparam_roottimeout:-5} - while [ ! -d $ROOTFS_DIR/dev ]; do + while ! mountpoint -q $ROOTFS_DIR; do if [ $(( $C * $delay )) -gt $timeout ]; then fatal "root '$bootparam_root' doesn't exist or does not contain a /dev." fi @@ -24,11 +24,15 @@ rootfs_run() { if [ "`echo ${bootparam_root} | cut -c1-5`" = "UUID=" ]; then root_uuid=`echo $bootparam_root | cut -c6-` bootparam_root="/dev/disk/by-uuid/$root_uuid" - fi - - if [ "`echo ${bootparam_root} | cut -c1-9`" = "PARTUUID=" ]; then - root_uuid=`echo $bootparam_root | cut -c10-` - bootparam_root="/dev/disk/by-partuuid/$root_uuid" + elif [ "`echo ${bootparam_root} | cut -c1-9`" = "PARTUUID=" ]; then + root_partuuid=`echo $bootparam_root | cut -c10-` + bootparam_root="/dev/disk/by-partuuid/$root_partuuid" + elif [ "`echo ${bootparam_root} | cut -c1-10`" = "PARTLABEL=" ]; then + root_partlabel=`echo $bootparam_root | cut -c11-` + bootparam_root="/dev/disk/by-partlabel/$root_partlabel" + elif [ "`echo ${bootparam_root} | cut -c1-6`" = "LABEL=" ]; then + root_label=`echo $bootparam_root | cut -c7-` + bootparam_root="/dev/disk/by-label/$root_label" fi if [ -e "$bootparam_root" ]; then @@ -46,14 +50,14 @@ rootfs_run() { flags="$flags -t$bootparam_rootfstype" fi mount $flags $bootparam_root $ROOTFS_DIR - if [ -d $ROOTFS_DIR/dev ]; then + if mountpoint -q $ROOTFS_DIR; then break else # It is unlikely to change, but keep trying anyway. # Perhaps we pick a different device next time. umount $ROOTFS_DIR - fi fi + fi fi debug "Sleeping for $delay second(s) to wait root to settle..." sleep $delay diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/setup-live b/meta/recipes-core/initrdscripts/initramfs-framework/setup-live index 4c79f41285..7e92f93322 100644 --- a/meta/recipes-core/initrdscripts/initramfs-framework/setup-live +++ b/meta/recipes-core/initrdscripts/initramfs-framework/setup-live @@ -1,4 +1,4 @@ -#/bin/sh +#!/bin/sh # Copyright (C) 2011 O.S. Systems Software LTDA. # Licensed on MIT diff --git a/meta/recipes-core/initrdscripts/initramfs-framework/udev b/meta/recipes-core/initrdscripts/initramfs-framework/udev index 79c8867823..4898b89246 100644 --- a/meta/recipes-core/initrdscripts/initramfs-framework/udev +++ b/meta/recipes-core/initrdscripts/initramfs-framework/udev @@ -6,6 +6,7 @@ udev_shutdown_hook_handler() { status=$1 module=$2 if [ "$status" = "pre" ] && [ "$module" = "finish" ]; then + udevadm settle killall `basename $_UDEV_DAEMON` 2>/dev/null fi } @@ -40,6 +41,9 @@ udev_run() { mkdir -p /run mkdir -p /var/run + # Workaround if console=null, systemd-udevd needs valid stdin, stdout and stderr to work + sh -c "exec 4< /dev/console" || { exec 0> /dev/null; exec 1> /dev/null; exec 2> /dev/null; } + $_UDEV_DAEMON --daemon udevadm trigger --action=add udevadm settle |