udev is how Linux figures out what hardware is plugged in and how to make it available to userspace.
Let’s watch udev in action.
First, we need a device to play with. A USB flash drive is perfect. Plug one in.
lsusb
You’ll see a line like this: Bus 001 Device 005: ID 0781:5583 SanDisk Corp. Ultra Fit. The ID 0781:5583 part is the vendor ID and product ID, a unique fingerprint for this specific drive.
Now, let’s see what udev does with it.
udevadm monitor
Keep this running in one terminal. In another, unplug and re-plug your USB drive. Watch the udevadm monitor output. You’ll see events like:
monitor: /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/host0/target0:0:0/0:0:0:0/block/sda
This is udev announcing that a new block device, /dev/sda, has appeared. It also shows the path in the kernel’s device tree.
udev rules are simple text files that tell udev what to do when it sees certain devices. They live in /etc/udev/rules.d/. The files are processed in alphanumeric order, so 99-myrules.rules runs after 10-default.rules.
Let’s create a rule to make our SanDisk USB drive always appear as /dev/myusb.
Create /etc/udev/rules.d/85-usb-storage.rules with this content:
SUBSYSTEM=="usb", ATTR{idVendor}=="0781", ATTR{idProduct}=="5583", SYMLINK+="myusb"
SUBSYSTEM=="usb": This rule only applies to USB devices.ATTR{idVendor}=="0781": Matches the vendor ID we saw earlier.ATTR{idProduct}=="5583": Matches the product ID.SYMLINK+="myusb": This is the action. It creates a symbolic link named/dev/myusbthat points to the actual device node (like/dev/sda1).
After creating the file, you need to tell udev to reload its rules:
sudo udevadm control --reload-rules
Now, unplug and re-plug your USB drive. You should see /dev/myusb appear:
ls -l /dev/myusb
This will show a link to /dev/sda1 (or whatever partition udev assigned).
udev can do more than just create symlinks. It can set permissions, run programs, and even rename devices.
For example, to set the owner and group for our USB drive:
SUBSYSTEM=="usb", ATTR{idVendor}=="0781", ATTR{idProduct}=="5583", OWNER="myuser", GROUP="mygroup", MODE="0660"
This makes /dev/myusb owned by myuser:mygroup with read/write permissions for them, and no permissions for others.
The SYMLINK directive creates a symlink, but it’s a bit of a legacy feature for device naming. A more modern approach is RUN to create a persistent name using tools like blkid or lsblk and then NAME to assign it. However, for simple device mapping, SYMLINK is often sufficient and easier to grasp initially.
When udev processes events, it matches rules based on device attributes. These attributes can be queried using udevadm info -a -p /sys/devices/.... The -a flag shows all attributes, and -p specifies the device path from sysfs.
A common pattern is to match on multiple attributes to ensure you’re targeting the exact device you want. For example, matching on KERNEL=="sda*" is too broad, but SUBSYSTEM=="block", ENV{ID_FS_TYPE}=="vfat", SYMLINK+="mydata" would target any block device formatted as FAT.
The magic of SYMLINK is that udev doesn’t just create the link once. If the underlying device node (/dev/sda1) is removed or changes, udev will automatically update or remove the SYMLINK to match. This ensures consistency even if the kernel assigns different device names over time.
The real power comes from combining SUBSYSTEM, KERNEL, and ATTR (or ENV) to precisely identify devices, and then using actions like SYMLINK, OWNER, GROUP, MODE, and RUN to control how they behave in userspace.
One subtle but powerful aspect is how udev resolves dependencies. When a device appears, udev doesn’t just process one rule. It builds a dependency tree. If a rule needs a device attribute that isn’t available yet (e.g., a partition label that requires the filesystem to be mounted and scanned), udev will wait for that event before applying the rule. This ordering is crucial for complex setups.
The next thing you’ll likely run into is needing to run custom scripts when a device is plugged in.