IT Tutorial

Mount Removable Devices with Persistent Names

Mount your USB drive so it appears as /media/music every time. Mount your FireWire drive so it appears as /media/data every time.
My storage setup on my Ubuntu box at home is a bit unusual. I have an external drive dedicated to music and another external drive that backs up the music drive. I also have an external drive to hold all my personal documents, pictures, and movies, with another external drive to back up that drive. Those four drives are all connected to my desktop via FireWire. Finally, I have an external drive that's a temp drive: when I download a new movie or set of pictures, or rip a new CD, I keep those files on the temp drive until I can properly place them on the music or personal data drive. Unlike the other four, the temp drive uses USB.

Five drives sounds cool, but there's a major annoyance associated with them. When I reboot Ubuntu (a rare occasion, to be sure, but it does happen), their mount points shift around. Sometimes FireWire drive number one gets /media/sdb1, and sometimes /media/sdc1. The same thing happens to the other drives as well, which wreaks havoc with my backup scripts and my attempts to SSH in from other machines, to name just two problems I've experienced. I want persistent naming of those drives, so that FireWire number one is always /media/, FireWire number two is always /media/, and so on.

After much searching, I found the answer on the Ubuntu forums, at http://ubuntuforums.org/showthread.php?t=91948, and in an excellent overview by Daniel Drake titled "Writing udev rules" (http://www.reactivated.net/writing_udev_rules.html). Basically, Ubuntu includes a technology called udev, which manages dynamic devices. I can tell udev how I want it to label each separate drive when I plug it in, a far more efficient and usable method than the default. Here's how to do so.
You're going to be editing a file found at /etc/udev/rules.d/10-local.rules. Check to see if that file already exists on your hard drive:
$ ls /etc/udev/rules.d/10-local.rules


If it's already there, then you're going to edit it; if it's not there currently, go ahead and create a blank file with the proper name and permissions:
$ sudo touch /etc/udev/rules.d/10-local.rules
$ sudo chmod 777 /etc/udev/rules.d/10-local.rules


At the end of the process described in this hack, the devices will be listed in the 10-local.rules file. The USB drive, for instance, will look like this:
BUS=="usb", SYSFS{serial}=="6R0000065086", NAME{all_partitions}=="temp"

The first partBUS=="usb"is obvious; that's how that drive connects to the machine. The third partNAME{all_partitions}=="temp"makes sense too, since "temp" is the name I want the drive to use in the future as its mount point, instead of /media/sdb1 or whatever else Ubuntu decides to use. But what about that second part? Where is "6R0000065086" coming from?
In order for udev to work, it has to know which specific drive I want to label "temp". When I plug in a drive (or any dynamic device), the drive identifies itself in a whole host of ways. I need to pick a unique data point that I can pass to udev to use for identification. To see what udev sees when you plug in a drive, I run the following command (notice that the path given is the current path that Ubuntu has assigned to the drivein this case, /dev/sda):
$ udevinfo -a -p $(udevinfo -q path -n /dev/sda)


Once I press Enter, an enormous amount of data streams by, looking something like this (this listing has been greatly truncated for length):
device '/sys/block/sda' has major:minor 8:0
looking at class device '/sys/block/sda':
SUBSYSTEM=="block"
SYSFS{dev}=="8:0"
SYSFS{range}=="16"
SYSFS{removable}=="0"
SYSFS{size}=="488397168"
SYSFS{stat}==" 2159 102 16586 1871738 28 17 360 204 0 14257 1871942"

...

looking at the device chain at
'/sys/devices/pci0000:00/0000:00:1e.0/0000:05:09.2/usb4/4-1/4-1.2/4-1.2:1.0':
BUS=="usb"
ID=="4-1.2:1.0"
DRIVER=="usb-storage"
SYSFS{bAlternateSetting}==" 0"
SYSFS{bInterfaceClass}=="08"
SYSFS{bInterfaceNumber}=="00"
SYSFS{bInterfaceProtocol}=="50"
SYSFS{bInterfaceSubClass}=="06"
SYSFS{bNumEndpoints}=="02"
SYSFS{modalias}=="usb:v04B4p6830d0001dc00dsc00dp00ic08isc06ip50"

