diff --git a/LDP/howto/linuxdoc/Linux-Daemon-HOWTO.sgml b/LDP/howto/linuxdoc/Linux-Daemon-HOWTO.sgml new file mode 100644 index 00000000..5eb05f43 --- /dev/null +++ b/LDP/howto/linuxdoc/Linux-Daemon-HOWTO.sgml @@ -0,0 +1,451 @@ + + +
+Linux Daemon Writing HOWTO +<author><url url="mailto:dmwatson@comcast.net" name="Devin Watson"> +<date>v1.0, May 2004 +<abstract> +This document shows how to write a daemon in Linux using GCC. Knowledge +of Linux and a familiarity with C are necessary to use this document. + +This HOWTO is Copyright by Devin Watson, under the terms of the BSD License. +</abstract> +<!-- Table of Contents --> +<toc> + +<sect>Introduction: What is a Daemon? +<p>A daemon (or service) is a background process that is designed to run +autonomously,with little or not user intervention. The Apache web server http +daemon (httpd) is one such example of a daemon. It waits in the background +listening on specific ports, and serves up pages or processes scripts, based on +the type of request. + +<p>Creating a daemon in Linux uses a specific set of rules in a given order. +Knowing how they work will help you understand how daemons operate in userland +Linux, but can operate with calls to the kernel also. In fact, a few daemons +interface with kernel modules that work with hardware devices, such as external +controller boards, printers,and PDAs. They are one of the fundamental building +blocks in Linux that give it incredible flexibility and power. + +<p>Throughout this HOWTO, a very simple daemon will be built in C. As we go +along, more code will be added, showing the proper order of execution required +to get a daemon up and running. + +<sect>Getting Started +<p>First off, you'll need the following packages installed on your Linux machine +to develop daemons, specifically: + +<itemize> + <item><tt>GCC 3.2.2 or higher</tt> + <item><tt>Linux Development headers and libraries</tt> +</itemize> + +If your system does not already have these installed (not likely, but check +anyway), you'll need them to develop the examples in this HOWTO. To find out +what version of GCC you have installed, use: + +<tscreen> +<verb> + gcc --version +</verb> +</tscreen> + + +<sect>Planning Your Daemon +<sect1>What Is It Going To Do? +<p>A daemon should do one thing, and do it well. That one thing may be as +complex as managing hundreds of mailboxes on multiple domains, or as simple as +writing a report and calling sendmail to mail it out to an admin. + +<p>In any case, you should have a good plan going in what the daemon should do. +If it is going to interoperate with some other daemons that you may or may not +be writing, this is something else to consider as well. + +<sect1>How Much Interaction? +<p>Daemons should never have direct communication with a user through a +terminal. In fact, a daemon shouldn't communicate directly with a user at all. +All communication should pass through some sort of interface (which you may or +may not have to write), which can be as complex as a GTK+ GUI, or as simple as a +signal set. + +<sect>Basic Daemon Structure +<p>When a daemon starts up, it has to do some low-level housework to get itself +ready for its real job. This involves a few steps: + +<itemize> + <item>Fork off the parent process + <item>Change file mode mask (umask) + <item>Open any logs for writing + <item>Create a unique Session ID (SID) + <item>Change the current working directory to a safe place + <item>Close standard file descriptors + <item>Enter actual daemon code +</itemize> + +<sect1>Forking The Parent Process +<p>A daemon is started either by the system itself or a user in a terminal or +script. When it does start, the process is just like any other executable on the +system. To make it truly autonomous, a <it>child process</it> must be created +where the actual code is executed. This is known as forking, and it uses the +<em>fork()</em> function: +<tscreen> +<verb> + pid_t pid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } +</verb> +</tscreen> + +<p>Notice the error check right after the call to <em>fork()</em>. When writing +a daemon, you will have to code as defensively as possible. In fact, a good +percentage of the total code in a daemon consists of nothing but error +checking. + +<p>The <em>fork()</em> function returns either the process id (PID) of the child +process (not equal to zero), or -1 on failure. If the process cannot fork a +child, then the daemon should terminate right here. + +<p>If the PID returned from <em>fork()</em> did succeed, the parent process must +exit gracefully. This may seem strange to anyone who hasn't seen it, but by +forking, the child process continues the execution from here on out in the code. + +<sect1>Changing The File Mode Mask (Umask) +<p>In order to write to any files (including logs) created by the daemon, the +file mode mask (umask) must be changed to ensure that they can be written to or +read from properly. This is similar to running umask from the command line, but +we do it programmatically here. We can use the <em>umask()</em> function to +accomplish this: + +<tscreen> +<verb> + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + /* Log failure (use syslog if possible) */ + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + +</verb> +</tscreen> + +<p>By setting the umask to 0, we will have full access to the files generated by +the daemon. Even if you aren't planning on using any files, it is a good idea to +set the umask here anyway, just in case you will be accessing files on the +filesystem. + +<sect1>Opening Logs For Writing +<p>This part is optional, but it is recommended that you open a log file +somewhere in the system for writing. This may be the only place you can look for +debug information about your daemon. + +<sect1>Creating a Unique Session ID (SID) +<p>From here, the child process must get a unique SID from the kernel in order +to operate. Otherwise, the child process becomes an orphan in the system. The +pid_t type, declared in the previous section, is also used to create a new +SID for the child process: +<tscreen> +<verb> + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + /* Log any failure */ + exit(EXIT_FAILURE); + } +</verb> +</tscreen> + +<p>Again, the <em>setsid()</em> function has the same return type +as <em>fork()</em>. We can apply the same error-checking routine here to see if +the function created the SID for the child process. + + +<sect1>Changing The Working Directory +<p>The current working directory should be changed to some place that is +guaranteed to always be there. Since many Linux distributions do not completely +follow the Linux Filesystem Hierarchy standard, the only directory that is +guaranteed to be there is the root (/). We can do this using the +<em>chdir()</em> function: + +<tscreen> +<verb> + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + /* Log any failure here */ + exit(EXIT_FAILURE); + } + + /* Change the current working directory */ + if ((chdir("/")) < 0) { + /* Log any failure here */ + exit(EXIT_FAILURE); + } + +</verb> +</tscreen> + +<p>Once again, you can see the defensive coding taking place. The +<em>chdir()</em> function returns -1 on failure, so be sure to check for that +after changing to the root directory within the daemon. + +<sect1>Closing Standard File Descriptors +<p>One of the last steps in setting up a daemon is closing out the standard file +descriptors (STDIN, STDOUT, STDERR). Since a daemon cannot use the terminal, +these file descriptors are redundant and a potential security hazard. + +<p>The <em>close()</em> function can handle this for us: + +<tscreen> +<verb> + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + /* Log any failure here */ + exit(EXIT_FAILURE); + } + + /* Change the current working directory */ + if ((chdir("/")) < 0) { + /* Log any failure here */ + exit(EXIT_FAILURE); + } + + + /* Close out the standard file descriptors */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); +</verb> +</tscreen> + +<p>It's a good idea to stick with the constants defined for the file descriptors, +for the greatest portability between system versions. + +<sect>Writing the Daemon Code +<sect1>Initialization +<p>At this point, you have basically told Linux that you're a daemon, so now +it's time to write the actual daemon code. Initialization is the first step +here. Since there can be a multitude of different functions that can be called +here to set up your daemon's task, I won't go too deep into here. + +<p>The big point here is that, when initializing anything in a daemon, the same +defensive coding guidelines apply here. Be as verbose as possible when writing +either to the syslog or your own logs. Debugging a daemon can be quite difficult +when there isn't enough information available as to the status of the daemon. + +<sect1>The Big Loop +<p>A daemon's main code is typically inside of an infinite loop. Technically, +it isn't an infinite loop, but it is structured as one: + +<tscreen> +<verb> + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + /* Log any failures here */ + exit(EXIT_FAILURE); + } + + + /* Change the current working directory */ + if ((chdir("/")) < 0) { + /* Log any failures here */ + exit(EXIT_FAILURE); + } + + /* Close out the standard file descriptors */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* Daemon-specific initialization goes here */ + + /* The Big Loop */ + while (1) { + /* Do some task here ... */ + sleep(30); /* wait 30 seconds */ + } +</verb> +</tscreen> + +<p>This typical loop is usually a <em>while</em> loop that has an infinite +terminating condition, with a call to <em>sleep</em> in there to make it run at +specified intervals. + +<p>Think of it like a heartbeat: when your heart beats, it +performs a few tasks, then waits until the next beat takes place. Many daemons +follow this same methodology. + +<sect>Putting It All Together +<sect1>Complete Sample +<p>Listed below is a complete sample daemon that shows all of the steps +necessary for setup and execution. To run this, simply compile using gcc, and +start execution from the command line. To terminate, use the <it>kill</it> +command after finding its PID. + +<p>I've also put in the correct include statements for interfacing with the syslog, +which is recommended at the very least for sending start/stop/pause/die log statements, in +addition to using your own logs with the <em>fopen()</em>/<em>fwrite()</em>/<em>fclose()</em> +function calls. + +<tscreen> +<verb> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <syslog.h> +#include <string.h> + +int main(void) { + + /* Our process ID and Session ID */ + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + exit(EXIT_FAILURE); + } + /* If we got a good PID, then + we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* Change the file mode mask */ + umask(0); + + /* Open any logs here */ + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + /* Log the failure */ + exit(EXIT_FAILURE); + } + + + + /* Change the current working directory */ + if ((chdir("/")) < 0) { + /* Log the failure */ + exit(EXIT_FAILURE); + } + + /* Close out the standard file descriptors */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* Daemon-specific initialization goes here */ + + /* The Big Loop */ + while (1) { + /* Do some task here ... */ + + sleep(30); /* wait 30 seconds */ + } + exit(EXIT_SUCCESS); +} +</verb> +</tscreen> +<p>From here, you can use this skeleton to write your own daemons. Be sure to +add in your own logging (or use the syslog facility), and code defensively, +code defensively, code defensively! + +</article>