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