diff options
author | Andreas Baumann <abaumann@yahoo.com> | 2008-12-21 12:13:55 +0100 |
---|---|---|
committer | Andreas Baumann <abaumann@yahoo.com> | 2008-12-21 12:13:55 +0100 |
commit | 738edc361f66cb8fc48a47563a2f12a60c087f76 (patch) | |
tree | ea53b47b7e6bcd7063bbc5cc02afbf7dcef0d28a /docs/daemon | |
parent | cd63c8db79eb28f47bbdbfcc9bbf3118de2079fc (diff) | |
download | wolfbones-738edc361f66cb8fc48a47563a2f12a60c087f76.tar.gz wolfbones-738edc361f66cb8fc48a47563a2f12a60c087f76.tar.bz2 |
renamed doc to docs to avoid stupid makefiles to fail (even with .PHONY)
Diffstat (limited to 'docs/daemon')
-rw-r--r-- | docs/daemon/README | 6 | ||||
-rw-r--r-- | docs/daemon/www_enderunix.org_daemon.html | 367 |
2 files changed, 373 insertions, 0 deletions
diff --git a/docs/daemon/README b/docs/daemon/README new file mode 100644 index 0000000..2ebdfd9 --- /dev/null +++ b/docs/daemon/README @@ -0,0 +1,6 @@ +How Unix daemons work see: +- general introduction: http://www.enderunix.org/documents/eng/daemon.php +- for handling user/groups: http://www.gmonline.demon.co.uk/cscene/CS4/CS4-07.html + +Other projects: +- libdaemon (in C): http://0pointer.de/lennart/projects/libdaemon/ diff --git a/docs/daemon/www_enderunix.org_daemon.html b/docs/daemon/www_enderunix.org_daemon.html new file mode 100644 index 0000000..c86ccff --- /dev/null +++ b/docs/daemon/www_enderunix.org_daemon.html @@ -0,0 +1,367 @@ +<html><head><!-- +--> + + + +<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-9"> +<meta http-equiv="Description" content="Unix Daemon Server Programming"> +<meta http-equiv="Keywords" content="Levent, Karakaž, Karakas, Unix, Daemon, Server, Programming"><title>Unix Daemon Server Programming</title> + +<style type="text/css"> +<!-- +BODY, TD { + background : #FFFFFF; + color : #000000; + font-family : normal arial, helvetica; + font-size: 12px; + text-align: justify; +} +H1 { + font-size : 20px; + text-align : center; +} +H2 { + font-size : 16px; + text-align : left; +} +A:link, A:visited { + color: #0000FF; + text-decoration: none; +} +//--> +</style></head><body> + +<div align="center"> + +<table border="0" cellpadding="0" cellspacing="0" width="600"> + <tbody><tr> + <td> + +<h1>Unix Daemon Server Programming</h1> + +<h2>Introduction</h2> + +<p>Unix processes works either in foreground or background. A process +running in foreground interacts with the user in front of the terminal +(makes I/O), whereas a background process runs by itself. The user can +check its status but he doesn't (need to) know what it is doing. The +term 'daemon' is used for processes that performs service in +background. A server is a process that begins execution at startup (not +neccessarily), runs forever, usually do not die or get restarted, +operates in background, waits for requests to arrive and respond to +them and frequently spawn other processes to handle these requests.</p> + +<p>Readers are suppossed to know Unix fundamentals and C language. For +further description on any topic use "man" command (I write useful +keywords in brackets), it has always been very useful, trust me :)) +Keep in mind that this document does not contain everything, it is just +a guide.</p> + + +<h2>1) Daemonizing (programming to operate in background) [fork]</h2> + +<p>First the fork() system call will be used to create a copy of our +process(child), then let parent exit. Orphaned child will become a +child of init process (this is the initial system process, in other +words the parent of all processes). As a result our process will be +completely detached from its parent and start operating in background.</p> + +<pre> i=fork(); + if (i<0) exit(1); /* fork error */ + if (i>0) exit(0); /* parent exits */ + /* child (daemon) continues */ +</pre> + +<h2>2) Process Independency [setsid]</h2> + +<p>A process receives signals from the terminal that it is connected +to, and each process inherits its parent's controlling tty. A server +should not receive signals from the process that started it, so it must +detach itself from its controlling tty.</p> + +<p>In Unix systems, processes operates within a process group, so that +all processes within a group is treated as a single entity. Process +group or session is also inherited. A server should operate +independently from other processes.</p> + +<pre> setsid() /* obtain a new process group */ +</pre> + +<p>This call will place the server in a new process group and session +and detach its controlling terminal. (setpgrp() is an alternative for +this)</p> + +<h2>3) Inherited Descriptors and Standart I/0 Descriptors [gettablesize,fork,open,close,dup,stdio.h]</h2> + +<p>Open descriptors are inherited to child process, this may cause the +use of resources unneccessarily. Unneccesarry descriptors should be +closed before fork() system call (so that they are not inherited) or +close all open descriptors as soon as the child process starts running.</p> + +<pre> for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */ +</pre> + +<p>There are three standart I/O descriptors: standart input 'stdin' +(0), standart output 'stdout' (1), standart error 'stderr' (2). A +standard library routine may read or write to standart I/O and it may +occur to a terminal or file. For safety, these descriptors should be +opened and connectedthem to a harmless I/O device (such as /dev/null).</p> + +<pre> i=open("/dev/null",O_RDWR); /* open stdin */ + dup(i); /* stdout */ + dup(i); /* stderr */ +</pre> + +<p>As Unix assigns descriptors sequentially, fopen call will open stdin and dup calls will provide a copy for stdout and stderr.</p> + +<h2>4) File Creation Mask [umask]</h2> + +<p>Most servers runs as super-user, for security reasons they should +protect files that they create. Setting user mask will pre vent +unsecure file priviliges that may occur on file creation.</p> + +<pre> umask(027); +</pre> + +<p>This will restrict file creation mode to 750 (complement of 027).</p> + +<h2>5) Running Directory [chdir]</h2> + +<p>A server should run in a known directory. There are many advantages, +in fact the opposite has many disadvantages: suppose that our server is +started in a user's home directory, it will not be able to find some +input and output files.</p> + +<pre> chdir("/servers/"); +</pre> + +<p>The root "/" directory may not be appropriate for every server, it +should be choosen carefully depending on the type of the server.</p> + +<h2>6) Mutual Exclusion and Running a Single Copy [open,lockf,getpid]</h2> + +<p>Most services require running only one copy of a server at a time. +File locking method is a good solution for mutual exclusion. The first +instance of the server locks the file so that other instances +understand that an instance is already running. If server terminates +lock will be automatically released so that a new instance can run. +Recording the pid of the running instance is a good idea. It will +surely be efficient to make 'cat mydaamon.lock' instead of 'ps -ef|grep +mydaemon'</p> + +<pre> lfp=open("exampled.lock",O_RDWR|O_CREAT,0640); + if (lfp<0) exit(1); /* can not open */ + if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */ + /* only first instance continues */ + + sprintf(str,"%d\n",getpid()); + write(lfp,str,strlen(str)); /* record pid to lockfile */ +</pre> + +<h2>7) Catching Signals [signal,sys/signal.h]</h2> + +<p>A process may receive signal from a user or a process, its best to +catch those signals and behave accordingly. Child processes send +SIGCHLD signal when they terminate, server process must either ignore +or handle these signals. Some servers also use hang-up signal to +restart the server and it is a good idea to rehash with a signal. Note +that 'kill' command sends SIGTERM (15) by default and SIGKILL (9) +signal can not be caught.</p> + +<pre> signal(SIG_IGN,SIGCHLD); /* child terminate signal */ +</pre> + +<p>The above code ignores the child terminate signal (on BSD systems +parents should wait for their child, so this signal should be caught to +avoid zombie processes), and the one below demonstrates how to catch +the signals.</p> + +<pre> void Signal_Handler(sig) /* signal handler function */ + int sig; + { + switch(sig){ + case SIGHUP: + /* rehash the server */ + break; + case SIGTERM: + /* finalize the server */ + exit(0) + break; + } + } + + signal(SIGHUP,Signal_Handler); /* hangup signal */ + signal(SIGTERM,Signal_Handler); /* software termination signal from kill */ +</pre> + +<p>First we construct a signal handling function and then tie up signals to that function.</p> + +<h2>8) Logging [syslogd,syslog.conf,openlog,syslog,closelog]</h2> + +<p>A running server creates messages, naturally some are important and +should be logged. A programmer wants to see debug messages or a system +operator wants to see error messages. There are several ways to handle +those messages.</p> + +<p><b>Redirecting all output to standard I/O : </b>This is what ancient +servers do, they use stdout and stderr so that messages are written to +console, terminal, file or printed on paper. I/O is redirected when +starting the server. (to change destination, server must be restarted) +In fact this kind of a server is a program running in foreground (not a +daemon).</p> + +<pre> # mydaemon 2> error.log +</pre> + +<p>This example is a program that prints output (stdout) messages to +console and error (stderr) messages to a file named "error.log". Note +that this is not a daemon but a normal program.</p> +<p><b>Log file method : </b>All messages are logged to files (to different files as needed). There is a sample logging function below.</p> + +<pre> void log_message(filename,message) + char *filename; + char *message; + { + FILE *logfile; + logfile=fopen(filename,"a"); + if(!logfile) return; + fprintf(logfile,"%s\n",message); + fclose(logfile); + } + + log_message("conn.log","connection accepted"); + log_message("error.log","can not open file"); +</pre> + +<p><b>Log server method : </b>A more flexible logging technique is +using log servers. Unix distributions have system log daemon named +"syslogd". This daemon groups messages into classes (known as facility) +and these classes can be redirected to different places. Syslog uses a +configuration file (/etc/syslog.conf) that those redirection rules +reside in.</p> + +<pre> openlog("mydaemon",LOG_PID,LOG_DAEMON) + syslog(LOG_INFO, "Connection from host %d", callinghostname); + syslog(LOG_ALERT, "Database Error !"); + closelog(); +</pre> + +<p>In openlog call "mydaemon" is a string that identifies our daemon, +LOG_PID makes syslogd log the process id with each message and +LOG_DAEMON is the message class. When calling syslog call first +parameter is the priority and the rest works like printf/sprintf. There +are several message classes (or facility names), log options and +priority levels. Here are some examples :</p> + +<dl> +<dd>Message classes : LOG_USER, LOG_DAEMON, LOG_LOCAL0 to LOG_LOCAL7</dd> +<dd>Log options : LOG_PID, LOG_CONS, LOG_PERROR</dd> +<dd>Priority levels : LOG_EMERG, LOG_ALERT, LOG_ERR, LOG_WARNING, LOG_INFO</dd> +</dl> + +<h2>About</h2> + +<p>This text is written by Levent Karakas <a href="mailto:levent%20at%20mektup%20dot%20at"><levent at mektup dot at ></a>. +Several books, sources and manual pages are used. This text includes a +sample daemon program (compiles on Linux 2.4.2, OpenBSD 2.7, SunOS 5.8, +SCO-Unix 3.2 and probably on your flavor of Unix). You can also +download plain source file : <a href="http://www.enderunix.org/documents/eng/exampled.c">exampled.c</a>. Hope you find this document useful. We do love Unix.</p> + +<pre> +/* +UNIX Daemon Server Programming Sample Program +Levent Karakas <levent at mektup dot at> May 2001 + +To compile: cc -o exampled examped.c +To run: ./exampled +To test daemon: ps -ef|grep exampled (or ps -aux on BSD systems) +To test log: tail -f /tmp/exampled.log +To test signal: kill -HUP `cat /tmp/exampled.lock` +To terminate: kill `cat /tmp/exampled.lock` +*/ + +#include <stdio.h> +#include <fcntl.h> +#include <signal.h> +#include <unistd.h> + +#define RUNNING_DIR "/tmp" +#define LOCK_FILE "exampled.lock" +#define LOG_FILE "exampled.log" + +void log_message(filename,message) +char *filename; +char *message; +{ +FILE *logfile; + logfile=fopen(filename,"a"); + if(!logfile) return; + fprintf(logfile,"%s\n",message); + fclose(logfile); +} + +void signal_handler(sig) +int sig; +{ + switch(sig) { + case SIGHUP: + log_message(LOG_FILE,"hangup signal catched"); + break; + case SIGTERM: + log_message(LOG_FILE,"terminate signal catched"); + exit(0); + break; + } +} + +void daemonize() +{ +int i,lfp; +char str[10]; + if(getppid()==1) return; /* already a daemon */ + i=fork(); + if (i<0) exit(1); /* fork error */ + if (i>0) exit(0); /* parent exits */ + /* child (daemon) continues */ + setsid(); /* obtain a new process group */ + for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */ + i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */ + umask(027); /* set newly created file permissions */ + chdir(RUNNING_DIR); /* change running directory */ + lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640); + if (lfp<0) exit(1); /* can not open */ + if (lockf(lfp,F_TLOCK,0)<0) exit(0); /* can not lock */ + /* first instance continues */ + sprintf(str,"%d\n",getpid()); + write(lfp,str,strlen(str)); /* record pid to lockfile */ + signal(SIGCHLD,SIG_IGN); /* ignore child */ + signal(SIGTSTP,SIG_IGN); /* ignore tty signals */ + signal(SIGTTOU,SIG_IGN); + signal(SIGTTIN,SIG_IGN); + signal(SIGHUP,signal_handler); /* catch hangup signal */ + signal(SIGTERM,signal_handler); /* catch kill signal */ +} + +main() +{ + daemonize(); + while(1) sleep(1); /* run */ +} + +/* EOF */ + +</pre> + +<p> </p> +<p>Last Update : 16.05.2001</p> +<p> </p> + + + </td> + </tr> +</tbody></table><br> + +</div> + + +</body></html>
\ No newline at end of file |