]> Pileus Git - ~andy/fetchmail/blob - daemon.c
b08f31e97a765891d70b1cb00be2b110dbadd22f
[~andy/fetchmail] / daemon.c
1 /* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond
2  * All rights reserved.
3  * For license terms, see the file COPYING in this directory.
4  */
5
6
7 /***********************************************************************
8   module:       daemon
9   project:      popclient
10   programmer:   Carl Harris, ceharris@mal.com
11   description:  This module contains all of the code needed to 
12                 turn a process into a daemon for POSIX, SysV, and
13                 BSD systems.
14
15  ***********************************************************************/
16
17
18 #include <config.h>
19
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/file.h>
23 #include <signal.h>
24 #include <fcntl.h>
25
26 #if defined(HAVE_SYS_WAIT_H)
27 #  include <sys/wait.h>
28 #endif
29
30 #if defined(HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif
33
34 #if defined(QNX)
35 #  include <unix.h>
36 #endif
37
38 /* BSD portability hack */
39 #if !defined(SIGCLD) && defined(SIGCHLD)
40 #define SIGCLD  SIGCHLD
41 #endif
42
43 #include "popclient.h"
44
45 /******************************************************************
46   function:     sigchld_handler
47   description:  Process the SIGCHLD (a.k.a SIGCLD) signal by calling
48                 a wait() variant to obtain the exit code of the 
49                 terminating process.
50   arguments:    none.
51   ret. value:   none (or undefined if REGSIGTYPE is int).
52   globals:      none.
53   calls:        none.
54  *****************************************************************/
55
56 RETSIGTYPE
57 sigchld_handler ()
58 {
59   pid_t pid;
60
61 #if defined(HAVE_UNION_WAIT)
62   union wait status;
63 #else
64   int status;
65 #endif
66
67 #if     defined(HAVE_WAIT3)
68   while ((pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0)
69     ; /* swallow 'em up. */
70 #elif   defined(HAVE_WAITPID)
71   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
72     ; /* swallow 'em up. */
73 #else   /* Zooks! Nothing to do but wait(), and hope we don't block... */
74   wait(&status);
75 #endif
76
77 }
78
79
80
81 /******************************************************************
82   function:     daemonize
83   description:  become a daemon process; i.e. detach from the 
84                 control terminal, don't reacquire a control terminal,
85                 become process group leader of our own process group,
86                 and set up to catch child process termination signals.
87   arguments:
88     logfile     file to direct stdout and stderr to, if non-NULL.
89
90   ret. value:   none.
91   globals:      termhook, sigchld_handler().
92   calls:        none.
93  *****************************************************************/
94
95 int
96 daemonize (logfile, termhook)
97 const char *logfile;
98 void (*termhook)(int);
99 {
100   int fd;
101   pid_t childpid;
102   RETSIGTYPE sigchld_handler();
103
104   /* if we are started by init (process 1) via /etc/inittab we needn't 
105      bother to detach from our process group context */
106
107   if (getppid() == 1) 
108     goto nottyDetach;
109
110   /* Ignore BSD terminal stop signals */
111 #ifdef  SIGTTOU
112   signal(SIGTTOU, SIG_IGN);
113 #endif
114 #ifdef  SIGTTIN
115   signal(SIGTTIN, SIG_IGN);
116 #endif
117 #ifdef  SIGTSTP
118   signal(SIGTSTP, SIG_IGN);
119 #endif
120
121   /* In case we were not started in the background, fork and let
122      the parent exit.  Guarantees that the child is not a process
123      group leader */
124
125   if ((childpid = fork()) < 0) {
126     perror("fork");
127     return(PS_IOERR);
128   }
129   else if (childpid > 0) 
130     exit(0);  /* parent */
131
132   
133   /* Make ourselves the leader of a new process group with no
134      controlling terminal */
135
136 #if     defined(HAVE_SETSID)            /* POSIX */
137   /* POSIX makes this soooo easy to do */
138   if (setsid() < 0) {
139     perror("setsid");
140     return(PS_IOERR);
141   }
142 #elif   defined(SIGTSTP)                /* BSD */
143   /* change process group */
144   setpgrp(0, getpid());
145
146   /* lose controlling tty */
147   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
148     ioctl(fd, TIOCNOTTY, (char *) 0);
149     close(fd);
150   }
151 #else                                   /* SVR3 and older */
152   /* change process group */
153   setpgrp();
154   
155   /* lose controlling tty */
156   signal(SIGHUP, SIG_IGN);
157   if ((childpid = fork) < 0) {
158     perror("fork");
159     return(PS_IOERR);
160   }
161   else if (childpid > 0) {
162     exit(0);    /* parent */
163   }
164 #endif
165
166 nottyDetach:
167
168   /* Close any/all open file descriptors */
169 #if     defined(HAVE_GETDTABLESIZE)
170   for (fd = getdtablesize()-1;  fd >= 0;  fd--)
171 #elif   defined(NOFILE)
172   for (fd = NOFILE-1;  fd >= 0;  fd--)
173 #else           /* make an educated guess */
174   for (fd = 19;  fd >= 0;  fd--)
175 #endif
176   {
177     close(fd);
178   }
179
180   /* Reopen stdin descriptor on /dev/null */
181   if ((fd = open("/dev/null", O_RDWR)) < 0) {   /* stdin */
182     perror("open: /dev/null");
183     return(PS_IOERR);
184   }
185
186   if (logfile)
187     fd = open(logfile, O_CREAT|O_WRONLY, 0777); /* stdout */
188   else
189     if (dup(fd) < 0) {                          /* stdout */
190       perror("dup");
191       return(PS_IOERR);
192     }
193   if (dup(fd) < 0) {                            /* stderr */
194     perror("dup");
195     return(PS_IOERR);
196   }
197
198   /* move to root directory, so we don't prevent filesystem unmounts */
199   chdir("/");
200
201   /* set our umask to something reasonable (we hope) */
202 #if defined(DEF_UMASK)
203   umask(DEF_UMASK);
204 #else
205   umask(022);
206 #endif
207
208   /* set up to catch child process termination signals */ 
209   signal(SIGCLD, sigchld_handler); 
210 #if defined(QNX)
211   signal(SIGPWR, sigchld_handler); 
212 #endif
213 }