]> Pileus Git - ~andy/fetchmail/blob - daemon.c
Changed copyrights, they're now by reference.
[~andy/fetchmail] / daemon.c
1 /*
2  * For license terms, see the file COPYING in this directory.
3  */
4
5
6 /***********************************************************************
7   module:       daemon
8   project:      fetchmail
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
12                 BSD systems.
13
14  ***********************************************************************/
15
16
17 #include <config.h>
18
19 #include <stdio.h>
20 #include <sys/types.h>
21 #include <sys/file.h>
22 #include <signal.h>
23 #include <fcntl.h>
24
25 #if defined(HAVE_SYS_WAIT_H)
26 #  include <sys/wait.h>
27 #endif
28
29 #if defined(HAVE_UNISTD_H)
30 #  include <unistd.h>
31 #endif
32
33 #if defined(QNX)
34 #  include <unix.h>
35 #endif
36
37 /* BSD portability hack */
38 #if !defined(SIGCLD) && defined(SIGCHLD)
39 #define SIGCLD  SIGCHLD
40 #endif
41
42 #include "fetchmail.h"
43
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 
48                 terminating process.
49   arguments:    none.
50   ret. value:   none (or undefined if REGSIGTYPE is int).
51   globals:      none.
52   calls:        none.
53  *****************************************************************/
54
55 RETSIGTYPE
56 sigchld_handler ()
57 {
58   pid_t pid;
59
60 #if defined(HAVE_UNION_WAIT)
61   union wait status;
62 #else
63   int status;
64 #endif
65
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... */
73   wait(&status);
74 #endif
75
76 }
77
78
79
80 /******************************************************************
81   function:     daemonize
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.
86   arguments:
87     logfile     file to direct stdout and stderr to, if non-NULL.
88
89   ret. value:   none.
90   globals:      termhook, sigchld_handler().
91   calls:        none.
92  *****************************************************************/
93
94 int
95 daemonize (logfile, termhook)
96 const char *logfile;
97 void (*termhook)(int);
98 {
99   int fd;
100   pid_t childpid;
101   RETSIGTYPE sigchld_handler();
102
103   /* if we are started by init (process 1) via /etc/inittab we needn't 
104      bother to detach from our process group context */
105
106   if (getppid() == 1) 
107     goto nottyDetach;
108
109   /* Ignore BSD terminal stop signals */
110 #ifdef  SIGTTOU
111   signal(SIGTTOU, SIG_IGN);
112 #endif
113 #ifdef  SIGTTIN
114   signal(SIGTTIN, SIG_IGN);
115 #endif
116 #ifdef  SIGTSTP
117   signal(SIGTSTP, SIG_IGN);
118 #endif
119
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
122      group leader */
123
124   if ((childpid = fork()) < 0) {
125     perror("fork");
126     return(PS_IOERR);
127   }
128   else if (childpid > 0) 
129     exit(0);  /* parent */
130
131   
132   /* Make ourselves the leader of a new process group with no
133      controlling terminal */
134
135 #if     defined(HAVE_SETSID)            /* POSIX */
136   /* POSIX makes this soooo easy to do */
137   if (setsid() < 0) {
138     perror("setsid");
139     return(PS_IOERR);
140   }
141 #elif   defined(SIGTSTP)                /* BSD */
142   /* change process group */
143   setpgrp(0, getpid());
144
145   /* lose controlling tty */
146   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
147     ioctl(fd, TIOCNOTTY, (char *) 0);
148     close(fd);
149   }
150 #else                                   /* SVR3 and older */
151   /* change process group */
152   setpgrp();
153   
154   /* lose controlling tty */
155   signal(SIGHUP, SIG_IGN);
156   if ((childpid = fork) < 0) {
157     perror("fork");
158     return(PS_IOERR);
159   }
160   else if (childpid > 0) {
161     exit(0);    /* parent */
162   }
163 #endif
164
165 nottyDetach:
166
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--)
174 #endif
175   {
176     close(fd);
177   }
178
179   /* Reopen stdin descriptor on /dev/null */
180   if ((fd = open("/dev/null", O_RDWR)) < 0) {   /* stdin */
181     perror("open: /dev/null");
182     return(PS_IOERR);
183   }
184
185   if (logfile)
186     fd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0777);        /* stdout */
187   else
188     if (dup(fd) < 0) {                          /* stdout */
189       perror("dup");
190       return(PS_IOERR);
191     }
192   if (dup(fd) < 0) {                            /* stderr */
193     perror("dup");
194     return(PS_IOERR);
195   }
196
197   /* move to root directory, so we don't prevent filesystem unmounts */
198   chdir("/");
199
200   /* set our umask to something reasonable (we hope) */
201 #if defined(DEF_UMASK)
202   umask(DEF_UMASK);
203 #else
204   umask(022);
205 #endif
206
207   /* set up to catch child process termination signals */ 
208   signal(SIGCLD, sigchld_handler); 
209 #if defined(QNX)
210   signal(SIGPWR, sigchld_handler); 
211 #endif
212 }