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