Wednesday, January 20, 2010

Automount USB drives on Ubuntu servers.

In most cases, Ubuntu desktop systems will automatically detect and mount removable media, and this is largely done with software that is part of the X Windows system; for server systems without X Windows however, this sort of thing requires a bit of work.

Now some may ask, "Why automount removable media at all?" It is unwise to remove an active device, such as unplugging a USB drive without first unmounting it, and automounting may encourage this sort of recklessness. I don't contend this, but if one runs a server using an external USB drive, there are two words which should spark an immediate interest in automatic mounts: power failure.


To manually mount an external USB drive, a user might enter a command such as: mount /dev/sdd1 /mnt/usbdrive. Naturally this assumes that sdd1 is the correct device node, and that's the thing about mounting things like USB drives-- there is no guarantee which device node it will use.

Fortunately UDEV, which is what handles all those devices in the /dev directory, has a rules syntax to control how those device nodes are named and what happens next. I'll explain briefly how to automount a USB drive, but readers looking for detailed information about UDEV rules should consult Writing udev rules by Daniel Drake as well as the udev man page (man udev).

Start by plugging in the device you want to mount, for these examples I have used a USB thumbdrive.  Run dmesg and look for something like:
[6388458.851691]  sdb: sdb1
[6388458.852594] sd 15:0:0:0: [sdb] Attached SCSI removable disk
[6388458.852635] sd 15:0:0:0: Attached scsi generic sg2 type 0

This tells me that the assigned device node is /dev/sdb1. To find out more about that device, run: udevinfo -a -p /sys/block/sdb and look for a single block of text that has a useful attribute-- a single rule may only match elements from a single block. In the example below, I've highlighted two lines I can use in my rule:

looking at parent device '/devices/pci0000:00/0000:00:02.1/usb2/2-5/2-5.1':
KERNELS=="2-5.1"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{dev}=="189:152"
... lots more ATTRS ...
ATTRS{manufacturer}=="Prolific Technology Inc."
ATTRS{product}=="USB Mass Storage Device"


I now have four bits of information I can use to write a useful rule:

  • The device node will be similar to /dev/sdb1, which I can match with sd?1

  • SUBSYSTEMS=="usb"

  • ATTRS{product}=="USB Mass Storage Device"

  • I want to run /bin/mount and mount the device at /mnt/usb


After looking up the correct syntax in the man page, I wrote my rule like so:
KERNEL=="sd?1", SUBSYSTEMS=="usb", ATTRS{product}=="USB Mass Storage Device",
↪ RUN+="/bin/mount /dev/%k /mnt/usb"

This I saved in a file at /etc/udev/rules.d/10-codefix.rules. The rule should be picked up automatically, but one can always run sudo udevcontrol reload_rules or sudo /etc/init.d/udev reload.

With the device attached, this rule can be tested with udevtest /sys/block/sdb/sdb1 usb. If the rule is correct, the output of udevtest will include the mount command.