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