In systemd setups,
init N all translate to various subcommands of
systemctl. I'll be talking in terms of
systemctl from now on.
So, what happens when you issue (for example) a
systemctl reboot command? Barring the polkit/logind abstraction layer (which is anyway not used when root privileges are available), this command translates to
systemctl isolate reboot.target, which is in turn equivalent to
systemctl start --job-mode=isolate reboot.target.
In systemd parlance, to "isolate" a unit (be it a target, a service or whatever else) means to start (activate) a given unit together with all its dependencies, AND stop (deactivate) all other units, unless they have
IgnoreOnIsolate=yes specified. So, when you issue a reboot command,
reboot.target (with its deps) is enqueued to start, and all other units are enqueued to stop.
We won't examine dependencies of these targets by hand (though it's possible with
systemctl list-dependencies command). Let's instead look at bootup(7), a man page describing what happens on startup/shutdown of a systemd-controlled system.
The corresponding ASCII-chart is copy-pasted here (FTR, it reflects systemd 221).
(conflicts with (conflicts with
all system all file system
services) mounts, swaps,
| devices, ...)
/ | | \
| | | |
v v v v
systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service
| | | |
v v v v
reboot.target poweroff.target halt.target kexec.target
The scheme is pretty self-explanatory. The special
shutdown.target target by default conflicts with all service units (unless they have
So, the first approach would be to make your
A service a dependency of
shutdown.target, so that it will get activated on all shutdowns. (Note that this will also require making it
However, by default, everything in systemd is done in parallel, so your
A service also needs to be ordered against
B — to delay shutdown of
A starts and completes its data retrieval. In systemd.unit(5) we may read:
If one unit with an ordering dependency on another unit is shut down while the latter is started up, the shut down is ordered before the start-up regardless of whether the ordering dependency is actually of type After= or Before=.
This is unfortunate: regardless of whether we will make A
Before=B.service, B will be stopped before A is started.
So, we must go another way. We can create a normal service of
Type=oneshot, which does nothing (
/bin/true) on activation, but does whatever is needed on deactivation. (This will also require making it
RemainsAfterExit=yes, or the service will get automatically marked as inactive as soon as
/bin/true exits.) Such service can be ordered against
B.service as needed:
Note that when two units with an ordering dependency between them are shut down, the inverse of the start-up order is applied. i.e. if a unit is configured with After= on another unit, the former is stopped before the latter if both are shut down.
Putting this all together, a unit file for
A.service will look something like this:
Description=Collect information about B
# we want to deactivate together with B
# we want to deactivate before B deactivates
# replace with whatever is needed
Also note that if a pretty recent (≥ 217) version of systemd is used, then
ExecStart=/bin/true may be completely left out.
- systemd(1) manual page, section "Concepts".
- systemd.unit(5) manual page, section "[Unit] Section Options".
- bootup(7) manual page.
- systemd.special(5) manual page.