Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python detect linux shutdown and run a command before shutting down

Is it possible to detect and interrupt linux (Ubuntu 16.04) shutdown signal (e.g. power button clicked or runs out of battery). I have a python application that is always recording a video and I want to detect such signal so I close the recording properly before OS shutdown.

like image 608
m.othman Avatar asked Sep 01 '16 15:09

m.othman


People also ask

How is the time to shut down set with the shutdown command Linux?

Schedule a time that suits your needs by using the format hh:mm (24-hour time designations). It's more likely that you'll want to halt the operating system a few minutes into the future. In that case, specify the number of minutes from now to begin the shutdown process.

Which runlevel shuts down Linux and powers off the computer?

Runlevel 0 is used to halt the system, runlevel 6 is used to reboot the system, and runlevel 1 is used to put the system into a state where administrative tasks can be performed (single-user mode).

How do I stop Linux from shutting down?

Cancel a shutdown You can use the -c option to cancel a scheduled shutdown.


1 Answers

When linux is shut down, all processes receive SIGTERM and if they won't terminate after some timeout they are killed with SIGKILL. You can implement a signal handler to properly shutdown your application using the signal module. systemd (opposed to upstart in earlier Ubuntu verions) additionally sends SIGHUP on shutdown.

To verfiy that this actually works, I tried the following script on two Ubuntu VMs (12.04 and 16.04). The system waits for 10s (12.04/upstart) or 90s (16.04/systemd) before issuing SIGKILL.

The script ignores SIGHUP (which would otherwise also kill the process ungracefully) and will continuously print the time since the SIGTERM signal has been received to a text file.

Note I used disown (built-in bash command) to detach the process from the terminal.

python signaltest.py &
disown

signaltest.py

import signal
import time

stopped = False

out = open('log.txt', 'w')

def stop(sig, frame):
    global stopped
    stopped = True
    out.write('caught SIGTERM\n')
    out.flush()

def ignore(sig, frsma):
    out.write('ignoring signal %d\n' % sig)
    out.flush()

signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGHUP, ignore)

while not stopped:
    out.write('running\n')
    out.flush()
    time.sleep(1)

stop_time = time.time()
while True:
    out.write('%.4fs after stop\n' % (time.time() - stop_time))
    out.flush()
    time.sleep(0.1)

The last line printed into log.txt was:

10.1990s after stop

for 12.04 and

90.2448s after stop

for 16.04.

like image 180
code_onkel Avatar answered Sep 28 '22 05:09

code_onkel