An Ubuntu Appliance
Appliance: an instrument or appratus for a specific purpose. In other words, an appliance is not a general-purpose machine like a desktop computer. Another term heard occasionally is media-pc. It’s a network end-point in the living room that can play and record audio/video, and is a connection point for USB devices like webcams or memory card readers. It’s silent and has no moving parts, and is controlled primarily with an infra-red remote.
Hardware
VIA Epia 5000 fanless mini-ITX motherboard, 512 MB
M-Audio Audiophile 24/96 soundcard
Compact flash IDE adapter, 8 GB card (8011422720 bytes,
255 heads, 63 sectors/track, 974 cylinders)
Serial IR receiver
Software
I use VirtualBox (the Sun version, not the OSE) as the experimental platform — it’s much more convenient to poke around on a virtual machine on a desktop than on the actual hardware. Install Ubuntu as usual from the install ISO file. Tweak at length. After the system is working as required, copy the virtual disk to the compact flash card, and move the card to the actual hardware.
VBoxManage internalcommands converttoraw \
~/.VirtualBox/HardDisks/disk-name.vdi \
Ubuntu-AUFS.img
sudo dd if=Ubuntu-AUFS.img of=/dev/sdd bs=1024
Of course your compact flash may not be /dev/sdd.
Disk Layout
No swap, one ext2 root partition.
Optional: Syslog
The intent is to not have anything written to the disk, and the writable overlay may be too small to support system log files. In that case log messages can be sent over the network (UDP) to a loghost. This is /etc/rsyslog.d/50-default.conf on the media-pc:
*.* @loghost
(Your loghost probably has a different name.)
The loghost’s syslogd needs to be told to accept UDP messages: syslogd -r. If the loghost is OpenBSD, add -r to the SYSLOGD entry in /etc/rc.conf.local. If it’s Debian or Ubuntu, edit /etc/default/syslogd.
Readonly Root
The best way to increase the life of a compact flash card is to never write to it. (It’s hard to see how you can use one without writing to it.) The next best thing is to make the system “disk” readonly, i.e. once the OS is installed, the system never writes to the disk again. All settings, temp. files etc. are stored in RAM. If you want to make any changes to the system, reboot into writeable mode, change, and reboot back into readonly mode.
Since the system will occasionally run in writeable mode to make changes, the number of writes to the system disk should still be minimized. This means temp. directories should be tmpfs filesystems (in RAM only). These lines in /etc/fstab will do that:
tmpfs /tmp tmpfs defaults 0 0 tmpfs /var/tmp tmpfs defaults 0 0
Overview
A script is run from the initrd that creates an aufs filesystem that combines the readonly root fs with a writeable overlay in memory.
Since the initrd is going to be constructing the overlaid aufs root, the aufs kernel module needs to be included in the initrd.
# echo aufs >> /etc/initramfs-tools/modules
Initrd script
The script that does all the readonly-root magic is /etc/initramfs-tools/scripts/init-bottom/rootaufs. After creating it, copy it into the initrd.
# update-initramfs -u
To unpack an initrd,
$ cd initrd-unpacked $ gunzip -c /boot/initrd.img-`uname -r` | cpio -i
The important bits are:
# Make the mount points
mkdir /aufs /rw /ro
# Mount the temp file system and move the real root out of the way
mount -t tmpfs aufs-tmpfs /rw
mount --move ${rootmnt} /ro
mount -t aufs -o dirs=/rw:/ro=ro aufs /aufs
# Make mount points on aufs file system
mkdir -p /aufs/ro /aufs/rw
# Move the real root to /ro and tmpfs to /rw
mount --move /ro /aufs/ro
mount --move /rw /aufs/rw
# Finally move the aufs filesystem to the root.
mount --move /aufs ${rootmnt}
Grub
Make a copy of the first stanza so at boot time you can decide whether to boot with a readonly root or with a vanilla writeable root. Add aufs=tmpfs to kernel line in the new readonly stanza.
title Ubuntu karmic (development branch), kernel 2.6.31-11-generic root (hd0,0) kernel /boot/vmlinuz-2.6.31-11-generic root=/dev/sda1 ro quiet splash initrd /boot/initrd.img-2.6.31-11-generic quiet title READONLY Ubuntu karmic (development branch), kernel 2.6.31-11-generic root (hd0,0) kernel /boot/vmlinuz-2.6.31-11-generic root=/dev/sda1 ro quiet splash aufs=tmpfs initrd /boot/initrd.img-2.6.31-11-generic quiet
Grub on Karmic alpha6 seems to have a bug using UUIDs for disks so I replaced root=UUID=nnn… with the real device name /dev/sda1.
The Good: It Works!
This is what the system looks like after it has booted with a readonly compact flash card:
# cat /proc/mounts rootfs / rootfs rw 0 0 none /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0 none /proc proc rw,nosuid,nodev,noexec,relatime 0 0 udev /dev tmpfs rw,relatime,mode=755 0 0 /dev/disk/by-uuid/273483e3-4b18-447a-996b-3f25db5c88c7 /ro ext2 ro,relatime,errors=continue 0 0 none /sys/kernel/security securityfs rw,relatime 0 0 aufs-tmpfs /rw tmpfs rw,relatime 0 0 aufs / aufs rw,relatime,si=54a414c1 0 0 none /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0 none /lib/init/rw tmpfs rw,nosuid,relatime,mode=755 0 0 none /dev/shm tmpfs rw,nosuid,nodev,relatime 0 0 none /sys/fs/fuse/connections fusectl rw,relatime 0 0 none /sys/kernel/debug debugfs rw,relatime 0 0 none /var/lock tmpfs rw,nosuid,nodev,noexec,relatime 0 0 none /var/run tmpfs rw,nosuid,relatime,mode=755 0 0 # df -h Filesystem Size Used Avail Use% Mounted on aufs 245M 7.8M 237M 4% / udev 245M 212K 245M 1% /dev /dev/sda1 7.4G 4.1G 2.9G 59% /ro aufs-tmpfs 245M 7.8M 237M 4% /rw none 245M 232K 245M 1% /dev/shm none 245M 0 245M 0% /lib/init/rw none 245M 0 245M 0% /var/lock none 245M 84K 245M 1% /var/run
The Bad: Network
NetworkManager and AppArmor together aren’t happy about the script. I think the fact that files move around clashes with dhclient’s permissions. I found it simplest to add the /ro version to the profile /etc/apparmor.d/sbin.dhclient3:
/usr/lib/NetworkManager/nm-dhcp-client.action {
#include <abstractions/base>
#include <abstractions/dbus>
/usr/lib/NetworkManager/nm-dhcp-client.action mr,
/ro/usr/lib/NetworkManager/nm-dhcp-client.action mr,
}
interacts badly crashes at startup so network doesn’t get set up. (Bug 430781)
Workaround: edit /etc/rc.local:
ADDR=`ifconfig eth0 | awk '/ inet addr:/{print $2}'`
if [ -z "$ADDR" ]; then
ifconfig eth0 192.168.1.N
route add default gw 192.168.1.1
fi
The Ugly: Sound
In the beginning, getting sound to work on Linux was always an adventure. Now here we are, almost two decades later, and the story is… not very different.
I have an M-Audio 24/96 soundcard, which is one of those niche cards. It supposedly can do amazing things, but I got it because it’s reputed to have a good analog section. The card is about six years old, and when I first got it I struggled mightily to get it to work. Ultimately I triumphed, but my victory was short-lived — the next version of the distribution put me back at square one.
Anyway, six years later, the card is apparently now well supported by Linux (ALSA). However, Ubuntu’s new sound server “PulseAudio” (why in the name of all that’s holy do we need yet another sound server?) doesn’t know anything about it.
Update: I’m giving up on goddamn PulseAudio, and I’m giving up on ALSA. In the ancient past I remember the OSS driver was the only one that worked with some other sound card I had. Now there are quite a few positve reports of OSS support for the Audiophile 2496, so the new plan is to go back to Jaunty (aka version 9.04) upgraded to the current kernel (2.6.31), with the BFS patch thrown in for good measure. Stay tuned….
References
- Walkthrough of Installing Ubuntu on VirtualBox.
- Ubuntu help on aufs Root File System On Usb Flash
- From Unixwars, Jaunty Server on Compact Flash