]> Pileus Git - ~andy/fetchmail/blob - daemon.c
Initial revision
[~andy/fetchmail] / daemon.c
1 /* Copyright 1993-95 by Carl Harris, Jr.
2  * All rights reserved
3  *
4  * Distribute freely, except: don't remove my name from the source or
5  * documentation (don't take credit for my work), mark your changes (don't
6  * get me blamed for your possible bugs), don't alter or remove this
7  * notice.  May be sold if buildable source is provided to buyer.  No
8  * warrantee of any kind, express or implied, is included with this
9  * software; use at your own risk, responsibility for damages (if any) to
10  * anyone resulting from the use of this software rests entirely with the
11  * user.
12  *
13  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
14  * I'll try to keep a version up to date.  I can be reached as follows:
15  * Carl Harris <ceharris@mal.com>
16  */
17
18
19 /***********************************************************************
20   module:       daemon
21   project:      popclient
22   programmer:   Carl Harris, ceharris@mal.com
23   description:  This module contains all of the code needed to 
24                 turn a process into a daemon for POSIX, SysV, and
25                 BSD systems.
26
27   $Log: daemon.c,v $
28   Revision 1.1  1996/06/25 14:32:01  esr
29   Initial revision
30
31   Revision 1.1  1995/08/14 18:36:38  ceharris
32   Patches to support POP3's LAST command.
33   Final revisions for beta3 release.
34
35  ***********************************************************************/
36
37
38 #include <config.h>
39
40 #include <stdio.h>
41 #include <sys/types.h>
42 #include <sys/file.h>
43 #include <signal.h>
44 #include <fcntl.h>
45
46 #if defined(HAVE_SYS_WAIT_H)
47 #  include <sys/wait.h>
48 #endif
49
50 #if defined(HAVE_UNISTD_H)
51 #  include <unistd.h>
52 #endif
53
54
55 #include "popclient.h"
56
57
58 /******************************************************************
59   function:     sigchld_handler
60   description:  Process the SIGCHLD (a.k.a SIGCLD) signal by calling
61                 a wait() variant to obtain the exit code of the 
62                 terminating process.
63   arguments:    none.
64   ret. value:   none (or undefined if REGSIGTYPE is int).
65   globals:      none.
66   calls:        none.
67  *****************************************************************/
68
69 RETSIGTYPE
70 sigchld_handler ()
71 {
72   pid_t pid;
73
74 #if defined(HAVE_UNION_WAIT)
75   union wait status;
76 #else
77   int status;
78 #endif
79
80 #if     defined(HAVE_WAIT3)
81   while ((pid = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0)
82     ; /* swallow 'em up. */
83 #elif   defined(HAVE_WAITPID)
84   while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
85     ; /* swallow 'em up. */
86 #else   /* Zooks! Nothing to do but wait(), and hope we don't block... */
87   wait(&status);
88 #endif
89
90 }
91
92
93
94 /******************************************************************
95   function:     daemonize
96   description:  become a daemon process; i.e. detach from the 
97                 control terminal, don't reacquire a control terminal,
98                 become process group leader of our own process group,
99                 and set up to catch child process termination signals.
100   arguments:
101     options     command-line options.
102
103   ret. value:   none.
104   globals:      refers to the address of sigchld_handler().
105   calls:        none.
106  *****************************************************************/
107
108 int
109 daemonize (options)
110 struct optrec *options;
111 {
112   int fd;
113   pid_t childpid;
114   RETSIGTYPE sigchild_handler();
115
116   /* if we are started by init (process 1) via /etc/inittab we needn't 
117      bother to detach from our process group context */
118
119   if (getppid() == 1) 
120     goto nottyDetach;
121
122   /* Ignore BSD terminal stop signals */
123 #ifdef  SIGTTOU
124   signal(SIGTTOU, SIG_IGN);
125 #endif
126 #ifdef  SIGTTIN
127   signal(SIGTTIN, SIG_IGN);
128 #endif
129 #ifdef  SIGTSTP
130   signal(SIGTSTP, SIG_IGN);
131 #endif
132
133   /* In case we were not started in the background, fork and let
134      the parent exit.  Guarantees that the child is not a process
135      group leader */
136
137   if ((childpid = fork()) < 0) {
138     perror("fork");
139     return(PS_IOERR);
140   }
141   else if (childpid > 0) 
142     exit(0);  /* parent */
143
144   
145   /* Make ourselves the leader of a new process group with no
146      controlling terminal */
147
148 #if     defined(HAVE_SETSID)            /* POSIX */
149   /* POSIX makes this soooo easy to do */
150   if (setsid() < 0) {
151     perror("setsid");
152     return(PS_IOERR);
153   }
154 #elif   defined(SIGTSTP)                /* BSD */
155   /* change process group */
156   setpgrp(0, getpid());
157
158   /* lose controlling tty */
159   if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
160     ioctl(fd, TIOCNOTTY, (char *) 0);
161     close(fd);
162   }
163 #else                                   /* SVR3 and older */
164   /* change process group */
165   setpgrp();
166   
167   /* lose controlling tty */
168   signal(SIGHUP, SIG_IGN);
169   if ((childpid = fork) < 0) {
170     perror("fork");
171     return(PS_IOERR);
172   }
173   else if (childpid > 0) {
174     exit(0);    /* parent */
175   }
176 #endif
177
178 nottyDetach:
179
180   /* Close any/all open file descriptors */
181 #if     defined(HAVE_GETDTABLESIZE)
182   for (fd = getdtablesize()-1;  fd >= 0;  fd--)
183 #elif   defined(NOFILE)
184   for (fd = NOFILE-1;  fd >= 0;  fd--)
185 #else           /* make an educated guess */
186   for (fd = 19;  fd >= 0;  fd--)
187 #endif
188   {
189     close(fd);
190   }
191
192   /* Reopen stdin descriptor on /dev/null */
193   if ((fd = open("/dev/null", O_RDWR)) < 0) {   /* stdin */
194     perror("open: /dev/null");
195     return(PS_IOERR);
196   }
197
198
199   if (dup(fd) < 0) {                            /* stdout */
200     log_perror("dup");
201     return(PS_IOERR);
202   }
203   if (dup(fd) < 0) {                            /* stderr */
204     log_perror("dup");
205     return(PS_IOERR);
206   }
207
208   /* move to root directory, so we don't prevent filesystem unmounts */
209   chdir("/");
210
211   /* set our umask to something reasonable (we hope) */
212 #if defined(DEF_UMASK)
213   umask(DEF_UMASK);
214 #else
215   umask(022);
216 #endif
217
218   /* set up to catch child process termination signals */ 
219   signal(SIGCLD, sigchild_handler); 
220
221 }