2

At this moment my laptop is starting to have what I think hardware issues. Sometimes I have to try 3 times before it starts successfully. I am trying to save the code I modify in my usb stick but sometimes I forget. That is why I am wondering if there is a way to run a script when the user wants to shutdown the computer. This script will check several things and depending on the situation it would either cancel the shutdown and ask the user to perform some action (insert a usb key for example), or execute some statements (save to usb if it is there) and allow the shutdown after. Because of this necessary interaction with the user just putting the script under /etc/rc0.d won't be enough.

Thanks

2 Answers 2

2

Use systemd inhibitors

Original Post is in section below and details how to intercept /sbin/shutdown command. This section is based on systemd inhibitors.

From systemd inhibitor:

Name

systemd-inhibit — Execute a program with an inhibition lock taken

Synopsis

systemd-inhibit [OPTIONS...] [COMMAND] [ARGUMENTS...]

systemd-inhibit [OPTIONS...] --list

Description

systemd-inhibit may be used to execute a program with a shutdown, sleep, or idle inhibitor lock taken. The lock will be acquired before the specified command line is executed and released afterwards.

Inhibitor locks may be used to block or delay system sleep and shutdown requests from the user, as well as automatic idle handling of the OS. This is useful to avoid system suspends while an optical disc is being recorded, or similar operations that should not be interrupted.

For more information see the Inhibitor Lock Developer Documentation.

Options

The following options are understood:

--what=

  • Takes a colon-separated list of one or more operations to inhibit: "shutdown", "sleep", "idle", "handle-power-key", "handle-suspend-key", "handle-hibernate-key", "handle-lid-switch", for inhibiting reboot/power-off/halt/kexec, suspending/hibernating, the automatic idle detection, or the low-level handling of the power/sleep key and the lid switch, respectively. If omitted, defaults to "idle:sleep:shutdown".

--who=

  • Takes a short, human-readable descriptive string for the program taking the lock. If not passed, defaults to the command line string.

--why=

  • Takes a short, human-readable descriptive string for the reason for taking the lock. Defaults to "Unknown reason".

--mode=

  • Takes either "block" or "delay" and describes how the lock is applied. If "block" is used (the default), the lock prohibits any of the requested operations without time limit, and only privileged users may override it. If "delay" is used, the lock can only delay the requested operations for a limited time. If the time elapses, the lock is ignored and the operation executed. The time limit may be specified in logind.conf(5). Note that "delay" is only available for "sleep" and "shutdown".

--list

  • Lists all active inhibition locks instead of acquiring one.

-h, --help

  • Print a short help text and exit.

--version

  • Print a short version string and exit.

Exit status

Returns the exit status of the executed program.

Example

# systemd-inhibit wodim foobar.iso

This burns the ISO image foobar.iso on a CD using wodim(1) Note: link is broken in systemd documentation, and inhibits system sleeping, shutdown and idle while doing so.

See Also

systemd(1), logind.conf(5)


Original Post

In concept it seems pretty easy. Simply find the command, rename it, and replace it with your own script that calls the renamed version:

$ type -a shutdown
shutdown is /sbin/shutdown
$ sudo mv /sbin/shutdown /sbin/shutdownoriginal

Then edit your own script in /sbin/shutdown containing at the very least:

#!/bin/bash
/sbin/shutdownoriginal

Then mark your script as executable for everyone:

$ sudo chmod a+x /sbin/shutdown

Voila! Everything that calls shutdown now calls your script which then calls the original commmand.

In reality by the time your script gets called things may not be in the state you expect. For example I put in some commands to record the shutdown but they do not appear to work:

echo "/sbin/shutdown custom script calling /sbin/shutdownoriginal"
shutdowntime=`date`
echo "Last shutdown: $shutdowntime" >> /home/rick/shutdownlog.txt

The first echo should have appeared in /var/log/syslog but it did not. The second echo should have appended a line to the log file but it did not. This tells me that by the time the /sbin/shutdown command is executed system logging is already turned off and the file I/O system is shutdown.

A better approach would be looking at systemd shutdown target and/or input inhibitors. I'll leave this answer here though for others that might think it could/would/should work.

As always remember YMMV--Your Mileage May Very.

2
  • I will give you some feedback for your answer that I think is a good first step in the right direction towards the right solution. When I click on the gear at the top right and choose shutdown, my shutdown is not executed. The original shutdown is just a link to /bin/systemctl so probably it is never called when using the gui. However when I type "shutdown" in the terminal it is executed with one minute delay. That is already a working solution. I will look at your other suggestions and I will update here. Thank you very much!
    – Karim Mtl
    Feb 27, 2018 at 1:01
  • @KarimMtl It was my pleasure. It's an interesting project so please keep us all updated. Feb 27, 2018 at 1:05
0

I looked at systemd-inhibit

What I understood is that when you use it before a command it waits until your command / script finishes before the system shuts down, there are some options to block the shutdown but it did not seem obvious to do to me. For now your first suggestion works for me (I do not mind typing "shutdown" instead of the graphical interface). Here is a basic script as an example:

#!/bin/bash

if [ ! -d /media/myusername/myusbname ]; then
  zenity --question --text "Are you sure you want to shutdown without saving? If not choose \"No\" and insert the usb key" 2> /dev/null
  answer=$?
else
  #save data
  answer=0
fi
if [ $answer -eq 0 ]; then
  /sbin/shutdownoriginal
else
  zenity --info --text="Shutdown canceled" 2> /dev/null
fi

Thank you

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.