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