Gentoo Wiki ArchivesGentoo Wiki

HOWTO_Read-only_root_filesystem


This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc


Please improve it in any way that you see fit, and remove this notice {{Cleanup}} from the article. For tips on cleaning and formatting see Cleanup process


The aim of this HOWTO is to have a read-only root. The method presented here is not perfect, however it should work well in most cases. The information used here come from a text written by Thomas Hood for the Debian distribution.

Contents

Aim and principles

The root filesystem doesn't have to be modified often, except for some configuration files. So it is possible to mount this directory read-only. There are several reasons:

Old Method

If you want to modify as few bootscripts as possible, skip down to the Unionfs Method section.

You need to use devfs or udev. Either of the two are standard for a while in Gentoo. Either are available or by default installed in Gentoo.

It is not possible to directly switch your root to read-only, because several important files in /etc have to be write-accessed at boot time. A first idea could be to have a separate partition for /etc with write access. However, this is not possible since /etc/fstab needs to be accessed before the partitions other than root are mounted.

Software should include in their code that /etc is for static configuration files and /var for files that can be modified. Meanwhile, you'll need to:

If the root partition has to be read-only, it must not contain directories needing a write access. Then you'll have to create a partition with write access for /home, /tmp, /var (either a separate partition for each, or only one for all using LVM or symbolic links e.g. pointing to /home/var or /home/tmp)

File in /etc that need write access have to be on a secure place. In the following, let's assume that /var/etc is created on a local disk for that use.

mtab

/etc/mtab describes the filesystems eventually mounted. It has to be written each time a filesystem is mounted or unmounted, specially at boot time. /etc/mtab is a special case because mount hasn't been designed to work with symbolic links.

Before you execute the following, you should probably first execute

  # find /etc -newer /etc/mtab  > /tmp/sinceboot.txt

This will write out what files have changed since the last boot. It will come in handy later.

First method

the first solution is to replace mtab by a symbolic link to /proc/mounts. This special file also describes the mounted filesystems, and can replace mtab without needing a write access on it. However, in some cases including loop devices, this may not work, because information provided by /proc/mounts are less precise than those in /etc/mtab. .

# cd /etc
# rm mtab
# ln -s /proc/mounts mtab

We also need to tell to the bootscripts that they should not try to write to mtab. It is as simple as adding the -n option to any mount option in /etc/init.d/localmount

In localmount, replace two lines:

File: /etc/init.d/localmount
line 13:
mount -at nocoda,nonfs,noproc,noncpfs,nosmbfs,noshm >/dev/null
becomes:
mount -nat nocoda,nonfs,noproc,noncpfs,nosmbfs,noshm >/dev/null
line 36:
mount -t ${usbfs} none /proc/bus/usb &>/dev/null
becomes:
mount -nt ${usbfs} none /proc/bus/usb &>/dev/null

(Comment: as of 1/25/2008, the script commands are slightly different and at different lines. However, the changes are still obvious and straightforward.)

Second method

Second solution, replace /etc/mtab by a symbolic link to a file on a partition with write access. To do that, we'll first have to apply a patch to mount. The patch, written originally for sys-apps/util-linux version 2.12, used to be available at Thomas Hood's page (link now dead).

There are updated versions of the patch that apply to util-linux-2.12q and util-linux-2.13.1.1 attached to bug #98403, along with an ebuild for util-linux-2.12q that applies the patch.

Let's assume that the sources of the package and the patch are on the disk. To apply the patch and recompile, type the following (modifying version numbers and directories if needed):

# ebuild /usr/portage/sys-apps/util-linux/util-linux-2.13.1.1.ebuild unpack
# cd /var/tmp/portage/sys-apps/util-linux-2.13.1.1/work/util-linux-*/
# patch -Np1 < /path/to/util-linux-2.13.1.1-symlink-mtab.patch
# cp /bin/mount /bin/mount.old
# cp /bin/umount /bin/umount.old
# ebuild /usr/portage/sys-apps/util-linux/util-linux-2.13.1.1.ebuild merge

It is then possible to switch mtab to a symbolic link:

# cd /etc/
# cp mtab /var/etc
# rm mtab
# ln -s /var/etc/mtab

If, for any reason, mtab was not synced with what it should be, it is possible to create a usable mtab typing:

# cat /proc/mounts > /var/etc/mtab

boot scripts

Some Gentoo boot scripts in /etc/init.d need write access even before file systems are mounted (which is done by localmount). This is the case of modules, checkroot, checkfs, and hostname. In this case, the best to do is to see if they don't do something too important with their write access. the script domainname needs write access but is launched after local filesystems are mounted.

modules

