dcsimg

Mastering udev

Learn how to use dynamic device files in Linux

If you’ve used Linux for very long, chances are you’ve seen changes to the way Linux handles device files. In Linux’s early days, device files were just ordinary files with appropriate attributes set, created by the mknod command in the /dev directory (or conceivably elsewhere). Then along came devfs, a kernel-based dynamic device filesystem that appeared in the 2.3.46 kernel. Adopted by some distributions, such as Mandrake and Gentoo, devfs created device files dynamically; however, devfs had some serious limitations and was removed from the kernel as of version 2.6.13. Its replacement is udev, a user-space program.

Linux distributions are adopting udev in a big way because it solves several problems in Linux device access, particularly for sites with extreme needs (such as the need to control thousands of hard disks) and for hot-pluggable devices (such as USB cameras and MP3 players). To gain control of your hardware on a system that uses udev, you should know how to manage it.

Chances are you won’t need to modify the standard udev configuration for hard disks, console devices, and so on, but you may need to tweak the udev configuration to use new or exotic hardware. Without such tweaks, Linux might not create device files for your hardware, or Linux might create device files with inappropriate names, ownership, or permissions. You might also want to modify ownership or permissions on RS-232 serial ports, audio device files, and so on.

Why Use udev?

Previous methods of managing device files (static files on a conventional filesystem and devfs) had several drawbacks:

*Uncertainty in device mapping. Particularly for dynamic devices, such as USB hardware, the mapping of device files to actual hardware wasn’t certain. For instance, if a system has two USB printers, one might be called /dev/usb/lp0 and the other /dev/usb/lp1, but which printer is which could change depending on which one (s) are powered on when the computer boots or after moving one or both printers to a USB hub. Ideally, the two printers should be assigned unique device files based on their serial numbers or other identifying information.

*Insufficient major/minor numbers. Each device file is assigned two 8-bit numbers: a major number and a minor number. These numbers, in conjunction with the device type (block or character) uniquely identify the device. Unfortunately, a fixed association of device files to these numbers runs into the problem that there aren’t sufficient numbers to handle all the possibilities. Creating a dynamic assignment of device names to major and minor numbers is the best solution to this problem.

*Too many /dev entries. On systems that use static device associations, the number of files in /dev is likely to be huge. This is particularly true if your distribution attempts to create entries for all the little oddball devices that exist. This can make it hard to figure out what device files are active on the system.

*Inflexible naming. Although devfs solves some of the preceding problems, it introduces some of its own. One of these is inflexible naming; you can’t easily change the names of device files. The default devfs naming scheme was also an odd one, requiring lots of changes to configuration files and programs.

*Kernel memory use. Another devfs-specific problem is that, as a kernel driver, devfs consumes a lot of memory, particularly on systems with lots of devices (such as the multi-thousand hard disk systems mentioned earlier).

The goal of udev was to solve these problems by providing a user-space tool for managing the /dev directory tree, which is actually a separate filesystem on computers that use udev. Distributions that rely on udev, which include most new distributions, typically ship with reasonable default configurations. Knowing how to change these configurations enable you to customize your system, similar to creating symbolic links or changing ownership or permissions in the older static device days.

udev Configuration Files

