Python detect linux shutdown and run a command before shutting down
<p>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.</p>

<p>When linux is shut down, all processes receive <code>SIGTERM</code> and if they won't  terminate after some timeout they are killed with <code>SIGKILL</code>. You can implement a signal handler to properly shutdown your application using the <a href="https://docs.python.org/2.7/library/signal.html" rel="nofollow"><code>signal</code></a> module. <code>systemd</code> (opposed to <code>upstart</code> in earlier Ubuntu verions) additionally sends <code>SIGHUP</code> on shutdown.</p>

<p>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 <code>SIGKILL</code>.</p>

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

<p><strong>Note</strong> I used <code>disown</code> (built-in bash command) to detach the process from the terminal.</p>

<pre><code>python signaltest.py &amp;
disown
</code></pre>

<p><strong>signaltest.py</strong></p>

<pre><code>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)
</code></pre>

<p>The last line printed into <code>log.txt</code> was:</p>

<pre><code>10.1990s after stop
</code></pre>

<p>for 12.04 and</p>

<pre><code>90.2448s after stop
</code></pre>

<p>for 16.04.</p>

python linux python-2.7 ubuntu