udev(8) is the latest development in the complicated history of device management in Linux. It has not been entirely uncontroversial. It was previously hated for its decision to change syntax. Its integration into systemd caused the eudev fork to happen, and the decision to remove firmware loading support made Linus grumble.

This article isn't about that though, this is about what udev(8) is, what it can do, and how you would use it.

udev(8) is for managing the contents of /dev to handle permissions of which users and groups may access devices under which names, and providing an API for other services to use to recieve notification of when devices change.

You tend not to need to interact with udev(8) directly unless you have obscure hardware that you need to categorise, or you need to perform actions when a device appears.

Granting permission to access devices

If the device has already been processed such that there's an entry in /dev, then you can use udevadm(8) and the steps in this ArchLinux wiki page on writing udev rules to work out how to create a persistent symlink.

To change the owner of the file, so you don't need to be root to use it, you can add GROUP="GROUPNAME", subtituting the group name wanted, and set file permission bits with MODE="0660" to make that group able to read or write to that device.

Performing actions when a device appears

Short, simple scripts

The simplest way to do this is to add RUN+="/path/to/your/script" to your udev(8) rule, however this is only suitable for short-lived scripts, as they will be killed if they are stil running after a timeout period.

Starting a daemon per-device

If you need a longer-running service, then you should integrate it with a systemd unit, by defining the unit like:

cat >/etc/systemd/system/my-service@.service <<'EOF'
[Unit]
Description=My Service
[Service]
Type=simple
ExecStart=/path/to/your/script %I
EOF

And add ENV{SYSTEMD_WANTS}="my-service@%k.service" to the udev rule.

This will run /path/to/your/script and pass it the path to the device that has just appeared.

Handling device events from a currently-running daemon

Sometimes it is not appropriate to have a model where there is an instance of your service running for every device that is added. In this case, it is more appropriate to have your service listen for udev events and handle the devices when they appear itself.

The details on how to do this vary with the programming language bindings, but the general flow is:

  1. Initialize the udev library context
  2. Create a udev monitor
  3. Configure the monitor to filter it to the class of devices you care about
  4. Add the monitor to an event loop
  5. Wait for udev to have a matching entry for you
  6. Read the device entry out of udev and process the event

Depending on your programming language of choice, you may want a guide for how to listen for devices with libudev, or pyudev.