The main, official udev configuration file is /etc/udev/udev.conf. This file is usually quite short; it’s likely to contain several comment lines, denoted by hash marks (#), and just a few options:

udev_root="/dev/"
udev_rules="/etc/udev/rules.d/"
udev_log="err"

Some implementations lack one or more of these options and instead rely on the defaults. The second option is particularly important because it’s where the udev rules are stored. Specifically, this directory holds files with names that end in .rules. Each of these files holds a series of rules that help udev assign names to device files for devices that have been identified by the kernel.

Your system is likely to hold multiple udev rules files in /etc/udev/rules.d. These files may be installed as part of the udev package or as part of another package that works with hardware. For instance, on a Fedora Core 5 system, the sane-backends package installs the 60-libsane.rules file, and the initscripts package installs the 60-net.rules file. The filenames generally begin with a two-digit number, which controls the order in which they’re applied.

The rules in the rules files consist of a list of key/value pairs, separated by commas. Each key is either a matching key or an assignment key. Matching keys determine whether or not the rule will be applied, and assignment keys assign values to the keys; these values affect the device files that udev creates. Assignment keys may hold a list of multiple values. Matching and assignment pairs separate the key and the value with one of the operators shown in Table One.

Table One: udev Name/Value Pair Operators
Operator Matching or Assignment Meaning
== Matching Compare for equality
!= Matching Compare for inequality
= Assignment Assign the specified value to the key, overwriting any old values
+= Assignment Add the specified value to the existing key values
:= Assignment Assign the specified value to the key and disallow changes by later rules

You can think of keys as variables in a programming language, but keys are really lists — each key can hold several values at once. Several keys, specified in Table Two, have special meaning to udev, and appear frequently in its rules files. Note that you can use wildcards (*, ?, and even ranges, such as [0-9]) in several of these keys’ values.

Table Two: Common udev keys
Key Meaning
ACTION The name of an event action, such as add when a device is added.
KERNEL The kernel’s name for a device, such as sd* to match any SCSI disk device.
DEVPATH The kernel’s device path, such as /devices/*.
SUBSYSTEM The subsystem’s name, such as sound or net.
BUS The name of a bus, such as ide or usb.
DRIVER A device driver name, such as ide-cdrom.
ID A device name, independent of the kernel name.
SYSFS{ value} A sysfs attribute value, which can be just about anything.
ENV{ key} An environment variable, which can be just about anything.
PROGRAM An external program, which is executed. The key is considered true if the program returns a 0 value.
RESULT The standard output returned by a previous PROGRAM call.
NAME The filename of the device file to be created by the rule. Note that only the first line with a NAME specification has any effect; subsequent NAME lines are ignored. Use SYMLINK if you want to use two or more names to access a device.
SYMLINK The filename of a symbolic link to be created by the rule.
OWNER The owner of the device file.
GROUP The group of the device file.
MODE The permissions of the device file, specified in octal.
RUN A list of programs to be executed for the device.
LABEL A named label used for internal control within the configuration file.
GOTO Skip matching of rules between this one and the specified rule (identified via a LABEL key).
IMPORT{ type} Import a file or the result of a program’s execution into the current file.
WAIT_FOR_SYSFS Waits for a specified device file to be created. Used to work around timing and dependency issues.
OPTIONS Enables specialized options: last_rule terminates rule execution for this type of device; ignore_device ignores the current rule; ignore_remove ignores subsequent remove requests; and all_partitions creates device files for all a disk’s partitions.

As an example of how to use these keys, consider Listing One, which shows a few lines from a Fedora Core 5 system’s standard configuration. (These lines are taken out of context and have been reformatted for publication.)

Listing One: Sample udev configuration rules

KERNEL==”*”, OWNER=”root” GROUP=”root”, \
MODE=”0600″
KERNEL==”tty”, NAME=”%k”, GROUP=”tty”, \
MODE=”0666″, OPTIONS=”last_rule”
KERNEL==”scd[0-9]*”, \
SYMLINK+=”cdrom cdrom-%k”
KERNEL==”hd[a-z]“, BUS==”ide”, \
SYSFS{removable}==”1″, \
SYSFS{device/media}==”cdrom”, \
SYMLINK+=”cdrom cdrom-%k”
ACTION==”add”, SUBSYSTEM==”scsi_device” \
RUN+=”/sbin/modprobe sg”

Listing One presents five rules, each of which begins with a KERNEL or ACTION key:

*The first rule is a default. It matches any device identified by the kernel, gives it ownership by root and the root group, and sets its mode to 0600. This serves as a safe default set of permissions for a generic device.

*The second rule is typical of many rules. It matches terminal (tty) devices, and specifies new permissions (0666) and group ownership (tty) to override the defaults. It also sets a particular device filename: %k. As demonstrated by this example, you can use C-style substitutions in certain keys; %k stands for the kernel name for the device.

*The third rule, beginning KERNEL==”scd[0-9]*”, identifies SCSI CD-ROM drives. It creates a pair of symbolic links for the device: cdrom and cdrom-%k.

*The fourth rule, beginning KERNEL==”hd[a-z]“, identifies ATA CD-ROM drives through the kernel name and a pair of sysfs values. This rule creates the same symbolic links as the previous rule does. ATA CD-ROM drives require sysfs values to distinguish them from other types of ATA devices, whereas SCSI CD-ROMs can be uniquely identified by their kernel names.

*The fifth rule, beginning ACTION==”add”, tells udev to add /sbin/modprobe sg to the list of commands to be run when any SCSI device is added to the system. The effect is that the computer should add the sg kernel module whenever the computer detects a new SCSI device, just in case this kernel module is required.

Of course, these are just examples of a few rules. If you examine any system that uses udev, you’ll find many more. You may want to peruse these rules, paying particular attention to any that relate to devices that you might want to change, say, if you want to alter the permissions on a device or create a new symbolic link.

Modifying Your udev Configuration

With this information in hand, you can tweak your udev configuration. As a general rule, you shouldn’t try to modify the rules in your distribution-provided files, and especially not the broadest rules, such as the first one in Listing One. Making incorrect changes can result in security problems or an inability of the computer to access important devices.

Instead, create a new rules file in /etc/udev/rules.d, being sure to give the file an extension of .rules and a sequence number that’s higher than that of the standard files. For instance, you might call the file 99-my-udev.rules. In your rules file, you can specify any changes you want to make to the standard configuration. For example, suppose you want to give group ownership of the floppy devices to the users group and create a new symbolic link, /dev/floppy, for this device:

KERNEL=="fd[0-9]*", GROUP="users", \
  SYMLINK+="floppy"

Some distributions, such as Fedora, use external scripts to change ownership and permissions on certain devices, including floppy devices, so the group ownership change might be ineffective for you. If you have this problem, tracking down and changing the script may be the thing to do, or you can change the PROGRAM or RUN call to the script in your udev configuration.

You could as easily break a change across two entries, one for the group assignment and one for the symbolic link. Do not create a new entry with a new NAME key, though; only the first NAME entry that matches a specific device applies, so such changes will work only if no other rule creates a device file for your device.

Some rule changes may require some digging. For example, you might need to use sysfs information on a device to uniquely identify a device. This information is best obtained via udevinfo:

$ udevinfo –a –p $(udevinfo –q path \
 –n /dev/whatever)

This sequence uses udevinfo twice: once to return a sysfs device path (which is different from the usual Linux device filename — /dev/whatever in this example) and a second time to query that device path. The result is a long string of lines summarizing sysfs information. If you can find enough information to uniquely identify your device, you can make appropriate substitutions in the udev configuration’s SYSFS options.

For instance, suppose you’re trying to modify the configuration of a USB scanner. Through trial and error, you’ve identified the Linux device filename for the scanner (which changes every time you turn the scanner on). You can then use the preceding command, substituting the correct Linux device filename and located SYSFS{idVendor} and SYSFS{idProduct} lines in the output. You can then use this information to create new options for the scanner:

SYSFS{idVendor}=="0686", \
 SYSFS{idProduct}=="400e", \
 SYMLINK+="scanner", MODE="0664", \
 group="scanner"

This line sets group ownership to scanner, sets the mode to 0664, and creates a symbolic link named /dev/scanner for the device. In practice, it may take some trial and error to figure out what SYSFS values uniquely identify a device. You’ll also have to carefully study the output of udevinfo just to locate your device. You may see information on the device bus in addition to the target device itself.

With this information in hand and (perhaps) with some trial-and-error experimentation, you should be able to adjust your udev configuration. Doing so lets you adjust ownership and permissions, add static device filenames for devices whose filenames are inconstant, and add more memorable device filenames than the defaults.

Comments are closed.