You are not logged in.

#1 2026-07-05 07:04:38

Beemo
Member
Registered: 2024-12-20
Posts: 88

[SOLVED] Start systemd unit after device is ready

I want to start hostapd after a USB Wi-Fi adapter is ready. What's the reason the following don't work?

Requisite: (Looks like it didn't even attempt to start?)

[Unit]
After=sys-subsystem-net-devices-wlp0s20f0u2.device
Requisite=sys-subsystem-net-devices-wlp0s20f0u2.device
$ systemctl status hostapd@ax-6.service
○ hostapd@ax-6.service - Hostapd IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
     Loaded: loaded (/usr/lib/systemd/system/hostapd@.service; enabled; preset: disabled)
    Drop-In: /etc/systemd/system/hostapd@ax-6.service.d
             └─override.conf
     Active: inactive (dead)
(No logs whatsoever)

Require:
TBH I don't think this unit should go and try to start the .device unit, so "Require" is not quite the right option...
systemd sees the device but hostapd doesn't?

[Unit]
After=sys-subsystem-net-devices-wlp0s20f0u2.device
Require=sys-subsystem-net-devices-wlp0s20f0u2.device
$ systemctl status hostapd@ax-6.service
× hostapd@ax-6.service - Hostapd IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
    Drop-In: /etc/systemd/system/hostapd@ax-6.service.d
             └─override.conf
     Active: failed (Result: exit-code)
hostapd[524]: nl80211: Driver does not support authentication/association or connect commands
hostapd[524]: nl80211: deinit ifname=wlp0s20f0u2 disabled_11b_rates=0
hostapd[524]: Could not read interface wlp0s20f0u2 flags: No such device
hostapd[524]: nl80211 driver initialization failed.

If I use "After=multi-user.target" then it works. But ideally I want the unit to not try to start if the USB device is not plugged in.

$ systemctl status hostapd@ax-6.service
● hostapd@ax-6.service - Hostapd IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
     Loaded: loaded (/usr/lib/systemd/system/hostapd@.service; enabled; preset: disabled)
    Drop-In: /etc/systemd/system/hostapd@ax-6.service.d
             └─override.conf
     Active: active (running)
hostapd[558]: wlp0s20f0u2: AP-ENABLED

P.S. I'm pretty sure I got the device name right:

$ systemctl list-units -a -t device
  sys-subsystem-net-devices-wlp0s20f0u2.device    loaded active plugged
$ systemctl status sys-subsystem-net-devices-wlp0s20f0u2.device
● sys-subsystem-net-devices-wlp0s20f0u2.device - Wireless_Device
     Loaded: loaded
     Active: active (plugged)

Last edited by Beemo (2026-07-05 13:43:19)

Offline

#2 2026-07-05 09:48:06

twig
Member
Registered: 2025-09-25
Posts: 9

Re: [SOLVED] Start systemd unit after device is ready

Hi!

The reason your attempts didn't work comes down to how systemd handles Requisite and Requires directives:

  • Requisite checks if the target unit is already active at the exact moment your service is evaluated. Since USB device enumeration takes a bit of time, this is rarely the case.

  • As for Requires, there was a slight typo ("Require"), but even spelled correctly, it wouldn't be the right solution here. It causes systemd to stall the boot sequence while waiting for the device until it times out. Also, if you plug the adapter in 5 minutes later, nothing will happen because systemd only evaluates that dependency during boot.

Technically, you could just use:

[Unit]
BindsTo=sys-subsystem-net-devices-wlp0s20f0u2.device
After=sys-subsystem-net-devices-wlp0s20f0u2.device

[Install]
WantedBy=sys-subsystem-net-devices-wlp0s20f0u2.device

This works, but if the network interface name ever changes, the service fails to start.

If you want a more robust solution, you can follow this Arch Wiki page https://wiki.archlinux.org/title/Udev#S … _processes:

  1. Disable hostapd@ax-6.service.

  2. Identify the adapter's idVendor and idProduct with:

    udevadm info --attribute-walk /sys/class/net/wlp0s20f0u2
  3. Create a new udev rule file, for example,

    /etc/udev/rules.d/99-hostapd.rules

    and add this rule filling the correct attributes:

    SUBSYSTEM=="net", ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="", ATTRS{idProduct}=="", TAG+="systemd", ENV{SYSTEMD_WANTS}+="hostapd@ax-6.service"
  4. Reload your configuration:

    systemctl daemon-reload
    udevadm control --reload-rules
    udevadm trigger

With this setup, you don't even need an override.conf file.

If you want the service to stop gracefully when you unplug the device, you can add

ENV{SYSTEMD_ALIAS}="/wifiadapter"

to that udev rule, and use your override.conf like this:

[Unit]
BindsTo=wifiadapter.device
After=wifiadapter.device

Let me know if this works!

Last edited by twig (2026-07-05 09:53:28)

Offline

#3 2026-07-05 13:36:07

Beemo
Member
Registered: 2024-12-20
Posts: 88

Re: [SOLVED] Start systemd unit after device is ready

"BindsTo=" and "Requires=" work.
("Requires=" didn't might be because of the typo, though I didn't see any error, or by chance of ordering. Idk...)

However I just want to rant that this behavior is nowhere to be found in the systemd documentation...

systemd.unit wrote:

Requires=
If this unit gets activated, the units listed will be activated as well.

Requisite=
Similar to Requires=. However, if the units listed here are not started already, they will not be started and the starting of this unit will fail immediately.

BindsTo=
in addition to the effects of Requires=, which already stops (or restarts) the configuring unit when a listed unit is explicitly stopped (or restarted), it also does so when a listed unit stops unexpectedly (which includes when it fails).

Before=, After=
After= ensures the opposite, that the listed unit is fully started up before the configured unit is started.

So the naive thought is that, what I want is "Requisite=" (not proactively start stuff), and that "After=" does what it says (wait for the other unit).

"Require=" only makes sure the unit runs, not whether it succeeds. That seems to be the function of "After=".

Requires=
If one of the other units fails to activate, and an ordering dependency After= on the failing unit is set, this unit will not be started.

Instead the only hint of it is in this issue:

thx1111 wrote:

The device unit does not wait around, and the jobs which depend upon the device unit do not wait around for the device unit to show up. Instead, the device unit times-out, and the units which now have this After= dependency are "failed".

Even more frustrating, Poettering and the documentation say that's the purpose of the ".device" -- for ordering stuff.

arvidjaar wrote:

BindsTo adds start job for device

arvidjaar wrote:

So to wait for a device, it needs (to fake) start job for this device - otherwise there is nothing to wait for. In this respect, every use of BindsTo today relies on forward start function to queue this (fake) start job.

arvidjaar wrote:

So you are left with a single additional job to start B - which in case of device means "wait for device B to appear".

I.E. "Requires=" does not attempt to start / enable a device as one naively think, but merely wait.

Also there was the gotcha of "Requisite=" requiring "After=" to work properly which was the main topic of that issue.

Last edited by Beemo (2026-07-05 13:40:27)

Offline

Board footer

Powered by FluxBB