Writing a custom daemon
In this last section, we'll learn how to write our own daemon in several programming languages using a skeleton that can be used to quickly develop really complex daemons. Due to the lack of space, we cannot add all the possible features a daemon has, but the presented skeletons will have whatever you need to know about daemon creation.
All example code will implement a daemon with the following command line usage:
usage: mydaemon [-h] [-d] [-f] [-l] -h - show this message -d - enable debugging messages -f - do not daemonize -l - log on stderr
The -h
option argument will show the help message, while -d
will enable the debugging messages. The -f
option argument will prevent the daemon from running in the background, and the -l
option will print the logging messages to the standard error channel. Apart from the -h
option argument, the other arguments are very useful during the debugging stages if used together in the form:
# ./mydaemon -d -f -l
The developer can run the daemon in the foreground with the debugging messages enabled and printed on the current terminal.
A daemon in C
In C language, a daemon skeleton can be written as in the chapter_04/mydaemon/my_daemon.c
file in the book's example code repository. The most important steps here are from the openlog()
function call and the daemon_body()
one. In fact, the two signal()
system calls are used to set up the signal handlers, while the whole job is done by the daemon()
function call (refer to the beginning of this chapter). Here is the relevant code:
/* Open the communication with syslogd */ loglevel = LOG_PID; if (logstderr) loglevel |= LOG_PERROR; openlog(NAME, loglevel, LOG_USER); /* Install the signals traps */ sig_h = signal(SIGTERM, sig_handler); if (sig_h == SIG_ERR) { fprintf(stderr, "unable to catch SIGTERM"); exit(-1); } sig_h = signal(SIGINT, sig_handler); if (sig_h == SIG_ERR) { fprintf(stderr, "unable to catch SIGINT"); exit(-1); } dbg("signals traps installed"); /* Should run as a daemon? */ if (daemonize) { ret = daemon(!daemonize, 1); if (ret) { fprintf(stderr, "unable to daemonize the process"); exit(-1); } } daemon_body();
Now we can compile the code using make
and then we can execute it using the following command line:
root@bbb:~# make cc -Wall -O2 -D_GNU_SOURCE mydaemon.c -o mydaemon root@bbb:~# ./mydaemon root@bbb:~#
We notice that it seems that nothing happens since the prompt is returned! However, after looking at the system log files, we can see the daemon's activity:
root@bbb:~/mydaemon# tail -f /var/log/syslog Apr 2 22:35:01 bbb mydaemon[3359]: I'm working hard! Apr 2 22:35:02 bbb mydaemon[3359]: I'm working hard! Apr 2 22:35:03 bbb mydaemon[3359]: I'm working hard!
The daemon can now be stopped using the killall
command, as follows:
root@bbb:~# killall mydaemon
A daemon in PHP
In PHP, creating a daemon is a bit more complex due the fact that there is no dedicated function to daemonize a running process; however, the task is still quite simple, as shown in the chapter_04/mydaemon/my_daemon.php
file in the book's example code repository. As for the C example, the important steps are all after the openlog()
function call; the pcntl_signal()
functions are used to install the signal handlers, while the daemon is created using the pcntl_fork()
, exit()
, chdir()
and fclose()
functions, as already explained at the beginning of this chapter. Here is the code snippet:
openlog(NAME, $loglevel, LOG_USER); # Install the signals traps pcntl_signal(SIGTERM, "sig_handler"); pcntl_signal(SIGINT, "sig_handler"); dbg("signals traps installed"); # Start the daemon if ($daemonize) { dbg("going in background..."); $pid = pcntl_fork(); if ($pid < 0) { die("unable to daemonize!"); } if ($pid) { # The parent can exit... exit(0); } # ... while the children goes on! # Set the working directory to / chdir("/"); # Close all of the standard file descriptors as we are running # as a daemon fclose(STDIN); fclose(STDOUT); fclose(STDERR); } daemon_body();
Note
The documentation of the pcntl_fork()
function is online at: http://php.net/manual/en/function.pcntl-fork.php .
In this case, the daemon can be executed using the following command line, and we get the same output as the earlier one:
root@bbb:~# ./mydaemon.php
We can check it by using again the tail
command:
root@bbb:~# tail -f /var/log/syslog Apr 2 22:36:59 bbb mydaemon.php[3365]: I'm working hard! Apr 2 22:37:00 bbb mydaemon.php[3365]: I'm working hard! Apr 2 22:37:01 bbb mydaemon.php[3365]: I'm working hard!
Then, to stop it, we use the killall
utility again:
root@bbb:~# killall mydaemon.php
A daemon in Python
In Python, the task is easier than in C due to the fact that we have a dedicated library to daemonize the running process.
The code is in the chapter_04/mydaemon/my_daemon.py
file in the book's example code repository. As earlier, the relevant part is after the syslog.openlog()
method call; we simply create a dedicated context with the daemon.DaemonContext()
method, and then within that context, we execute our daemon_body()
function. The relevant code is reported as follows:
# Open the communication with syslogd loglevel = syslog.LOG_PID if logstderr: loglevel |= syslog.LOG_PERROR syslog.openlog(NAME, loglevel, syslog.LOG_USER) # Define the daemon context and install the signals traps context = daemon.DaemonContext( detach_process = daemonize, ) context.signal_map = { signal.SIGTERM: sig_handler, signal.SIGINT: sig_handler, } dbg("signals traps installed") # Start the daemon with context: daemon_body()
Note
The documentation of the Python standard daemon process library is at: https://www.python.org/dev/peps/pep-3143/ .
The daemon is launched as earlier with the following command line:
root@bbb:~# ./mydaemon.py
Again, we can check the functioning with tail
:
root@bbb:~# tail -f /var/log/syslog Apr 2 22:47:59 bbb mydaemon.py[4339]: I'm working hard! Apr 2 22:48:00 bbb mydaemon.py[4339]: I'm working hard! Apr 2 22:48:01 bbb mydaemon.py[4339]: I'm working hard!
Then, we use killall
to stop the daemon:
root@bbb:~# killall mydaemon.py
A daemon in Bash
As a last example, we present the daemon implementation of a Bash script. This example is not as relevant as the previous ones since it is very rare to implement a daemon as a Bash script; however, it's interesting in order to show you how Bash scripting can be powerful.
The Bash demon code is reported in the chapter_04/mydaemon/my_daemon.sh
file in the book's example code repository. In this case, the relevant code is after the trap
command, which is used to install the signals handler, and it's all concentrated in the line with the eval
command. The daemon_body()
function is called in such a way that the stdin
and stdout
channels are redirected to the /dev/null
file, while the stderr
is redirected if no option is supplied, while the background or foreground execution mode is selected by the respective command-line option argument. The relevant code is as follows:
# Install the signals traps trap sig_handler SIGTERM SIGINT dbg "signals traps installed" # Start the daemon if [ -n "$daemonize" ] ; then dbg "going in background..." # Set the working directory to / cd / fi [ -z "$logstderr" ] && tmp="2>&1" eval daemon_body </dev/null >/dev/null $tmp $daemonize
Note
To get more information on the background process execution, standard input/output redirection and other Bash-related stuff used in this example, you can take a look at Bash's man pages using the usual command:
$ man bash
In this case, we can run the daemon in the debugging mode and then look at its output directly on the terminal:
root@bbb:~# ./mydaemon.sh -d -f -l mydaemon.sh: signals traps installed mydaemon.sh: start main loop mydaemon.sh: I'm working hard! mydaemon.sh: I'm working hard! mydaemon.sh: I'm working hard!
This time, we can stop the daemon by simply pressing the CRTL + C keys sequence, and this is the output:
^Cmydaemon.sh: signal trapped! root@bbb:~#