How to run commands at shutdown on Linux

653 readers like this.
Penguins gathered together in the Artic

Opensource.com

Linux and Unix systems have long made it pretty easy to run a command on boot. Just add your command to /etc/rc.local and away you go. But as it turns out, running a command on shutdown is a little more complicated.

Why would you want to run a command as the computer shuts down? Perhaps you want to de-register a machine or service from a database. Maybe you want to copy data from a volatile storage system to a permanent location. Want your computer to post "#RIP me!" on its Twitter account before it shuts down?

I should clarify at this point that I'm talking about so-called "one-shot" commands as opposed to stopping a daemon. It's tempting to think of them the same way, though. If you're familiar with SysVinit you might think, "Oh, I'll just create a kill script." For example, /etc/rc.d/rc3.d/K99runmycommandatshutdown should get invoked when your system exits runlevel 3. After all, that's how the scripts in /etc/init.d/ get stopped.

That's a great guess, but it turns out that it's wrong. SysVinit does not blindly run the kill scripts. Instead, it looks for (on Red Hat 6) /var/lock/subsys/service_name (where service_name here would be runmycommandatshutdown). So you have to get a little bit tricky and treat your script like a regular service. The script below gives an example:

#!/bin/sh
# chkconfig: 2345 20 80
# description: An example init script to run a command at shutdown

# runmycommandatshutdown runs a command at shutdown. Very creative.

LOCKFILE=/var/lock/subsys/
start(){
    # Touch our lock file so that stopping will work correctly
    touch ${LOCKFILE}
}

stop(){
# Remove our lock file
rm ${LOCKFILE}
# Run that command that we wanted to run
mycommand
}

case "$1" in
    start) start;;
    stop) stop;;
    *)
        echo $"Usage: $0 {start|stop}"
        exit 1
esac
exit 0

After putting that script in /etc/init.d/runmycommandatshutdown and enabling it with chkconfig on runmycommandatshutdown, your command will be run at shutdown.

systemd

All of that is great, but what if you're running a distribution of Linux that uses systemd instead of SysVinit? Turns out, it's much simpler with systemd. All you have to do is put your script in /usr/lib/systemd/system-shutdown/, which is handled by systemd-halt.service. Of course, if you need to manage dependencies in a particular order (e.g., you can't post a tweet if the network stack is down), then you can write a systemd service unit file. For example:

[Unit]
Description=Run mycommand at shutdown
Requires=network.target
DefaultDependencies=no
Before=shutdown.target reboot.target

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/true
ExecStop=mycommand

[Install]
WantedBy=multi-user.target
Tags
User profile image.
Ben Cotton is a meteorologist by training, but weather makes a great hobby. Ben works as the Fedora Program Manager at Red Hat. He is the author of Program Management for Open Source Projects. Find him on Twitter (@FunnelFiasco) or at FunnelFiasco.com.

10 Comments

"Turns out, it's much simpler with systemd."

I dispute that - for years I've been running a script when my system shuts down that copies all files that have changed to an external disk. Getting systemd to wait until the job finishes before shutting down was a major headache. Supposedly, systemd honours rc.d scripts, but I couldn't get this to work.

Thanks for expanding what I know about Linux. I want to get 'fstrim' to run once a week when I shut down. I've experimented with 'cron' and 'anacron' but I'm not sure it's happening. I guess i should check the logs to be sure.

ubuntu 16.04 it's automatically runs fstrim once a weak, ubuntu 14.04 lts only runs fstrims one a week on intel and Samsung ssd's unless you add a no vender check opion, to a line some where, if you go to youtube ad serch how collins, and click on his name you can watch a video where he talks a little bit abought Darrin and how to add the no venerchech option in ubuntu 14.04 lts, not to sure about other Linux distros though

In reply to by Don Watkins

In Slackware (sysvinit in BSD compatible mode) it's even easier :)

$ cat /etc/rc.d/rc.local_shutdown
#!/bin/sh
#
# /etc/rc.d/rc.local_shutdown: Local system shutdown script.
#
# Put any local shutdown commands in here.

my_command_at_shutdown
exit 0

$ sudo chmod +x /etc/rc.d/rc.local_shutdown

I miss the days when shutdown used to be a script that could be edited. We ran Informix. We'd give a long period of grace, say 15 minutes, to the users. That gave them time to finish up what they were doing but there'd always be one who'd keep working up to the wire & get in the way of the final shutdown. Informix has a mode where it can continue processing on existing connections but inhibits the creation of new ones so I just put the command to enter that mode into the shutdown script alongside the wall that sent out the first warning message. It was more flexible way of doing things than relying on the sysv run levels.

That does sound really handy. When I was a sysadmin in academia, I'd always try to schedule shutdowns for times when people would be asleep. But of course no matter what time you pick, there's always at least one grad student doing work then. :-)

In reply to by igoddard (not verified)

A few modifications were necessary, on my end. First, I have to add the script:

sudo chkconfig --add runmycommandatshutdown

Second, the argument "on" needed to be at the end of the script:
sudo chkconfig runmycommandatshutdown on

Cheers!

I tried a script on my Fedora 24 box with systemd, but it failed to run. have two possible causes:

1. the article doesn't mention making the script executable -- is it necessary?

2. my script does a 'dnf upgrade -y && dnf clean all' (system upgrade, clean cache) that is only allowed by su, I don't use sudo -- does the systemd routine automatically run root scripts when shutting down as a normal user?

TIA

Thanks for reading. I'm pretty sure the first suggestion is the problem. The script probably does need to be executable. I apologize for leaving that out.

In reply to by meine

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.