Bug 3406

Summary: Read-only rootfs support
Product: [Build System, Metadata & Runtime] OE-Core Reporter: Paul Eggleton <bluelightning>
Component: coreAssignee: Chen Qi <Qi.Chen>
Status: VERIFIED FIXED QA Contact:
Severity: enhancement    
Priority: Medium+ CC: jessica.zhang, liezhi.yang, maciek, mark.hatle, meta.mr.watcher, meta.watcher, Qi.Chen, sgw, song.liu, sstncr, yi.zhao, zhenfeng.zhao
Version: 1.4   
Target Milestone: 1.4 M5   
Hardware: All   
OS: Multiple   
Whiteboard: Patch Review
OS type for building Yocto: --- Type of Regression: ---
Verified: Documentation change: ---
Bug Depends on: 3407    
Bug Blocks:    
Attachments:
Description Flags
Log of read-only boot of core-image-sato none

Description Paul Eggleton 2012-11-12 14:55:27 UTC
Created attachment 937 [details]
Log of read-only boot of core-image-sato

At the moment, booting a target with the root filesystem being read-only causes some problems and this is something we'd like to support.

For core-image-minimal the issues are:

1) update-modules needing to be run on the target as a postinstall - this should be able to be run on the host without too much difficulty.

2) populate-volatile.sh which runs as an initscript; the parts of this that write to the rootfs should be able to be done on the host.

Attached is a log when running core-image-sato with a read-only rootfs, showing other issues. I'm not sure how many of those we can commit to fixing though.
Comment 1 Maciek 2012-11-13 13:20:48 UTC
/etc/init.d/bootmisc.sh:59

# This is as good a place as any for a sanity check
# /tmp should be a symlink to /var/tmp to cut down on the number     
# of mounted ramdisks.       
if test ! -L /tmp && test -d /var/tmp
then                       
        rm -rf /tmp                             
        ln -sf /var/tmp /tmp                                   
fi

On read-only / you can't delete /tmp it should be done before image creation
Comment 2 Chen Qi 2012-11-14 07:40:10 UTC
There are also some other initscripts that may write to rootfs.
udev-cache, bootmisc.sh, avahi-daemon, rmnologin.sh
Comment 3 Chen Qi 2012-12-11 03:11:06 UTC
A first implementation, please have a look at it.

From 2090c4034958af58f9df950cd171c63fe71d4ace Mon Sep 17 00:00:00 2001
From: Chen Qi <Qi.Chen@windriver.com>
Date: Mon, 10 Dec 2012 14:30:48 +0800
Subject: [PATCH] Read-only Rootfs Support

Signed-off-by: Chen Qi <Qi.Chen@windriver.com>
---
 .../initscripts-1.0/readonly-rootfs-hook.sh        |  151 ++++++++++++++++++++
 meta/recipes-core/initscripts/initscripts_1.0.bb   |    6 +-
 2 files changed, 156 insertions(+), 1 deletions(-)
 create mode 100755 meta/recipes-core/initscripts/initscripts-1.0/readonly-rootfs-hook.sh