looking at the device chain at
'/sys/devices/pci0000:00/0000:00:1e.0/0000:05:09.2/usb4/4-1/4-1.2':
BUS=="usb"
ID=="4-1.2"
DRIVER=="usb"
SYSFS{bConfigurationValue}=="1"
SYSFS{bDeviceClass}=="00"
SYSFS{bDeviceProtocol}=="00"
SYSFS{bDeviceSubClass}=="00"
SYSFS{bMaxPower}==" 0mA"
SYSFS{bNumConfigurations}=="1"
SYSFS{bNumInterfaces}==" 1"
SYSFS{bcdDevice}=="0001"
SYSFS{bmAttributes}=="c0"
SYSFS{configuration}==""
SYSFS{devnum}=="3"
SYSFS{idProduct}=="6830"
SYSFS{idVendor}=="04b4"
SYSFS{manufacturer}=="Cypress Semiconductor"
SYSFS{maxchild}=="0"
SYSFS{product}=="USB2.0 Storage Device"
SYSFS{serial}=="6R0000065086"
SYSFS{speed}=="480"
SYSFS{version}==" 2.00"

...

See the line in bold that says SYSFS{serial}=="6R0000065086"? That's the unique serial number for this device, so that's exactly what I'll use in the line I'm adding to 10-local.rules. Notice also that the line BUS=="usb" is also present, in case I don't know how /dev/sda is connected to my box (hey, with five drives, it could happen!). Once again, then, the new line in /etc/udev/rules.d/10-local.rules is:
BUS=="usb", SYSFS{serial}=="6R0000065086", NAME{all_partitions}=="temp"

I need to repeat the process for any other drives as well. Although the next four drives are all connected with FireWire, the process is the same; it's just the listings that are different:
$ udevinfo -a -p $(udevinfo -q path -n /dev/sdb)

device '/sys/block/sdb' has major:minor 8:16
looking at class device '/sys/block/sdb':
SUBSYSTEM=="block"
SYSFS{dev}=="8:16"
SYSFS{range}=="16"
SYSFS{removable}=="0"
SYSFS{size}=="234441648"
SYSFS{stat}=="1166 102 8386 739882 27 16 344 52 0 6575 739934"

...

looking at the device chain at
'/sys/devices/pci0000:00/0000:00:1e.0/0000:05:04.0/fw-host0/0030e0f4e020dca0/0030e0f4e020dca0-0':
BUS=="ieee1394"
ID=="0030e0f4e020dca0-0"
DRIVER=="sbp2"
SYSFS{address}=="0x0000fffff0000830"
SYSFS{ignore_driver}=="0"
SYSFS{length}=="0"
SYSFS{model_id}=="0x000001"
SYSFS{model_name_kv}=="OXFORD IDE Device LUN 0 "
SYSFS{specifier_id}=="0x00609e"
SYSFS{version}=="0x010483"

looking at the device chain at
'/sys/devices/pci0000:00/0000:00:1e.0/0000:05:04.0/fw-host0/0030e0f4e020dca0':
BUS=="ieee1394"
ID=="0030e0f4e020dca0"
DRIVER=="unknown"
SYSFS{bus_options}=="IRMC_0_ CMC_0_ ISC_0_ BMC_0_ PMC_0_ GEN_0_
LSPD_2_ MAX_REC_64_ MAX_ROM_0_ CYC_CLK_ACC_255_"
SYSFS{capabilities}=="0x0083c0"
SYSFS{guid_vendor_id}=="0x0030e0"
SYSFS{guid}=="0x0030e0f4e020dca0"
SYSFS{nodeid}=="0xffc0"
SYSFS{tlabels_allocations}=="1262"
SYSFS{tlabels_free}=="64"
SYSFS{tlabels_mask}=="0x05965272090596527209"
SYSFS{vendor_id}=="0x0030e0"
SYSFS{vendor_name_kv}=="Oxford Semiconductor Ltd. "

