How can I start a systemd service when a given USB device (ethernet dongle) is plugged in?
Solution 1
I've seen "How to write a systemd service that depends on a device being present?" but that doesn't seem to be about plugging it in, just about it being present.
It's very similar, only you need the opposite dependency: instead of (or perhaps in addition to) your service depending on the device, you want the virtual device unit to depend on your service.
In fact, despite the linked question's title seemingly asking the opposite thing, the accepted answer in the thread already documents one of the exact methods that would make the device start a service (the udev-rule method).
But if you have an exact .device unit name, it's simpler to use systemd dependencies directly:
If the exact sysfs path is known:
For example, you have determined that the device is sys-subsystem-net-devices-usb0.device. You can use various ways of expanding that unit (despite it being virtual), such as foo.device.d/*.conf
drop-ins or foo.device.wants/
symlinks (which work the same way as e.g. multi-user.target.wants/).
-
You can add an
[Install]
configuration in your service, then systemctl enable it:[Install] WantedBy=sys-subsystem-net-devices-%i.device
-
Or you can get the same result directly with
systemctl add-wants
:# systemctl add-wants sys-subsystem-net-devices-usb0.device [email protected]
Both methods just result in a symlink that can be made by hand via
ln -s
.
This generally works the same for user units.
If only partial name (or some combination of other properties) is known:
Write a udev rule that matches your device (the exact udev rule syntax is out of scope here) and have it set the SYSTEMD_WANTS
udev property (aka "device environment variable") indicating your unit:
ACTION=="add", SUBSYSTEM=="net", KERNEL=="usb*", ENV{SYSTEMD_WANTS}+="netctl-ifplugd@%k.service"
As all *.rules
files are processed in alphabetical order, make sure your rule is placed later than systemd's own "persistent network interfaces" rules.
This works with user units if you use ENV{SYSTEMD_USER_WANTS}
.
You might be tempted to use RUN+="/bin/systemctl start foo"
via udev. Don't do that. But if you do, then at least use the systemctl --no-block
option so that you won't create a possible deadlock between the two components.
Solution 2
udev is what you want to look at. It will allow you to do things like execute commands when hardware is plugged in, unplugged, state changes happen etc. You can also specify a wide variety of criteria to control triggering (i.e. when any storage device is plugged in or just a particular model from a particular manufacturer etc.) You should see any existing rules on your system in /etc/udev/rules.d/
Related videos on Youtube
SoniEx2
Updated on September 18, 2022Comments
-
SoniEx2 over 1 year
I have an USB ethernet dongle I use for ethernet access, but I'd like to automatically start
netctl-ifplugd@...
when plugging it in. (Not to be confused with plugging in the ethernet cable - that's handled bynetctl-ifplugd
.) How can I make this happen?I've seen How to write a systemd service that depends on a device being present? but that doesn't seem to be about plugging it in, just about it being present.
-
Stephen Smith over 4 yearsI'm trying to solve this same problem using the add-wants systemd command - I just got a new ethernet adapter ens4u1u2 so I enabled
[email protected]
and then tried to add-wants usingsudo systemctl add-wants sys-subsystem-net-devices-ens4u1u2.device [email protected]
, but I getFailed to add dependency: Unit file sys-subsystem-net-devices-ens4u1u2.device does not exist.
. Runningsystemctl status sys-subsystem-net-devices-ens4u1u2.device
shows that the device is active but it won't accept it for add-wants. Enabling the .device gives the same error. -
user1686 over 4 yearsIf systemd no longer allows this in add-wants, then just create the symlink manually at
/etc/systemd/system/sys-....device.wants/
, or use the udev rule method (which might be preferred). -
Stephen Smith over 4 yearsThanks, I got the udev method to work. For posterity, what I ended up with is
ACTION=="add", SUBSYSTEM=="net", KERNEL=="usb*", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="8153", ENV{SYSTEMD_WANTS}+="[email protected]"
, using values fromlsusb