A udev rule for my USB stick (disk-on-key)

This post was written by eli on June 16, 2011
Posted Under: Linux,USB

Writing udev rules is well-documented all over the web, but I still wrote down my own quick summary, so I have it handy for the next time.

Update: On systemd-enabled system (that’s all of them by 2017?), the system’s udev rules reside in /lib/udev/. The rules in /etc/udev take precedence, and it’s still the correct place to put local rules. Just don’t be surprised that it’s empty.

Update II: I have a more recent post with udev hacking.

Following this excellent guide, I plugged in the USB stick and went

$ udevadm info -a -n /dev/sdd

Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can  be composed by the attributes of the device and the attributes from one single parent device.

On another computer a similar command could be

$ udevinfo -q all -n /dev/sda

The output from the first command was:

 looking at device '/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host15/target15:0:0/15:0:0:0/block/sdd':
 KERNEL=="sdd"
 SUBSYSTEM=="block"
 DRIVER==""
 ATTR{range}=="16"
 ATTR{ext_range}=="256"
 ATTR{removable}=="1"
 ATTR{ro}=="0"
 ATTR{size}=="7821312"
 ATTR{alignment_offset}=="0"
 ATTR{discard_alignment}=="0"
 ATTR{capability}=="51"
 ATTR{stat}=="      49      438     3182      274        0        0        0        0        0      127      274"
 ATTR{inflight}=="       0        0"

 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host15/target15:0:0/15:0:0:0':
 KERNELS=="15:0:0:0"
 SUBSYSTEMS=="scsi"
 DRIVERS=="sd"
 ATTRS{device_blocked}=="0"
 ATTRS{type}=="0"
 ATTRS{scsi_level}=="3"
 ATTRS{vendor}=="SanDisk "
 ATTRS{model}=="Cruzer Blade    "
 ATTRS{rev}=="1.01"
 ATTRS{state}=="running"
 ATTRS{timeout}=="30"
 ATTRS{iocounterbits}=="32"
 ATTRS{iorequest_cnt}=="0x1a8"
 ATTRS{iodone_cnt}=="0x1a8"
 ATTRS{ioerr_cnt}=="0x1"
 ATTRS{modalias}=="scsi:t-0x00"
 ATTRS{evt_media_change}=="0"
 ATTRS{dh_state}=="detached"
 ATTRS{queue_depth}=="1"
 ATTRS{queue_type}=="none"
 ATTRS{max_sectors}=="240"

 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host15/target15:0:0':
 KERNELS=="target15:0:0"
 SUBSYSTEMS=="scsi"
 DRIVERS==""

 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host15':
 KERNELS=="host15"
 SUBSYSTEMS=="scsi"
 DRIVERS==""

 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0':
 KERNELS=="2-1:1.0"
 SUBSYSTEMS=="usb"
 DRIVERS=="usb-storage"
 ATTRS{bInterfaceNumber}=="00"
 ATTRS{bAlternateSetting}==" 0"
 ATTRS{bNumEndpoints}=="02"
 ATTRS{bInterfaceClass}=="08"
 ATTRS{bInterfaceSubClass}=="06"
 ATTRS{bInterfaceProtocol}=="50"
 ATTRS{modalias}=="usb:v0781p5567d0100dc00dsc00dp00ic08isc06ip50"
 ATTRS{supports_autosuspend}=="0"

 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb2/2-1':
 KERNELS=="2-1"
 SUBSYSTEMS=="usb"
 DRIVERS=="usb"
 ATTRS{configuration}==""
 ATTRS{bNumInterfaces}==" 1"
 ATTRS{bConfigurationValue}=="1"
 ATTRS{bmAttributes}=="80"
 ATTRS{bMaxPower}=="200mA"
 ATTRS{urbnum}=="938"
 ATTRS{idVendor}=="0781"
 ATTRS{idProduct}=="5567"
 ATTRS{bcdDevice}=="0100"
 ATTRS{bDeviceClass}=="00"
 ATTRS{bDeviceSubClass}=="00"
 ATTRS{bDeviceProtocol}=="00"
 ATTRS{bNumConfigurations}=="1"
 ATTRS{bMaxPacketSize0}=="64"
 ATTRS{speed}=="480"
 ATTRS{busnum}=="2"
 ATTRS{devnum}=="8"
 ATTRS{devpath}=="1"
 ATTRS{version}==" 2.00"
 ATTRS{maxchild}=="0"
 ATTRS{quirks}=="0x0"
 ATTRS{avoid_reset_quirk}=="0"
 ATTRS{authorized}=="1"
 ATTRS{manufacturer}=="SanDisk"
 ATTRS{product}=="Cruzer Blade"
 ATTRS{serial}=="200610803009F0712206"

 looking at parent device '/devices/pci0000:00/0000:00:1d.7/usb2':
 KERNELS=="usb2"
 SUBSYSTEMS=="usb"
 DRIVERS=="usb"
 ATTRS{configuration}==""
 ATTRS{bNumInterfaces}==" 1"
 ATTRS{bConfigurationValue}=="1"
 ATTRS{bmAttributes}=="e0"
 ATTRS{bMaxPower}=="  0mA"
 ATTRS{urbnum}=="4053"
 ATTRS{idVendor}=="1d6b"
 ATTRS{idProduct}=="0002"
 ATTRS{bcdDevice}=="0206"
 ATTRS{bDeviceClass}=="09"
 ATTRS{bDeviceSubClass}=="00"
 ATTRS{bDeviceProtocol}=="00"
 ATTRS{bNumConfigurations}=="1"
 ATTRS{bMaxPacketSize0}=="64"
 ATTRS{speed}=="480"
 ATTRS{busnum}=="2"
 ATTRS{devnum}=="1"
 ATTRS{devpath}=="0"
 ATTRS{version}==" 2.00"
 ATTRS{maxchild}=="8"
 ATTRS{quirks}=="0x0"
 ATTRS{avoid_reset_quirk}=="0"
 ATTRS{authorized}=="1"
 ATTRS{manufacturer}=="Linux 2.6.35.4-OCHO1 ehci_hcd"
 ATTRS{product}=="EHCI Host Controller"
 ATTRS{serial}=="0000:00:1d.7"
 ATTRS{authorized_default}=="1"

 looking at parent device '/devices/pci0000:00/0000:00:1d.7':
 KERNELS=="0000:00:1d.7"
 SUBSYSTEMS=="pci"
 DRIVERS=="ehci_hcd"
 ATTRS{vendor}=="0x8086"
 ATTRS{device}=="0x3b34"
 ATTRS{subsystem_vendor}=="0x1458"
 ATTRS{subsystem_device}=="0x5006"
 ATTRS{class}=="0x0c0320"
 ATTRS{irq}=="23"
 ATTRS{local_cpus}=="00000000,00000000,00000000,00000000,00000000,00000000,00000000,000000ff"
 ATTRS{local_cpulist}=="0-7"
 ATTRS{modalias}=="pci:v00008086d00003B34sv00001458sd00005006bc0Csc03i20"
 ATTRS{numa_node}=="-1"
 ATTRS{dma_mask_bits}=="32"
 ATTRS{consistent_dma_mask_bits}=="32"
 ATTRS{broken_parity_status}=="0"
 ATTRS{msi_bus}==""
 ATTRS{companion}==""

 looking at parent device '/devices/pci0000:00':
 KERNELS=="pci0000:00"
 SUBSYSTEMS==""
 DRIVERS==""

