systemdkit talks to org.freedesktop.systemd1 over D-Bus and returns
idiomatic {:ok, value} / {:error, %Systemd.Error{}} tuples. It does not
retry through sudo or shell out to systemctl.
Short-lived connections
Use the top-level Systemd module for one-off operations:
{:ok, units} = Systemd.list_units()
{:ok, jobs} = Systemd.list_jobs()
{:ok, unit_files} = Systemd.list_unit_files()
{:ok, state} = Systemd.unit_file_state("sshd.service")
:ok = Systemd.reload()
:ok = Systemd.start_unit("my_app@4000.service")
:ok = Systemd.reload_or_restart_unit("my_app@4000.service")
:ok = Systemd.reset_failed_unit("my_app@4000.service")Mutating operations may fail with a policy or polkit error:
case Systemd.start_unit("my_app@4000.service") do
:ok -> :ok
{:error, error} ->
if Systemd.Error.permission?(error) do
# Ask the operator to run with suitable policy/root privileges.
{:error, :permission_denied}
else
{:error, error}
end
endReusing a connection
For multiple calls, keep a D-Bus connection open:
Systemd.with_connection([], fn conn ->
with {:ok, unit} <- Systemd.Manager.get_unit(conn, "dbus.service"),
{:ok, state} <- Systemd.UnitObject.state(conn, unit),
{:ok, jobs} <- Systemd.Manager.list_jobs(conn) do
{:ok, {state, jobs}}
end
end)Job tracking
Unit lifecycle methods return jobs through Systemd.Manager. Top-level helpers
wait for jobs by default; pass wait: false to inspect the job yourself.
Polling is available through Systemd.Job.await/3; signal-driven waiting is
available through Systemd.Job.await_signal/3 and systemd's JobRemoved signal:
{:ok, conn} = Systemd.Manager.connect()
{:ok, job} = Systemd.Manager.restart_unit(conn, "my_app@4000.service")
{:ok, :running} = Systemd.Job.state(conn, job)
:ok = Systemd.Job.await_signal(conn, job, timeout: 10_000)For lower-level signal handling, subscribe to manager signals directly:
{:ok, sub} = Systemd.Signal.subscribe_manager(conn)
{:ok, removed} = Systemd.Signal.await_job_removed(sub, job.object_path)
:ok = Systemd.Signal.unsubscribe(sub)Jobs can be cancelled through the job object when systemd still exposes it:
Systemd.Job.cancel(conn, job)User bus
Pass bus: :session for user units when a systemd user session bus is available:
Systemd.list_units(bus: :session)