Discussion:
[systemd-devel] How to reboot from within a service
Norbert Lange
2021-04-18 10:01:41 UTC
Permalink
Hello,

My setup is some embedded system without logind, running a service
that should be able to poweroff, reboot or reboot-and-update.
Generally I guess this also includes triggering further services
programmatically fron another.

1) As I do currently: send SIGRTMIN+5 to PID1
(not really the complete solution, would need to discern between
reboot/update).
2) exec 'systemctl start reboot.target'
basically a variant of 1).
3) Same thing as 2), but do it with dbus or varlink.
4) Some unknown and likely not existing configuration of unit files.
doing something like "IfExitCode=121 then start reboot.target"
5) Use the Watchdog and let it expire.

While working, I would expect the first 3 options to be depended on
various level of rights to interfere with
PID1, aswell as being systemd specific (using dbus or systemd DSO).
Some sort of separation between
advertising the need for reboot and acting on it would be cleaner (ie.
hooking it up in service files).

What are the best option(s) here?
I thought about creating a service that waits on a PathExists (within
the runtime directory of the potentially isolated service),
then executing the reboot command (2), ideally after the service
finished (using Conflicts and After, but that also means the runtime
directory and PathExists file will be gone).

Regards,
Norbert
Lennart Poettering
2021-04-19 14:02:38 UTC
Permalink
Post by Norbert Lange
Hello,
My setup is some embedded system without logind, running a service
that should be able to poweroff, reboot or reboot-and-update.
Generally I guess this also includes triggering further services
programmatically fron another.
1) As I do currently: send SIGRTMIN+5 to PID1
(not really the complete solution, would need to discern between
reboot/update).
2) exec 'systemctl start reboot.target'
basically a variant of 1).
3) Same thing as 2), but do it with dbus or varlink.
4) Some unknown and likely not existing configuration of unit files.
doing something like "IfExitCode=121 then start reboot.target"
5) Use the Watchdog and let it expire.
While working, I would expect the first 3 options to be depended on
various level of rights to interfere with
PID1, aswell as being systemd specific (using dbus or systemd DSO).
Some sort of separation between
If you want to reboot the system in a sysv compatible way you can only
fork off "reboot" or "shutdown -r", or maybe send SIGINT to PID 1. The
latter is pretty ugly though, since this will be treated as if people
actually used Ctlr-Alt-Del on the console by PID 1, i.e. this is
subject to misleading log messages and the reboot hard after hitting
this 7x in 2s.
Post by Norbert Lange
advertising the need for reboot and acting on it would be cleaner (ie.
hooking it up in service files).
What are the best option(s) here?
Use logind's D-Bus APIs. It's the cleanest way to reboot, as it
honours inhibitors and stuff.

Lennart

--
Lennart Poettering, Berlin
Norbert Lange
2021-04-19 20:08:16 UTC
Permalink
Am Mo., 19. Apr. 2021 um 16:02 Uhr schrieb Lennart Poettering
Post by Lennart Poettering
Post by Norbert Lange
Hello,
My setup is some embedded system without logind, running a service
that should be able to poweroff, reboot or reboot-and-update.
Generally I guess this also includes triggering further services
programmatically fron another.
1) As I do currently: send SIGRTMIN+5 to PID1
(not really the complete solution, would need to discern between
reboot/update).
2) exec 'systemctl start reboot.target'
basically a variant of 1).
3) Same thing as 2), but do it with dbus or varlink.
4) Some unknown and likely not existing configuration of unit files.
doing something like "IfExitCode=121 then start reboot.target"
5) Use the Watchdog and let it expire.
While working, I would expect the first 3 options to be depended on
various level of rights to interfere with
PID1, aswell as being systemd specific (using dbus or systemd DSO).
Some sort of separation between
If you want to reboot the system in a sysv compatible way you can only
fork off "reboot" or "shutdown -r", or maybe send SIGINT to PID 1. The
latter is pretty ugly though, since this will be treated as if people
actually used Ctlr-Alt-Del on the console by PID 1, i.e. this is
subject to misleading log messages and the reboot hard after hitting
this 7x in 2s.
I wasn't particularly talking about sysv, but like not trying to
reboot the developers PC if he sent wrond command ;)
Post by Lennart Poettering
Post by Norbert Lange
advertising the need for reboot and acting on it would be cleaner (ie.
hooking it up in service files).
What are the best option(s) here?
Use logind's D-Bus APIs. It's the cleanest way to reboot, as it
honours inhibitors and stuff.
Yeah.. that makes sense once you got use sessions I guess.
I dont even have a dbus daemon running.

I ended up testing touching /run/custom/requestshutdown from the service,
and hooking up another service thats acts on it.
Seems to run fine so far, and if no reboot service is available,
nothing happens.

#custom.service
[Unit]
Description=Custom

[Service]
ExecStart=/opt/custom

ProtectSystem=strict
RuntimeDirectory=custom

#custom-reboot.path
[Unit]
Description=Custom Reboot Service
# think thats bad/not needed?
# PartOf=custom-reboot.service

[Path]
PathExists=/run/custom/requestshutdown
PathExists=/run/custom/requestupdate

#custom-reboot.service
[Unit]
Description=Custom Reboot Service

[Service]
ExecStart=/bin/systemctl start reboot.target --job-mode=replace-irreversibly
RemainAfterExit=yes
Post by Lennart Poettering
Lennart
Thanks for your input.

regards, Norbert

Loading...