Ubuntu 20.04 – running script at shutdown/restart

I’m trying to run a script at shutdown and reboot without success. I have a script to run as root at startup and it works just fine: stored the script in /etc/init.d, created a link to it in /etc/rc2.d starting with S99 and make it executable. After some research I did the same with the shutdown script creating the links in /etc/rc0.d and /etc/rc6.d, making it executable and starting links name with ‘K99myscript’ but the script doesn’t run. I’ve tried changing the links name to ‘K00myscript’ to run before the others, changing from sh to bash (#! /bin/sh to #! /bin/bash) but nothing seems to help. I’m running Xubunto and using ‘systemctl poweroff’ to shutdown and ‘systemctl reboot’ to restart. Is this an obsolete method?

I’ve also tried to create a .service in /etc/systemd/system as suggested:

[Unit]
Description=Pre-Shutdown Processes
DefaultDependencies=no
Before=shutdown.target reboot.target halt.target kexec.target

[Service]
Type=oneshot
User=root
Group=root
ExecStart=/etc/init.d/myscript

[Install]
WantedBy=shutdown.target reboot.target halt.target kexec.target

Both with and without User/Group fields but it didn't worked...


Solution 1:

[SOLVED] Being a bit stubborn is, sometimes, the good path for a solution. Nevertheless, thanks for your contributions. After some research based on the link of my previous comment (Sebastian Stark's answer), I ended up with this script (let’s call it ‘myoffscript’) in my /etc/init.d folder:

#!/bin/sh
### BEGIN INIT INFO
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Provides:          Shutdown or Reboot Exec
# Default-Start:     4
# Default-Stop:      0 6
# Description:       Shutdown or Reboot
### END INIT INFO

case "$1" in
    stop)
             echo $(date) >> /ZZZdate # REPLACE PREVIOUS EXAMPLE: EXECUTE SHUTDOWN/REBOOT COMMANDS HERE
         ;;
esac

exit 0

Regarding the above script the most important to highlight is:

1 - The LSB (Linux Standard Base) header – ‘Default-Start’ and ‘Default-Stop’ run levels must be both present, corresponding ‘0’ to shutdown (rc0.d) and ‘6’ to reboot (rc6.d). As my script is only for shutdown and reboot and the ‘Default-Start’ must be specified, I’ve chosen ‘4’ (rc4.d) witch is not used/user-definable. But it should be run level ‘2’ (rc2.d) if starting something at boot time is needed (like a service, daemon,…)

2 - The case statement - As the scrip is executed by systemd as a service with the arguments ‘start’ or ‘stop’ according to the ‘Default-Start’ and ‘Default-Stop’ from the LSB header, all the commands must be inside of the case statement. (Commands before the case statement were ignored in my tests.) Corresponding to run levels ‘0’ and ‘6’, my case statement has only the stop) option, but if running at boot time is needed, a start) option should be included (and run level ‘2’ must be specified in the LSB header ‘Default-Start’).

Now, let’s make it work. First make the script /etc/init.d/myoffscript executable. Then, we have two options - with a command or manually.

With a command:

# systemctl enable myoffscript

or

# /lib/systemd/systemd-sysv-install enable myoffscript

The relative symbolic links will be automatically created in the corresponding rc*.d folders (S01myoffscript in rc4.d and K01myoffscript in rc0.d and rc6.d according the to the script above) The commands wil only work if the links were not created before. Otherwise errors will be reported.

Manually: From each rc*.d folder create the symbolic link

# cd /etc/rc4.d
# ln -s ../init.d/myoffscript S01myoffscript
# cd /etc/rc0.d
# ln -s ../init.d/myoffscript K01myoffscript
# cd /etc/rc6.d
# ln -s ../init.d/myoffscript K01myoffscript

Note: if run level ‘2’ was specified in ‘Default-Start’, the first link should be created in /etc/rc2.d and so on... Restart the system and everything should work.

This is the only way that I’ve found to run a script as root at both shutdown and reboot with Ubuntu 20.04

Note: Despite the /etc/int.d and /etc/rc2.d links method is still working to run scripts/commands at boot time, as mentioned in my previous comment link, a long-term approach would be to convert init scripts to systemd service units, so the LBS header with the case statement method described above may be useful for startup scripts/commands in a few time.