1

I'm setting up my Linux box (that is connected to a UPS) to gracefully shutdown my pfsense router prior to shutting down. I'm running Ubuntu 16.04, and using systemd to accomplish this. I have the systemd service configured, and it works. However, it's initiating the script on shutdown AND on reboot. This is no good since anytime I reboot my linux box, I'll be shutting down my router. How can I change my systemd service so that it only activates during shutdown?

My setup is as follows:

[Unit]
Description=PFSense Shutdown script
After=poweroff.target

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/path/to/script/pfsenseshutdown.sh
RemainAfterExit=yes


[Install]
WantedBy=multi-user.target

And, for reference, the pfsenseshutdown.sh script is fairly simple:

#!/bin/bash
ssh user@x.x.x.x -i "sudo /etc/rc.halt"

Any help would be greatly appreciated.

  • You may want to add this to WantedBy=shtudown.target instead of WantedBy=multi-user.target. I think you also have to change the ExecStart and ExecStop assignments. – Thomas Jan 6 '17 at 15:18
  • OK...I'll try the WantedBy statement in a bit. I'm not sure what you mean by the ExecStart/Stop assignments. What do you think they need to be changed to? – cgram Jan 6 '17 at 16:14
  • Not really sure, but I think your script has to be assigned to ExecStart=/path/to/script/pfsenseshutdown.sh. – Thomas Jan 6 '17 at 16:19
  • Perhaps you can hook into the reboot sequence with another script that writes something to a file in /dev/shm/ (is a memory file system, and is cleared when you boot). In the pfsenseshutdown.sh script you could then look for that file to see if it's a reboot or shutdown. – brm Jan 6 '17 at 16:53
  • brm...sounds promising. I'm still learning systemd....and bash for that matter....so I'm not entirely sure how to go about that. – cgram Jan 6 '17 at 17:01
3

The following approach seems to run a script on shutdown only, and not on reboot. You can edit the systemd-poweroff.service file as follows:

sudo systemctl edit --full systemd-poweroff.service

In the [Service] section, you can then add an ExecStartPre line:

ExecStartPre=/path/to/script/pfsenseshutdown.sh

This way, the script will not be executed if you shutdown the system with halt however. To handle this case, you can add the same line to systemd-halt.service.

Note that in this approach the config file shown in the question is not used.

EDIT: a possible shortcoming in the previous approach, is that the script to be executed contains an ssh command, which may not work right before shutting down the system (systemd may already have stopped necessary network services). The approach below tries to avoid this.

For this solution, I created a pfsenseshutdown.service unit with the following contents

[Unit]
Description=PFSense Shutdown script
DefaultDedendencies=no

[Service]
Type=oneshot
ExecStart=/usr/bin/touch /dev/shm/shuttingdown

[Install]
WantedBy=systemd-halt.service systemd-poweroff.service

When starting the shutdown procedure, this file seems to cause the ExecStart line to be executed right away, causing the file /dev/shm/shuttingdown to exist (the /dev/shm directory is a memory file system, so it will be cleared after a reboot).

Now, to make sure that your script is executed before the network is completely de-initialized, I ran

systemctl edit --full networking.service

Originally, it contained the following ExecStop line on my ubuntu 16.04 virtual machine:

ExecStop=/sbin/ifdown -a --read-environment

This line was replaced by a version that first runs your script, in this example:

ExecStop=/path/to/script/pfsenseshutdown.sh && /sbin/ifdown -a --read-environment

The pfsenseshutdown.sh script, then tests if the file in /dev/shm exists, and performs the ssh command accordingly. I also added a small sleep command: systemd does many things in parallel, and this hopefully helps prevent the test from failing because the file does not exist yet.

#!/bin/bash

sleep 1

if [ -e /dev/shm/shuttingdown ] ; then

    # Your ssh command here

fi
  • No dice. I edited the systemd-poweroff.service to include the ExecStartPre command, but it's not executing the script. Actually...the linux box is halting at the "Reached target Shutdown", and will not actually power off. I know the script path works, because if works fine in original systemd service. Is there a way to shutdown more verbosely to see what it's choking on? – cgram Jan 6 '17 at 19:49
  • Maybe there's a difference in how the shutdown is initiated? I'm testing using a virtual machine, and if I just type 'halt' at the command line, I get the same behavior that you mention: the "Reached target Shutdown" message is shown, but the script is not executed and the VM doesn't really power off. On the other hand, I can also initiate shutdown by selecting "shutdown" in the GUI, and then the script is executed and the system powers off – brm Jan 7 '17 at 12:42
  • I did some more experiments and made a slight addition to the answer (about editing systemd-halt.service as well). Can you try again? – brm Jan 7 '17 at 13:07
  • Thanks for helping out, brm...but still no luck. I've added the ExecStartPre line to both systemd-shutdown.service and systemd-halt.service. However, each time I enter "sudo shutdown now", it stops at the "Reached target Shutdown" message and never powers off. It also does not execute the pfsenseshutdown script. I did notice that the status of the halt and shutdown services says "Active: inactive (dead)"...but I'm not sure if that matters or not. Any other advice? – cgram Jan 7 '17 at 15:21
  • And just for comparison, I commented out the ExecStartPre command in both services, and entered 'sudo shutdown now', and the box powered down normally. So, there does seem to be something about the ExecStartPre line that's causing issues. – cgram Jan 7 '17 at 15:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.