Run Service Actions with deb-systemd-invoke Safely

Your package script says restart, policy-rc.d says no, and the install still reports success: deb-systemd-invoke is why. It is the Debian helper that asks policy-rc.d before passing selected service actions on to systemctl. This guide gives you a safe mental model and a command template. The examples match init-system-helpers 1.66ubuntu1 as installed here.

Allow about fifteen minutes. You need a shell and a unit name from the package or deployment you are working on. The guide is mainly for maintainer scripts and the administrators who review them. The installed manual says plainly that ordinary interactive users should use systemctl instead.

Warning: starting, stopping or restarting a real service can interrupt work. Test in a maintenance window with a known rollback path.

1. Confirm the installed helper

Check the executable and package version first. These commands are read-only and need no elevated privileges:

$ command -v deb-systemd-invoke
/usr/bin/deb-systemd-invoke
$ dpkg-query -W -f='${Package} ${Version}\n' init-system-helpers
init-system-helpers 1.66ubuntu1
$ deb-systemd-invoke
Syntax: /usr/bin/deb-systemd-invoke <action> [<unit file> [<unit file> ...]]

The last command only demonstrates the missing-argument check. It exits with status 1 and makes no systemd request. The supported command shapes are deliberately narrow:

Checkpoint: if the version or path differs, stop and read that installation's manual before copying these details into a package script.

2. Understand the policy gate

Before a service action, the helper looks for an executable /usr/sbin/policy-rc.d. If it is there, the helper calls it once per requested unit, passing the unit name and the action. The return code decides what happens:

So a locally written policy helper must use the documented Debian policy return values deliberately. And a policy denial will not look like a failed package installation: code 101 is a permitted, successful skip.

Inspect the policy file before diagnosing a package-script result:

$ if [ -x /usr/sbin/policy-rc.d ]; then
>     ls -l /usr/sbin/policy-rc.d
> else
>     echo 'no executable policy-rc.d'
> fi
no executable policy-rc.d

That output is specific to this host. A container image or an administrator-managed system may have a policy file, and its decision can explain why a service did not start.

Warning: do not edit or remove that file just to force a package action. It is a system-wide installation policy, and changing it can affect unrelated packages.

3. Use the service-action form

In a maintainer script, replace UNIT_NAME.service with the exact unit file the package owns:

# deb-systemd-invoke start UNIT_NAME.service
# deb-systemd-invoke restart UNIT_NAME.service
# deb-systemd-invoke stop UNIT_NAME.service

These actions can change running services and normally need root when run against the system manager. The # is the root prompt, so do not paste a placeholder as if it were a real unit. Pick one action that suits the package lifecycle, quote or validate any variable used to build a unit name, and never accept an arbitrary user-supplied action.

Several units are accepted in one call:

# deb-systemd-invoke start first-unit.service second-unit.service

Policy is checked for each unit before the systemctl call. The helper also avoids starting a disabled or static unit:

That protects package installation from quietly starting a unit the administrator deliberately left disabled.

Before a potentially disruptive action, inspect the unit with ordinary, read-only systemctl queries:

$ systemctl is-enabled -- UNIT_NAME.service
$ systemctl is-active -- UNIT_NAME.service
$ systemctl cat UNIT_NAME.service

Possible results include enabled, disabled, static, active, or a non-zero status when the unit is absent or inactive. Treat the unit's actual state as evidence, not as a reason to add --force. This wrapper has no such option.

4. Reload or re-exec the manager

Use the second command form after a unit-file change, when the package script really needs the manager to reread its files:

# deb-systemd-invoke daemon-reload
# deb-systemd-invoke daemon-reexec

daemon-reload asks systemd to reload unit definitions. It does not start a service by itself. daemon-reexec re-executes the manager process and is more specialised, so do not swap it in for a normal reload without a clear reason. Both affect the service manager and count as privileged operational actions.

The optional --no-dbus flag works only with these two manager actions. In the installed implementation it uses signals instead of the usual manager communication path: SIGHUP for daemon-reload and SIGRTMIN+25 for daemon-reexec. Leave it out unless the package's execution environment specifically needs that route. It is not a general switch for the service-action form.

Warning: never append a unit file to a reload command. Keep the two forms separate. A unit argument belongs to start, stop or restart. Reload and re-exec are manager-wide.

5. Handle user units deliberately

Add --user when the target is a user manager rather than the system manager:

$ deb-systemd-invoke --user start user-example.service
$ deb-systemd-invoke --user stop user-example.service

The command checks the user-manager instances it can discover and addresses them through systemd's machine-aware interface. On this installation the helper checks that the systemctl version supports acting on user instances, and older versions may skip the request instead. A user action is not a way to start a system service, and a system action is no substitute for a user's environment or permissions.

Use an ordinary user shell for inspection where you can. Elevated privileges do not fix a missing user manager or invent a user unit. If the unit is meant to run for a logged-out user, investigate that account's systemd setup and lifecycle separately instead of changing this wrapper invocation blindly.

6. Recover from a surprising result

Work through these checks in order:

  1. Confirm the exact action and unit. Check spelling, instance syntax and whether the package meant a system or user unit.
  2. Check policy. Read the executable policy-rc.d and record its exit decision. A 101 result is an intentional skip, not a request to retry as root.
  3. Check enablement and activity. Run systemctl is-enabled and systemctl is-active without changing state.
  4. Check the manager state. Run systemctl --failed and inspect the unit's journal through your normal operational process.

Recovery: to undo a service action you have just run, use the inverse action, but only after confirming the unit and the intended state. For a deliberate test start, that is systemctl stop UNIT_NAME.service or the matching wrapper call in the same policy context.

Warning: do not disable a unit as a recovery shortcut. That is persistent configuration and may break the administrator's intended boot behaviour.

Done means