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

Category: software, hardware


Leave a Reply

You must be logged in to post a comment.

Back to top