From which I extracted the idVendor, idProduct and most important, serial attributes, marked in red above.

So I generated /etc/udev/rules.d/10-local-usbstick-rules saying:

SUBSYSTEMS=="usb", ATTRS{idVendor}=="0781", ATTRS{idProduct}=="5567", ATTRS{serial}=="200610803009F0712206", NAME="usbstick_trials", OWNER="eli"

Note that I set myself as the owner of the device file. This means that the data on the USB stick is not so safe, because I can accidentally write data directly to the device file. The upside is that root privileges are not necessary, so the chances for messing up a real hard disk are significantly diminished.

That’s it. /dev/sdd doesn’t appear now, and neither do partition device files, so it’s a bit more difficult to mount the disk (but there’s a trick). On the other hand, raw writing to it just became much safer.

Plug out, plug in again and we have:

$ ls -l /dev/usbstick_trials
brw-rw----. 1 eli disk 8, 48 2011-06-16 17:54 /dev/usbstick_trials

On the other computer (Centos 5.5) the rule was /etc/udev/rules.d/90-local-imagedisk.rules as follows:

KERNEL=="sda1", ENV{ID_SERIAL}=="SATA_WDC_WD5000AAKX-_WD-WCAYUFH69712", NAME="playdisk", OWNER="eli", MODE="666", OPTIONS="last_rule"

The reason for placing the rule late is to allow 50-udev.rules to set up the ID_SERIAL environment variable, which is created from the disk’s serial number. So no other disk gets messed up this way accidentally

Alternative: Monitor events

# udevadm monitor --udev --property

This prints out the udev events as they happen. The relevant info is there too. Useful when you’re not sure which device belongs to what, but a plug-in event makes it very clear. Unfortunately, it doesn’t print out any actions udev takes as it applies the rules.

Reader Comments

“/dev/sdd doesn’t appear now, and neither do partition device files, so it’s a bit more difficult to mount the disk”

can’t you just add an additional rule for the partitions, with smth like
SUBSYSTEM==”block”, ATTR{partition}==”1″, ATTRS{serial}==”200610803009F0712206″, NAME=”usbstick_trials1″, SYMLINK+=”%k”

#1 
Written By Sid on November 11th, 2011 @ 10:26

That sounds like a good idea: Doing the raw writing to a device file with a distinct name, and then mount a classic device. Thanks.

#2 
Written By eli on November 11th, 2011 @ 11:39

Add a Comment

required, use real name
required, will not be published
optional, your blog address