Some Nifty udev Rules and Examples

Dynamic device management made easy with udev

Connecting flash drives, hard disks, cameras or mobile phones to your Linux system has never been so easy and manageable, thanks to udev, developed by Greg Kroah-Hartman, Kay Sievers and Dan Stekloff. First implemented in Linux kernel 2.6, udev handles devices that are hot-plugged into a running system, as well as cold-plugged devices (connected before the system is powered on). In this article, we cover how udev dynamically adds device nodes to the /dev directory, and provide some examples of configurations for your use or amusement.

udev stands for “userspace implementation of devfs”. It includes a udevd daemon, configuration files and rule files, which are used to dynamically manage device files in the /dev directory in Linux, in response to uevents generated by the kernel. udev has successfully and completely replaced the older devfs since the Linux kernel 2.6 series.

Why did we need a totally new implementation of device mapping? Why has udev been such a success? The answer involves the history of the Linux device driver mapping scheme.

Each device file is assigned two 8-bit numbers: a major number and a minor number. Each device driver has a major device number; and all device files for devices controlled by that driver have the same major number. Minor device numbers distinguish between different devices controlled by the driver.

In earlier Linux kernel versions, /dev contained one static device file for each device that could be connected to the system (and controlled by a device driver). Unfortunately, this had problems: there weren’t sufficient numbers to handle all the possibilities, especially since the list of device drivers kept increasing. Also, over 18,000 device files consumed too much extra space on the disk. These problems were resolved by adding the ability to ignore the major and minor numbers in udev.

Particularly for hot-pluggable devices like USB hardware, there was no consistency in the naming/mapping of device files to the actual hardware device. For instance, on a system with two USB printers, one might be called /dev/usb/lp0 and the other /dev/usb/lp1 — but it was never certain which printer was referred to by which device node. That could change based on which one was powered on when the computer booted, or was connected first — or could change if they were connected to a USB hub instead of directly to the system USB ports. This often proved frustrating and confusing to users. udev provides a means to assign a persistent name to a device, using the udev rules feature.

Other udev features resolve many problems inherent to devfs:

  • udev works in user-space, reducing kernel code and complexity.
  • •udev provides a way to assign persistent names to devices, independent of the order of connection or location on a bus.
  • •udev dynamically populates the /dev directory with device nodes for only the devices that are actually present/connected to the system. It also enables the assignment of common names to devices via symbolic links to the actual device node.
  • •udev provides complete device information to user-space programs, removing the need to access kernel-space for the information.

How udev works

The udevd daemon listens to a netlink socket for uevents issued by the kernel on the connection or removal of a device. You can monitor these events with the command udevmonitor — run it, attach a USB device like a flash drive, and remove it. (In newer distributions, udevmonitor may not be available — in that case, use udevadm monitor instead of udevmonitor.)

At start-up, udev mounts a tmpfs filesystem for the /dev directory. It then copies device nodes from /lib/udev/device to /dev and begins collecting uevents from the kernel for cold-plugged devices. /etc/udev/rules.d is used to apply device parameters, to create symbolic links, and to take other action. For hot-plugged devices, udevd catches the uevent via D-Bus, and matches the attributes of the new device as exposed in the /sys directory, with udev rules — and then creates the device node in the /dev directory. udev can also load properly-written device drivers for detected hardware, using the modalias mechanism.

udev rules and examples

udev gives you the power to handle your devices by writing your own rules and configuration files. You can override the behaviour of package-supplied rules (usually found in /lib/udev/rules.d), or add custom and specific behaviour to suit your needs. You add your own rules file in /etc/udev/rules.d/ — the directory meant for local/custom rules.

Create your own rules (which assign the name, symlinks, permissions, etc, that you want) in this directory. To ensure your rule file takes precedence, begin the file name with a number that is lower than the rules file you want to override — for example, 10-local.rules.

Here are some sample rules with comments, which may help you write your own rules.

Disable root login until the admin connects his USB drive

BUS=="usb", SUBSYSTEM=="block", PROGRAM="/bin/enable_root_login"

To get this rule to work, you will need to code a program/script with the given name, which obtains the serial numbers of the USB devices connected to the system, and compares each with the serial number of the admin’s USB device, which is known. If matched, this program will delete a line from the /etc/pam.d/login file — auth requisite pam_deny.so so that root login is enabled. There will be no change in the login file if any other USB drive is connected to the system. Conversely, as soon as the USB drive is unplugged, this line will again be added to the login file.

This rule has been checked on RHEL 5.0 and works fine, but when using the su command, or when logging in to single-user mode on boot, this rule will not work. To lock down root login for the su command, you can:

  1. Edit /etc/security/access.conf and add root: ALL
  2. Edit /etc/pam.d/system-auth and add account required pam_access.so as the second line.
  3. Edit /etc/pam.d/su and make account include system_auth the first line of this file.

These tasks will, of course, be handled by the enable_root_login program. After checking if the attached USB device is the admin’s, your program should undo all the changes to the above files, and if the attached device is not the admin’s, then apply the changes to the files mentioned above.

This will still not work in single-user mode, so if you need that locked down, perhaps you can assign a GRUB password to prevent easy access to the single-user mode.

To retrieve information like the serial number, kernel name, vendor ID, manufacturer’s name, etc, for a particular device, you can run the following command:

udevinfo -a -p /sys/block/sdb

In newer distributions, udevinfo may not be available — in that case, substitute udevadm info instead of udevinfo.

Disable all USB ports

BUS=="usb", OPTIONS+="ignore_device"

The effect of this rule will be to disable all devices connected to all USB ports of your system — USB printers, keyboards and mouses will not work. So use it with care!

Disable all USB block devices

BUS=="usb", SUBSYSTEM=="block", OPTIONS+="ignore_device"

This particular rule prevents USB block storage devices from being recognised. This may be useful for information security or confidentiality within an organisation.

Assign a persistent name to your second IDE disk

KERNEL=="sdb", NAME="my_spare"

Adjust sdb if you want to apply this rule to another drive.

Ignore the second USB SCSI/IDE disk connected via USB

BUS=="usb", KERNEL=="sdb", OPTIONS+="ignore_device"

OR

BUS=="usb", KERNEL=="hdb", OPTIONS+="ignore_device"

Add a symbolic link to a specific USB mouse device’s name

SUBSYSTEM=="input", BUS=="usb", SYSFS{serial}=="0000:00:1d.0", SYMLINK+=="MY-USB-MOUSE"

Change device node name based on the manufacturer’s name

BUS=="usb", SYSFS{manufacturer}=="JetFlash", NAME="UNIVERSE"

This rule states that if the name of a USB drive’s manufacturer is JetFlash, the device’s node name will be ‘UNIVERSE’.

Selectively allow USB block devices via a custom program

BUS=="usb", SUBSYSTEM=="block", PROGRAM="/bin/usbc.jar", RESULT!="my", OPTIONS+="ignore_device"

If the output generated by the program is equal to the ‘my’ value that is specified, then allow the USB device; if the output is anything else, then ignore the device.

For further reference, visit:

This article was originally published in May 2010 issue.

  • Nagora Nerides

    “Why has udev been such a success? ”

    Udev is not a success, it’s just marginally less worse than the previous options. It still sucks, it is still badly documented and it still is far too complicated and unpredictable when dealing with new hardware.

    In short, it is bloody awful.

All published articles are released under Creative Commons Attribution-NonCommercial 3.0 Unported License, unless otherwise noted.
Open Source For You is powered by WordPress, which gladly sits on top of a CentOS-based LEMP stack.

Creative Commons License.