Systemd : How to execute script at shutdown only (not at reboot)

28,930

Solution 1

I've finally found how to do that.

It's a bit hackish thought, but it works.

I've used some part of this thread : https://stackoverflow.com/questions/25166085/how-can-a-systemd-controlled-service-distinguish-between-shutdown-and-reboot

and this thread : How to run a script with systemd right before shutdown?

I've created this service /etc/systemd/system/shutdown_screen.service

[Unit]
Description=runs only upon shutdown
Conflicts=reboot.target
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/bin/bash /usr/local/bin/shutdown_screen
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Which will be executed at shudown/reboot/halt/whatever. (don't forget to enable it)

And in my script /usr/local/bin/shutdown_screen I put the following :

#!/bin/bash
# send a shutdown message only at shutdown (not at reboot)    
/usr/bin/systemctl list-jobs | egrep -q 'reboot.target.*start' || echo "shutdown" | nc 192.168.0.180 4243 -w 1

Which will send a shutdown message to my arduino, whom will shutdown my screen.

Solution 2

According to the systemd.special man-page, you should use Before=poweroff.target.

poweroff.target

A special target unit for shutting down and powering off the system.

Applications wanting to power off the system should start this unit.

runlevel0.target is an alias for this target unit, for compatibility with SysV.

Additionally, as I mentioned in my comment, you should put custom scripts into /etc/systemd/system/. The /usr/lib/systemd/system/ directory is meant to be used for system-provided scripts.

So, maybe something like this:

[Unit]
Description=runs only upon shutdown
DefaultDependencies=no
Conflicts=reboot.target
Before=shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/bin/true
ExecStop=/usr/local/bin/yourscript
RemainAfterExit=yes

Solution 3

From reading the answers here there seems to be a lot misunderstanding about how systemd works. Firstly don't use conflicts to exclude a target. It is ment to keep to conflicting services from being run at the same time.

If a unit has a Conflicts= setting on another unit, starting the former will stop the latter and vice versa.

Unit means a .service file ment to launch perticular service not a target to be reach. In other-words Conflicts=reboot.target is meaningless at best and at worst it will prevent you from rebooting. Don't do this. It does not mean don't run this on reboot. It means abort either this service or the reboot.target depending on timing and how systemd interprets this erroneous use of conflicts.

Here is example of a currently setup unit (aka .service file) that runs only on shutdown not reboot:

[Unit]
Description=Play sound
DefaultDependencies=no
Before=poweroff.target halt.target

[Service]
ExecStart=/usr/local/bin/playsound.sh
ExecStop=/usr/local/bin/playsound.sh
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=poweroff.target halt.target 

poweroff.target is equivalent to the old systemv run level0 which is only reached at shutdown. halt.target is an alternate shutdown path used by systemd also not reachable by reboot. The install section tells systemd to add this service to the list that must be completed before poweroff.target or halt.target will be considered reached.

This service is installed and running on my system.

Share:
28,930

Related videos on Youtube

benoit2600
Author by

benoit2600

Updated on September 18, 2022

Comments

  • benoit2600
    benoit2600 over 1 year

    There is a lot of solution here to execute a script at shutdown/reboot, but I want my script to only execute at shutdown.

    I've tried to put my script in /usr/lib/systemd/systemd-shutdown, and check the $1 parameter, as seen here, but it doesn't work.

    Any ideas ?

    system : archlinux with gnome-shell

    $systemctl --version                                                                                                                                                                                 
    systemd 229
    +PAM -AUDIT -SELINUX -IMA -APPARMOR +SMACK -SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN
    
    • ILMostro_7
      ILMostro_7 almost 8 years
      I don't think this will be the solution, but you should put custom scripts into /etc/systemd/system/. The /usr/lib/systemd/system/ directory is meant to be used for system-provided scripts.
  • benoit2600
    benoit2600 almost 8 years
    Well, it doesn't seems to work. I've edited your .service like this (otherwise, symlink aren't created) http://pastebin.com/dq01rQVM But nothing is executed at shutdown. I forgot to said that I need a working connection for my script. But I've tried with a echo "test" > /root and nothing was created.
  • Damien Martin-Guillerez
    Damien Martin-Guillerez over 4 years
    Works fine but the conflict line is not needed.
  • Damien Martin-Guillerez
    Damien Martin-Guillerez over 4 years
    For me this did not worked. It ran both on reboot and halt on a raspbian. Also I could not make it worked before the network is down.
  • Outright
    Outright over 4 years
    For anyone else trying to run a unit before the network is down you need to use a different target in before. The above example is not guaranteed to do so.