keventd: add class/<subsystem>/<name> and driver/<name> conditions

dev/<X> only fires when a device gets a /dev node, which leaves a lot of
embedded-relevant hardware uncoverable: DSA switch cores, IIO sensors,
LEDs, backlight, PHYs, regulators -- all live purely under sysfs.

Two new condition namespaces:

  class/<subsystem>/<sysname>  asserted on every sysfs class device add
                                (e.g. <class/leds/blue>)
  driver/<name>                 asserted while the driver is bound to at
                                least one device (e.g. <driver/mt7530>)

A driver can bind to several devices, so driver/ conditions are
refcounted: asserted on first bind, cleared when the last device is
unbound.

dev_cond() is generalized into a static cond_emit(prefix, rel, set) so
class_cond() and driver_cond() share the same mkpath + symlink/erase
code.  The name avoids colliding with src/cond.h's public cond_path()
helper (unrelated function that returns a condition's filesystem path).

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-08-16 22:03:34 +02:00
1 parent e4d9193f06
commit f3461ce2ba
6 files changed
+174 -13

No files matched your search

+9 -1
View File
@@ -177,7 +177,8 @@ Built-in Conditions
Finit comes with a set of plugins for conditions:
- `keventd`: provides `<dev/...>` and `<sys/pwr/...>`
- `keventd`: provides `<dev/...>`, `<class/...>`, `<driver/...>`, and
`<sys/pwr/...>`
- `devmon` (built-in fallback for `<dev/...>` without keventd)
- `netlink`: provides `<net/...>`
- `pidfile`: provides `<pid/...>`
@@ -191,6 +192,11 @@ condition is cleared. If keventd is not in use (an external device
manager like udevd is used instead), the `devmon` built-in provides the
same conditions by monitoring `/dev` and `/dev/dir` with inotify.
keventd also asserts `class/<subsystem>/<name>` for devices that have
no `/dev` node, e.g. LEDs and DSA switch ports, and `driver/<name>`
while a driver is bound to at least one device. See
[keventd](keventd.md) for details.
The `pidfile` plugin recursively watches `/run/` for PID files created
by the monitored services, and sets a corresponding condition in the
`pid/` namespace.
@@ -234,6 +240,8 @@ Built-in conditions:
- `usr/foo`
- `boot/arg`
- `dev/node` and `dev/dir/node`
- `class/<subsystem>/<name>`
- `driver/<name>`
> [!NOTE]
> Here, `up` means administratively up, the interface flag `IFF_UP`.
+51
View File
@@ -227,9 +227,60 @@ devices:
command = "/usr/sbin/gps-daemon"
}
Network interfaces are not device nodes and do not live in the `dev/`
namespace -- a `/dev/wan` node created by a user must not be confused
with a `wan` interface. To wait for an interface, use the `netlink`
plugin's `net/<iface>/exist` condition, plus `net/<iface>/up` (admin
up) and `net/<iface>/running` (carrier present) to gate on link state:
service dhcpcd {
description = "DHCP client"
runlevel = "2345"
conditions = { "net/wan/exist" }
command = "/usr/sbin/dhcpcd"
}
keventd provides the parallel `class/net/<iface>` condition, like for
any other sysfs class device.
When the device is removed, the condition is cleared and Finit stops
the dependent services.
### Class Conditions (`class/`)
Many devices live in sysfs without a `/dev/` node -- DSA switch ports,
IIO sensors, LEDs, backlight, PHYs, regulators. For those, keventd
asserts `class/<subsystem>/<sysname>` on every `add` event so services
can still wait for them:
service blink-blue {
description = "LED driver"
runlevel = "2345"
conditions = { "class/leds/blue" }
command = "/usr/sbin/blink-blue"
}
The condition is cleared on `remove`.
### Driver Conditions (`driver/`)
`driver/<name>` is asserted while the driver `<name>` is bound to at
least one device, from the kernel's `bind`/`unbind` uevents. Use this
to gate on slow-probing hardware whose readiness isn't marked by a
class device or `/dev` node, such as a switch core or complex PHY:
service dsa-probe {
description = "DSA topology probe"
runlevel = "2345"
conditions = { "driver/mt7530" }
command = "/usr/sbin/dsa-probe"
}
A driver bound to several devices keeps the condition asserted until
the last device is unbound. To wait for one specific device instance,
gate on what its probe creates instead: the `class/` condition or
`/dev` node of the child device.
### Power Supply Conditions (`sys/pwr/`)
keventd monitors the `power_supply` subsystem and provides: