tl;dr go here
One day, I suddenly wondered how to detect when a USB device is plugged or unplugged from a computer running Linux. For most users, this would be solved by relying on libusb. However, the use case I was investigating might not actually want to do so, and so this led me down a poorly-documented rabbit hole.
udev
By browsing the libusb source code, we can see that there are two hotplug backends: linux_netink.c and linux_udev.c . What is the difference?
If we pull up the original commit introducing those files, the commit description reads:
Add hotplug support to the Linux backend. There are two ways to configure hotplug support for Linux: udev, and netlink. It is strongly recommened that udev support is used on systems that utilize udev. We reenforce this recommendation by defaulting to --with-udev=yes at configure time. To enable netlink support run configure with --with-udev=no. If udev support is enabled all device enumeration is done with udev.
I've certainly encountered udev before (usually in the context of changing permissions of USB devices so that I can access them without being root ), but I suppose it's time to look deeper into what it actually does.
Fortunately, Free Electrons / Bootlin has the history well-covered. TL;DR, the kernel uses netlink to tell udev about devices, udev does its necessary handling of them, and then udev re-broadcasts these events to every other program interested in them.
The reason libusb so strongly recommends using the udev mechanism is to avoid race conditions. For example, udev might be in the process of changing Unix permissions, uploading firmware, or mode-switching USB devices.
But… how do we listen for these rebroadcasted events? Can we do it without linking in libudev? What IPC mechanisms are actually in use here? It turns out that udev and libudev have long since been folded into systemd while I wasn't looking. We're going to have to dive into the code and have a look.
... continue reading