mirror of https://github.com/tLDP/LDP
450 lines
13 KiB
Plaintext
450 lines
13 KiB
Plaintext
<!doctype linuxdoc system>
|
|
|
|
<article>
|
|
<title>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 is designed to run
|
|
autonomously,with little or no 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 also operate with calls to the kernel. 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.
|
|
|
|
<p>In any case, you should have a good plan as to what the daemon should do.
|
|
If it is going to interoperate with other daemons (which 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 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 <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 directory (/). 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 must not use the terminal,
|
|
these file descriptors are both 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 them here.
|
|
|
|
<p>The big point here is, when initializing anything in a daemon, the same
|
|
defensive coding guidelines apply. 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 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 include statements for interfacing with the syslog,
|
|
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 should be able to use this skeleton to write your own daemons. Be sure to
|
|
add in your own logging (or use the syslog facility). Finally, code defensively,
|
|
code defensively, code defensively!
|
|
|
|
</article>
|