mirror of https://github.com/tLDP/LDP
452 lines
13 KiB
Plaintext
452 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 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>
|