summaryrefslogtreecommitdiff
path: root/recipes-core/initrdscripts/files
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-core/initrdscripts/files')
-rwxr-xr-xrecipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh356
1 files changed, 356 insertions, 0 deletions
diff --git a/recipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh b/recipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh
new file mode 100755
index 0000000..199fc17
--- /dev/null
+++ b/recipes-core/initrdscripts/files/init-readonly-rootfs-overlay-boot.sh
@@ -0,0 +1,356 @@
+#!/bin/bash
+# fsck output of the upper file system (rw) is
+# written to /dev/kmsg
+
+# Kernel arguments for this script:
+# This script allows one to specify the root read-only device with
+# kernel argument:
+# root=
+# What follows can be a PARTUUID, PARTLABEL, or some other mechanism
+# understood by findfs, including the plain device name.
+#
+# The rw file system overlayed on top of root defaults to:
+# rootrw='PARTLABEL=user_data'
+# This is the first GPT partition found with the name user_data.
+#
+# Another file system can be specified by PARTUUID, or the
+# plain device name, or anything understood by findfs.
+# For instance:
+# rootrw=/dev/mmcblk0p10
+# to use the SD card.
+#
+# fsck is not done to the root file system. It is assumed it cannot be
+# corrupted.
+# By default, fsck -p [rootrw device] is done.
+#
+# There are two kernel options governing fsck:
+#
+# fsck.repair=true|false|force
+# false skips fsck, force adds the -f option.
+# true is the default (fsck with no -f option)
+# fsck.mode=preen|yes|no
+# These represent -p, -y, and -n options.
+# Preen (-p) is the default
+#
+# Additional options exist to specify the init program
+# mount options, file system type. rootrwreset="yes"
+# will cause the read/write file system to be erased.
+#
+# shintramfs starts a shell. To continue boot from
+# shell:
+#
+# bash-4.4# export ROOT_MOUNT=/mnt
+# bash-4.4# export INIT=/sbin/init
+# bash-4.4# exec switch_root $ROOT_MOUNT $INIT
+#
+#
+# U-Boot environment example to add an init overlay parameter:
+#
+# => printenv args_mmc
+# args_mmc=run finduuid;setenv bootargs console=${console} ${optargs} root=PARTUUID=${uuid} rw rootfstype=${mmcrootfstype}
+#
+# => setenv args_mmc 'run finduuid;setenv bootargs console=${console} ${optargs} root=PARTUUID=${uuid} rw rootfstype=${mmcrootfstype} rootrwreset=yes'
+
+
+# Enable strict shell mode
+set -euo pipefail
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+MOUNT="/bin/mount"
+UMOUNT="/bin/umount"
+
+INIT="/sbin/init"
+ROOT_ROINIT="/sbin/init"
+
+ROOT_MOUNT="/mnt"
+ROOT_RODEVICE=""
+ROOT_RWDEVICE=""
+ROOT_ROMOUNT="/run/media/rfs/ro"
+ROOT_RWMOUNT="/run/media/rfs/rw"
+ROOT_RWRESET="no"
+
+ROOT_ROFSTYPE=""
+ROOT_ROMOUNTOPTIONS="bind"
+ROOT_ROMOUNTOPTIONS_DEVICE="noatime,nodiratime,discard,ro"
+
+ROOT_RWFSTYPE=""
+ROOT_RWMOUNTOPTIONS="rw,noatime,mode=755 tmpfs"
+ROOT_RWMOUNTOPTIONS_DEVICE="rw,noatime,nodiratime,discard"
+
+# Arithmetic assignments of 0 are false, and then
+# script uses set -e, so use let instead.
+DO_FSCK=1
+DO_STOP=0
+FSCKOPT="-p"
+
+
+finddevice() {
+ DEVICE="$1"
+ if dev=$(findfs "${DEVICE}") && ((${#dev})) ; then
+ # Replace the rootfs string with the findfs device result
+ log "Searched for ${DEVICE} and found $dev"
+ echo "$dev"
+ return 0
+ fi
+ log "Could not find $DEVICE"
+ return 1
+}
+
+early_setup() {
+ mkdir -p /proc
+ mkdir -p /sys
+ $MOUNT -t proc proc /proc
+ $MOUNT -t sysfs sysfs /sys
+ grep -w "/dev" /proc/mounts >/dev/null || $MOUNT -t devtmpfs none /dev
+}
+
+read_args() {
+ # Default is to do fsck with -p option on user_data partition.
+ [ -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
+ shinitramfs)
+ ((DO_STOP=1)) ;;
+ root=*)
+ ROOT_RODEVICE=$optarg
+ if rootdev=$(finddevice "${ROOT_RODEVICE}") ; then
+ # Replace the rootfs string with the findfs device result
+ ROOT_RODEVICE="${rootdev}"
+ log "Actual root device to be used: $ROOT_RODEVICE"
+ fi
+ ;;
+ rootfstype=*)
+ ROOT_ROFSTYPE="$optarg" ;;
+ rootinit=*)
+ ROOT_ROINIT=$optarg ;;
+ rootoptions=*)
+ ROOT_ROMOUNTOPTIONS_DEVICE="$optarg" ;;
+ rootrw=*)
+ ROOT_RWDEVICE=$optarg
+ if rootrwdev="$(finddevice ${ROOT_RWDEVICE})" ; then
+ # Replace the rootfs string with the findfs device result
+ ROOT_RWDEVICE="${rootrwdev}"
+ fi
+ ;;
+ rootrwfstype=*)
+ ROOT_RWFSTYPE="$optarg" ;;
+ rootrwreset=*)
+ ROOT_RWRESET=$optarg ;;
+ rootrwoptions=*)
+ ROOT_RWMOUNTOPTIONS_DEVICE="$optarg" ;;
+ init=*)
+ INIT=$optarg ;;
+ fsck.mode=*)
+ fsck_mode=$optarg
+ case $fsck_mode in
+ preen)
+ FSCKOPT="-p" ;;
+ yes)
+ FSCKOPT="-y" ;;
+ no)
+ FSCKOPT="-n" ;;
+ esac
+ ;;
+ fsck.repair=*)
+ fsck_repair=$optarg
+ case $fsck_repair in
+ force)
+ if ((${#FSCKOPT})) ; then
+ FSCKOPT+="f"
+ else
+ FSCKOPT="-f"
+ fi
+ DO_FSCK=1
+ ;;
+ yes)
+ DO_FSCK=1
+ ;;
+ no)
+ DO_FSCK=0
+ ;;
+ esac
+
+ ;;
+ esac
+ done
+}
+
+fatal() {
+ echo "rorootfs-overlay: $1" >$CONSOLE
+ echo >$CONSOLE
+ exec bash
+}
+
+log() {
+ echo "rorootfs-overlay: ${BASH_LINENO[*]}: ${*-""}" >$CONSOLE
+}
+
+early_setup
+
+[ -z "${CONSOLE+x}" ] && CONSOLE="/dev/kmsg"
+
+log "Kernel args are:"
+log "$(cat /proc/cmdline)"
+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_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
+ log "ROOT_RODEVICE: empty: ${ROOT_RODEVICE}"
+ ROOT_ROMOUNTPARAMS="$ROOT_ROMOUNTPARAMS_BIND"
+ fi
+
+ mountlog=$($MOUNT $ROOT_ROMOUNTPARAMS "$ROOT_ROMOUNT" 2>&1)
+ mountresult=$?
+ if ((mountresult != 0)) ; then
+ log "Failed root mount (result $mountresult): $mountlog"
+ else
+ log "Mounted root: $MOUNT $ROOT_ROMOUNTPARAMS "$ROOT_ROMOUNT": $mountlog"
+ log "Mounted ro root: $(grep "$ROOT_ROMOUNT" /proc/mounts)"
+ 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
+
+ # find user_data
+ if [[ -z ${ROOT_RWDEVICE} ]] ; then
+ userdata=$(findfs PARTLABEL=user_data)
+ blkid_out=$(blkid $userdata)
+ if [[ -n $userdata ]] ; then
+ if [[ $blkid_out =~ TYPE=\"([^\"]+)\" ]]; then
+ log "Detected user_data partition with ${BASH_REMATCH[1]} file system"
+ else
+ log "Create new user_data partition ext4 file system"
+ mkfs.ext4 -O 64bit $userdata
+ fi
+ ROOT_RWDEVICE="$userdata"
+ fi # Found user_data GPT partition
+ fi # Empty ROOT_RWDEVICE
+
+ # Build mount options for read write root file system.
+ # If a read-write device was specified via kernel command line
+ # or partition table, use it, otherwise default to tmpfs.
+ if [ -n "${ROOT_RWDEVICE}" ]; then
+ 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
+
+ if ((DO_FSCK == 1)) ; then
+ if log_result=$(fsck $FSCKOPT $ROOT_RWDEVICE 2>&1) ; then
+ log "OK fsck user_data: fsck $FSCKOPT $ROOT_RWDEVICE:"
+ log "fsck user_data: $log_result"
+ else
+ log "ERR fsck user_data: fsck $FSCKOPT $ROOT_RWDEVICE:"
+ log "$log_result"
+ fi
+ fi
+
+ log "user_data: $MOUNT $ROOT_RWMOUNTPARAMS $ROOT_RWMOUNT"
+ # Mount read-write file system into initram root file system
+ if ! $MOUNT $ROOT_RWMOUNTPARAMS $ROOT_RWMOUNT ; then
+ fatal "Could not mount read-write rootfs"
+ fi
+
+ # Reset read-write file system if specified
+ log "ROOT_RWRESET=$ROOT_RWRESET ROOT_RWMOUNT=$ROOT_RWMOUNT"
+ if [ "yes" == "$ROOT_RWRESET" -a -n "${ROOT_RWMOUNT}" ]; then # JAK
+ log "Removing user_data files"
+ rm -rf $ROOT_RWMOUNT/*
+ log "Completed removal of user_data files"
+ 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
+ if ! $MOUNT -t overlay overlay \
+ -o "$(printf "%s%s%s" \
+ "lowerdir=$ROOT_ROMOUNT," \
+ "upperdir=$ROOT_RWMOUNT/upperdir," \
+ "workdir=$ROOT_RWMOUNT/work")" \
+ $ROOT_MOUNT ; then
+ log "$MOUNT -t overlay overlay \
+ -o \"$(printf \"%s%s%s\" \
+ \"lowerdir=$ROOT_ROMOUNT,\" \
+ \"upperdir=$ROOT_RWMOUNT/upperdir,\" \
+ \"workdir=$ROOT_RWMOUNT/work\")\" \
+ $ROOT_MOUNT"
+ fatal "Cound not mount overlay"
+ fi
+ ;;
+ "aufs")
+ $MOUNT -t aufs i\
+ -o "dirs=$ROOT_RWMOUNT=rw:$ROOT_ROMOUNT=ro" \
+ aufs $ROOT_MOUNT
+ ;;
+ "")
+ fatal "No overlay filesystem type available"
+ ;;
+ esac
+
+ # 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
+
+
+ # Create persistent storage directory and bind-mount it as /var/persistent.
+ # The directory name starts with "." so "rm -rf" will skip it on read-write file system reset.
+ mkdir -p ${ROOT_MOUNT}/$ROOT_RWMOUNT/.persistent
+ mkdir -p ${ROOT_MOUNT}/var/persistent
+ $MOUNT -n --bind ${ROOT_MOUNT}/$ROOT_RWMOUNT/.persistent ${ROOT_MOUNT}/var/persistent
+
+ if ((DO_STOP)) ; then
+ fatal "Initramfs Shell mode selected -- bash shell"
+ fi
+
+ $MOUNT -n --move /proc ${ROOT_MOUNT}/proc
+ $MOUNT -n --move /sys ${ROOT_MOUNT}/sys
+ $MOUNT -n --move /dev ${ROOT_MOUNT}/dev
+
+ CONSOLE="${ROOT_MOUNT}/dev/kmsg"
+ log "Mounted filesystems:"
+ log "$(cat ${ROOT_MOUNT}/proc/mounts)"
+ 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