]> Pileus Git - ~andy/fetchmail/blob - daemon.c
Licensing and copyright changes pursuant to Carl Harris handing me the
[~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
35 #include "popclient.h"
36
37 static void (*my_termhook)(void);
38
39 /******************************************************************
40   function:     sigchld_handler
41   description:  Process the SIGCHLD (a.k.a SIGCLD) signal by calling
42                 a wait() variant to obtain the exit code of the 
43                 terminating process.
44   arguments:    none.
45   ret. value:   none (or undefined if REGSIGTYPE is int).
46   globals:      none.
47   calls:        none.
48  *****************************************************************/
49
50 RETSIGTYPE
51 sigchld_handler ()
52 {
53   pid_t pid;
54
55 #if defined(HAVE_UNION_WAIT)
56   union wait status;
57 #else
58   int status;
59 #endif
60
61   if (my_termhook)
62       (*my_termhook)();
63
64 #if     defined(HAVE_WAIT3)
65   while ((pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0)
66     ; /* swallow 'em up. */
67 #elif   defined(HAVE_WAITPID)
68   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
69     ; /* swallow 'em up. */
70 #else   /* Zooks! Nothing to do but wait(), and hope we don't block... */
71   wait(&status);
72 #endif
73
74 }
75
76
77
78 /******************************************************************
79   function:     daemonize
80   description:  become a daemon process; i.e. detach from the 
81                 control terminal, don't reacquire a control terminal,
82                 become process group leader of our own process group,
83                 and set up to catch child process termination signals.
84   arguments:
85     logfile     file to direct stdout and stderr to, if non-NULL.
86
87   ret. value:   none.
88   globals:      refers to the address of sigchld_handler().
89   calls:        none.
90  *****************************************************************/
91
92 int
93 daemonize (logfile, termhook)
94 const char *logfile;
95 void (*termhook)(void);
96 {
97   int fd;
98   pid_t childpid;
99   RETSIGTYPE sigchld_handler();
100
101   /* if we are started by init (process 1) via /etc/inittab we needn't 
102      bother to detach from our process group context */
103
104   my_termhook = termhook;
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     open(logfile, O_CREAT|O_WRONLY, 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
210 }