the module dependencies are calculated at Gentoo boot time and need write access on root partition. To circumvent the problem, just follow this TIP (in French, for now, sorry). If you update your configuration in /etc/modprobe.d, you'll have to launch update-modules with write-access on root filesystem to update /etc/modprobe.conf.

(Comment: as of 1/25/2008, the script no longer exists at that site.)

checkroot

The script checkroot initializes mtab from /proc/mounts. If the method chosen for mtab is a link to /proc/mounts, there is nothing to be done. The system will use /proc/mounts. There is no need to initialize mtab but doing it won't hurt.

For the second method (a link to /var/etc/mtab), the initialization of mtab has to be done after the filesystems have been mounted. To do that, it is possible to include the needed code in a boot script. The simplest way is to add that code in /etc/conf.d/local.start, specially dedicated to user modifications. However, the best is to do the initialization as soon as possible, as soon as the filesystem on which mtab resides have been mounted. If this solution is preferred, then the code would be added to the function start of localmount.

The code is from /etc/init.d/checkroot, just replacing /etc/mtab by /var/etc/mtab

File: /etc/init.d/checkroot
#
# Create /etc/mtab
#

# Clear the existing mtab
> /var/etc/mtab

# Add the entry for / to mtab
mount -f /

# Don't list root more than once
awk '$2 != "/" {print}' /proc/mounts >> /var/etc/mtab

# Now make sure /etc/mtab have additional info (gid, etc) in there
for x in $(awk '{ print $2 }' /proc/mounts | uniq)
do
        for y in $(awk '{ print $2 }' /etc/fstab)
        do
                if [ "${x}" = "${y}" ]
                then
                        mount -f -o remount $x
                        continue
                fi
         done
done

checkfs

If the method chosen is a link to /proc/mounts, there is no problem.

If the method chosen for mtab is the link to /var/etc/mtab, then /etc/init.d/checkfs won't be able to access mtab and will complain at boot time for systems labelled in /etc/fstab as noauto. For example:

ext2fs_check_if_mount: No such file or directory while determining whether /edv/hdax is mounted

The filesystems for which it cannot guess whether they are mounted or not are precisely those which are not mounted. So the failure of check_if_mount is no problem (see e2fsprogs/e2fsck/unix.c, function check_mount).

hostname

/etc/init.d/hostname reads /etc/hostname, sets the name of the machine and write it in /etc/env.d/hostname. If write access of not possible, this information won't be updated. This is not important as long as the machine name does not change. If you decide to change the name (updating /etc/hostname), think to execute the hostname script (with write access allowed).

domainname

The script /etc/init.d/domainname is launched after the flesystems are mounted and will create resolv.conf and resolv.conf.new. It is not sufficient to create a link to /var/etc/resolv.conf, because domainname wants to rename /etc/resolv.conf.new, but mv does not follow symlinks. If you want the script to end as it should, you'll have to modify domainname. Either, you can:

(Comment: as of 1/25/2008, the domainname script no longer exists in a default gentoo installation.)

Individual files

The exact list of files that need to be write accessed depends on software installed. Recall the find command that you executed earlier. You can now look at

# more sinceboot.txt

This command prints the list of files modified since the last time a filesystem was mounted.

Among the files which need write access in /etc, there are:

Those files are used only after the local filesystems are mounted, so we can replace them by a link to /var/etc. This has to be done for all files. In the case of adjtime, the FHS standard recommends /var/lib/hwclock as a suitable directory.

# cd /var/lib
# mkdir hwclock
# cp /etc/adjtime /var/lib/hwclock
# cd /etc
# rm adjtime
# ln -s /var/lib/hwclock/adjtime

varia

It is necessary to make symlinks to redirect some directories on a location with write access. This is the case of /usr/tmp which can be redirected to /tmp or /var/tmp.

# cd /usr/
# rmdir tmp/
# ln -s /tmp/

Additional modifications

If you use services like samba, cups or ppp, you'll have to make some additional modifications.

cups

In the case of cups,, you'll have to create a symbolic link as above for the directory /etc/cups/certs. Don't forget to give right permissions. The directory must belong to lp group.

# cd /var/etc/
# mkdir cups/
# chown root:lp cups
# cd cups
# cp -p -r /etc/cups/certs certs
# cd /etc/cups
# mv certs certs.old
# ln -s /var/etc/cups/certs
# chown root:lp /var/etc/cups/certs/*

Unionfs Method

Unionfs allows different directories to be "stacked" into a single filesystem. Using unionfs and tmpfs, you can make all your bootscripts think that /etc is read-write.

This can be accompished in three steps.

Step 1: Preparing the kernel

As of kernel 2.6.20, unionfs is not included in vanilla-sources; but it is included in mm-sources. If you don't want to use mm-sources, then you must obtain the patch from the unionfs website

