2

I'm setting up an embedded device running Debian Jessie to shut down when a UPS experiences a power failure. Unfortunately, the device's bootloader restarts the OS whenever it quits, so shutdown/halt commands are equivalent to restart.

My main concern is protecting the data on the attached hard disks. I think my best option is to kill as many tasks as possible and then wait for the power to cut. systemctl isolate emergency.target seems close to what I want, except it leaves the disks mounted. Is there a way to basically get Systemd to final.target without an actual shutdown/halt command?

2 Answers2

2

systemctl halt might do the trick. From the manual:

halt
    Shut down and halt the system. This is mostly equivalent to
    systemctl start halt.target --job-mode=replace-irreversibly
    --no-block, but also prints a wall message to all users. This
    command is asynchronous; it will return after the halt operation is
    enqueued, without waiting for it to complete. Note that this
    operation will simply halt the OS kernel after shutting down,
    leaving the hardware powered on. Use systemctl poweroff for
    powering off the system (see below).
  • See also https://unix.stackexchange.com/questions/195898/ and https://unix.stackexchange.com/questions/8690/ for more on this. – JdeBP Mar 17 '18 at 10:39
  • Alas, no joy. As JdeBP's wonderfully in depth answer to the first question they links above says, systemctl halt and shutdown -H now are equivalent in systemd. All these commands do halt the OS kernel, but that's when the bootloader starts the system again! I need a way to shut everything else down but leave a minimal kernel running. – Bethanie Mar 17 '18 at 17:18
  • This is the right answer for the general question of how to halt a machine or VM running systemd. In OP's case, they have a watchdog-like system that impedes this, but I thought it would be good to mention that it is correct for the general case. (Which is what I came here for.) – eil Sep 26 '23 at 13:31
1

Assuming this isn't just a problem with some sort of watchdog device, you can try hijacking the kexec target for systemd. That's ordinarily used for loading a kdump kernel to dump memory, but you can really set up that target to do anything.

I created a systemd unit called kexec-sleep and put it into /etc/systemd/system/kexec-sleep.service (I'm not sure if these Requires/After/Before lines are quite right, but they worked for me in a virtual machine):

[Unit]
Description=Sleep forever at kexec
DefaultDependencies=no
Requires=umount.target
After=umount.target
Before=final.target

[Service]
Type=oneshot
ExecStart=/sbin/kexec-sleep
KillMode=none

[Install]
WantedBy=kexec.target

That will call /sbin/kexec-sleep, which is just a shell script (shown below). It attempts to remount the root filesystem read-only, so it should stay in a clean state until the device powers down. I have some sleeps in there that are probably longer than what you need, plus a prompt at the end that will let you reboot without needing to pull the power cord.

#!/bin/sh

stty sane < /dev/console       # enable automatic CRLF output on console
exec < /dev/console > /dev/console 2>&1  # redirect stdio to/from console
echo "Sleeping several seconds for processes to terminate..."
sleep 10
# kill some expected processes
killall dhclient
# sleep again...
sleep 5
echo "Processes still running:"
/bin/ps --ppid 2 -p 2 --deselect    # list non-kernel processes
echo "Attempting to remount root filesystem read-only..."
sync; sync; sync
mount -o remount,ro /
grep /dev/sda /proc/mounts
while true; do
    echo "System paused. Type 'reboot' to reboot"
    read -p '> ' entry
    if [ "$entry" = "reboot" ]; then
        /sbin/reboot -f
    fi
done

After creating those files, run chmod +x /sbin/kexec-sleep and systemctl enable kexec-sleep.

To trigger this instead of a normal shutdown, run systemctl kexec.

mulad
  • 139
  • This is awesome, and seems really close to working. When I run systemctl kexec, it culminates with 3 lines from systemd-shutdown[1]: Rebooting with kexec. / kexec failed with error code 1. / Rebooting. -- I don't see the expected echo outputs, so I'm not sure where the failure is. – Bethanie Mar 25 '18 at 22:02
  • It fails this way even if /sbin/kexec-sleep only contains exit 0... – Bethanie Mar 25 '18 at 22:21