2 * For license terms, see the file COPYING in this directory.
6 /***********************************************************************
9 programmer: Carl Harris, ceharris@mal.com
10 description: This module contains all of the code needed to
11 turn a process into a daemon for POSIX, SysV, and
14 ***********************************************************************/
20 #include <sys/types.h>
25 #if defined(HAVE_SYS_WAIT_H)
26 # include <sys/wait.h>
29 #if defined(HAVE_UNISTD_H)
37 /* BSD portability hack */
38 #if !defined(SIGCLD) && defined(SIGCHLD)
39 #define SIGCLD SIGCHLD
42 #include "fetchmail.h"
44 /******************************************************************
45 function: sigchld_handler
46 description: Process the SIGCHLD (a.k.a SIGCLD) signal by calling
47 a wait() variant to obtain the exit code of the
50 ret. value: none (or undefined if REGSIGTYPE is int).
53 *****************************************************************/
60 #if defined(HAVE_UNION_WAIT)
66 #if defined(HAVE_WAIT3)
67 while ((pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0)
68 ; /* swallow 'em up. */
69 #elif defined(HAVE_WAITPID)
70 while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
71 ; /* swallow 'em up. */
72 #else /* Zooks! Nothing to do but wait(), and hope we don't block... */
80 /******************************************************************
82 description: become a daemon process; i.e. detach from the
83 control terminal, don't reacquire a control terminal,
84 become process group leader of our own process group,
85 and set up to catch child process termination signals.
87 logfile file to direct stdout and stderr to, if non-NULL.
90 globals: termhook, sigchld_handler().
92 *****************************************************************/
95 daemonize (logfile, termhook)
97 void (*termhook)(int);
101 RETSIGTYPE sigchld_handler();
103 /* if we are started by init (process 1) via /etc/inittab we needn't
104 bother to detach from our process group context */
109 /* Ignore BSD terminal stop signals */
111 signal(SIGTTOU, SIG_IGN);
114 signal(SIGTTIN, SIG_IGN);
117 signal(SIGTSTP, SIG_IGN);
120 /* In case we were not started in the background, fork and let
121 the parent exit. Guarantees that the child is not a process
124 if ((childpid = fork()) < 0) {
128 else if (childpid > 0)
129 exit(0); /* parent */
132 /* Make ourselves the leader of a new process group with no
133 controlling terminal */
135 #if defined(HAVE_SETSID) /* POSIX */
136 /* POSIX makes this soooo easy to do */
141 #elif defined(SIGTSTP) /* BSD */
142 /* change process group */
143 setpgrp(0, getpid());
145 /* lose controlling tty */
146 if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
147 ioctl(fd, TIOCNOTTY, (char *) 0);
150 #else /* SVR3 and older */
151 /* change process group */
154 /* lose controlling tty */
155 signal(SIGHUP, SIG_IGN);
156 if ((childpid = fork) < 0) {
160 else if (childpid > 0) {
161 exit(0); /* parent */
167 /* Close any/all open file descriptors */
168 #if defined(HAVE_GETDTABLESIZE)
169 for (fd = getdtablesize()-1; fd >= 0; fd--)
170 #elif defined(NOFILE)
171 for (fd = NOFILE-1; fd >= 0; fd--)
172 #else /* make an educated guess */
173 for (fd = 19; fd >= 0; fd--)
179 /* Reopen stdin descriptor on /dev/null */
180 if ((fd = open("/dev/null", O_RDWR)) < 0) { /* stdin */
181 perror("open: /dev/null");
186 fd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0777); /* stdout */
188 if (dup(fd) < 0) { /* stdout */
192 if (dup(fd) < 0) { /* stderr */
197 /* move to root directory, so we don't prevent filesystem unmounts */
200 /* set our umask to something reasonable (we hope) */
201 #if defined(DEF_UMASK)
207 /* set up to catch child process termination signals */
208 signal(SIGCLD, sigchld_handler);
210 signal(SIGPWR, sigchld_handler);