mirror of
https://github.com/troglobit/finit.git
synced 2026-10-26 12:14:37 +00:00
libink: a message bus is not a peer
libink was written against the only bus it had, its own, where the peer on the other end is the client. A broker is not: it routes for senders it names itself, expects a DESTINATION on anything addressed through it, and answers on its own schedule rather than next. Runlevels go on the wire as S and N rather than the digits Finit keeps internally, since that is what a caller outside Finit means by one. The library stays a convenience library, linked into finit and initctl and installed nowhere: the ABI promise waits until libink is its own project. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
6310d9e760
commit
b55dada80b
16 files changed
+340
-250
No files matched your search
+8
-1
@@ -50,9 +50,16 @@ Below are a few of the main switches to configure:
|
||||
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
||||
init for container apps that can see the host's `/proc` filesystem
|
||||
|
||||
* `--disable-dbus`: Opt out of Finit's built-in D-Bus support, enabled by
|
||||
default. See [D-Bus Integration](dbus.md) for what it provides. Not to
|
||||
be confused with `--enable-dbus-plugin` below, which only starts an
|
||||
external `dbus-daemon`
|
||||
|
||||
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
||||
|
||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin.
|
||||
* `--enable-dbus-plugin`: Enable the optional D-Bus `dbus.so` plugin, which
|
||||
launches `dbus-daemon` at boot. Unrelated to the built-in bus, see
|
||||
`--disable-dbus` above.
|
||||
|
||||
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional plugin.
|
||||
|
||||
|
||||
+152
-166
@@ -1,45 +1,45 @@
|
||||
D-Bus Integration
|
||||
=================
|
||||
|
||||
Finit ships with a built-in, brokerless [D-Bus][] implementation,
|
||||
**libink**, that exposes the running init system as a peer on its own
|
||||
private bus, and optionally on the system bus when `dbus-daemon` is
|
||||
available. Everything `initctl` does is also reachable from any
|
||||
generic D-Bus tooling — `dbus-send`, `dbus-monitor`, `gdbus`,
|
||||
language bindings, dashboards, monitoring agents, etc.
|
||||
Finit ships with a built-in, brokerless [D-Bus][] implementation, **libink**
|
||||
(`-link`), that exposes the running init system as a peer on its own private
|
||||
bus, and optionally on the system bus when `dbus-daemon` is available.
|
||||
Everything `initctl` does is also reachable from any generic D-Bus tooling —
|
||||
`dbus-send`, `dbus-monitor`, `gdbus`, language bindings, dashboards,
|
||||
monitoring agents, etc.
|
||||
|
||||
> [!NOTE]
|
||||
> D-Bus support is enabled at build time with `--enable-dbus`. See
|
||||
> [Building](build.md) for details. When disabled, `initctl` keeps
|
||||
> using the legacy `INIT_SOCKET` transport and Finit exposes no bus.
|
||||
> D-Bus support is enabled by default, opt out at build time with
|
||||
> `--disable-dbus`, see [Building](build.md) for details. When disabled,
|
||||
> `initctl` keeps using the legacy `INIT_SOCKET` transport and Finit
|
||||
> exposes no bus.
|
||||
|
||||
Bus address
|
||||
-----------
|
||||
|
||||
| Bus | Address |
|
||||
| --- | --- |
|
||||
| Local (always) | `unix:path=/run/finit/bus` |
|
||||
| System (opportunistic) | `unix:path=/var/run/dbus/system_bus_socket`, well-known name `org.finit` |
|
||||
| Bus | Address |
|
||||
|------------------------|---------------------------------------------|
|
||||
| Local (always) | `unix:path=/run/finit/bus` |
|
||||
| System (opportunistic) | `unix:path=/var/run/dbus/system_bus_socket` |
|
||||
|
||||
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 don't ship one.
|
||||
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
|
||||
don't ship one.
|
||||
|
||||
The **system** bus is best-effort: at start-up Finit probes for a
|
||||
running `dbus-daemon` and, if reachable, registers `org.finit` so that
|
||||
standard tooling sees Finit just like any other system service:
|
||||
The **system** bus is best-effort: Finit probes for a running `dbus-daemon`
|
||||
and, when reachable, claims the well-known name `org.finit` so that standard
|
||||
tooling sees Finit just like any other system service:
|
||||
|
||||
```sh
|
||||
dbus-send --system --print-reply --dest=org.finit \
|
||||
/org/finit/manager \
|
||||
dbus-send --system --print-reply --dest=org.finit /org/finit/manager \
|
||||
org.finit.Manager1.ListServices
|
||||
|
||||
dbus-monitor --system "sender='org.finit'"
|
||||
```
|
||||
|
||||
If no system bus is present (the common case on embedded targets),
|
||||
this step is silently skipped.
|
||||
If no system bus is present (the common case on embedded targets), this step
|
||||
is silently skipped.
|
||||
|
||||
Object tree
|
||||
-----------
|
||||
@@ -59,12 +59,15 @@ Object tree
|
||||
|
||||
Every node implements the usual stock interfaces:
|
||||
|
||||
| Interface | Purpose |
|
||||
| ------------------------------------ | ------- |
|
||||
| `org.freedesktop.DBus` | `Hello`, `AddMatch`, `RemoveMatch` (on `/org/freedesktop/DBus`) |
|
||||
| `org.freedesktop.DBus.Peer` | `Ping`, `GetMachineId` |
|
||||
| `org.freedesktop.DBus.Introspectable`| `Introspect()` — XML description |
|
||||
| `org.freedesktop.DBus.Properties` | `Get`, `GetAll` (Set not yet implemented) |
|
||||
| Interface | Purpose |
|
||||
|---------------------------------------|-------------------------------------------|
|
||||
| `org.freedesktop.DBus` | `Hello`, `AddMatch`, `RemoveMatch` |
|
||||
| `org.freedesktop.DBus.Peer` | `Ping`, `GetMachineId` |
|
||||
| `org.freedesktop.DBus.Introspectable` | `Introspect()` — XML description |
|
||||
| `org.freedesktop.DBus.Properties` | `Get`, `GetAll` (Set not yet implemented) |
|
||||
|
||||
Note: `Hello`, `AddMatch`, and `RemoveMatch` are answered on the canonical
|
||||
`/org/freedesktop/DBus` object only, as per the D-Bus specification.
|
||||
|
||||
`org.finit.Manager1`
|
||||
--------------------
|
||||
@@ -74,88 +77,89 @@ and the service registry.
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | In sig | Out sig | Privileged | Notes |
|
||||
| ----------------------- | ------ | ------- | ---------- | ----- |
|
||||
| `ListServices` | — | `as` | no | Returns the identities (`name`, `name:id`) of every loaded service. |
|
||||
| `GetService` | `s` | `o` | no | Resolves a service identity to its `Service1` object path. |
|
||||
| `Start` | `s` | — | yes | Start the service(s) matching the identity. |
|
||||
| `Stop` | `s` | — | yes | Stop the service(s) matching the identity. |
|
||||
| `Restart` | `s` | — | yes | Restart (stop + start) the service(s). |
|
||||
| `Reload` | — | — | yes | Re-read all `*.conf` and apply changes (same as `initctl reload`). |
|
||||
| `SetRunlevel` | `u` | — | yes | Transition to runlevel `u` (0–6). |
|
||||
| `SetDebug` | — | — | yes | Toggle Finit's runtime debug flag. |
|
||||
| `Signal` | `su` | — | yes | Send signal number `u` (1–31) to every running service matching identity `s`. Halted matches are silently skipped. |
|
||||
| `Suspend` | — | — | yes | `sync()` + suspend-to-RAM. |
|
||||
| `Reboot` / `Halt` / `Poweroff` | — | — | yes | Trigger the corresponding shutdown sequence. |
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|------------------------------|--------|---------|-------|-----------------------------------------------------------|
|
||||
| `ListServices` | — | `as` | no | Returns identities (`name`, `name:id`) of loaded services |
|
||||
| `GetService` | `s` | `o` | no | Resolves an identity to its `Service1` object path |
|
||||
| `Start` | `s` | — | yes | Start the service(s) matching the identity |
|
||||
| `Stop` | `s` | — | yes | Stop the service(s) matching the identity |
|
||||
| `Restart` | `s` | — | yes | Restart (stop + start) the service(s) |
|
||||
| `Reload` | — | — | yes | Re-read all `*.conf` and apply changes |
|
||||
| `SetRunlevel` | `u` | — | yes | Transition to runlevel `u` (0–6) |
|
||||
| `SetDebug` | — | — | yes | Toggle Finit's runtime debug flag |
|
||||
| `Signal` | `su` | — | yes | Send signal `u` (1–31) to services matching identity `s` |
|
||||
| `Suspend` | — | — | yes | `sync()` + suspend-to-RAM |
|
||||
| `Reboot`, `Halt`, `Poweroff` | — | — | yes | Trigger the corresponding shutdown sequence |
|
||||
|
||||
### Properties
|
||||
|
||||
All read-only strings; observable via `Properties.Get` and
|
||||
`Properties.GetAll`.
|
||||
|
||||
| Property | Type | Returns |
|
||||
| -------------- | ---- | ------- |
|
||||
| `Runlevel` | `s` | Current runlevel as a digit (`"2"`, `"3"`, …) or `"S"`. |
|
||||
| `PrevRunlevel` | `s` | Previous runlevel, same encoding. |
|
||||
| `Version` | `s` | Finit's version string (`PACKAGE_VERSION`). |
|
||||
| Property | Type | Returns |
|
||||
|----------------|------|--------------------------------------------------------|
|
||||
| `Runlevel` | `s` | Current runlevel as a digit (`"2"`, `"3"`, …) or `"S"` |
|
||||
| `PrevRunlevel` | `s` | Previous runlevel, same encoding, `"N"` when none |
|
||||
| `Version` | `s` | Finit's version string (`PACKAGE_VERSION`) |
|
||||
|
||||
### Signals
|
||||
|
||||
| Signal | Body | Fires when |
|
||||
| ----------------------- | ---- | ---------- |
|
||||
| `ServiceStateChanged` | `(sss)` — identity, old state, new state | A service transitions between supervisor states. |
|
||||
| `RunlevelChanged` | `(ss)` — old level, new level | The system enters a new runlevel. |
|
||||
| Signal | Body | Fires when |
|
||||
|-----------------------|----------------------------------------|------------------------|
|
||||
| `ServiceStateChanged` | `sss` — identity, old state, new state | Service transitions |
|
||||
| `RunlevelChanged` | `ss` — old level, new level | System runlevel change |
|
||||
|
||||
State names emitted by `ServiceStateChanged` are stable wire strings:
|
||||
`halted`, `done`, `dead`, `cleanup`, `teardown`, `stopping`, `setup`,
|
||||
`paused`, `waiting`, `starting`, `running`.
|
||||
`paused`, `waiting`, `starting`, `running`. `RunlevelChanged` levels
|
||||
use the same encoding as the `Runlevel` property: digits, `"S"`, `"N"`.
|
||||
|
||||
`org.finit.Service1` (per-service objects)
|
||||
------------------------------------------
|
||||
|
||||
Lives at **`/org/finit/service/<encoded>`**, one object per loaded
|
||||
service. `<encoded>` is the service identity (name, or `name:id` for
|
||||
templated services) put through systemd-style `_HH` hex escaping —
|
||||
ASCII alphanumerics and `_` pass through, anything else becomes `_HH`
|
||||
where `HH` is the hex byte. Use `Manager1.GetService(identity)` to
|
||||
look up the exact path rather than constructing it by hand.
|
||||
Lives at **`/org/finit/service/<encoded>`**, one object per loaded service.
|
||||
`<encoded>` is the service identity (name, or `name:id` for templated
|
||||
services) put through systemd-style `_HH` hex escaping — ASCII alphanumerics
|
||||
and `_` pass through, anything else becomes `_HH` where `HH` is the hex byte.
|
||||
Use `Manager1.GetService(identity)` to look up the exact path rather than
|
||||
constructing it by hand.
|
||||
|
||||
| Method | In sig | Out sig | Privileged | Notes |
|
||||
| --------- | ------ | ------- | ---------- | ----- |
|
||||
| `Start` | — | — | yes | Equivalent to `Manager1.Start(<identity>)` for this service. |
|
||||
| `Stop` | — | — | yes | … |
|
||||
| `Restart` | — | — | yes | … |
|
||||
| `Reload` | — | — | yes | Reload (SIGHUP if supported, else restart). |
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|-----------|--------|---------|-------|-------------------------------------------------------------|
|
||||
| `Start` | — | — | yes | Equivalent to `Manager1.Start(<identity>)` for this service |
|
||||
| `Stop` | — | — | yes | … |
|
||||
| `Restart` | — | — | yes | … |
|
||||
| `Reload` | — | — | yes | Reload (SIGHUP if supported, else restart) |
|
||||
|
||||
### Properties
|
||||
|
||||
All read-only; observable via `Properties.Get` and `Properties.GetAll`.
|
||||
|
||||
| Property | Type | Returns |
|
||||
| -------------- | ---- | ------- |
|
||||
| `Identity` | `s` | Service identity, `name` or `name:id`. |
|
||||
| `Name` | `s` | Program name (basename of the command). |
|
||||
| `State` | `s` | Current status, same vocabulary as `initctl status` (richer than the coarse `ServiceStateChanged` strings). |
|
||||
| `Pid` | `u` | Current PID, 0 when not running. |
|
||||
| `RestartCount` | `u` | Restarts since the last stable run. |
|
||||
| `Runlevels` | `u` | Allowed runlevels as a bitmask, bit N = runlevel N, bit 10 = S. |
|
||||
| `Description` | `s` | The service's `description` string. |
|
||||
| `Command` | `s` | Full command line, arguments included. |
|
||||
| `Conditions` | `s` | Declared conditions, raw `.conf` form. |
|
||||
| `Type` | `s` | Unit type: `service`, `task`, `run`, `sysv`, `tty`, `free`. |
|
||||
| `Origin` | `s` | Source `.conf` file, empty for built-ins. |
|
||||
| `Environment` | `s` | The service's `env` setting, raw. |
|
||||
| `PidFile` | `s` | Declared PID file, raw (`!` prefix included). |
|
||||
| `User` | `s` | User the service runs as. |
|
||||
| `Group` | `s` | Group the service runs as. |
|
||||
| `Uptime` | `u` | Seconds since start, 0 when not running. |
|
||||
| `ExitStatus` | `u` | Raw `waitpid(2)` status from the last exit. |
|
||||
| `RestartsTotal`| `u` | Restarts over the service's lifetime. |
|
||||
| `RestartMax` | `u` | Restart limit before the service is blocked. |
|
||||
| `Starts` | `u` | Times started, for `manual-start` units. |
|
||||
| `ManualStart` | `b` | `manual-start` set in the `.conf`. |
|
||||
| `Forking` | `b` | Daemon forks to background. |
|
||||
| `Started` | `b` | Run/task completed successfully. |
|
||||
| Property | Type | Returns |
|
||||
|-----------------|------|----------------------------------------------------------------|
|
||||
| `Identity` | `s` | Service identity, `name` or `name:id` |
|
||||
| `Name` | `s` | Program name (basename of the command) |
|
||||
| `State` | `s` | Current status, same vocabulary as `initctl status` |
|
||||
| `Pid` | `u` | Current PID, 0 when not running |
|
||||
| `RestartCount` | `u` | Restarts since the last stable run |
|
||||
| `Runlevels` | `u` | Allowed runlevels as a bitmask, bit N = runlevel N, bit 10 = S |
|
||||
| `Description` | `s` | The service's `description` string |
|
||||
| `Command` | `s` | Full command line, arguments included |
|
||||
| `Conditions` | `s` | Declared conditions, raw `.conf` form |
|
||||
| `Type` | `s` | Unit type: `service`, `task`, `run`, `sysv`, `tty`, `free` |
|
||||
| `Origin` | `s` | Source `.conf` file, empty for built-ins |
|
||||
| `Environment` | `s` | The service's `env` setting, raw |
|
||||
| `PidFile` | `s` | Declared PID file, raw (`!` prefix included) |
|
||||
| `User` | `s` | User the service runs as |
|
||||
| `Group` | `s` | Group the service runs as |
|
||||
| `Uptime` | `u` | Seconds since start, 0 when not running |
|
||||
| `ExitStatus` | `u` | Raw `waitpid(2)` status from the last exit |
|
||||
| `RestartsTotal` | `u` | Restarts over the service's lifetime |
|
||||
| `RestartMax` | `u` | Restart limit before the service is blocked |
|
||||
| `Starts` | `u` | Times started, for `manual-start` units |
|
||||
| `ManualStart` | `b` | `manual-start` set in the `.conf` |
|
||||
| `Forking` | `b` | Daemon forks to background |
|
||||
| `Started` | `b` | Run/task completed successfully |
|
||||
|
||||
On every state transition the object also emits the standard
|
||||
`org.freedesktop.DBus.Properties.PropertiesChanged` signal: `State`
|
||||
@@ -174,89 +178,87 @@ Lives at **`/org/finit/cond`**. Exposes Finit's
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | In sig | Out sig | Privileged | Notes |
|
||||
| -------- | ------ | ------- | ---------- | ----- |
|
||||
| `Get` | `s` | `s` | no | Returns `"on"`, `"off"`, or `"flux"` for the named condition. |
|
||||
| `Set` | `s` | — | yes | Assert a `usr/<name>` condition. Non-`usr/*` paths are rejected with `InvalidArgs` (system conditions belong to Finit's state machine). |
|
||||
| `Clear` | `s` | — | yes | Deassert a `usr/<name>` condition. |
|
||||
| `List` | — | `as` | no | Names of all known conditions. |
|
||||
| `Dump` | — | `a(ss)` | no | `(name, state)` pairs for everything `List` returns. |
|
||||
| Method | In sig | Out sig | Priv. | Notes |
|
||||
|---------|--------|---------|-------|--------------------------------------------------------------|
|
||||
| `Get` | `s` | `s` | no | Returns `"on"`, `"off"`, or `"flux"` for the named condition |
|
||||
| `Set` | `s` | — | yes | Assert a `usr/<name>` condition |
|
||||
| `Clear` | `s` | — | yes | Deassert a `usr/<name>` condition |
|
||||
| `List` | — | `as` | no | Names of all known conditions |
|
||||
| `Dump` | — | `a(ss)` | no | `(name, state)` pairs for everything `List` returns |
|
||||
|
||||
Note: non-`usr/*` paths are rejected with `InvalidArgs` -- system
|
||||
conditions belong to Finit's state machine.
|
||||
|
||||
### Signals
|
||||
|
||||
| Signal | Body | Fires when |
|
||||
| ------------------- | ---- | ---------- |
|
||||
| `ConditionChanged` | `(ss)` — name, new state | A condition is asserted or deasserted. |
|
||||
| Signal | Body | Fires when |
|
||||
|--------------------|------------------------|---------------------------------------|
|
||||
| `ConditionChanged` | `ss` — name, new state | A condition is asserted or deasserted |
|
||||
|
||||
Authorization
|
||||
-------------
|
||||
|
||||
Privileged methods reject any caller whose peer `uid` isn't 0.
|
||||
On the **local** bus the kernel's `SO_PEERCRED` socket option tells
|
||||
Finit exactly who's calling, so privilege escalation through the bus
|
||||
is impossible.
|
||||
Privileged methods reject any caller whose peer `uid` isn't 0. On the
|
||||
**local** bus the kernel's `SO_PEERCRED` socket option tells Finit exactly
|
||||
who's calling, so privilege escalation through the bus is impossible.
|
||||
|
||||
On the **system** bus, all incoming traffic is treated as
|
||||
unprivileged: it arrives through `dbus-daemon` (typically running as
|
||||
root) and Finit cannot yet ask the daemon for the real requester's
|
||||
uid via `GetConnectionUnixUser`. This means external tooling can
|
||||
freely `Get`/`Introspect`/`ListServices`, but every state-changing
|
||||
method returns `org.freedesktop.DBus.Error.AccessDenied`. Per-sender
|
||||
uid lookup is on the roadmap.
|
||||
On the **system** bus, all incoming traffic is treated as unprivileged: it
|
||||
arrives through `dbus-daemon` (typically running as root) and Finit cannot yet
|
||||
ask the daemon for the real requester's uid via `GetConnectionUnixUser`. This
|
||||
means external tooling can freely `Get`/`Introspect`/`ListServices`, but every
|
||||
state-changing method returns `org.freedesktop.DBus.Error.AccessDenied`.
|
||||
Per-sender uid lookup is on the roadmap.
|
||||
|
||||
When a privileged method is rejected the error name is exactly
|
||||
`org.freedesktop.DBus.Error.AccessDenied`, and the body carries a
|
||||
short reason string (e.g. `"permission denied: Start requires root"`).
|
||||
`org.freedesktop.DBus.Error.AccessDenied`, and the body carries a short reason
|
||||
string (e.g. `"permission denied: Start requires root"`).
|
||||
|
||||
`initctl` integration
|
||||
---------------------
|
||||
|
||||
`initctl` transparently routes through D-Bus when the bus socket is
|
||||
present, and falls back to the legacy `INIT_SOCKET` transport
|
||||
otherwise. Concretely, the following subcommands use the bus first:
|
||||
`initctl` transparently routes through D-Bus when the bus socket is present,
|
||||
and falls back to the legacy `INIT_SOCKET` transport otherwise. Concretely,
|
||||
the following subcommands use the bus first:
|
||||
|
||||
| Subcommand | Method |
|
||||
| ------------------- | ------------------------------- |
|
||||
| `initctl start` | `Manager1.Start(svc)` |
|
||||
| `initctl stop` | `Manager1.Stop(svc)` |
|
||||
| `initctl restart` | `Manager1.Restart(svc)` |
|
||||
| `initctl reload` | `Manager1.Reload()` |
|
||||
| `initctl reload S` | `Service1.Reload()` (per-svc) |
|
||||
| `initctl reboot` | `Manager1.Reboot()` |
|
||||
| `initctl halt` | `Manager1.Halt()` |
|
||||
| `initctl poweroff` | `Manager1.Poweroff()` |
|
||||
| `initctl suspend` | `Manager1.Suspend()` |
|
||||
| `initctl debug` | `Manager1.SetDebug()` |
|
||||
| `initctl signal` | `Manager1.Signal(svc, signo)` |
|
||||
| `initctl runlevel` | `Properties.Get(Manager1.Runlevel/PrevRunlevel)` |
|
||||
| `initctl cond set/get/clr` | `Cond1.{Set,Get,Clear}` |
|
||||
| Subcommand | Method |
|
||||
|----------------------------|--------------------------------------------------|
|
||||
| `initctl start` | `Manager1.Start(svc)` |
|
||||
| `initctl stop` | `Manager1.Stop(svc)` |
|
||||
| `initctl restart` | `Manager1.Restart(svc)` |
|
||||
| `initctl reload` | `Manager1.Reload()` |
|
||||
| `initctl reload S` | `Service1.Reload()` (per-svc) |
|
||||
| `initctl reboot` | `Manager1.Reboot()` |
|
||||
| `initctl halt` | `Manager1.Halt()` |
|
||||
| `initctl poweroff` | `Manager1.Poweroff()` |
|
||||
| `initctl suspend` | `Manager1.Suspend()` |
|
||||
| `initctl debug` | `Manager1.SetDebug()` |
|
||||
| `initctl signal` | `Manager1.Signal(svc, signo)` |
|
||||
| `initctl runlevel` | `Properties.Get(Manager1.Runlevel/PrevRunlevel)` |
|
||||
| `initctl cond set/get/clear` | `Cond1.{Set,Get,Clear}`, `clr` is an alias |
|
||||
|
||||
Two `initctl` subcommands are pure D-Bus features without legacy
|
||||
equivalents:
|
||||
Two `initctl` subcommands are pure D-Bus features without legacy equivalents:
|
||||
|
||||
* `initctl monitor` — subscribes to every signal on the local bus and
|
||||
prints one line per delivery (with timestamp, interface and
|
||||
member). Same idea as `dbus-monitor`, but scoped to Finit and with
|
||||
no need to pass `--address`.
|
||||
* `initctl monitor` — subscribes to every signal on the local bus and prints
|
||||
one line per delivery (with timestamp, interface and member). Same idea as
|
||||
`dbus-monitor`, but scoped to Finit and with no need to pass `--address`.
|
||||
|
||||
* `initctl cond` (when D-Bus is reachable) emits the standard
|
||||
`Cond1.ConditionChanged` signal as a side effect, so subscribers
|
||||
observe user-driven state changes the same way they observe
|
||||
service-driven ones.
|
||||
* `initctl cond` emits the standard `Cond1.ConditionChanged` signal as a side
|
||||
effect, so subscribers observe user-driven state changes the same way they
|
||||
observe service-driven ones.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
The examples below use `dbus-send` and `dbus-monitor`, which ship as
|
||||
part of the [dbus][] reference implementation; they're widely
|
||||
packaged and don't pull in any extra runtime. Any tool that speaks
|
||||
D-Bus over an AF_UNIX socket works equally well — `gdbus`, Python's
|
||||
`jeepney`/`dasbus`, etc. — substitute their syntax for setting the
|
||||
bus address.
|
||||
The examples below use `dbus-send` and `dbus-monitor`, which ship as part of
|
||||
the [dbus][] reference implementation; they're widely packaged and don't pull
|
||||
in any extra runtime. Any tool that speaks D-Bus over an AF_UNIX socket works
|
||||
equally well — `gdbus`, Python's `jeepney`/`dasbus`, etc. — substitute their
|
||||
syntax for setting the bus address. The wire protocol is the compatibility
|
||||
surface: Finit's own **libink** is an internal implementation detail, external
|
||||
clients should use any standard D-Bus library.
|
||||
|
||||
When `org.finit` is registered on the system bus you can replace
|
||||
`--address=unix:path=/run/finit/bus` with `--system` in any example
|
||||
below.
|
||||
`--address=unix:path=/run/finit/bus` with `--system` in any example below.
|
||||
|
||||
List the running services:
|
||||
|
||||
@@ -309,21 +311,5 @@ The `--dest=org.finit` argument is informational on the local
|
||||
brokerless bus — Finit accepts any destination because there's no
|
||||
broker to route by name — but `dbus-send` requires it syntactically.
|
||||
|
||||
[dbus]: https://gitlab.freedesktop.org/dbus/dbus
|
||||
|
||||
Implementation notes
|
||||
--------------------
|
||||
|
||||
The D-Bus server library lives in `libink/`. It speaks the binary
|
||||
D-Bus 1.0 wire format directly, has no `libdbus`/`sd-bus`/`GIO`
|
||||
dependency, and is tiny — a few thousand lines of C. The Finit-side
|
||||
glue in `src/dbus.c` registers vtables for Manager1/Service1/Cond1,
|
||||
emits the four signals from the appropriate hook points (state
|
||||
transitions, runlevel transitions, condition flips), and bridges the
|
||||
event loop to the libink server.
|
||||
|
||||
The `initctl` client uses the same library — `link_client_open`,
|
||||
`link_client_call_v`, `link_client_reply`, `link_reader_*` — so the
|
||||
single wire-format implementation serves both ends.
|
||||
|
||||
[dbus]: https://gitlab.freedesktop.org/dbus/dbus
|
||||
[D-Bus]: https://dbus.freedesktop.org/doc/dbus-specification.html
|
||||
Reference in new issue
Block a user