...

In this instance, udevinfo tells me how this drive is connected to my Ubuntu desktop: BUS=="ieee1394" (remember that IEEE1394 is the official name for FireWire). FireWire drives don't include SYSFS{serial} like USB drives do; instead, their unique identifiers are SYSFS{guid}. This particular drive holds my personal files, so I want it to show up as /media/data. Put all that together, and I add this line to /etc/udev/rules.d/10-local.rules:
BUS=="ieee1394", SYSFS{guid}=="0x0030e0f4e020e229", NAME{all_


partitions}=="data"

After performing the same task three more times, /etc/udev/rules.d/10-local.rules looks like this:
BUS=="usb", SYSFS{serial}=="6R0000065086", NAME{all_partitions}=="temp"
BUS=="ieee1394", SYSFS{guid}=="0x0030e0f4e020e229",
NAME{all_partitions}=="data"
BUS=="ieee1394", SYSFS{guid}=="0x0030e0f4e020dca0",
NAME{all_partitions}=="data_copy"
BUS=="ieee1394", SYSFS{guid}=="0x0030e0f4e020912c",
NAME{all_partitions}=="music"
BUS=="ieee1394", SYSFS{guid}=="0x0030e0f4e020c727",
NAME{all_partitions}=="music_copy"

Now I need to test my changes to make sure they'll actually work. First, I need to restart udev, the subsystem that is managing all this craziness:
$ sudo /etc/init.d/udev restart


Now I'll test the rules for the USB external drive to make sure everything will work. To test, I use udevtest. The syntax of the command is:
$ sudo udevtest

sysfs_device_path



subsystem



How do I know what the sysfs_device_path and subsystem are? Look back when I ran udevinfo -a -p $(udevinfo -q path -n /dev/sda) and notice the first things reported back to me:
looking at class device '/sys/block/sda':
SUBSYSTEM=="block"

My udevtest command therefore looks like this:
$ sudo udevtest /sys/block/sda block


The results appear immediately below it (some error messages about other items in udev that aren't important here have been removed):
udevtest.c: looking at device '/block/sda' from subsystem 'block'
...
udevtest.c: opened class_dev->name='sda'
udev_rules.c: configured rule in '/etc/udev/rules.d/10-local.rules:1' applied, 'sda' becomes 'temp'
udev_add.c: creating device node '/dev/temp', major = '8', minor = '0', mode = '0640', uid = '0', gid = '46'
udev_add.c: creating device partition nodes '/dev/temp[1-15]'

Excellent! Now I know that udev would in fact create a device name /dev/tempand therefore a mount point at /media/tempinstead of /dev/sda and /media/sda, and will always use that in the future. By the way, don't worryeven though the output says it was creating nodes, it really wasn't. It was just showing me what it would do when it runs for real.
So I know the USB drive works, but what about one of the FireWire drives?
$ sudo udevtest /sys/block/sdd block


Here are the results for that drive (again, some unnecessary data has been removed):
udevtest.c: looking at device '/block/sdd' from subsystem 'block'
...
udevtest.c: opened class_dev->name='sdd'
udev_rules.c: configured rule in '/etc/udev/rules.d/10-local.rules:5' applied, 'sdd' becomes 'music_copy'
udev_add.c: creating device node '/dev/music_copy', major = '8', minor = '48', mode = '0640', uid = '0', gid = '46'
udev_add.c: creating device partition nodes '/dev/music_copy[1-15]'

Exactly what I wanted, so it looks like everything will work as intended. Now I restart the machine, and lo and behold, my drives appear, just as I wanted them:
/media/temp
/media/data
/media/data_copy
/media/music
/media/music_copy

Of course, there's nothing stopping you from setting up udev so that your digital camera always shows up as /media/camera. Or so your iRiver music jukebox consistently mounts as /media/iriver. And so on. Basically, if your system sees it as a dynamic device, you can use udev to map it to a specific mount point.






Mount Removable Devices with Persistent Names