Recently I discovered the boot-complete.target
and reading the systemd.special man page sounded like it was exactly what I was looking for:
This target is intended as generic synchronization point for services that shall determine or act on whether the boot process completed successfully.
Also reading the AUTOMATIC_BOOT_ASSESSMENT documentation sounded like I am on the right track, so I decided to use the target. Unfortunately the boot-complete.target
seemed not to get activated, so I started to dig deeper.
My target was a (non-UEFI) ARM system. Since the Automatic Boot Assessment documentation indicated that the scheme should also work with non-UEFI systems, I was first assuming that systemd has the target already activated by default. But I was wrong…
But this was not the case on my non-UEFI system as well as on my UEFI machine. The only service which activates the boot-complete.target
was the systemd-bless-boot.service
. This however isn’t present on the non-UEFI board (since it depends on systemd being built with the meson option `efi` enabled). On the UEFI system the service was not enabled.
Further reading the initial pull-request led me to the right path: The systemd-bless-boot.service only gets enabled if the `systemd-bless-boot-generator` does so (through a wanted in basic.target). Running the generator in debug mode revealed that boot counting is not enabled:
$ export SYSTEMD_LOG_LEVEL=debug $ /usr/lib/systemd/system-generators/systemd-bless-boot-generator Failed to read $container of PID 1, ignoring: Permission denied Found container virtualization none. Skipping generator, not booted with boot counting in effect.
Boot counting is controlled through the EFI variable `LoaderBootCountPath` which is written by the boot loader (at this point systemd-boot is the only boot loader implementing this). The documentation of systemd-boot does have a chapter about Boot Counting, and how it can be enabled.
So to use all this machinery, one has to make sure two things:
- systemd-boot version 240 or later is in use, e.g. by checking bootctl
- The loader entry file has a plus sign plus a number (number of tries) before its .conf ending (e.g. /boot/loader/entries/arch-lts+3.conf)
To me it seems strange that the target is only activated when boot counting is enabled (e.g. systemd-bless-boot.service
is active, since only this service has a Requires=
dependency to the boot-complete.target
). After all, the target has a rather generic name and can be useful outside of the context of boot counting. But anyway, that is what it is by default currently: A vehicle for boot counting.
To activate the target anyhow a dependency from a commonly used target is necessary (e.g. basic.target
, what the above mentioned generator uses). This can be done by adding the following to the boot-complete.target
:
[Install] WantedBy=basic.target
With that in place, make sure the target dependency is enabled:
# systemctl enable boot-complete.target
Note that this actually reaches the boot-complete.target
fairly early. This is because by default nothing delays the target from completing early. According to Lennart this is by design:
The boot counter update service
systemd-boot-complete.service
is ordered aftersysinit.target
by default, as well asboot-complete.target
. The latter is supposed to be the extension point which people can use to configure precisely how early or late they want the boot counter update to happen.
He also mentions that enabling systemd-boot-check-no-failures.service
can be used to order the boot-complete.target
fairly late, however in my test this lead to a circular dependency.