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