Random Wisdom

Fine grained system control with custom udev rules

by on Feb.16, 2012, under Hardware, How To ..., Linux

When a new hardware device is plugged into a Linux system, udev handles the creation of device nodes and symbolic links under ‘/dev’. Certain aspects of this process, such as initial file permissions, can be controlled using custom udev rules placed in the appropriate configuration file directory (e.g. ‘/etc/udev/rules.d/’). Recently, I found myself looking into custom udev rules for two reasons: setting the default device permissions on a USB scanner and setting a unique name for an external disk.

udev rules always start with directives that tell udev how to match a device of interest. E.g.

ACTION=="add", KERNEL=="sg[0-9]*", BUS=="scsi", SYSFS{type}=="8", \
        SYMLINK+="changer changer-%k", MODE="0660", GROUP="disk"

In this particular example, if the keys ACTION, KERNEL, BUS and SYSFS{type} for the new device match the given values, then the values specified for SYMLINK, MODE and GROUP are applied to each of those attributes when creating the device node. A list of the valid test and assignment operators for udev rules can be found in the man page for udev.

The key/value pairs necessary to match a given device can be discovered by using the ‘udevadm‘ tool. For a USB device, ‘lsusb‘ can be used first to determine the generic device node after plugging in the hardware:

[root@localhost ~]# lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 003: ID 0644:0200 TEAC Corp. All-In-One Multi-Card Reader CA200/B/S
Bus 004 Device 003: ID 04b8:010f Seiko Epson Corp. Perfection 1250
Bus 002 Device 003: ID 0665:5161 Cypress Semiconductor USB to Serial
Bus 001 Device 007: ID 0bc2:5071 Seagate RSS LLC 

In this list, ‘Bus 004 Device 003: ID 04b8:010f Seiko Epson Corp. Perfection 1250‘ is the scanner and it is at device node ‘/dev/bus/usb/004/003’. Armed with that information, it is now possible to use ‘udevadm’ to get the key/value pairs:

[root@localhost ~]# udevadm info --attribute-walk --path \
                    $(udevadm info --query path --name /dev/bus/usb/004/003)

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.

  looking at device '/devices/pci0000:00/0000:00:1d.2/usb4/4-2':
    KERNEL=="4-2"
    SUBSYSTEM=="usb"
    DRIVER=="usb"
    ATTR{configuration}==""
    ATTR{bNumInterfaces}==" 1"
    ATTR{bConfigurationValue}=="1"
    ATTR{bmAttributes}=="c0"
    ATTR{bMaxPower}=="  2mA"
    ATTR{urbnum}=="282"
    ATTR{idVendor}=="04b8"
    ATTR{idProduct}=="010f"
    ATTR{bcdDevice}=="0100"
    ATTR{bDeviceClass}=="ff"
    ATTR{bDeviceSubClass}=="00"
    ATTR{bDeviceProtocol}=="ff"
    ATTR{bNumConfigurations}=="1"
    ATTR{bMaxPacketSize0}=="8"
    ATTR{speed}=="12"
    ATTR{busnum}=="4"
    ATTR{devnum}=="3"
    ATTR{version}==" 1.10"
    ATTR{maxchild}=="0"
    ATTR{quirks}=="0x0"
    ATTR{authorized}=="1"
    ATTR{manufacturer}=="EPSON"
    ATTR{product}=="EPSON Scanner 010F"

  looking at parent device '/devices/pci0000:00/0000:00:1d.2/usb4':
    KERNELS=="usb4"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ...
    ...
    [output trimmed]

Using this information from ‘udevadm‘ the following rule was created:

[root@localhost ~]# cat /etc/udev/rules.d/60-scanner.rules 
# UDEV rules for Epson scanner

ACTION!="add", GOTO="epson_rules_end"
SUBSYSTEM!="usb", GOTO="epson_rules_end"

SUBSYSTEM=="usb", DRIVER=="usb", ATTR{idVendor}=="04b8", ATTR{idProduct}=="010f", \
 MODE="0666", SYMLINK+="scanner" LABEL="epson_rules_end"

LABEL="epson_rules_end"

This rule instructs udev to create an additional device node at ‘/dev/scanner’ and set the access permissions to ‘rw-rw-rw-‘. After saving the rules file, it is necessary to apply the changes using:

[root@localhost ~]# udevadm trigger

Useful resources: “Writing udev rules“, udev and udevadm man pages.

:, , ,

1 Comment for this entry

  • some name

    Can’t believe there’s no comments, as it’s one of the best explainations I’ve seen. Particularly finding the proper node from lsusb, that’s where I’ve always gotten lost in the past. One small detraction, I believe the sysfs{value} syntax has been deprecated for years. Not complaining though, helped me a bunch, thank you

Leave a Reply