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