Debian on read-only media

From Electron Cloud

Jump to: navigation, search
The system has built-in video, 2 serial ports, parallel... good for home automation. Replaced the fan with a nearly silent Noctua.
Look ma, no spinning media!
I replaced the fansink with one that was designed for overclocking Celerons, then removed the fan. It just gets slightly warm with this low-power processor. The power supply has the only fan.

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. A Via EPIA or some such would work just as well if that's what you happen to have lying around. A SheevaPlug might even be enough, actually. My EPIA board died after only a year or two of use, due to bad caps, so I'd just as soon re-use old junk that still works rather than "investing" in a replacement.

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. (I'm normally a gentoo user but not too keen on doing so much building on such a slow machine. And have tried building a custom distro with openembedded too, but bleh... it's too much work, and not every package that I want is available.) 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 the root filesystem ro first, then does fsck then mounts rw again, even with modern journaling filesystems (go figure). It could be there's a good reason for that, but I think to the extent that there are no bugs in ext3 (heh) it should be able to deal with being mounted read-write from the start. At least, reiserfs always could... but ext3 will give you a warning after a while that fsck is recommended because it's been too many days (oh ye of little faith). I think I will just deal with that manually since it's going to be mounted read-only most of the time. This is the kind of system that's going to (in theory) go for years at a time without significant modifications.

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

Then we have to stop it from fscking and remounting read-write, which is simply a matter of removing any symlinks that point to checkroot.sh from /etc/rc*.

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 (most of the big stuff isn't really "variable"). 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 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

And we need to limit the logging since there's only 64M total... no point in filling it up until there's no RAM left for running processes:

 rm /etc/rc2.d/S10rsyslog

/etc/mtab can be replaced with a link to /proc/mounts. /etc/adjtime can be replaced with a link to /tmp/adjtime.

That's about it... it boots with only a couple of 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.

Personal tools