diff --git a/meta/recipes-core/initscripts/initscripts-1.0/readonly-rootfs-hook.sh b/meta/recipes-core/initscripts/initscripts-1.0/readonly-rootfs-hook.sh
new file mode 100755
index 0000000..d9a3c7a
--- /dev/null
+++ b/meta/recipes-core/initscripts/initscripts-1.0/readonly-rootfs-hook.sh
@@ -0,0 +1,151 @@
+#!/bin/sh
+# Short-Description: Hook script to support read-only rootfs 
+
+# This script starts after mountall.sh and before populate-volatile.sh
+# This script stops after postintalls on the target having been done
+
+# helper functions
+migrate() {
+    orig_dir=$1
+    volatile_dir=$2
+    # migrate $orig_dir to be under $volatile_dir, and make a link to it
+    # $volatile_dir is supposed to be under /var/volatile
+    [ -d "$volatile_dir" ] || mkdir -p "$volatile_dir"
+    [ -d "$orig_dir" ] && cp -r "$orig_dir" "$volatile_dir"
+    rm -rf "$orig_dir"
+    ln -sf "$volatile_dir" "$orig_dir"
+}
+
+# functions to help fix the first boot problem
+module_id() {
+        awk 'BEGIN { FS=": " } /Hardware/ { print $2 } ' </proc/cpuinfo
+}
+
+support_irattach() {
+    if [ ! -f /etc/sysconfig/irda ]; then                                  
+	case `module_id` in                                                
+            "HP iPAQ H2200" | "HP iPAQ HX4700" | "HTC Universal")          
+		IRDA=yes                                                   
+		DEVICE=/dev/ttyS2                                          
+		DONGLE=                                                    
+		DISCOVERY=                                                 
+		;;                                                         
+            *)                                                             
+		IRDA=yes                                                   
+		DEVICE=/dev/ttyS1                                
+		DONGLE=                                          
+		DISCOVERY=                                       
+		;;                                               
+	esac                                                     
+	mkdir -p /etc/sysconfig                                   
+	echo "IRDA=$IRDA" > /etc/sysconfig/irda                   
+	if [ $IRDA = "yes" ]; then                                
+            echo "DEVICE=$DEVICE" >> /etc/sysconfig/irda          
+            echo "DONGLE=$DONGLE" >> /etc/sysconfig/irda     
+            echo "DISCOVERY=$DISCOVERY" >> /etc/sysconfig/irda   
+	fi                                                        
+    fi    
+}
+
+# Set basic varibles
+RO_ROOTFS_INFO_FILE="/etc/.ro_rootfs_info_file"
+[ -w /etc ] && ROOTMODE="rw" || ROOTMODE="ro"
+FLAG_TMP_RW_ROOTFS="no"
+ACTION="$1"
+case "$0" in
+    *stop-readonly-rootfs-hook*)
+	ACTION="stop"
+	;;
+esac
+
+# Actions
+case "$ACTION" in
+    start)
+	# Certain directories under /var/lib and /var/volatile/ have to be handled properly
+	# to deal with the following situations correctly.
+	# last-time this-time
+	# ro ro -> may need to make some dirs under /var/volatile
+	# ro rw -> may need to make dirs under /var/lib
+	# rw rw -> nothing to do (keep the same as before)
+	# rw ro -> nothing to do (the stop-readonly-rootfs-hook will take care of this situation)
+	# -- ro -> nothing to do (the stop-readonly-rootfs-hook will take care of this situation)
+	# -- rw -> nothing to do (keep the same as before)
+	# We do this for three reasons:
+	# 1) /var/volatile is a mount point for tmpfs, every time the system reboots, everything's lost
+	# 2) some application may need to write to /var/lib/xxx at run time, this type of directory should be handled carefully
+	# 3) we want things to keep the same as before if the rootfs is writable
+	LASTROOTMODE=""
+	[ -f "$RO_ROOTFS_INFO_FILE" ] && LASTROOTMODE=$(cat "$RO_ROOTFS_INFO_FILE")
+	if [ "$LASTROOTMODE" == "ro" ] && [ "$ROOTMODE" == "ro" ]; then
+	    echo "last: readonly; now: readonly; make dirs under /var/volatile/lib"
+#	    mkdir -p /var/volatile/lib/xxx
+	    mkdir -p /var/volatile/lib/dropbear
+	    mkdir -p /var/volatile/lib/nfs
+	    mkdir -p /var/volatile/lib/dbus
+	elif [ "$LASTROOTMODE" == "ro" ] && [ "$ROOTMODE" == "rw" ]; then
+	    echo "last: readonly; now: readwrite; rm links, and make dirs undr /var/lib"
+#	    [ -L /var/lib/xxx ] && { rm /var/lib/xxx; mkdir /var/lib/xxx; }
+	    [ -L /var/lib/dropbear ] && { rm /var/lib/dropbear; mkdir /var/lib/dropbear; }
+	    [ -L /var/lib/nfs ] && { rm /var/lib/nfs; mkdir /var/lib/nfs; }
+	    [ -L /var/lib/dbus ] && { rm /var/lib/dbus; mkdir /var/lib/dbus; }
+	fi	    
+	if [ -f "$RO_ROOTFS_INFO_FILE" ] && [ "$LASTROOTMODE" == "ro" ]; then
+	    echo $ROOTMODE > "$RO_ROOTFS_INFO_FILE"
+	    exit 0
+	fi
+	if [ "$ROOTMODE" == "ro" ]; then
+	    # boot with read-only rootfs & last time rootmode isn't ro ==> mount it as rw temporarily
+	    # let other daemons and init scripts do their job properly
+	    mount -o remount,rw /
+	    if [ $? != 0 ]; then
+		echo "Remount rootfs as read-write Failed"
+		exit 1
+	    else
+		echo "Remount rootfs as read-write Succeed"
+	    fi
+	fi
+	touch "$RO_ROOTFS_INFO_FILE"
+	echo $ROOTMODE > "$RO_ROOTFS_INFO_FILE"
+	;;
+    stop)
+	# If $RO_ROOTFS_INFO_FILE has "ro" in it, but the rootfs is writable now,
+	# We can assert that the rootfs has been mounted as rw temporarily
+	if [ $(cat "$RO_ROOTFS_INFO_FILE") == "ro" ] && [ -w /etc ]; then
+	    FLAG_TMP_RW_ROOTFS="yes"
+	fi
+	[ "$FLAG_TMP_RW_ROOTFS" == "no" ] && { echo "rootfs is not mounted as rw temporarily"; exit 0; }
+	# $FLAG_TMP_RW_ROOTFS == "yes" ==> rootfs should be readonly but now it's rw temporarily
+	# Do all stuff here to support read-only rootfs
+	# For example, migrate directories from /var/lib/xxx to /var/volatile/lib/xxx.
+	# These directories are needed to be written to by other applications or daemons at run time.
+
+#	migrate /var/lib/xxx /var/volatile/lib/xxx
+	migrate /var/lib/dropbear /var/volatile/lib/dropbear
+	migrate /var/lib/nfs /var/volatile/lib/nfs
+	migrate /var/lib/dbus /var/volatile/lib/dbus
+
+	# Another problem we need to take into consideration is the first boot problem.
+	# Some scripts in /etc/init.d may need to write to /etc/xxx at first boot, for example, irattach.
+	# This kind of operation should be done even if the rootfs is supposed to be read-only after system's set up.
+	# This is the section to collect all operations of such kind.
+	support_irattach
+
+	# Remount rootfs as read-only
+	mount -n -o remount,ro /
+	if [ $? == 0 ]; then
+	    echo "Remount rootfs as read-only succeed"
+	    exit 0
+	else
+	    echo "Remount rootfs as read-only failed"
+	    exit 1
+	fi
+	;;
+    *)
+        Prog=${0##*/}
+	Prog=${Prog#[SK]??}
+        echo "Usage: $Prog {start|stop}" >&2
+	exit 1
+	;;
+esac
+
+exit 0
\ No newline at end of file
diff --git a/meta/recipes-core/initscripts/initscripts_1.0.bb b/meta/recipes-core/initscripts/initscripts_1.0.bb
index d25838b..175653e 100644
--- a/meta/recipes-core/initscripts/initscripts_1.0.bb
+++ b/meta/recipes-core/initscripts/initscripts_1.0.bb
@@ -3,7 +3,7 @@ DESCRIPTION = "Initscripts provide the basic system startup initialization scrip
 SECTION = "base"
 LICENSE = "GPLv2"
 LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe"
-PR = "r137"
+PR = "r138"
 
 INHIBIT_DEFAULT_DEPS = "1"
 
@@ -31,6 +31,7 @@ SRC_URI = "file://functions \
            file://populate-volatile.sh \
            file://volatiles \
            file://save-rtc.sh \
+           file://readonly-rootfs-hook.sh \
 	   file://GPLv2.patch"
 
 SRC_URI_append_arm = " file://alignment.sh"
@@ -85,6 +86,7 @@ do_install () {
 	install -m 0755    ${WORKDIR}/sysfs.sh		${D}${sysconfdir}/init.d
 	install -m 0755    ${WORKDIR}/populate-volatile.sh ${D}${sysconfdir}/init.d
 	install -m 0755    ${WORKDIR}/save-rtc.sh	${D}${sysconfdir}/init.d
+	install -m 0755    ${WORKDIR}/readonly-rootfs-hook.sh ${D}${sysconfdir}/init.d
 	install -m 0644    ${WORKDIR}/volatiles		${D}${sysconfdir}/default/volatiles/00_core
 	if [ "${TARGET_ARCH}" = "arm" ]; then
 		install -m 0755 ${WORKDIR}/alignment.sh	${D}${sysconfdir}/init.d
@@ -119,11 +121,13 @@ do_install () {
 	ln -sf		../init.d/checkroot.sh	${D}${sysconfdir}/rcS.d/S10checkroot.sh
 #	ln -sf		../init.d/checkfs.sh	${D}${sysconfdir}/rcS.d/S30checkfs.sh
 	ln -sf		../init.d/mountall.sh	${D}${sysconfdir}/rcS.d/S35mountall.sh
+	ln -sf          ../init.d/readonly-rootfs-hook.sh ${D}${sysconfdir}/rcS.d/S36readonly-rootfs-hook
 	ln -sf		../init.d/hostname.sh	${D}${sysconfdir}/rcS.d/S39hostname.sh
 	ln -sf		../init.d/mountnfs.sh	${D}${sysconfdir}/rcS.d/S45mountnfs.sh
 	ln -sf		../init.d/bootmisc.sh	${D}${sysconfdir}/rcS.d/S55bootmisc.sh
 #	ln -sf		../init.d/urandom	${D}${sysconfdir}/rcS.d/S55urandom
 #	ln -sf		../init.d/finish.sh	${D}${sysconfdir}/rcS.d/S99finish.sh
+	ln -sf          ../init.d/readonly-rootfs-hook.sh ${D}${sysconfdir}/rcS.d/S99stop-readonly-rootfs-hook
 	ln -sf		../init.d/sysfs.sh	${D}${sysconfdir}/rcS.d/S02sysfs.sh
 	# udev will run at S03 if installed
 	ln -sf		../init.d/populate-volatile.sh	${D}${sysconfdir}/rcS.d/S37populate-volatile.sh
-- 
1.7.5.4
Comment 4 Chen Qi 2013-03-08 02:32:31 UTC
merged into poky/master: d823759b4594143d522eae0b2a2498436a6dcb1e

http://git.openembedded.org/?p=openembedded-core.git&a=commit;h=05182ee354a9f773c8ab2f4cd7f1fdf552e7fcda
Comment 5 Stefan Stanacar 2013-03-19 14:12:57 UTC
Verified with commit 410d1e049a1933c44b29416f3ac833ed001f8248, adding read-only-rootfs to EXTRA_IMAGE_FEATURES, build core-image-sato, the root fs is indeed read only.