Index: aaa_base/etc/rwtab
===================================================================
--- /dev/null
+++ aaa_base/etc/rwtab
@@ -0,0 +1,45 @@
+dirs	/var/cache/man
+#dirs	/var/gdm
+dirs	/var/lock
+dirs	/var/log
+dirs	/var/run
+
+empty	/tmp
+#empty	/var/cache/foomatic
+#empty	/var/cache/logwatch
+#empty	/var/cache/mod_ssl
+#empty	/var/cache/mod_proxy
+#empty	/var/cache/php-pear
+empty	/var/cache/systemtap
+#empty	/var/db/nscd
+#empty	/var/lib/dav
+#empty	/var/lib/dhcp
+#empty	/var/lib/dhclient
+empty	/var/lib/dhcpcd
+#empty	/var/lib/php
+#empty	/var/lib/ups
+empty	/var/tmp
+empty	/var/tux
+empty	/media
+
+files	/etc/adjtime
+files	/etc/fstab
+files	/etc/ntp.conf
+files	/etc/resolv.conf
+files	/etc/yp.conf
+files	/etc/lvm/.cache
+files	/var/account
+files	/var/adm/netconfig/md5
+files	/var/arpwatch
+files	/var/cache/alchemist
+files	/var/lib/iscsi
+files	/var/lib/logrotate.status
+files	/var/lib/ntp
+files	/var/lib/xen
+
+files	/var/lib/gdm
+#files	/etc/X11/xdm
+
+state	/var/lib/misc/random-seed
+state	/etc/ssh
+state	/etc/HOSTNAME
Index: aaa_base/usr/share/man/man5/rwtab.5
===================================================================
--- /dev/null
+++ aaa_base/usr/share/man/man5/rwtab.5
@@ -0,0 +1,95 @@
+.\"
+.\" SuSE man page rwtab
+.\" Copyright (c) 2010 SuSE Linux Products GmbH, Nuernberg, Germany.
+.\" please send bugfixes or comments to http://www.suse.de/feedback.
+.\"
+.\"
+.TH RWTAB 5 "December 18th, 2010" "Version 0.0" "Configuration for read-only root file systems"
+.\"
+.UC 5
+.SH NAME
+.\"
+rwtab \- Configuration for read-only root file systems
+.SH SYNOPSIS
+.\"
+.IR /etc/rwtab ", " /etc/rwtab.d
+.\"
+.SH DESCRIPTION
+The file /etc/rwtab and additional files in /etc/rwtab.d specify
+locations on a read-only root file system which are made writable by
+bind mounting a writable file system at that location.  These files are
+processed at boot time after the local file systems have been mounted.
+
+The following kernel command line options determine how rwtab processing
+is done during boot:
+.TP 1.5i
+readonlyroot
+Mount the root file system read-only.  Process rwtab and all files in
+/etc/rwtab.d as described below.
+.TP
+.RI scratch= device
+Mount \fIdevice\fR, and remove all files on this file
+system.  If this option is not specified, a tmpfs file system is used instead.
+.TP
+.RI state= device
+Mount \fIdevice\fR.  Alternatively, if a directory is specified instead of a device,
+assume that the directory is the mount point of a local "auto" mount defined in
+/etc/fstab (which is already mounted when this option is processed).
+
+If this file system contains the files etc/rwtab or etc/rwtab.d, bind
+mount these files over /etc/rwtab and /etc/rwtab.d, respectively, before
+rwtab processing.
+.P
+Each line in rwtab files consists of a keyword followed by a
+\fIpathname\fR.  Empty lines and lines starting with a hash character (#)
+are ignored.  The following keywords are recognized:
+.TP 1.5i
+empty
+Create a new directory \fIpathname\fR and all its parents on
+the scratch file system, and bind mount it to \fIpathname\fR.
+The pathname must be a directory.  If \fIpathname\fR does not exist
+on the read-only root file system, do nothing.
+.TP
+dirs
+Like empty, but copy all directories in the original
+\fIpathname\fR to the writable scratch directory before bind mounting
+the scratch directory over \fIpathname\fR.  Copying is recursive.  The
+pathname must be a directory.
+.TP
+files
+Like empty, but copy all files and directories in the original
+\fIpathname\fR to the writable scratch directory before bind mounting
+the scratch directory over \fIpathname\fR.  Copying is recursive. The
+pathname can be a file or directory.
+.TP
+state
+If \fIpathname\fR exists on the read-only root file system as well as on
+the state file system (see the "state=\fIdevice\fR" kernel command line
+parameter above), bind mount \fIpathname\fR on the state mount to
+\fIpathname\fR on the read-only root file system.
+
+When INIT_STATE_AUTOMATICALLY is set to "yes" in the sysconfig file
+(which is the default),  files or directories which do not yet exist on
+the state file system will be initialized by copying the files on the
+read-only root file system to the state file system first.
+.P
+The state and scratch file systems are mounted as defined in the
+syconfig file, and remain mounted at the specified locations (by
+default /var/lib/readonlyroot/state and /var/lib/readonlyroot/scratch,
+respectively).
+.SH WARNING
+When a file system is specified as a scratch area with the
+"scratch=\fIdevice\fR" kernel command line parameter, all files on that
+file system will be removed at boot time.
+.SH BUGS
+The way how \fImount\fR(1) locks /etc/mtab for modification and updates it is
+incompatible with a read-only /etc directory.  There are two possible
+workarounds: (1) convert /etc/mtab into a symlink to /proc/self/mounts
+on the read-only root file system, or (2) add the entire /etc directory
+to /etc/rwtab.  If neither is done, booting will fail.
+.SH SEE ALSO
+.B /etc/sysconfig/readonlyroot
+.SH COPYRIGHT
+2010 SuSE Linux Products GmbH, Nuernberg, Germany.
+.SH AUTHOR
+Andreas Gruenbacher <agruen@suse.de>
Index: aaa_base/etc/init.d/boot.localfs
===================================================================
--- aaa_base.orig/etc/init.d/boot.localfs
+++ aaa_base/etc/init.d/boot.localfs
@@ -149,6 +149,32 @@ case "$1" in
         fi
 	FSCK_RETURN=0
 	if test ! -f /fastboot -a "$DO_FASTBOOT" != "yes" -a $MAY_FSCK -eq 1 ; then
+	    if rc_readonlyroot ; then
+		. /etc/sysconfig/readonlyroot
+		STATE_DEV=$(rc_cmdline state)
+		STATE_DEV=${STATE_DEV#state=}
+		SCRATCH_DEV=$(rc_cmdline scratch)
+		SCRATCH_DEV=${SCRATCH_DEV#scratch=}
+
+		FSTAB_FILE=/dev/shm/readonlyroot-fstab
+		if test -d "$STATE_DEV" ; then
+		    : # Assume the state filesystem is already mounted (i.e., listed in /etc/fstab).
+		elif test -n "$STATE_DEV" -a -n "$STATE_MOUNT" ; then
+		    echo "$STATE_DEV $STATE_MOUNT auto ${STATE_MOUNT_OPTS:-defaults} 0 2" \
+			>> $FSTAB_FILE
+		fi
+		if test -n "$SCRATCH_DEV" -a -n "$SCRATCH_MOUNT" ; then
+		    echo "$SCRATCH_DEV $SCRATCH_MOUNT auto ${SCRATCH_MOUNT_OPTS:-defaults} 0 2" \
+			>> $FSTAB_FILE
+		fi
+		if test -e $FSTAB_FILE ; then
+		    cat /etc/fstab >> $FSTAB_FILE
+		    export FSTAB_FILE
+		else
+		    unset FSTAB_FILE
+		fi
+	    fi
+
 	    # common options for file system check
 	    FSCK_OPTS="-R -A -M -a"
 	    # force file system check if forced
@@ -167,6 +193,7 @@ case "$1" in
 	    # were corrected, but that the boot may proceed.
 	    # A return code of 2 or larger indicates failure.
 	    FSCK_RETURN=$?
+	    test -n "$FSTAB_FILE" && rm -f $FSTAB_FILE
 	    test $FSCK_RETURN -lt 4
 	    rc_status -v1 -r
 	    if test $FSCK_RETURN -gt 1 -a $FSCK_RETURN -lt 4 ; then
@@ -258,6 +285,123 @@ case "$1" in
 	# mount the rest
 	mount -av -t $nofs -O no_netdev
 	rc_status -v1 -r
+
+	if rc_readonlyroot ; then
+	    init_state() {
+		if test -n "$STATE_MOUNT" -a -e "$1" -a ! -e "$STATE_MOUNT/$1" ; then
+		    echo "Initializing $STATE_MOUNT/$1 from $1"
+		    cp -a --parents "$1" "$STATE_MOUNT/"
+		fi
+	    }
+
+	    mount_state() {
+		if test -n "$STATE_MOUNT" -a -e "$STATE_MOUNT/$1" -a -e "$1" ; then
+		    mount -v --bind "$STATE_MOUNT/$1" "$1" &&
+		    STATE_MOUNT_USED=1
+		fi
+	    }
+
+	    mount_empty() {
+		if test -n "$SCRATCH_MOUNT" -a -e "$1" ; then
+		    echo "$1" \
+		    | cpio --pass-through --make-directories --quiet "$SCRATCH_MOUNT" &&
+		    mount -v --bind "$SCRATCH_MOUNT$1" "$1" &&
+		    SCRATCH_MOUNT_USED=1
+		fi
+	    }
+
+	    mount_dirs() {
+		if test -n "$SCRATCH_MOUNT" -a -d "$1" ; then
+		    /usr/bin/find "$1" -type d -print0 \
+		    | cpio --pass-through --make-directories --null --quiet "$SCRATCH_MOUNT" &&
+		    mount -v --bind "$SCRATCH_MOUNT$1" "$1" &&
+		    SCRATCH_MOUNT_USED=1
+		fi
+	    }
+
+	    mount_files() {
+		if test -n "$SCRATCH_MOUNT" -a -e "$1" ; then
+		    cp -a --parents "$1" "$SCRATCH_MOUNT" &&
+		    mount -v --bind "$SCRATCH_MOUNT$1" "$1" &&
+		    SCRATCH_MOUNT_USED=1
+		fi
+	    }
+
+	    if test -d "$STATE_DEV" ; then
+		# Assume the state filesystem is already mounted (i.e., listed in /etc/fstab).
+		STATE_MOUNT=$STATE_DEV
+	    elif test -n "$STATE_MOUNT" -a -n "$STATE_DEV" ; then
+		# Mount state filesystem if a state= kernel command line option is
+		# specified.
+		echo "Mounting state filesystem ..."
+		if ! err=$(mount -v -n $STATE_MOUNT_OPTS $STATE_DEV $STATE_MOUNT 2>&1) &&
+		   ! echo "$err" | grep -q "is already mounted on" ; then
+		    rc_status
+		    STATE_MOUNT=
+		fi
+		test -n "$err" && echo "$err" >&2
+	    else
+		STATE_MOUNT=
+	    fi
+
+	    # Allow to override rwtab from the state file system, too.
+	    for file in /etc/rwtab /etc/rwtab.d ; do
+		mount_state "$file"
+	    done
+
+	    if test -n "$SCRATCH_MOUNT" ; then
+		# Mount scratch areas.
+		if test -z "$SCRATCH_DEV" ; then
+		    # The default if no scratch= kernel command line option is
+		    # specified is a tmpfs scratch file system.
+		    SCRATCH_DEV="-t tmpfs scratch"
+		fi
+
+		echo "Mounting scratch filesystem ..."
+		if err=$(mount -v -n $SCRATCH_MOUNT_OPTS $SCRATCH_DEV $SCRATCH_MOUNT 2>&1) ||
+		   echo "$err" | grep -q "is already mounted on" ; then
+		    rm -rf "$SCRATCH_MOUNT" &>/dev/null
+		else
+		    rc_status
+		    SCRATCH_MOUNT=
+		fi
+		test -n "$err" && echo "$err" >&2
+	    fi
+
+	    echo "Bind mounting ${STATE_MOUNT:+state and }scratch data ..."
+	    for file in /etc/rwtab /etc/rwtab.d/* ; do
+		[ -f $file ] || continue
+		while read type path ; do
+		    case "$type" in
+		    state)
+		        test "$INIT_STATE_AUTOMATICALLY" = yes && init_state "$path"
+			mount_state "$path"
+			;;
+		    empty)
+		        mount_empty "$path"
+			;;
+		    files)
+		        mount_files "$path"
+			;;
+		    dirs)
+		        mount_dirs "$path"
+			;;
+		    '#'* | '')
+		    	;;
+		    *)
+			echo "$file: Keyword \"$type\" not recognized." >&2
+			;;
+		    esac
+		done < $file
+		rc_status
+		if test -n "$STATE_MOUNT" -a -z "$STATE_MOUNT_USED" ; then
+		    umount -n "$STATE_MOUNT"
+		fi
+		if test -n "$SCRATCH_MOUNT" -a -z "$SCRATCH_MOUNT_USED" ; then
+		    umount -n "$SCRATCH_MOUNT"
+		fi
+	    done
+	fi
 	;;
     stop)
 	mounts=/etc/fstab
