82

What do I need to put in the [install] section, so that systemd runs /home/me/so.pl right before shutdown and also before /proc/self/net/dev gets destroyed?

[Unit]
Description=Log Traffic

[Service]
ExecStart=/home/me/so.pl

[Install]
?
0

4 Answers 4

95

The suggested solution is to run the service unit as a normal service - have a look at the [Install] section. So everything has to be thought reverse, dependencies too. Because the shutdown order is the reverse startup order. That's why the script has to be placed in ExecStop=.

The following solution is working for me:

[Unit]
Description=...

[Service]
Type=oneshot
RemainAfterExit=true
ExecStop=<your script/program>

[Install]
WantedBy=multi-user.target

RemainAfterExit=true is needed when you don't have an ExecStart action.

After creating the file, make sure to systemctl daemon-reload and systemctl enable yourservice --now.

I just got it from systemd IRC, credits are going to mezcalero.

7
  • 9
    At ubuntu 16.04 you must have a ExecStart=/bin/true.
    – niels
    Dec 29, 2016 at 20:50
  • 4
    My assumption to WHY RemainAfterExit=true is required when there is no ExecStart is because systemd will not attempt to run ExecStop if it thinks that the service is not running. RemainAfterExit=true causes systemd to believe that the service is running, thereby causing it to run ExecStop at shutdown. Jun 15, 2017 at 0:30
  • 1
    Is there anyway to ensure this script will run and complete before user sessions and user processes are terminated?
    – richmb
    Oct 19, 2017 at 13:19
  • @richmb Not at all. From the docs: Note that it is usually not sufficient to specify a command for this setting that only asks the service to terminate (for example, by queuing some form of termination signal for it), but does not wait for it to do so.
    – svenwltr
    Nov 30, 2017 at 11:19
  • 1
    @2rs2ts, can you clarify "does not work" with more specificity? Does the service not load? Does its ExecStop begin execution but get killed before the process is able to complete? Something else? Sep 26, 2019 at 19:46
16
  • To run a service right before starting any of reboot/shutdown/halt/kexec services (i.e. in the last moment before root filesystem becomes remounted read-only) use this service config:

    [Unit]
    Description=Save system clock on shutdown
    DefaultDependencies=no
    After=final.target
    
    [Service]
    Type=oneshot
    ExecStart=/usr/lib/systemd/scripts/fake-hwclock.sh save
    
    [Install]
    WantedBy=final.target
    

    Enable it with:

    systemctl enable my_service.service
    
  • To run a script right before actual reboot/shutdown/halt/kexec (when you cannot write to the root filesystem, because it was remounted read-only) add this script executable to the /usr/lib/systemd/system-shutdown directory.

    Immediately before executing the actual system halt/poweroff/reboot/kexec systemd-shutdown will run all executables in /usr/lib/systemd/system-shutdown/ and pass one arguments to them: either "halt", "poweroff", "reboot" or "kexec", depending on the chosen action. All executables in this directory are executed in parallel, and execution of the action is not continued before all executables finished.

Also see:

https://www.freedesktop.org/software/systemd/man/bootup.html

https://www.freedesktop.org/software/systemd/man/systemd-halt.service.html

3
  • 8
    I want to execute something as near as possible after initiating a reboot, way before the final.target. Ideally I would like that it is the first thing being executed after the user do $ sudo reboot. May 25, 2019 at 22:29
  • I tested the first approach on RHEL 7 and the service is actually executed after the root-filesystem is remounted read-only. That means hwclock state can't be written to /etc/adjtime then. This behavior is also what I expected after looking at the linked chart - because the umount.target readonly-remounts the root filesystem and final.target depends on that target. Jun 21, 2020 at 10:05
  • @JaimeHablutzel Are you able to achieve? Jul 29, 2020 at 22:08
10

As far as I can see this does what I need (but I don't know exactly why).

[Unit]
Description=Log Traffic
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target


[Service]
ExecStart=/usr/local/bin/perl /home/me/log_traffic.pl --stop
Type=oneshot
5
  • 4
    It happens to work because of 2 things: 1) DefaultDependencies=no makes it ignores all dependencies and run "at first" on start and "at last" on stop, always respecting "Before" and "After" clauses. 2) It happens to have a Before clause on shutdown/reboot/halt targets, so it will run just before shutdown/reboot/halt is reached on stop (because they only run on stop it happens to do what you want).
    – RDP
    Jan 29, 2016 at 1:01
  • You may want to add kexec.target to the Before bit
    – hanetzer
    Mar 26, 2016 at 11:11
  • This doesn't work for me
    – Bug Killer
    Sep 7, 2016 at 1:50
  • 2
    I don't see how this will work unless you also add WantedBy=shutdown.target reboot.target halt.target to the [Unit] section. Before= & After= don't change dependencies.
    – rsaw
    Sep 8, 2016 at 15:57
  • This answer doesn't solve the problem where you need something to run before other things shut down
    – 2rs2ts
    Sep 21, 2018 at 1:35
7

I am not totally sure but i don't think you need the install part though i added it explicitly. I also didn't test it but i think it should help you get started:

[Unit]
Description=Log Traffic
Requires=network.target
After=network.target
Before=shutdown.target
DefaultDependencies=no

[Service]
ExecStart=/home/me/so.pl
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target
2

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