udev Explained

Plug in a USB drive and it instantly appears as /dev/sdb with a filesystem mounted. Plug in a printer and it's ready to use. This magic is udev — the Linux device manager. It listens for kernel hardware events and takes action: creating device files, loading drivers, mounting filesystems, and running custom scripts.

How udev Works

Hardware event sequence: 1. Hardware plugged in (USB, PCIe, etc.) 2. Kernel detects hardware → generates uevent 3. Kernel broadcasts uevent via netlink socket 4. udevd (daemon) receives uevent 5. udevd reads rules from /etc/udev/rules.d/ and /lib/udev/rules.d/ 6. Rules match device attributes (vendor, product, subsystem, etc.) 7. udevd takes action: → creates /dev/sdX device file (via mknod) → sets permissions and ownership → creates symlinks (/dev/disk/by-id/, /dev/disk/by-uuid/) → loads kernel module if needed → runs scripts or programs → notifies other daemons (udisks2, NetworkManager)
What ran before udev? Before udev (pre-2.6 kernel era), device files were created statically at install time — every possible device node existed in /dev even if the hardware wasn't present. A few thousand device files cluttered /dev. devfs tried to fix this but had fundamental design issues. udev solved the problem correctly: only devices actually present get entries, names are stable, and user space can react to hardware events.

udev Rules — How to Customize

Rules files live in /etc/udev/rules.d/ (your rules) and /lib/udev/rules.d/ (distro rules). Files processed in alphabetical order. Higher numbers win (80-*.rules overrides 60-*.rules).

# Rule syntax: KEY=="value", KEY="action" # Match keys use == (test) # Assignment keys use = or := (set) # Give USB drive a persistent name SUBSYSTEM=="block", ATTRS{idVendor}=="0781", ATTRS{idProduct}=="5571", \ SYMLINK+="my_usb_drive" # Set permissions on a device KERNEL=="video[0-9]*", GROUP="video", MODE="0660" # Run a script when USB plugged in ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="046d", \ RUN+="/usr/local/bin/camera-plugged.sh" # Rename network interface (the reason eth0 became enp3s0): SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", \ ATTRS{address}=="00:11:22:33:44:55", NAME="eth0"

Persistent Device Names

Why does /dev/sda sometimes become /dev/sdb after adding a disk? Kernel assigns names (sda, sdb) in discovery order — which can change between boots. udev solves this with symlinks in /dev/disk/by-id/ and /dev/disk/by-uuid/ that always point to the right device regardless of discovery order. Always use these stable paths in /etc/fstab and mdadm.conf.
# Stable paths created by udev automatically ls -la /dev/disk/by-id/ # ata-WDC_WD10EZEX_WD-WCC6Y0 → ../../sda # ata-WDC_WD10EZEX_WD-WCC6Y0-part1 → ../../sda1 ls -la /dev/disk/by-uuid/ # 6f6f-2b1a → ../../sda1 # abc12345-... → ../../sda2 ls -la /dev/disk/by-label/ # data → ../../sdb1 # Network interfaces — predictable names (since systemd 197): ls /sys/class/net/ # enp3s0 ← en=ethernet, p3=PCI bus 3, s0=slot 0 # wlp2s0 ← wl=wireless, p2=PCI bus 2, s0=slot 0 # lo ← loopback (always lo) # Naming scheme: # en = Ethernet # wl = Wireless LAN # ww = Wireless WAN # p<bus>s<slot> = PCI location

Monitoring Hardware Events

# Watch live udev events (plug in a device to see output) udevadm monitor # KERNEL[1234.5] add /devices/pci.../usb1/... (usb) # UDEV [1234.6] add /devices/pci.../usb1/... (usb) # Monitor only udev-processed events: udevadm monitor --udev # Get full attributes for a device (useful for writing rules): udevadm info --attribute-walk /dev/sda # looking at device '/devices/pci.../ata1/host0/.../sda': # ATTRS{model}=="WDC WD10EZEX" # ATTRS{vendor}=="ATA " # ATTRS{rev}=="1A01" # For USB device: udevadm info --attribute-walk /dev/bus/usb/001/002 # Test if a rule matches a device (without triggering action): udevadm test /sys/block/sda # Reload rules after editing (no reboot needed): udevadm control --reload-rules udevadm trigger # re-run rules on existing devices

Practical Rule Examples

# /etc/udev/rules.d/99-my-devices.rules # Mount USB drive automatically when plugged in ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_TYPE}!="", \ RUN+="/usr/bin/systemd-mount --no-block %N" # Give Arduino consistent device name SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", \ SYMLINK+="arduino", MODE="0666" # Disable USB autosuspend for a specific device ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="046d", \ ATTRS{idProduct}=="c52b", ATTR{power/autosuspend}="-1" # Lock screen when a YubiKey is removed ACTION=="remove", SUBSYSTEM=="usb", ATTRS{idVendor}=="1050", \ RUN+="/usr/bin/loginctl lock-sessions" # Create /dev/video_webcam symlink KERNEL=="video[0-9]*", ATTRS{idVendor}=="046d", \ SYMLINK+="video_webcam"

Frequently Asked Questions

What will I learn here?

This page covers the core concepts and techniques you need to understand the topic and progress confidently to the next lesson.

How should I use this page?

Start with the overview, then follow the section links to deepen your understanding. Use the table of contents on the right to jump to specific sections.

What should I read next?

Use the navigation below to continue to the next lesson or explore related topics.