keventd: serve org.finit.Device1 on /run/keventd/bus

The udev parity gaps that were blocked on IPC -- settle, trigger,
info, queue introspection, runtime rule reload -- become bus methods.
keventd serves its own socket the way Finit serves /run/finit/bus:
brokerless, libink, one socket per daemon, no forwarding between the
two.

  Settle(u) -> b      parked until the queue drains or the timeout
                      passes; true when settled
  Trigger(s, s)       replay events, action + subsystem glob
  Info(s) -> a{ss}    /run/udev/data properties for a devpath
  RulesReload() -> u  re-read rules dirs, returns rule count
  QueueEmpty (b), SeqnumProcessed (t) properties
  DeviceProcessed (ss) signal after each fully handled event

The queue state is the highest kernel seqnum keventd has handled,
baselined at startup, against /sys/kernel/uevent_seqnum.  keventd -S
now asks the running daemon first and falls back to seqnum polling.
In passive mode Trigger and RulesReload refuse.  Adds
link_call_connection() for the park bookkeeping.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-08-16 22:03:43 +02:00
1 parent 6e60b8183a
commit 292e87c0d1
10 files changed
+811 -23

No files matched your search

+7
View File
@@ -51,6 +51,13 @@ All relevant changes are documented in this file.
- New `org.finit.Cond1` interface at `/org/finit/cond`: `Get`, `Set`,
`Clear`, `List`, `Dump` for [user-defined conditions](conditions.md),
with a `ConditionChanged (ss)` signal
- keventd serves `org.finit.Device1` on its own bus at
`/run/keventd/bus`: `Settle`, `Trigger`, `Info`, `RulesReload`,
queue-state properties, and a `DeviceProcessed (ss)` signal. The
`udevadm` settle/trigger/info equivalents are thereby bus methods
and `keventd -S` asks the running daemon first. Finit also gained a
`Manager1.ConfigReloaded` signal, fired when `initctl reload`
completes, for external condition providers and monitoring
- Privileged D-Bus methods accept root and members of the
`--with-group` group; everyone else is refused. On the local bus
the caller's uid and groups come straight from the kernel
+5
View File
@@ -22,6 +22,10 @@ Bus address
| Local (always) | `unix:path=/run/finit/bus` |
| System (opportunistic) | `unix:path=/var/run/dbus/system_bus_socket` |
The bundled device manager serves its own `org.finit.Device1` the same
way on `unix:path=/run/keventd/bus`, see [keventd](keventd.md); one
socket per daemon, no forwarding between them.
The **local** bus is brokerless: clients connect straight to Finit over a
Unix-domain socket using the standard D-Bus SASL EXTERNAL handshake. No
`dbus-daemon` is required, which makes it suitable for embedded systems that
@@ -133,6 +137,7 @@ All read-only strings; observable via `Properties.Get` and
|-----------------------|----------------------------------------|------------------------|
| `ServiceStateChanged` | `sss` — identity, old state, new state | Service transitions |
| `RunlevelChanged` | `ss` — old level, new level | System runlevel change |
| `ConfigReloaded` | — | `initctl reload` completed; external condition providers re-assert |
State names emitted by `ServiceStateChanged` are stable wire strings:
`halted`, `done`, `dead`, `cleanup`, `teardown`, `stopping`, `setup`,
+55 -6
View File
@@ -40,6 +40,8 @@ kernel events and handles:
system when device nodes appear or disappear
- **Netlink rebroadcast**: rebroadcasts processed uevents to netlink
group 0x4 for [libudev-zero][] consumers (enabled by default)
- **D-Bus interface**: `org.finit.Device1` -- settle, trigger, device
info, rules reload, and queue state over its own bus socket
Device Nodes
@@ -331,12 +333,15 @@ It is the `udevadm settle` equivalent for migration scenarios:
keventd -S -t 10 && start-graphical-session
It does not talk to the running keventd (or any device manager) -- it
simply opens `/sys/kernel/uevent_seqnum` and polls until the kernel's
sequence counter has been stable for 200ms, then exits zero. After
the `-t SECONDS` timeout (default 30) it exits non-zero instead.
Because `uevent_seqnum` is maintained by the kernel itself, `-S` works
regardless of which device manager is active, or even if none is.
With D-Bus support it asks the running keventd over
[`Device1.Settle`](#d-bus-interface-orgfinitdevice1), which tracks the
event queue where the events actually flow. When no bus answers --
another device manager, or a build without D-Bus -- it falls back to
polling `/sys/kernel/uevent_seqnum` until the kernel's sequence
counter has been stable for 200ms, then exits zero. After the
`-t SECONDS` timeout (default 30) it exits non-zero instead. The
fallback works regardless of which device manager is active, or even
if none is.
Prefer the condition-based model (`<dev/X>`, `<class/...>`,
`<driver/...>`) over settle when you control the service definition --
@@ -349,6 +354,50 @@ Debug logging can also be toggled at runtime by sending `SIGUSR1`:
kill -USR1 $(pidof keventd)
D-Bus Interface (`org.finit.Device1`)
-------------------------------------
With D-Bus support (default, `--disable-dbus` opts out) keventd serves
`org.finit.Device1` at `/org/finit/device` on its own brokerless bus,
`unix:path=/run/keventd/bus`, the same way Finit serves
[`org.finit`](dbus.md) on `/run/finit/bus`. There is no forwarding
between the two -- clients that want both connect to both.
| Method | In sig | Out sig | Priv. | Notes |
|---------------|--------|---------|-------|----------------------------------------------|
| `Settle` | `u` | `b` | no | Wait until the event queue drains, timeout in seconds; `false` on timeout |
| `Trigger` | `ss` | — | yes | Replay events: action, subsystem glob (empty = all) |
| `Info` | `s` | `a{ss}` | no | `/run/udev/data` properties for a devpath |
| `RulesReload` | — | `u` | yes | Re-read the rules directories, returns rule count |
| Property | Sig | Notes |
|-------------------|-----|-------------------------------------------|
| `QueueEmpty` | `b` | No device events in flight |
| `SeqnumProcessed` | `t` | Highest kernel seqnum keventd has handled |
| Signal | Body | Fires when |
|-------------------|-------------------------|---------------------------------|
| `DeviceProcessed` | `ss` — devpath, action | An event has been fully handled: node, symlinks, database |
Example, wait up to ten seconds for the queue to drain:
```sh
dbus-send --address=unix:path=/run/keventd/bus \
--type=method_call --print-reply --dest=org.finit \
/org/finit/device org.finit.Device1.Settle uint32:10
```
In passive mode (`-p`) `Trigger` and `RulesReload` refuse -- device
events are not handled here -- while `Settle` and the queue-state
properties remain meaningful.
keventd's conditions are symlinks to Finit's `reconf` generation
marker, so they read the current generation by construction and never
enter `flux` -- like user-defined conditions, they need no reassert
after `initctl reload`. Device state does not change because Finit
re-read its configuration.
Integration with Finit
----------------------