]> Pileus Git - ~andy/fetchmail/blob - daemon.c
Fix the illegal-terminal problem.
[~andy/fetchmail] / daemon.c
1 /* Copyright 1993-95 by Carl Harris, Jr. Copyright 1996 by Eric S. Raymond
2  * All rights reserved.
3  * For license terms, see the file COPYING in this directory.
4  */
5
6
7 /***********************************************************************
8   module:       daemon
9   project:      popclient
10   programmer:   Carl Harris, ceharris@mal.com
11   description:  This module contains all of the code needed to 
12                 turn a process into a daemon for POSIX, SysV, and
13                 BSD systems.
14
15  ***********************************************************************/
16
17
18 #include <config.h>
19
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <sys/file.h>
23 #include <signal.h>
24 #include <fcntl.h>
25
26 #if defined(HAVE_SYS_WAIT_H)
27 #  include <sys/wait.h>
28 #endif
29
30 #if defined(HAVE_UNISTD_H)
31 #  include <unistd.h>
32 #endif
33
34
35 #include "popclient.h"
36
37 /******************************************************************
38   function:     sigchld_handler
39   description:  Process the SIGCHLD (a.k.a SIGCLD) signal by calling
40                 a wait() variant to obtain the exit code of the 
41                 terminating process.
42   arguments:    none.
43   ret. value:   none (or undefined if REGSIGTYPE is int).
44   globals:      none.
45   calls:        none.
46  *****************************************************************/
47
48 RETSIGTYPE
49 sigchld_handler ()
50 {
51   pid_t pid;
52
53 #if defined(HAVE_UNION_WAIT)
54   union wait status;
55 #else
56   int status;
57 #endif
58
59 #if     defined(HAVE_WAIT3)
60   while ((pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0)
61     ; /* swallow 'em up. */
62 #elif   defined(HAVE_WAITPID)
63   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
64     ; /* swallow 'em up. */
65 #else   /* Zooks! Nothing to do but wait(), and hope we don't block... */
66   wait(&status);
67 #endif
68
69 }
70
71
72
73 /******************************************************************
74   function:     daemonize
75   description:  become a daemon process; i.e. detach from the 
76                 control terminal, don't reacquire a control terminal,
77                 become process group leader of our own process group,
78                 and set up to catch child process termination signals.
79   arguments:
80     logfile     file to direct stdout and stderr to, if non-NULL.
81
82   ret. value:   none.
83   globals:      termhook, sigchld_handler().
84   calls:        none.
85  *****************************************************************/
86
87 int
88 daemonize (logfile, termhook)
89 const char *logfile;
90 void (*termhook)(int);
91 {
92   int fd;
93   pid_t childpid;
94   RETSIGTYPE sigchld_handler();
95
96   /* if we are started by init (process 1) via /etc/inittab we needn't 
97      bother to detach from our process group context */
98
99   if (getppid() == 1) 
100     goto nottyDetach;
101
102   /* Ignore BSD terminal stop signals */
103 #ifdef  SIGTTOU
104   signal(SIGTTOU, SIG_IGN);
105 #endif
106 #ifdef  SIGTTIN
107   signal(SIGTTIN, SIG_IGN);
108 #endif
109 #ifdef  SIGTSTP
110   signal(SIGTSTP, SIG_IGN);
111 #endif
112
113   /* In case we were not started in the background, fork and let
114      the parent exit.  Guarantees that the child is not a process
115      group leader */
116
117   if ((childpid = fork()) < 0) {
118     perror("fork");
119     return(PS_IOERR);
120   }
121   else if (childpid > 0) 
122     exit(0);  /* parent */
123
124   
125   /* Make ourselves the leader of a new process group with no
126      controlling terminal */
127
128 #if     defined(HAVE_SETSID)            /* POSIX */
129   /* POSIX makes this soooo easy to do */
130   if (setsid() < 0) {
131     perror("setsid");
132     return(PS_IOERR);
133   }
134 #elif   defined(SIGTSTP)                /* BSD */
135   /* change process group */
136   setpgrp(0, getpid());
137
138   /* lose controlling tty */
139   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
140     ioctl(fd, TIOCNOTTY, (char *) 0);
141     close(fd);
142   }
143 #else                                   /* SVR3 and older */
144   /* change process group */
145   setpgrp();
146   
147   /* lose controlling tty */
148   signal(SIGHUP, SIG_IGN);
149   if ((childpid = fork) < 0) {
150     perror("fork");
151     return(PS_IOERR);
152   }
153   else if (childpid > 0) {
154     exit(0);    /* parent */
155   }
156 #endif
157
158 nottyDetach:
159
160   /* Close any/all open file descriptors */
161 #if     defined(HAVE_GETDTABLESIZE)
162   for (fd = getdtablesize()-1;  fd >= 0;  fd--)
163 #elif   defined(NOFILE)
164   for (fd = NOFILE-1;  fd >= 0;  fd--)
165 #else           /* make an educated guess */
166   for (fd = 19;  fd >= 0;  fd--)
167 #endif
168   {
169     close(fd);
170   }
171
172   /* Reopen stdin descriptor on /dev/null */
173   if ((fd = open("/dev/null", O_RDWR)) < 0) {   /* stdin */
174     perror("open: /dev/null");
175     return(PS_IOERR);
176   }
177
178   if (logfile)
179     fd = open(logfile, O_CREAT|O_WRONLY, 0777); /* stdout */
180   else
181     if (dup(fd) < 0) {                          /* stdout */
182       perror("dup");
183       return(PS_IOERR);
184     }
185   if (dup(fd) < 0) {                            /* stderr */
186     perror("dup");
187     return(PS_IOERR);
188   }
189
190   /* move to root directory, so we don't prevent filesystem unmounts */
191   chdir("/");
192
193   /* set our umask to something reasonable (we hope) */
194 #if defined(DEF_UMASK)
195   umask(DEF_UMASK);
196 #else
197   umask(022);
198 #endif
199
200   /* set up to catch child process termination signals */ 
201   signal(SIGCLD, sigchld_handler); 
202
203 }