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