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:- Edit
/etc/security/access.conf
and addroot: ALL
- Edit
/etc/pam.d/system-auth
and addaccount required pam_access.so
as the second line. - Edit
/etc/pam.d/su
and makeaccount 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: