Systemd Client Library
libsdexec (src/common/libsdexec/) is a C library that abstracts the D-Bus
interface to systemd. It translates libsubprocess-style command objects into
StartTransientUnit D-Bus calls, manages I/O channels, and tracks unit
state.
Unit States
Unit state is tracked with two enums that map to the ActiveState
and SubState D-Bus properties on org.freedesktop.systemd1.Unit.
-
enum sdexec_state_t
-
enumerator STATE_UNKNOWN
State string was not recognized.
-
enumerator STATE_INACTIVE
Unit is stopped (ActiveState = "inactive").
-
enumerator STATE_ACTIVATING
Unit is starting (ActiveState = "activating").
-
enumerator STATE_ACTIVE
Unit is running (ActiveState = "active").
-
enumerator STATE_DEACTIVATING
Unit is stopping (ActiveState = "deactivating").
-
enumerator STATE_FAILED
Unit failed to start or was killed (ActiveState = "failed").
-
enumerator STATE_UNKNOWN
-
enum sdexec_substate_t
-
enumerator SUBSTATE_UNKNOWN
Substate string was not recognized.
-
enumerator SUBSTATE_DEAD
No processes running.
-
enumerator SUBSTATE_START
Start sequence in progress.
-
enumerator SUBSTATE_RUNNING
Main process is running.
-
enumerator SUBSTATE_EXITED
Main process has exited; unit cleanup may be pending.
-
enumerator SUBSTATE_FAILED
Unit stopped due to an error.
-
enumerator SUBSTATE_UNKNOWN
-
const char *sdexec_statetostr(sdexec_state_t state)
-
const char *sdexec_substatetostr(sdexec_substate_t substate)
-
sdexec_state_t sdexec_strtostate(const char *s)
-
sdexec_substate_t sdexec_strtosubstate(const char *s)
Convert between
sdexec_state_t/sdexec_substate_tand their string representations. Conversion from an unknown string returns the_UNKNOWNenumerator.
Unit Object
A struct unit accumulates D-Bus property updates for a single transient
unit and exposes typed accessors. It is the primary object passed between
the property and lifecycle layers.
-
struct unit *sdexec_unit_create(const char *name)
Allocate a unit object for the unit named name. Returns NULL on allocation failure.
-
bool sdexec_unit_update(struct unit *unit, json_t *property_dict)
Apply a property dictionary (from
sdexec_property_changed_dict()orsdexec_property_get_all_dict()) to unit. Returns true if any tracked field changed, false if the update was a no-op.
-
bool sdexec_unit_update_frominfo(struct unit *unit, struct unit_info *info)
Like
sdexec_unit_update()but applies data from aunit_inforeturned bysdexec_list_units_next().
-
void *sdexec_unit_aux_get(struct unit *unit, const char *name)
-
int sdexec_unit_aux_set(struct unit *unit, const char *name, void *aux, flux_free_f destroy)
Attach or retrieve arbitrary caller data keyed by name.
sdexec_unit_aux_set()returns 0 on success, -1 on error.
-
sdexec_state_t sdexec_unit_state(struct unit *unit)
-
sdexec_substate_t sdexec_unit_substate(struct unit *unit)
-
pid_t sdexec_unit_pid(struct unit *unit)
-
const char *sdexec_unit_path(struct unit *unit)
-
const char *sdexec_unit_name(struct unit *unit)
Accessors for current state, substate, main PID, D-Bus object path, and unit name.
-
int sdexec_unit_wait_status(struct unit *unit)
Returns the wait(2) status of the main process if
sdexec_unit_has_finished()returns true, otherwise -1.
-
int sdexec_unit_systemd_error(struct unit *unit)
Returns the systemd error code if
sdexec_unit_has_failed()returns true, otherwise -1.
-
bool sdexec_unit_has_started(struct unit *unit)
-
bool sdexec_unit_has_finished(struct unit *unit)
-
bool sdexec_unit_has_failed(struct unit *unit)
Lifecycle predicates.
has_startedbecomes true when the unit reaches ACTIVE/RUNNING andExecMainPIDis set.has_finishedbecomes true whenExecMainCodeis available.has_failedbecomes true when the unit reaches FAILED state.
Starting Units
-
flux_future_t *sdexec_start_transient_unit(flux_t *h, uint32_t rank, const char *mode, json_t *cmd, int stdin_fd, int stdout_fd, int stderr_fd, flux_error_t *error)
Send a
StartTransientUnitD-Bus call viasdbus.callon rank. cmd is a libsubprocess command object; the unit name must be set as theSDEXEC_NAMEcommand option (with.servicesuffix).stdin_fd, stdout_fd, and stderr_fd are file descriptors to pass to the new unit as its stdio streams. Pass -1 to have systemd manage a stream itself. The caller may close its copies after the future is first fulfilled.
Command options with the
SDEXEC_PROP_prefix are translated to service unit properties. The following are given special treatment; all others are passed as strings:Option (after SDEXEC_PROP_)
D-Bus type
Value format
MemoryHigh, MemoryMax, MemoryLow, MemoryMin
t (uint64)
"infinity", "98%", or quantity with K/M/G/T suffix
AllowedCPUs, AllowedMemoryNodes
ay (byte array)
Flux idset notation, e.g. "0,2-4,7"
DeviceAllow
a(ss)
Comma-separated "specifier perms" pairs, e.g. "/dev/nvidiactl rw,/dev/nvidia0 rw"
DevicePolicy
s (string)
"auto", "closed", or "strict"
See systemd.resource-control(5) for property semantics.
Note
DeviceAllowandDevicePolicyare accepted byStartTransientUnitbut are not enforced in the Flux user systemd instance. Systemd implements device containment via eBPFBPF_CGROUP_DEVICEprograms, which requireCAP_BPForCAP_SYS_ADMIN— capabilities the unprivileged Flux user instance does not hold and that cannot be delegated via cgroup ownership. Per-job device containment will be implemented through the IMP until systemd makes device restriction delegatable without elevated privileges.Returns a
flux_future_t. On error, returns NULL with error set if non-NULL.
-
int sdexec_start_transient_unit_get(flux_future_t *f, const char **job)
Extract the job object path from a fulfilled
sdexec_start_transient_unit()future. The path is valid for the lifetime of f. Returns 0 on success, -1 witherrnoset on error.
Stopping Units
-
flux_future_t *sdexec_stop_unit(flux_t *h, uint32_t rank, const char *name, const char *mode)
Send a
StopUnitD-Bus call for the unit name on rank. mode is typically"fail"; see the systemd D-Bus API for other values. Returns aflux_future_t.
-
flux_future_t *sdexec_reset_failed_unit(flux_t *h, uint32_t rank, const char *name)
Send a
ResetFailedUnitD-Bus call to clear the failed state of unit name on rank.
-
flux_future_t *sdexec_kill_unit(flux_t *h, uint32_t rank, const char *name, const char *who, int signum)
Send a
KillUnitD-Bus call to deliver signum to the processes in unit name on rank. who selects the target:"main"for the main process,"control"for the control process, or"all"for both.
Properties
-
flux_future_t *sdexec_property_get(flux_t *h, const char *service, uint32_t rank, const char *path, const char *name)
Issue a
Getcall on the D-Bus Properties interface at object path path via service (typically"sdbus"). Usesdexec_property_get_unpack()to extract the result.
-
int sdexec_property_get_unpack(flux_future_t *f, const char *fmt, ...)
Unpack the variant value from a fulfilled
sdexec_property_get()future. fmt is a Jansson-style unpack format string applied to the unwrapped value. Returns 0 on success, -1 on error.
-
flux_future_t *sdexec_property_get_all(flux_t *h, const char *service, uint32_t rank, const char *path)
Issue a
GetAllcall on the D-Bus Properties interface at path. Usesdexec_property_get_all_dict()to access the result.
-
json_t *sdexec_property_get_all_dict(flux_future_t *f)
Return the property dictionary from a fulfilled
sdexec_property_get_all()future. The dict is valid for the lifetime of f and can be queried withsdexec_property_dict_unpack()or passed tosdexec_unit_update().
-
flux_future_t *sdexec_property_changed(flux_t *h, const char *service, uint32_t rank, const char *path)
Subscribe to
PropertiesChangedsignals for the unit at path. Each fulfillment of the returned streaming future represents one signal. Pass path = NULL to receive signals for all paths and usesdexec_property_changed_path()to filter.
-
json_t *sdexec_property_changed_dict(flux_future_t *f)
-
const char *sdexec_property_changed_path(flux_future_t *f)
Extract the property dictionary or object path from the current fulfillment of a
sdexec_property_changed()future. Both are valid for the lifetime of the current fulfillment. The dict can be passed directly tosdexec_unit_update().
-
int sdexec_property_dict_unpack(json_t *dict, const char *name, const char *fmt, ...)
Look up property name in a property dictionary and unpack its variant value using the Jansson format string fmt. Returns 0 on success, -1 if the property is absent or the type does not match.
I/O Channels
-
CHANNEL_LINEBUF
Flag for
sdexec_channel_create_output(): buffer output and deliver it line-by-line rather than in arbitrary chunks.
-
typedef void (*channel_output_f)(struct channel *ch, json_t *io, void *arg)
Output callback type. io is an ioencode-formatted JSON object containing the stream name, broker rank, and data (or EOF flag).
-
typedef void (*channel_error_f)(struct channel *ch, flux_error_t *error, void *arg)
Error callback type. Called on a read error before the output callback delivers EOF.
-
struct channel *sdexec_channel_create_output(flux_t *h, const char *name, size_t bufsize, int flags, channel_output_f output_cb, channel_error_f error_cb, void *arg)
Create a channel for output from the systemd unit (stdout or stderr). The internal fd watcher is not started until
sdexec_channel_start_output()is called. SetCHANNEL_LINEBUFin flags to enable line buffering.
-
struct channel *sdexec_channel_create_input(flux_t *h, const char *name)
Create a channel for input to the systemd unit (stdin). Write to it using
sdexec_channel_write().
-
int sdexec_channel_write(struct channel *ch, json_t *io)
Write ioencode-formatted data to an input channel. The rank and stream name fields of io are ignored. This may block if the socket buffer is full. Returns 0 on success, -1 on error.
-
int sdexec_channel_get_fd(struct channel *ch)
-
const char *sdexec_channel_get_name(struct channel *ch)
Return the file descriptor for the systemd end of the socketpair, or the channel name.
sdexec_channel_get_fd()returns -1 if the fd has been closed or ch is NULL.
-
void sdexec_channel_close_fd(struct channel *ch)
Close the systemd-side fd. Call this after systemd has duped it — the response handler for
StartTransientUnitis the right place.
-
void sdexec_channel_start_output(struct channel *ch)
Arm the reactor watcher for an output channel. Data arriving after this call triggers output_cb.
-
void sdexec_channel_destroy(struct channel *ch)
Destroy ch and free all associated resources.
Unit List
-
struct unit_info
Snapshot of a unit entry returned by
ListUnitsByPatterns.-
const char *name
Unit name (e.g.
flux-job-123-abc.service).
-
const char *description
Unit description string.
-
const char *load_state
Load state ("loaded", "not-found", etc.).
-
const char *active_state
Active state string; see
sdexec_state_t.
-
const char *sub_state
Sub-state string; see
sdexec_substate_t.
-
const char *path
D-Bus object path for the unit.
-
json_int_t job_id
ID of a queued systemd job for this unit, or 0 if none.
-
const char *job_type
Type string of the queued job ("start", "stop", etc.).
-
const char *job_path
D-Bus object path of the queued job.
-
const char *name
-
flux_future_t *sdexec_list_units(flux_t *h, const char *service, uint32_t rank, const char *pattern)
Issue a
ListUnitsByPatternsD-Bus call via service on rank. pattern is a glob matched against unit names; pass"*"for all units. Iterate results withsdexec_list_units_next().
-
bool sdexec_list_units_next(flux_future_t *f, struct unit_info *info)
Fill info with the next unit entry from a fulfilled
sdexec_list_units()future. Returns true on success, false when the list is exhausted. Pointers in info are valid until the next call or until f is destroyed.
Object Paths
systemd maps unit names to D-Bus object paths by appending an encoded form of
the unit name to /org/freedesktop/systemd1/unit/. Any character that is
not alphanumeric or underscore is replaced with _XX where XX is the
lowercase hex byte value. libsdexec handles this via sd_bus_path_encode(3) and
sd_bus_path_decode(3) in objpath.c.
Note
This encoding is a systemd convention, not a D-Bus standard. Its presence in sdbus's object-path type handler means sdbus has inadvertently absorbed systemd-specific knowledge that ideally would live only here.
Unit name |
D-Bus object path |
|---|---|
dbus.service |
/org/freedesktop/systemd1/unit/dbus_2eservice |
flux-broker.service |
/org/freedesktop/systemd1/unit/flux_2dbroker_2eservice |
flux-job-f23abc.service |
/org/freedesktop/systemd1/unit/flux_2djob_2df23abc_2eservice |
user@1000.service |
/org/freedesktop/systemd1/unit/user_401000_2eservice |
D-Bus Interface Reference
The following D-Bus interfaces and members are used by the systemd integration. See the org.freedesktop.systemd1 man page for the full interface specification.
org.freedesktop.systemd1.Manager
Method |
In |
Out |
Notes |
|---|---|---|---|
StartTransientUnit |
ssa(sv)a(sa(sv)) |
o |
Launches a transient unit; returns the job object path |
StopUnit |
ss |
o |
Stops a unit; mode is typically "fail" |
KillUnit |
ssi |
Sends a signal to unit processes; who is "main", "control", or "all" |
|
ResetFailedUnit |
s |
Clears a failed unit so it can be restarted |
|
ListUnitsByPatterns |
asas |
a(ssssssouso) |
Lists units matching state/name patterns (used in tests) |
org.freedesktop.systemd1.Service
Properties polled via GetAll or received via PropertiesChanged:
Property |
D-Bus type |
Notes |
|---|---|---|
ExecMainPID |
u |
Main process PID; available once unit is active |
ExecMainCode |
i |
Exit code (CLD_* constant) |
ExecMainStatus |
i |
Raw wait status |
ActiveState |
s |
One of: inactive, activating, active, deactivating, failed |
SubState |
s |
One of: dead, start, running, exited, failed |
Result |
s |
One of: done, exited, killed, timeout, etc. |
org.freedesktop.DBus.Properties
Method / Signal |
In |
Out |
Notes |
|---|---|---|---|
Get |
ss |
v |
Fetch a single property by interface and name |
GetAll |
s |
a{sv} |
Fetch all properties as a string→variant dictionary |
PropertiesChanged (signal) |
Emitted on property changes; sdexec subscribes per-unit |
org.freedesktop.DBus
Method |
Notes |
|---|---|
Subscribe |
Request signal delivery to this connection |
AddMatch |
Add a match rule to filter incoming signals |