mirror of https://github.com/tLDP/LDP
Adding Devin's document to the collection. Review process has started.
This commit is contained in:
parent
f8aabf1aca
commit
1e44b5ea04
|
@ -0,0 +1,451 @@
|
|||
<!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>
|
Loading…
Reference in New Issue