This is the first part of the post on how I daemonised my Podcast XML auto generating Python programme. Part 3b can be found here.
After some research, I found this blog post to contain most of the information I needed.
I already knew that I could generate a daemon by altering the
init.d file found in
/etc/init.d/ to point to the appropriate file. However, I was unsure how to set the flags on the
start-stop-daemon command to ensure a Python script behaved properly. The
skeleton file is structured as follows:
- Start daemon function
- Stop daemon function
- Restart daemon function
caseblock to process which function is called through
sudo service myservice command
The start, stop and restart functions contain the appropriate flags to achieve the wanted behaviour from the
start-stop-daemon command. Details on how I edited the
skeleton file can be found below the fold.
The Start Function
skeleton file provides the following code:
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS
$PIDFILE is defined as
$NAME is the user defined name for the daemon. This is typically the name of the script being demonised, as
$DAEMON is defined as
The flags are fairly self explanatory;
--start obviously starts the daemon,
--pidfile points to the location of the pid file, and
--exec executes the script the
$DAEMON variable points to.
--quiet does not allow any information to be printed, only error messages. (I got rid of this flag to ensure I could see what was happening when writing the script for the first time, and used
--verbose for extra debugging help when editing the stop function>
There are a few differences between the flags used in the Philips blog post and those outlined above. First, Philips uses the
--chuid sets which user the daemon runs under, while the
--user flag can be used to look for scripts with the same name being ran by the user identified by the flag, to check whether the daemon is already running.
--background flag is explained by Philips as enabling the daemon to run in the background; the manual sheds more information on this. This flag tells
start-stop-daemon to fork before the process being daemonised is initiated and then forces it to run this process in the background. This is an important flag for my purposes as I have yet to learn how to fork processes in this way in Python or Linux.
--make-pidfile flag is required as my Python script does not generate its own pidfile file – I need
start-stop-daemon to do that for me. Although this would be a rather straightforward thing to do, it would take a few lines of python and require a couple of modules to be imported. Adding this flag is rather quicker!
The other difference is that the
skeleton file initiates the script with the
--exec flag, while Philips uses is the
--start-as flag. The manual warns that
--exec might not work as intended with interpreted scripts, as it might point to the interpreter. i.e. it might point to
/usr/bin/env python rather than
/path/to/myservice. A nice little explanation of this is provided here.
I therefore ended up using the following flags:
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --startas $DAEMON -- \ $DAEMON_ARGS
The Stop Function
The stop function provided by the
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?"
was a little bit more complicated than that provided by Philips:
start-stop-daemon --stop --pidfile $PIDFILE --retry 10
by virtue of the difference in the
--retry flag. Philips explains that his choice of flags will send a
TERM signal to the process and then, after 10 seconds, check if the process is still running. If it is, it sends a
KILL signal, which will definitely kill the process. The
--retry flag provided by the
skeleton file, therefore, sends a
TERM signal, waits 30 seconds before sending a
KILL signal if the process is still running, and then waits another 5, after which, if the process is still running,
start-stop-daemon exits with an error status 2.
When modifying the
skeleton file, I consistently hit problems with
start-stop-daemon identifying the process to kill. I would receive errors that indicated, for example, that it could not find processes with the name given in
$NAME. This indicated that
start-stop-daemon was not finding anything satisfying the “matching” flags (i.e.
--exec). The changes in the start function meant that the process should have been identifiable through
--pidfile, but this was failing (possibly due to this being an interpreted script, i.e. the “name” path actually having “python” in front of it, while the name variable did not contain this). Removing the –name flag solved this problem, allowing the process to be found through the pid file.
Before reaching this rather simple solution, however, I had been searching for why I was unable to stop the Python script/process through the
sudo service myservice stop command. Quite a few of the results, such as this and this, stated that the Python script needed to include some code to handle the
TERM signal being sent. Adding this code (specifically that found in the first example result) didn’t have any effect. This was because the signal couldn’t be sent to the process, as the process itself was not being found, rather than the process being unable to handle the
In the end, using the
--verbose flag allowed me to identify that
start-stop-daemon was not identifying the process; once this problem was solved (as outlined above), I could stop the daemon with the normal
sudo service myservice stop command, and did not require any extra code to handle the
TERM signal (presumably because the kill command was succeeding).
Typically, a service controlled via the
sudo service commands would report a nice status message, such as
[ ok ] Starting python daemon test: myservice. However, the initial code provided by the
skeleton file (given below) only produced these messages for the
start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;;
The culprit for the lack of these messages was the if statement checking whether the
$VERBOSE variable was set to “yes” or “no”. To check this variable, one appears to be required to include
. /lib/init/vars.sh. I did not do much research into what this file is or does, as simply removing the if statement allowed the messages to appear.
init.d script for the Podcast XML generated programme can be found here
 A pid file is a file which contains the process id and nothing more. It’s generated when the process starts and allows for an easy way to identify the process id of the daemon, and therefore an easy way to interact with the process, such as issuing the
kill command to stop/kill the process.
 See the manual for more information.