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