Ensure that "Virtual memory file system support (former shm fs)" (CONFIG_TMPFS) and "Union file system" (CONFIG_UNION_FS) are enabled, then compile and reboot.

Step 2: Creating the tmpfs mountpoint in /etc

# mkdir /unionfs/etc

This directory will be used to mount a small tmpfs volume where writes to /etc will be redirected. All writes will be lost after each reboot.

Step 3: Modifying /sbin/rc

This is the only bootscript file that must be modified.

Open /sbin/rc with your favorite text editor. We need to setup the unionfs mount early in the sysinit runlevel. Do a text search for "sysinit" and you should find something like this:

# First time boot stuff goes here.  Note that 'sysinit' is an internal runlevel
# used to bring up local filesystems, and should not be started with /sbin/rc
# directly ...
if [[ ( ${RUNLEVEL} == "S" || ${RUNLEVEL} == "1" ) && ${argv1} = "sysinit" ]]
then
        # Setup initial $PATH just in case
        PATH="/bin:/sbin:/usr/bin:/usr/sbin:${PATH}"

Add the following lines after the PATH statement:

/bin/mount -n -t tmpfs tmpfs /unionfs/etc -o size=1M
/bin/mount -n -t unionfs unionfs /etc -o dirs=/unionfs/etc=rw:/etc=ro
echo "tmpfs /unionfs/etc tmpfs rw,size=1M 0 0" >> /etc/mtab
echo "unionfs /etc unionfs rw,dirs=/unionfs/etc=rw:/etc=ro 0 0" >> /etc/mtab

Final modifications

When these modifications are done, it is necessary to place the directory for the next reboot. In the file /etc/fstab, the line containing the root directory has to be modified to add the read-only (ro) option.

File: /etc/fstab

For example, the line:

/dev/hdax	/	ext2	noatime		0 1

becomes:

/dev/hdax	/	ext2	noatime,ro	0 1

In everyday use, you'll need from time to time to write to the root directory - if you want to install new software or update the configuration, etc.

This will be the case if you need to use your /root directory: it must not be on a separate partition, since it is useful in case of severe problems to be connected as root on the system, as other filesystems are not mounted.

To switch to write access and go back to read-only, the following command typed as superuser is sufficient:

# mount -w -o remount / # Write allowed
# mount -r -o remount / # Read-only

To ease that task, it is possible to write aliases for the superuser shell.

# echo "alias rw='mount -w -o remount /'" >> ~/.bashrc
# echo "alias ro='mount -r -o remount /'" >> ~/.bashrc

(The bash initfile is sometimes called .bash_login)

Switch to read-only and reboot. Look carefully at the boot messages; they will warn you of any problems caused by the inability to write. Once you have resolved the problems, you can go back and add material to this tutorial.

Using write access

If you wish to remount your root filesystem with write access, remember that some programs (mount for example, if the patch from Thomas Hood is not used) will try as soon as they can to replace the symlinks by regular files. When you finish your work in write access mode, if you have launched any programs needing access to the files you have symlinked, check that your links still exist and create them again if necessary.

Before launching any emerge think to go back to write access. If you forget to do so, emerge will not be able to copy the files it has compiled. Also, for emerge --unmerge, it will not be able to remove files you asked to remove, but it may think it did, so it will incorrectly update its database of installed programs. Then you'll need to recompile the program to be able to remove it!

If you used the unionfs method, then modifying /etc requires a few extra steps. After your root filesystem is remounted read-write, unmount the unionfs mount:

# umount -n /etc

Make your changes, then restore the unionfs mount. Don't mount or unmount any filesystems until you preform the next step, as your /etc/mtab file will become out of sync with reality.

# mount -n -t unionfs unionfs /etc -o dirs=/unionfs/etc=rw:/etc=ro

Remarks

If you follow this tip, you had to modify modules and maybe localmount and domainname; or /sbin/rc. If this is the case, you'll be obliged to apply the same modifications when you'll update your system with emerge baselayout.

Some modifications are necessary in the Gentoo initscripts so that the user can choose to use its root filesystem read-only. But these modifications are not very complex, and could be integrated in the distribution (as Thomas Hood is trying to do for Debian). If some Gentoo developer reads these lines...

if you have modified mount/umount manually to apply the patch mentioned above, don't forget to do "chmod 4711 /bin/mount /bin/umount".

References

The basic information of this method are taken from a text from Thomas Hood. The document is no longer available from his website.

Retrieved from "http://www.gentoo-wiki.info/HOWTO_Read-only_root_filesystem"

Last modified: Tue, 05 Aug 2008 19:27:00 +1000 Hits: 57,763

Created by NickStallman.net, Luxury Homes Australia
Real estate agents should list their apartments, townhouses and units in Australia.