Conversation
|
@troglobit this is amazing! this code looks like it is pretty close to providing a full replacement for if you get to a point where you think this is good enough i'm more than happy to test it out, just let me know! |
Glad to hear you like it! 😊
It should be fairly complete, except for libudev, which some packages need. You can use libudev-zero as a stand-in though. That's how I've been testing in Infix OS. I should put something like this in the docs to help:
I'll probably do some commit housekeeping before I port it to the |
actually there is a fork which added this functionality, but it doesn't exist upstream. i hope upstream would welcome a PR implementing this. obviously this is an important step for us.
i would love to hear more about your user cases and testing! |
|
i booted into a graphical environment with do you have any suggestions for |
|
Three good points! libudev-zero: you are right, I was mislead by "a common friend" 😅 I'll fix the docs. The Gardenhouse fork that adds Zombies from missing helpers: bug. I'll make sure to refactor to handle this better, thanks for taking the time to test and report! Regarding settle: I think we have a really good abstraction with conditions in Finit, so my idea has been to to declare device requirements in the service file. For example: Good point about settle being discouraged, I had missed that and just tried to build something that wouldn't require it. Honestly, I didn't quite understand how it worked anyway. Investigating it a bit more it seems they've deprecated it because it races and slows (serializes) the boot process. Unknowingly I went my own merry way that turned out to be right. E.g., I've added
For your greetd case, One more thing about keventd's design: it folds the common udev helpers ( |
i think you have a very concrete way to solve my problem, i understood this and maybe should have elaborated... what happens if my graphics device flip flops between
very cool!
ahh! so this is a consistent design in keventd... wonderful! i had noticed it for device ownership and permission assignment, though not for these common helpers - very cool! i think i will go through the code again a bit deeper... all sorts of wonderful things exist in there 😃 thanks @troglobit! |
Yeah that sounds like you should match on a devpath or similar and create a symlink in an udev rule. We do similar things for gps devices that can be plugged into any USB port, or the other way around provide usb-to-ttl converters with a fixed device name based on the USB port they are plugged into.
Glad you like it! |
|
still running one question: did you want |
Wow, by now you've probably logged more miles than me on it 😅 Any chance you can share the libudev-zero patch? I'd love to pull it into my Infix branch.
Good question, the idea was to provide a reliable hand-over point " In Infix I lean on Finit conditions to set up "barriers". Most services depend on Separately, I've added a |
sure! i only added tag filtering from the udev database... i think if someone were to fill in more udev function stubs there is better ways to structure this code though... 😅 did you implement any other udev functions? i'll try the new version and report back - thanks! |
Thanks 👍
Nothing more than the two new condition classes I mentioned before, 5a86ff8 covers that.
Much appreciated! |
|
still running... no problems, loving it 😄 please please please merge this before |
Wow, that's high praise, thank you! 🙇♂️ Actually, 5.0 might be closer than you think ... Swedish Midsummer is just around the corner, and with that my vacation. Although a lot of time this year will go to painting and renovations (house), I will need some stimulating code sessions as well. So hang in there! 😅 |
|
i was trying to run my system by linking against the this means net devices are never found in my theory is that if |
Should be fixed now. The branch is rebased on the new master with new .conf syntax.
Interesting! 🤔💡 |
|
i found what i think are a few more inconsistencies between what is your plan for merging this branch? considering that nothing currently uses does that seem reasonable? |
That would be great, thank you!
Yeah it does. However, I'll rebase this branch on |
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Evolve keventd from a power_supply-only monitor into a full device
manager capable of replacing mdev/mdevd on embedded systems. This
is the first step towards Finit v5.0 where keventd absorbs devmon.
New capabilities:
- Parse all uevent actions (add, remove, change, bind, unbind)
- Create and remove /dev nodes with subsystem-aware permissions
- Create persistent symlinks in /dev/disk/by-{id,path} and
/dev/input/by-{id,path}, tracked for cleanup on device removal
- Load firmware from /lib/firmware/ via the sysfs loading protocol
- Spawn modprobe for MODALIAS events (async, non-blocking)
- Coldplug support via -c flag (walks /sys/devices to replay events)
- Set dev/* conditions for Finit's service dependency system
The original power_supply monitoring and sys/pwr/ac condition are
preserved.
New files: keventd.h (structures/API), uevent.c (all device logic).
The receive buffer is increased to 8K with a 1MB socket buffer to
reduce event loss during coldplug bursts.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Rewrite doc/keventd.md from a 14-line stub into comprehensive documentation covering all features of the new unified keventd: device node creation, persistent symlinks, firmware loading, module loading, coldplug, conditions, and command-line usage. Update doc/conditions.md to list keventd as the primary provider of dev/* and sys/pwr/* conditions, with devmon as fallback when an external device manager is used instead. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
After keventd processes a uevent (creating device nodes, loading modules, etc.), rebroadcast the original event to netlink group 0x4 so that libudev-zero consumers -- graphical applications, Wayland/X11 compositors, libinput, and anything else using libudev to monitor device hotplug -- can receive device events. Rebroadcast is enabled by default. Use -g to override the target netlink group mask, or -G to disable rebroadcast entirely. Bit 0 (kernel group) is always masked out to prevent feedback loops. Ref: #451 (comment) See: https://github.com/illiliti/libudev-zero Suggested-by: Aaron Andersen <aaron@fosslib.net> Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
When started with -c (the default when keventd is the device manager), gate the pidfile on the kernel's uevent_seqnum having been stable for 200ms. Up to now ready signaling with the pidfile was done right after coldplug() triggered the kernel to re-emit events, but before uev_run() had drained any of them, so <pid/keventd> really only meant "listening on netlink". With the gate, services that depend on <pid/keventd> can now assume /dev is populated and persistent symlinks are live. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
keventd links libblkid, which finit itself does not, but sysroot.mk
only copied the libraries finit links. Inside the sysroot keventd
then fails to start:
Service keventd[18] died (exit status: 127)
Collect libraries from finit and everything installed under
libexec/finit/ instead.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
A service with a <class/net/eth0>, or any other keventd-provided, condition is never started when the device appears. keventd asserts the condition file, but devmon only watches /dev, so no cond_update() ever reaches affected services. Reload made it worse: devmon_reconf() clears any registered dev/ condition without a /dev node behind it. Watch the dev/, class/, and driver/ condition directories, like the sys and usr plugins do for their namespaces, and treat an existing condition file as device presence in devmon_reconf(). Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The unified keventd has no automated coverage, only the devmon fallback is exercised by the test suite. Network interfaces are the one device class an unprivileged test can hotplug: the sandbox has its own network namespace, so 'ip link add' makes the kernel emit genuine uevents. Verify keventd readiness, <class/net/IFNAME> driving a service -- and <dev/IFNAME> NOT asserted, interfaces are not device nodes -- libudev-compatible n<ifindex> keying in /run/udev/data, conditions surviving initctl reload, and cleanup on interface remove. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Once it gives up it forks the post:script and reports that PID as the service's, so a slay still waiting for the service to come back killed the script instead, and crashing.sh lost the /tmp/post it checks for. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The legacy INIT_CMD_SUSPEND is refused in runlevel S, 0, and 6, the bus method suspended unconditionally, even mid-shutdown. Add the same guard, replying WrongRunlevel like the reboot family. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The bus method called sm_runlevel() unconditionally. In runlevel 0 and 6 that aborts an in-flight shutdown, which INIT_CMD_RUNLVL refuses with a warning, and during bootstrap it switches immediately where the legacy path defers via cfglevel to the end of runlevel S. Port both. A bad runlevel argument still returns InvalidArgs, where the legacy protocol acks silently: a typed interface rejects garbage. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Manager1.Signal silently skipped stopped services, so the same command gave different exit codes depending on transport: the legacy INIT_CMD_SIGNAL path fails when the service is not running. Mirror the legacy behavior. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Service1 Start/Stop/Restart discarded the action return value, their Manager1 twins map it to org.finit.Error.Failed. Cond1 Set/Clear replied success even when the condition symlink operation failed, where legacy initctl exits 73. Verify the resulting condition state with cond_get() rather than the noupdate return values, which report no-change, not failure, and would reject an idempotent re-set. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
initctl -t N reboot arms an emergency bypass timer over the legacy socket, but the bus methods took no argument, so the timeout was silently dropped whenever D-Bus was up. Reboot, Halt, and Poweroff now take a timeout in seconds, 0 for none, armed via the same shutdown_bypass() the legacy path uses. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Regression tests for the recent handler fixes: bogus SetRunlevel is InvalidArgs, Signal on a stopped service is Failed, and the reboot family declares the timeout argument. Reboot cannot be invoked without taking down the sandbox, so the latter is asserted via introspection. New call-u and call-su modes in dbus-auth-client. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The D-Bus methods carried byte-for-byte copies of api.c's static start/stop/restart helpers. Promote them to service.c alongside service_reload(), which already serves both callers, and reduce both sides to svc_parse_jobstr-style adapters. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
All three org.finit signals were invisible to generated proxies, and org.freedesktop.DBus was missing from the standard interfaces even though Hello, AddMatch, and RemoveMatch are answered. Add a link_signal_t table to the vtable, emitted like methods and properties, declare the Manager1 and Cond1 signals, and complete the static XML with PropertiesChanged and org.freedesktop.DBus. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The path encoding in libink/path.c was untested for identities with separators; dbus-service.sh only used the bare keventd identity. Declare a dhcp-client:eth1 service and verify the escaped path, that the object introspects, and that Identity round-trips. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
initctl_CPPFLAGS is only assigned under the DBUS conditional, but an
automake per-target variable exists even when its conditional is
false, so a --disable-dbus build dropped AM_CPPFLAGS entirely:
util.c:319:16: error: invalid use of undefined type 'struct FTW'
Assign the base flags unconditionally and append under DBUS.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The D-Bus support is default-enabled, so the HAVE_DBUS paths only bit-rot silently without this: the leg caught initctl failing to build with --disable-dbus on its first local run. Also asserts the binaries carry no bus references and smoke-runs one non-dbus test. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
dbus.md was orphaned: not in dist_docs_DATA, not linked from the user guide. Wire it into the doc dist and link it from the index features list, features.md, initctl.md, and plugins.md, where the dbus.so plugin entry now disambiguates the external system bus from the built-in org.finit API. Document the 64-peer cap, the supported AddMatch keys, the busconfig policy file, the legacy-parity edge semantics with the deliberate SetRunlevel InvalidArgs divergence, the reload-signal behavior of Service1.Reload, and the reboot family timeout. Refresh the stale initctl.md usage paste, add monitor and the D-Bus transport to initctl(8), add /run/finit/bus to the filesystem layout, and flatten the ChangeLog D-Bus entry to house style. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Device seqnums are 64-bit; the writer and reader stopped at u32.
Adds t/x/d to the skip path so a{sv} consumers tolerate them.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
The park machinery was welded to broker uid resolution; a handler that cannot answer yet, like a device-settle call waiting for the event queue to drain, had no way to defer. link_call_park() holds the request, link_call_resume() re-runs the handler with link_call_resumed() reading true, and the expire sweep remains the backstop for a resume that never comes. Resume also no longer drops a local caller's kernel group set in the privileged re-check: group source now keys on broker-ness. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
coldplug_trigger(action, subsystem-glob) replays events for a subset
of devices, the D-Bus Trigger method needs both knobs; coldplug() is
now the ("add", NULL) case. nftw() has no user cookie, so the
parameters ride in file statics.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
udevdb_read_parent() contained the general capability, keyed from sysfs when no uevent is in hand. Split it out as udevdb_read_devpath() for the D-Bus Info method; parent lookup becomes a wrapper. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
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>
Introspection, queue-state properties, immediate and bus-first settle, Info by devpath, Trigger(add, net) observed via the DeviceProcessed signal, and RulesReload -- driven by dummy interface hotplug like keventd.sh. New call-ss and call-u client modes, and getprop learns the b and t variants. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
initctl reload freezes conditions to the old generation and each owner re-asserts. Finit's own providers do this in-process; an external provider whose conditions are generation files, rather than the oneshot symlinks keventd uses, has no way to know the moment. Emit Manager1.ConfigReloaded when reconfiguration completes. keventd needs no subscriber: its conditions are symlinks to the reconf marker itself, so they read the current generation by construction and never flux, which the device bus test now pins down. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Three copies of read-first-line-from-a-file (sysfs_read_file, a static sysfs_read, fgetline), two condition emitters symlinking the same reconf marker (cond_emit, sys_cond), two seqnum-stable loops, and five hand-rolled logit() prototypes, none with a printf attribute, so no format string was ever checked. Keep one of each: cond_emit() is exported and mkpaths its parents, which also retires init_dev_condition_dir() and the sys/ directory priming loop; logit() moves to keventd.h with the format attribute; the stability test becomes seqnum_stable(), shared by the coldplug gate and settle; kev_now_ms() serves dbus.c too. rule_ctx_free() and kev_seq_baseline() had one caller each in their own files, now static. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
Half the daemon was missing: -p, -r, -S, -t from SYNOPSIS and OPTIONS, class/ and driver/ conditions, SIGHUP rules reload, the rules engine and its directories, /run/udev/data, and the D-Bus socket in FILES. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
Remaining work before merge:
¹) meaning a real monster |

The changes to Finit's
keventdon this branch, in conjunction with libudev-zero, should prove to be a good-enough replacement for many systems.We might adopt libudev-zero to the project in case that's needed, but hopefully we can bring it some new fresh blood instead 🧛
Important
This branch is still an active work in progress, and it may even be dropped and its feature set be moved to the
nextbranch, which is the canonical branch for all Finit 5 work.