How can I give a grace period to CTRL-ALT-DEL in systemd

Solution 1:

In systemd, the CTRL-ALT-DEL key sequence triggers the ctrl-alt-del.target (which by default lives in the system path, /lib/systemd/system/ctrl-alt-del.target on Debian) and starts the systemd-reboot.service. It can be overridden by creating a local version, /etc/systemd/system/ctrl-alt-del.target. Creating it as an empty file effectively disables the key sequence.

One way to schedule the reboot in the future would be to have this target require a service (ex local-delayed-reboot.service - create the file in the same directory) and have this service configured as oneshot with ExecStart=shutdown -r <delay>.

What bugs me in this method is that we're going all over the place, ctrl-alt-del trigger a systemd service which calls a binary which send a dbus message back to systemd to schedule the shutdown (logind handles it...). I though it might be cleaner to actually keep starting the same target but only after executing a systemd timer. This is how I implemented it:

Create a warning service - this is to warn (using wall + tee console in case no one is logged in) that the reboot is going to happen. adjust the message - esp. the delay - as desired:

/etc/systemd/system/local-delay-reboot-warn.service

[Unit]
Description=Reboot Warning

[Service]
Type=oneshot
ExecStart=/bin/sh -c '/bin/echo -e "\aCTRL-ALT-DEL has been hit! Reboot in 60 seconds...\n\nTo abort:\n  systemctl stop ctrl-alt-del.target"|tee /dev/console|/usr/bin/wall'

Create a timer that starts the shutdown unit after specified time - the timer depends on the warning service so warning message is fired first (likewise, update the delay as desired):

/etc/systemd/system/local-delay-reboot.timer

[Unit]
Description=Reboot delay
DefaultDependencies=no
# Warn first...
Requires=local-delay-reboot-warn.service
After=local-delay-reboot-warn.service
# Make this timer stop if ctrl-alt-del.target is stopped
PartOf=ctrl-alt-del.target

[Timer]
OnActiveSec=60s
RemainAfterElapse=no
Unit=systemd-reboot.service
# Disable systemd's timer optimisations
AccuracySec=1us

[Install]
WantedBy=ctrl-alt-del.target

Finally override ctrl-alt-del.target with this:

/etc/systemd/system/ctrl-alt-del.target

# Custom reboot action 

[Unit]
Description=Reboot (delayed)
DefaultDependencies=no
Requires=local-delay-reboot-warn.service local-delay-reboot.timer
After=systemd-reboot.service
AllowIsolate=yes
JobTimeoutSec=30min
JobTimeoutAction=reboot-force

[Install]
Alias=ctrl-alt-del.target

After all I'm not sure it was really worth it but it was definitively educational in understanding how to use timers.