blob: d40342dc59d9318be47e5390045747ba625dbea8 [file] [log] [blame]
Andrew Geissler9aee5002022-03-30 16:27:02 +00001#!/bin/sh
2
3# SPDX-License-Identifier: MIT
4#
5# Copyright 2022 (C), Microsoft Corporation
6
7# Simple initramfs module intended to mount a read-write (RW)
8# overlayfs on top of /, keeping the original root filesystem
9# as read-only (RO), free from modifications by the user.
10#
11# NOTE: The read-only IMAGE_FEATURE is not required for this to work
12#
13# This script is based on the overlay-etc.bbclass, which sets up
14# an overlay on top of the /etc directory, but in this case allows
15# accessing the original, unmodified rootfs at /rofs after boot.
16#
17# It relies on the initramfs-module-rootfs to mount the original
18# root filesystem, and requires 'rootrw=<foo>' to be passed as a
19# kernel parameter, specifying the device/partition intended to
20# use as RW.
21#
22# This module needs to be executed after the initramfs-module-rootfs
23# since it relies on it to mount the filesystem at initramfs startup
24# but before the finish module which normally switches root.
25# After overlayroot is executed the usual boot flow continues from
26# the real init process.
27#
28# If something goes wrong while running this module, the rootfs
29# is still mounted RO (with no overlay) and the finish module is
30# executed to continue booting normally.
31#
32# It also has a dependency on overlayfs being enabled in the
33# running kernel via KERNEL_FEATURES (kmeta) or any other means.
34
35
36PATH=/sbin:/bin:/usr/sbin:/usr/bin
37
38# We get OLDROOT from the rootfs module
39OLDROOT="/rootfs"
40
41NEWROOT="${RWMOUNT}/root"
42RWMOUNT="/overlay"
43ROMOUNT="${RWMOUNT}/rofs"
44UPPER_DIR="${RWMOUNT}/upper"
45WORK_DIR="${RWMOUNT}/work"
46
47MODULES_DIR=/init.d
48
49# Something went wrong, make sure / is mounted as read only anyway.
50exit_gracefully() {
51 echo $1 >/dev/console
52 echo >/dev/console
53 echo "OverlayRoot mounting failed, starting system as read-only" >/dev/console
54 echo >/dev/console
55
56 # The following is borrowed from rootfs-postcommands.bbclass
57 # This basically looks at the real rootfs mounting options and
58 # replaces them with "ro"
59
60 # Tweak the mount option and fs_passno for rootfs in fstab
61 if [ -f ${OLDROOT}/etc/fstab ]; then
62 sed -i -e '/^[#[:space:]]*\/dev\/root/{s/defaults/ro/;s/\([[:space:]]*[[:digit:]]\)\([[:space:]]*\)[[:digit:]]$/\1\20/}' ${OLDROOT}/etc/fstab
63 fi
64
65 # Tweak the "mount -o remount,rw /" command in busybox-inittab inittab
66 if [ -f ${OLDROOT}/etc/inittab ]; then
67 sed -i 's|/bin/mount -o remount,rw /|/bin/mount -o remount,ro /|' ${OLDROOT}/etc/inittab
68 fi
69
70 # Continue as if the overlayroot module didn't exist to continue booting
71 . $MODULES_DIR/99-finish
72 eval "finish_run"
73}
74
75
76if [ -z "$bootparam_rootrw" ]; then
77 exit_gracefully "rootrw= kernel parameter doesn't exist and its required to mount the overlayfs"
78fi
79
80mkdir -p ${RWMOUNT}
81
82# Mount RW device
83if mount -n -t ${bootparam_rootfstype:-ext4} -o ${bootparam_rootflags:-defaults} ${bootparam_rootrw} ${RWMOUNT}
84then
85 # Set up overlay directories
86 mkdir -p ${UPPER_DIR}
87 mkdir -p ${WORK_DIR}
88 mkdir -p ${NEWROOT}
89 mkdir -p ${ROMOUNT}
90
91 # Remount OLDROOT as read-only
92 mount -o bind ${OLDROOT} ${ROMOUNT}
93 mount -o remount,ro ${ROMOUNT}
94
95 # Mount RW overlay
96 mount -t overlay overlay -o lowerdir=${ROMOUNT},upperdir=${UPPER_DIR},workdir=${WORK_DIR} ${NEWROOT} || exit_gracefully "initramfs-overlayroot: Mounting overlay failed"
97else
98 exit_gracefully "initramfs-overlayroot: Mounting RW device failed"
99fi
100
101# Set up filesystems on overlay
102mkdir -p ${NEWROOT}/proc
103mkdir -p ${NEWROOT}/dev
104mkdir -p ${NEWROOT}/sys
105mkdir -p ${NEWROOT}/rofs
106
107mount -n --move ${ROMOUNT} ${NEWROOT}/rofs
108mount -n --move /proc ${NEWROOT}/proc
109mount -n --move /sys ${NEWROOT}/sys
110mount -n --move /dev ${NEWROOT}/dev
111
112exec chroot ${NEWROOT}/ ${bootparam_init:-/sbin/init} || exit_gracefully "Couldn't chroot into overlay"