I wanted to put together a low-power home automation system, with a fixed set of tasks, with read-only rootfs such that if anything goes wrong it's OK to just hit reset. (Or if the power goes out it will reboot drama-free by itself.) For low-power hardware I wanted to make use of an old 233MHz Cyrix MediaGX system which has not had much use until now. With only the motherboard, an AT power supply modified with a Noctua fan, PCI USB and S3 Virge boards, and a 2 GB CF card for the "hard drive", it takes in the range of 20-25 watts... not bad compared to around 100 watts for a more modern PC.
So... given that it's not quite a 686-compatible, we need a Linux distro which doesn't make such assumptions about the hardware (increasingly rare). Debian 5.0 still runs on a 486. So I installed with default options onto the CF card, then went about modifying it to work even if I mount the root filesystem read-only.
grub is already configured "ro" because Debian still mounts ro first, then does fsck then mounts rw again, even with modern journaling filesystems (go figure). So I added a "maintenance mode" entry, and turned off swap on the default entry (/boot/grub/menu.lst):
title Debian GNU/Linux, kernel 2.6.26-2-486 root (hd0,0) kernel /boot/vmlinuz-2.6.26-2-486 root=/dev/hda1 ro noswap initrd /boot/initrd.img-2.6.26-2-486 title Debian GNU/Linux, kernel 2.6.26-2-486 read/write root (hd0,0) kernel /boot/vmlinuz-2.6.26-2-486 root=/dev/hda1 rw initrd /boot/initrd.img-2.6.26-2-486
In /etc/fstab there are some tmpfs filesystems:
proc /proc proc defaults 0 0 /dev/hda1 / ext3 errors=remount-ro 0 1 /dev/hda5 none swap sw 0 0 tmpfs /tmp tmpfs rw 0 0 tmpfs /etc/network/run tmpfs rw 0 0
/var needs to be tmpfs too, but that gets tricky, because /var normally holds more stuff than I could fit in 64 megs of RAM. So I made /var-ro and /var-tmp, and moved stuff from /var which I wanted to be read-only (in normal mode) into /var-ro, and at boot it mounts /var as tmpfs then copies everything from /var-tmp into there... so we want only the bare directory structures for in /var-tmp, as well as symlinks to the stuff that is actually in /var-ro.
[earll][08:58:25 PM] du -sh /var-ro/* 8.0K /var-ro/backups 162M /var-ro/cache 52M /var-ro/lib 236K /var-ro/run 8.0K /var-ro/www [earll][08:58:27 PM] ll /var-tmp/ total 40 drwxr-xr-x 10 root root 4096 Jul 24 20:11 . drwxr-xr-x 23 root root 4096 Jul 24 19:41 .. lrwxrwxrwx 1 root root 15 Jul 24 19:53 backups -> /var-ro/backups lrwxrwxrwx 1 root root 13 Jul 24 19:40 cache -> /var-ro/cache lrwxrwxrwx 1 root root 11 Jul 24 19:41 lib -> /var-ro/lib drwxrwsr-x 2 root staff 4096 Jun 18 15:17 local drwxrwxrwt 3 root root 4096 Jul 24 19:13 lock drwxr-xr-x 9 root root 4096 Jul 24 20:11 log drwxrwsr-x 2 root mail 4096 Nov 6 2005 mail drwxr-xr-x 2 root root 4096 Nov 6 2005 opt drwxr-xr-x 6 root root 4096 Jul 24 19:55 run drwxr-xr-x 6 root root 4096 Nov 6 2005 spool drwxrwxrwt 2 root root 4096 Jun 18 15:17 tmp lrwxrwxrwx 1 root root 11 Jul 24 19:40 www -> /var-ro/www [earll][08:58:53 PM] find /var-tmp /var-tmp /var-tmp/mail /var-tmp/www /var-tmp/local /var-tmp/cache /var-tmp/opt /var-tmp/backups /var-tmp/lib /var-tmp/run /var-tmp/run/apache2 /var-tmp/run/portmap_mapping /var-tmp/run/exim4 /var-tmp/run/dbus /var-tmp/run/utmp /var-tmp/run/network /var-tmp/run/motd /var-tmp/spool /var-tmp/spool/mail /var-tmp/spool/exim4 /var-tmp/spool/exim4/input /var-tmp/spool/exim4/db /var-tmp/spool/exim4/gnutls-params /var-tmp/spool/exim4/msglog /var-tmp/spool/samba /var-tmp/spool/cups /var-tmp/spool/cups/tmp /var-tmp/spool/cron /var-tmp/spool/cron/crontabs /var-tmp/spool/cron/atjobs /var-tmp/spool/cron/atjobs/.SEQ /var-tmp/spool/cron/atspool /var-tmp/tmp /var-tmp/log /var-tmp/log/installer /var-tmp/log/installer/cdebconf /var-tmp/log/apache2 /var-tmp/log/exim4 /var-tmp/log/samba /var-tmp/log/samba/cores /var-tmp/log/samba/cores/smbd /var-tmp/log/samba/cores/winbindd /var-tmp/log/samba/cores/nmbd /var-tmp/log/news /var-tmp/log/fsck /var-tmp/log/apt /var-tmp/lock /var-tmp/lock/apache2
And in /etc/init.d/mountkernfs.sh, we do the copying into the tmpfs, right after the part where it optionally mounts /var/run and /var/lock as tmpfs (we don't enable that option since all of /var is basically tmpfs):
# Mount /var as tmpfs and copy some initial stuff into there domount tmpfs "" /var var -omode=0777 cp -a /var-tmp/* /var
That's about it... it boots with only a couple complaints about "read-only file system", e.g. "cannot remove /var/lib/exim4/config.autogenerated.tmp" (which is not actually there anyhow), etc.
If I want to change files which are normally read-only, I can either reboot into maintenance mode or just
mount / -o remount,rw
then reboot again afterwards.