Most daemon will share the same code to daemonize(), we use
a generic one, lib/daemon.c, so any bug fix will impact the others and reduce maintainance/duplication. * lib/Makefile.am: Addition daemon.c * lib/daemon.c: New file. * pop3d/pop3d.c (pop3d_daemon_init): Use lib/daemon.c:daemon() code instead. * imap4d/imap4d.c (imap4d_daemon_init): Use lib/daemon.c:daemon code instead. * comstat/comstat.c (comstat_daemon_init): Use lib/daemon.c:daemon code instead. Remove trailing spaces.
Showing
6 changed files
with
254 additions
and
132 deletions
1 | 2001-11-11 Alain Magloire | ||
2 | |||
3 | Most daemon will share the same code to daemonize(), we use | ||
4 | a generic one, lib/daemon.c, so any bug fix will impact the | ||
5 | others and reduce maintainance/duplication. | ||
6 | |||
7 | * lib/Makefile.am: Addition daemon.c | ||
8 | * lib/daemon.c: New file. | ||
9 | * pop3d/pop3d.c (pop3d_daemon_init): Use lib/daemon.c:daemon() code | ||
10 | instead. | ||
11 | * imap4d/imap4d.c (imap4d_daemon_init): Use lib/daemon.c:daemon code | ||
12 | instead. | ||
13 | * comstat/comstat.c (comstat_daemon_init): Use lib/daemon.c:daemon code | ||
14 | instead. Remove trailing spaces. | ||
15 | |||
1 | 2001-11-11 Sergey Poznyakoff | 16 | 2001-11-11 Sergey Poznyakoff |
2 | 17 | ||
3 | * comsat/action.c: (new) User-defined actions for comsat. | 18 | * comsat/action.c: (new) User-defined actions for comsat. | ... | ... |
... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
21 | 21 | ||
22 | #ifndef PATH_DEV | 22 | #ifndef PATH_DEV |
23 | # define PATH_DEV "/dev" | 23 | # define PATH_DEV "/dev" |
24 | #endif | 24 | #endif |
25 | #ifndef PATH_TTY_PFX | 25 | #ifndef PATH_TTY_PFX |
26 | # define PATH_TTY_PFX PATH_DEV | 26 | # define PATH_TTY_PFX PATH_DEV |
27 | #endif | 27 | #endif |
... | @@ -96,7 +96,7 @@ main(int argc, char **argv) | ... | @@ -96,7 +96,7 @@ main(int argc, char **argv) |
96 | { | 96 | { |
97 | int c; | 97 | int c; |
98 | char *config_file = NULL; | 98 | char *config_file = NULL; |
99 | 99 | ||
100 | while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) | 100 | while ((c = getopt_long (argc, argv, short_options, long_options, NULL)) |
101 | != -1) | 101 | != -1) |
102 | { | 102 | { |
... | @@ -171,7 +171,7 @@ sig_hup (int sig) | ... | @@ -171,7 +171,7 @@ sig_hup (int sig) |
171 | syslog (LOG_ERR, "can't restart: not started with absolute pathname"); | 171 | syslog (LOG_ERR, "can't restart: not started with absolute pathname"); |
172 | else | 172 | else |
173 | execvp (xargv[0], xargv); | 173 | execvp (xargv[0], xargv); |
174 | 174 | ||
175 | signal (sig, sig_hup); | 175 | signal (sig, sig_hup); |
176 | } | 176 | } |
177 | 177 | ||
... | @@ -185,7 +185,7 @@ comsat_init () | ... | @@ -185,7 +185,7 @@ comsat_init () |
185 | list_append (bookie, path_record); | 185 | list_append (bookie, path_record); |
186 | 186 | ||
187 | gethostname (hostname, sizeof hostname); | 187 | gethostname (hostname, sizeof hostname); |
188 | 188 | ||
189 | /* Set signal handlers */ | 189 | /* Set signal handlers */ |
190 | signal (SIGTTOU, SIG_IGN); | 190 | signal (SIGTTOU, SIG_IGN); |
191 | signal (SIGCHLD, SIG_IGN); | 191 | signal (SIGCHLD, SIG_IGN); |
... | @@ -196,46 +196,15 @@ comsat_init () | ... | @@ -196,46 +196,15 @@ comsat_init () |
196 | static void | 196 | static void |
197 | comsat_daemon_init (void) | 197 | comsat_daemon_init (void) |
198 | { | 198 | { |
199 | pid_t pid; | 199 | extern int daemon (int, int); |
200 | |||
201 | pid = fork (); | ||
202 | if (pid == -1) | ||
203 | { | ||
204 | perror ("fork failed:"); | ||
205 | exit (EXIT_FAILURE); | ||
206 | } | ||
207 | else if (pid > 0) | ||
208 | exit (EXIT_SUCCESS); /* Parent exits. */ | ||
209 | |||
210 | /* Child: */ | ||
211 | signal (SIGHUP, sig_hup); | ||
212 | 200 | ||
213 | setsid (); /* Become session leader. */ | 201 | /* Become a daemon. Take care to close inherited fds and to hold |
214 | 202 | first three one, in, out, err. Do not do the chdir("/"). */ | |
215 | /* The second fork is to guarantee that the daemon cannot acquire a | 203 | if (daemon (1, 0) < 0) |
216 | controlling terminal. */ | ||
217 | pid = fork (); | ||
218 | if (pid == -1) | ||
219 | { | 204 | { |
220 | perror("fork failed"); | 205 | perror ("failed to become a daemon:"); |
221 | exit (EXIT_FAILURE); | 206 | exit (EXIT_FAILURE); |
222 | } | 207 | } |
223 | else if (pid > 0) | ||
224 | exit (EXIT_SUCCESS); /* Parent exits. */ | ||
225 | |||
226 | /* Close inherited file descriptors. */ | ||
227 | { | ||
228 | size_t i, fdmax; | ||
229 | #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) | ||
230 | fdmax = sysconf(_SC_OPEN_MAX); | ||
231 | #elif defined(HAVE_GETDTABLESIZE) | ||
232 | fdmax = getdtablesize ();*/ | ||
233 | #else | ||
234 | fdmax = 64; | ||
235 | #endif | ||
236 | for (i = 0; i < fdmax; ++i) | ||
237 | close (i); | ||
238 | } | ||
239 | } | 208 | } |
240 | 209 | ||
241 | unsigned maxrequests = 16; /* Maximum number of request allowed per | 210 | unsigned maxrequests = 16; /* Maximum number of request allowed per |
... | @@ -256,14 +225,14 @@ comsat_daemon (int port) | ... | @@ -256,14 +225,14 @@ comsat_daemon (int port) |
256 | unsigned overflow_count = 0; /* Number of overflows achieved during | 225 | unsigned overflow_count = 0; /* Number of overflows achieved during |
257 | the current interval */ | 226 | the current interval */ |
258 | time_t now; | 227 | time_t now; |
259 | 228 | ||
260 | fd = socket (AF_INET, SOCK_DGRAM, 0); | 229 | fd = socket (AF_INET, SOCK_DGRAM, 0); |
261 | if (fd == -1) | 230 | if (fd == -1) |
262 | { | 231 | { |
263 | syslog (LOG_CRIT, "socket: %m"); | 232 | syslog (LOG_CRIT, "socket: %m"); |
264 | exit (1); | 233 | exit (1); |
265 | } | 234 | } |
266 | 235 | ||
267 | memset (&local_sin, 0, sizeof local_sin); | 236 | memset (&local_sin, 0, sizeof local_sin); |
268 | local_sin.sin_family = AF_INET; | 237 | local_sin.sin_family = AF_INET; |
269 | local_sin.sin_addr.s_addr = INADDR_ANY; /*FIXME*/ | 238 | local_sin.sin_addr.s_addr = INADDR_ANY; /*FIXME*/ |
... | @@ -276,13 +245,13 @@ comsat_daemon (int port) | ... | @@ -276,13 +245,13 @@ comsat_daemon (int port) |
276 | } | 245 | } |
277 | 246 | ||
278 | syslog (LOG_NOTICE, "GNU comsat started"); | 247 | syslog (LOG_NOTICE, "GNU comsat started"); |
279 | 248 | ||
280 | last_request_time = last_overflow_time = time (NULL); | 249 | last_request_time = last_overflow_time = time (NULL); |
281 | while (1) | 250 | while (1) |
282 | { | 251 | { |
283 | fd_set fdset; | 252 | fd_set fdset; |
284 | int rc; | 253 | int rc; |
285 | 254 | ||
286 | FD_ZERO (&fdset); | 255 | FD_ZERO (&fdset); |
287 | FD_SET (fd, &fdset); | 256 | FD_SET (fd, &fdset); |
288 | rc = select (fd+1, &fdset, NULL, NULL, NULL); | 257 | rc = select (fd+1, &fdset, NULL, NULL, NULL); |
... | @@ -316,7 +285,7 @@ comsat_daemon (int port) | ... | @@ -316,7 +285,7 @@ comsat_daemon (int port) |
316 | overflow_count = 0; | 285 | overflow_count = 0; |
317 | last_overflow_time = time (NULL); | 286 | last_overflow_time = time (NULL); |
318 | } | 287 | } |
319 | 288 | ||
320 | if (now - last_request_time <= request_control_interval) | 289 | if (now - last_request_time <= request_control_interval) |
321 | reqcount++; | 290 | reqcount++; |
322 | else | 291 | else |
... | @@ -341,7 +310,7 @@ comsat_main (int fd) | ... | @@ -341,7 +310,7 @@ comsat_main (int fd) |
341 | char *p, *endp; | 310 | char *p, *endp; |
342 | size_t offset; | 311 | size_t offset; |
343 | char *path = NULL; | 312 | char *path = NULL; |
344 | 313 | ||
345 | len = sizeof sin_from; | 314 | len = sizeof sin_from; |
346 | rdlen = recvfrom (fd, buffer, sizeof buffer, 0, | 315 | rdlen = recvfrom (fd, buffer, sizeof buffer, 0, |
347 | (struct sockaddr*)&sin_from, &len); | 316 | (struct sockaddr*)&sin_from, &len); |
... | @@ -359,9 +328,9 @@ comsat_main (int fd) | ... | @@ -359,9 +328,9 @@ comsat_main (int fd) |
359 | inet_ntoa (sin_from.sin_addr)); | 328 | inet_ntoa (sin_from.sin_addr)); |
360 | return 1; | 329 | return 1; |
361 | } | 330 | } |
362 | 331 | ||
363 | syslog (LOG_INFO, "%d bytes from %s", rdlen, inet_ntoa (sin_from.sin_addr)); | 332 | syslog (LOG_INFO, "%d bytes from %s", rdlen, inet_ntoa (sin_from.sin_addr)); |
364 | 333 | ||
365 | buffer[rdlen] = 0; | 334 | buffer[rdlen] = 0; |
366 | 335 | ||
367 | /* Parse the buffer */ | 336 | /* Parse the buffer */ |
... | @@ -399,7 +368,7 @@ comsat_main (int fd) | ... | @@ -399,7 +368,7 @@ comsat_main (int fd) |
399 | syslog (LOG_ERR, "fork: %m"); | 368 | syslog (LOG_ERR, "fork: %m"); |
400 | return 1; | 369 | return 1; |
401 | } | 370 | } |
402 | 371 | ||
403 | if (pid > 0) | 372 | if (pid > 0) |
404 | { | 373 | { |
405 | struct timeval tv; | 374 | struct timeval tv; |
... | @@ -408,7 +377,7 @@ comsat_main (int fd) | ... | @@ -408,7 +377,7 @@ comsat_main (int fd) |
408 | select (0, NULL, NULL, NULL, &tv); | 377 | select (0, NULL, NULL, NULL, &tv); |
409 | kill (pid, SIGKILL); /* Just in case the child is hung */ | 378 | kill (pid, SIGKILL); /* Just in case the child is hung */ |
410 | return 0; | 379 | return 0; |
411 | } | 380 | } |
412 | 381 | ||
413 | /* Child: do actual I/O */ | 382 | /* Child: do actual I/O */ |
414 | notify_user (buffer, tty, path, offset); | 383 | notify_user (buffer, tty, path, offset); |
... | @@ -420,7 +389,7 @@ get_newline_str (FILE *fp) | ... | @@ -420,7 +389,7 @@ get_newline_str (FILE *fp) |
420 | { | 389 | { |
421 | #if defined(OPOST) && defined(ONLCR) | 390 | #if defined(OPOST) && defined(ONLCR) |
422 | struct termios tbuf; | 391 | struct termios tbuf; |
423 | 392 | ||
424 | tcgetattr (fileno (fp), &tbuf); | 393 | tcgetattr (fileno (fp), &tbuf); |
425 | if ((tbuf.c_oflag & OPOST) && (tbuf.c_oflag & ONLCR)) | 394 | if ((tbuf.c_oflag & OPOST) && (tbuf.c_oflag & ONLCR)) |
426 | return "\n"; | 395 | return "\n"; |
... | @@ -484,7 +453,7 @@ notify_user (char *user, char *device, char *path, off_t offset) | ... | @@ -484,7 +453,7 @@ notify_user (char *user, char *device, char *path, off_t offset) |
484 | path, strerror (status)); | 453 | path, strerror (status)); |
485 | return; | 454 | return; |
486 | } | 455 | } |
487 | 456 | ||
488 | /* Read headers */ | 457 | /* Read headers */ |
489 | size -= offset; | 458 | size -= offset; |
490 | blurb = malloc (size + 1); | 459 | blurb = malloc (size + 1); |
... | @@ -514,7 +483,7 @@ notify_user (char *user, char *device, char *path, off_t offset) | ... | @@ -514,7 +483,7 @@ notify_user (char *user, char *device, char *path, off_t offset) |
514 | mailbox_set_stream (tmp, stream); | 483 | mailbox_set_stream (tmp, stream); |
515 | mailbox_messages_count (tmp, &count); | 484 | mailbox_messages_count (tmp, &count); |
516 | mailbox_get_message (tmp, 1, &msg); | 485 | mailbox_get_message (tmp, 1, &msg); |
517 | 486 | ||
518 | run_user_action (fp, cr, msg); | 487 | run_user_action (fp, cr, msg); |
519 | fclose (fp); | 488 | fclose (fp); |
520 | } | 489 | } |
... | @@ -624,7 +593,7 @@ mailbox_path (const char *user) | ... | @@ -624,7 +593,7 @@ mailbox_path (const char *user) |
624 | { | 593 | { |
625 | struct passwd *pw; | 594 | struct passwd *pw; |
626 | char *mailbox_name; | 595 | char *mailbox_name; |
627 | 596 | ||
628 | pw = mu_getpwnam (user); | 597 | pw = mu_getpwnam (user); |
629 | if (!pw) | 598 | if (!pw) |
630 | { | 599 | { |
... | @@ -638,7 +607,7 @@ mailbox_path (const char *user) | ... | @@ -638,7 +607,7 @@ mailbox_path (const char *user) |
638 | + strlen (pw->pw_name) + 1, 1); | 607 | + strlen (pw->pw_name) + 1, 1); |
639 | sprintf (mailbox_name, "%s/%s", _PATH_MAILDIR, pw->pw_name); | 608 | sprintf (mailbox_name, "%s/%s", _PATH_MAILDIR, pw->pw_name); |
640 | } | 609 | } |
641 | else | 610 | else |
642 | { | 611 | { |
643 | mailbox_name = calloc (strlen (pw->pw_dir) + strlen ("/INBOX"), 1); | 612 | mailbox_name = calloc (strlen (pw->pw_dir) + strlen ("/INBOX"), 1); |
644 | sprintf (mailbox_name, "%s/INBOX", pw->pw_dir); | 613 | sprintf (mailbox_name, "%s/INBOX", pw->pw_dir); | ... | ... |
... | @@ -102,7 +102,7 @@ main (int argc, char **argv) | ... | @@ -102,7 +102,7 @@ main (int argc, char **argv) |
102 | case 'S': | 102 | case 'S': |
103 | set_namespace (NS_SHARED, optarg); | 103 | set_namespace (NS_SHARED, optarg); |
104 | break; | 104 | break; |
105 | 105 | ||
106 | case 't': | 106 | case 't': |
107 | timeout = strtoul (optarg, NULL, 10); | 107 | timeout = strtoul (optarg, NULL, 10); |
108 | break; | 108 | break; |
... | @@ -145,7 +145,7 @@ main (int argc, char **argv) | ... | @@ -145,7 +145,7 @@ main (int argc, char **argv) |
145 | #ifdef USE_VIRTUAL_DOMAINS | 145 | #ifdef USE_VIRTUAL_DOMAINS |
146 | mu_register_getpwnam (getpwnam_virtual); | 146 | mu_register_getpwnam (getpwnam_virtual); |
147 | #endif | 147 | #endif |
148 | 148 | ||
149 | /* Set the signal handlers. */ | 149 | /* Set the signal handlers. */ |
150 | signal (SIGINT, imap4d_signal); | 150 | signal (SIGINT, imap4d_signal); |
151 | signal (SIGQUIT, imap4d_signal); | 151 | signal (SIGQUIT, imap4d_signal); |
... | @@ -161,9 +161,11 @@ main (int argc, char **argv) | ... | @@ -161,9 +161,11 @@ main (int argc, char **argv) |
161 | 161 | ||
162 | if (mode == DAEMON) | 162 | if (mode == DAEMON) |
163 | imap4d_daemon_init (); | 163 | imap4d_daemon_init (); |
164 | 164 | else | |
165 | /* Make sure we are in the root. */ | 165 | { |
166 | chdir ("/"); | 166 | /* Make sure we are in the root. */ |
167 | chdir ("/"); | ||
168 | } | ||
167 | 169 | ||
168 | /* Set up for syslog. */ | 170 | /* Set up for syslog. */ |
169 | openlog ("gnu-imap4d", LOG_PID, LOG_FACILITY); | 171 | openlog ("gnu-imap4d", LOG_PID, LOG_FACILITY); |
... | @@ -203,7 +205,7 @@ imap4d_mainloop (int infile, int outfile) | ... | @@ -203,7 +205,7 @@ imap4d_mainloop (int infile, int outfile) |
203 | imap4d_bye (ERR_NO_OFILE); | 205 | imap4d_bye (ERR_NO_OFILE); |
204 | 206 | ||
205 | setvbuf(ofile, NULL, _IOLBF, 0); | 207 | setvbuf(ofile, NULL, _IOLBF, 0); |
206 | 208 | ||
207 | syslog (LOG_INFO, "Incoming connection opened"); | 209 | syslog (LOG_INFO, "Incoming connection opened"); |
208 | 210 | ||
209 | /* log information on the connecting client */ | 211 | /* log information on the connecting client */ |
... | @@ -240,43 +242,15 @@ imap4d_mainloop (int infile, int outfile) | ... | @@ -240,43 +242,15 @@ imap4d_mainloop (int infile, int outfile) |
240 | static void | 242 | static void |
241 | imap4d_daemon_init (void) | 243 | imap4d_daemon_init (void) |
242 | { | 244 | { |
243 | pid_t pid; | 245 | extern int daemon (int, int); |
244 | 246 | ||
245 | pid = fork (); | 247 | /* Become a daemon. Take care to close inherited fds and to hold |
246 | if (pid == -1) | 248 | first three one, in, out, err */ |
247 | { | 249 | if (daemon (0, 0) < 0) |
248 | perror ("fork failed:"); | ||
249 | exit (1); | ||
250 | } | ||
251 | else if (pid > 0) | ||
252 | exit (0); /* Parent exits. */ | ||
253 | |||
254 | setsid (); /* Become session leader. */ | ||
255 | |||
256 | signal (SIGHUP, SIG_IGN); /* Ignore SIGHUP. */ | ||
257 | |||
258 | /* The second fork is to guarantee that the daemon cannot acquire a | ||
259 | controlling terminal. */ | ||
260 | pid = fork (); | ||
261 | if (pid == -1) | ||
262 | { | 250 | { |
263 | perror("fork failed:"); | 251 | perror("fork failed:"); |
264 | exit (1); | 252 | exit (1); |
265 | } | 253 | } |
266 | else if (pid > 0) | ||
267 | exit (0); /* Parent exits. */ | ||
268 | |||
269 | /* Close inherited file descriptors. */ | ||
270 | { | ||
271 | size_t i; | ||
272 | #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) | ||
273 | size_t fdlimit = sysconf(_SC_OPEN_MAX); | ||
274 | #else | ||
275 | size_t fdlimit = 64; | ||
276 | #endif | ||
277 | for (i = 0; i < fdlimit; ++i) | ||
278 | close (i); | ||
279 | } | ||
280 | 254 | ||
281 | /* SIGCHLD is not ignore but rather use to do some simple load balancing. */ | 255 | /* SIGCHLD is not ignore but rather use to do some simple load balancing. */ |
282 | #ifdef HAVE_SIGACTION | 256 | #ifdef HAVE_SIGACTION | ... | ... |
... | @@ -3,9 +3,9 @@ noinst_LIBRARIES = libmailutils.a | ... | @@ -3,9 +3,9 @@ noinst_LIBRARIES = libmailutils.a |
3 | 3 | ||
4 | SUBDIRS = posix | 4 | SUBDIRS = posix |
5 | 5 | ||
6 | INCLUDES = -I${top_srcdir}/include | 6 | INCLUDES = -I${top_srcdir}/include |
7 | libmailutils_a_SOURCES = basename.c getopt.c getopt1.c md5.c mu_dbm.c getline.c \ | 7 | libmailutils_a_SOURCES = basename.c daemon.c getopt.c getopt1.c md5.c \ |
8 | xstrdup.c xmalloc.c argcv.c | 8 | mu_dbm.c getline.c xstrdup.c xmalloc.c argcv.c |
9 | 9 | ||
10 | EXTRA_DIST = alloca.c fnmatch.c setenv.c snprintf.c strchrnul.c strndup.c \ | 10 | EXTRA_DIST = alloca.c fnmatch.c setenv.c snprintf.c strchrnul.c strndup.c \ |
11 | strnlen.c strtok_r.c strsignal.c xstrtol.c vasprintf.c malloc.c realloc.c \ | 11 | strnlen.c strtok_r.c strsignal.c xstrtol.c vasprintf.c malloc.c realloc.c \ | ... | ... |
lib/daemon.c
0 → 100644
1 | /*- | ||
2 | * Copyright (c) 1990, 1993 | ||
3 | * The Regents of the University of California. All rights reserved. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions | ||
7 | * are met: | ||
8 | * 1. Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * 2. Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * 4. Neither the name of the University nor the names of its contributors | ||
14 | * may be used to endorse or promote products derived from this software | ||
15 | * without specific prior written permission. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
27 | * SUCH DAMAGE. | ||
28 | */ | ||
29 | |||
30 | #include <config.h> | ||
31 | #include <fcntl.h> | ||
32 | #include <unistd.h> | ||
33 | #include <signal.h> | ||
34 | #include <sys/types.h> | ||
35 | #include <sys/wait.h> | ||
36 | |||
37 | #ifdef HAVE_PATHS_H | ||
38 | # include <paths.h> | ||
39 | #endif | ||
40 | |||
41 | #ifndef _PATH_DEVNULL | ||
42 | # define _PATH_DEVNULL "/dev/null" | ||
43 | #endif | ||
44 | |||
45 | /* | ||
46 | According to Unix-FAQ maintained by Andrew Gierth: | ||
47 | |||
48 | 1.fork() so the parent can exit, this returns control to the command | ||
49 | line or shell invoking your program. This step is required so that the | ||
50 | new process is guaranteed not to be a process group leader. The next | ||
51 | step, setsid(), fails if you're a process group leader. | ||
52 | |||
53 | 2.setsid() to become a process group and session group leader. Since a | ||
54 | controlling terminal is associated with a session, and this new session | ||
55 | has not yet acquired a controlling terminal our process now has no | ||
56 | controlling terminal, which is a Good Thing for daemons. | ||
57 | |||
58 | 3.fork() again so the parent, (the session group leader), can exit. This | ||
59 | means that we, as a non-session group leader, can never regain a | ||
60 | controlling terminal. | ||
61 | |||
62 | 4.chdir("/") to ensure that our process doesn't keep any directory in use. | ||
63 | Failure to do this could make it so that an administrator couldn't unmount | ||
64 | a filesystem, because it was our current directory. | ||
65 | [Equivalently, we could change to any directory containing files important | ||
66 | to the daemon's operation.] | ||
67 | |||
68 | 5.umask(0) so that we have complete control over the permissions of | ||
69 | anything we write. We don't know what umask we may have inherited. | ||
70 | [This step is optional] | ||
71 | |||
72 | 6.close() fds 0, 1, and 2. This releases the standard in, out, and error | ||
73 | we inherited from our parent process. We have no way of knowing where | ||
74 | these fds might have been redirected to. Note that many daemons use | ||
75 | sysconf() to determine the limit _SC_OPEN_MAX. _SC_OPEN_MAX tells you the | ||
76 | maximun open files/process. Then in a loop, the daemon can close all | ||
77 | possible file descriptors. You have to decide if you need to do this or not. | ||
78 | If you think that there might be file-descriptors open you should close | ||
79 | them, since there's a limit on number of concurrent file descriptors. | ||
80 | |||
81 | 7.Establish new open descriptors for stdin, stdout and stderr. Even if | ||
82 | you don't plan to use them, it is still a good idea to have them open. | ||
83 | The precise handling of these is a matter of taste; if you have a logfile, | ||
84 | for example, you might wish to open it as stdout or stderr, and open | ||
85 | `/dev/null' as stdin; alternatively, you could open `/dev/console' as | ||
86 | stderr and/or stdout, and `/dev/null' as stdin, or any other combination | ||
87 | that makes sense for your particular daemon. */ | ||
88 | |||
89 | #define MAXFD 64 | ||
90 | |||
91 | void | ||
92 | waitdaemon_timeout (int signo) | ||
93 | { | ||
94 | int left; | ||
95 | |||
96 | (void)signo; | ||
97 | left = alarm (0); | ||
98 | signal (SIGALRM, SIG_DFL); | ||
99 | if (left == 0) | ||
100 | errx (1, "timed out waiting for child"); | ||
101 | } | ||
102 | |||
103 | /* waitdaemon is like daemon, but optionally the parent pause up | ||
104 | until maxwait before exiting. Return -1, on error, otherwise | ||
105 | waitdaemon will return the pid of the parent. */ | ||
106 | |||
107 | int | ||
108 | waitdaemon (int nochdir, int noclose, int maxwait) | ||
109 | { | ||
110 | int fd; | ||
111 | pid_t childpid; | ||
112 | pid_t ppid; | ||
113 | |||
114 | ppid = getpid (); | ||
115 | |||
116 | switch (childpid = fork ()) | ||
117 | { | ||
118 | case -1: /* Something went wrong. */ | ||
119 | return (-1); | ||
120 | |||
121 | case 0: /* In the child. */ | ||
122 | break; | ||
123 | |||
124 | default: /* In the parent. */ | ||
125 | if (maxwait > 0) | ||
126 | { | ||
127 | signal (SIGALRM, waitdaemon_timeout); | ||
128 | alarm (maxwait); | ||
129 | pause (); | ||
130 | } | ||
131 | _exit(0); | ||
132 | } | ||
133 | |||
134 | if (setsid () == -1) | ||
135 | return -1; | ||
136 | |||
137 | /* SIGHUP is ignore because when the session leader terminates | ||
138 | all process in the session (the second child) are sent the SIGHUP. */ | ||
139 | signal (SIGHUP, SIG_IGN); | ||
140 | |||
141 | switch (fork ()) | ||
142 | { | ||
143 | case 0: | ||
144 | break; | ||
145 | |||
146 | case -1: | ||
147 | return -1; | ||
148 | |||
149 | default: | ||
150 | _exit (0); | ||
151 | } | ||
152 | |||
153 | if (!nochdir) | ||
154 | chdir ("/"); | ||
155 | |||
156 | if (!noclose) | ||
157 | { | ||
158 | int i; | ||
159 | long fdlimit = -1; | ||
160 | |||
161 | #if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX) | ||
162 | fdlimit = sysconf (_SC_OPEN_MAX); | ||
163 | #elif defined (HAVE_GETDTABLESIZE) | ||
164 | fdlimit = getdtablesize (); | ||
165 | #endif | ||
166 | |||
167 | if (fdlimit == -1) | ||
168 | fdlimit = MAXFD; | ||
169 | |||
170 | for (i = 0; i < fdlimit; i++) | ||
171 | close (i); | ||
172 | |||
173 | fd = open (_PATH_DEVNULL, O_RDWR, 0); | ||
174 | if (fd != -1) | ||
175 | { | ||
176 | dup2 (fd, STDIN_FILENO); | ||
177 | dup2 (fd, STDOUT_FILENO); | ||
178 | dup2 (fd, STDERR_FILENO); | ||
179 | if (fd > 2) | ||
180 | close (fd); | ||
181 | } | ||
182 | } | ||
183 | return ppid; | ||
184 | } | ||
185 | |||
186 | int | ||
187 | daemon (int nochdir, int noclose) | ||
188 | { | ||
189 | return (waitdaemon (nochdir, noclose, 0) == -1) ? -1 : 0; | ||
190 | } |
... | @@ -151,9 +151,11 @@ main (int argc, char **argv) | ... | @@ -151,9 +151,11 @@ main (int argc, char **argv) |
151 | 151 | ||
152 | if (mode == DAEMON) | 152 | if (mode == DAEMON) |
153 | pop3d_daemon_init (); | 153 | pop3d_daemon_init (); |
154 | 154 | else | |
155 | /* Make sure we are in the root directory. */ | 155 | { |
156 | chdir ("/"); | 156 | /* Make sure we are in the root directory. */ |
157 | chdir ("/"); | ||
158 | } | ||
157 | 159 | ||
158 | /* Set up for syslog. */ | 160 | /* Set up for syslog. */ |
159 | openlog ("gnu-pop3d", LOG_PID, LOG_FACILITY); | 161 | openlog ("gnu-pop3d", LOG_PID, LOG_FACILITY); |
... | @@ -179,43 +181,15 @@ main (int argc, char **argv) | ... | @@ -179,43 +181,15 @@ main (int argc, char **argv) |
179 | static void | 181 | static void |
180 | pop3d_daemon_init (void) | 182 | pop3d_daemon_init (void) |
181 | { | 183 | { |
182 | pid_t pid; | 184 | extern int daemon (int, int); |
183 | |||
184 | pid = fork (); | ||
185 | if (pid == -1) | ||
186 | { | ||
187 | perror ("fork failed:"); | ||
188 | exit (EXIT_FAILURE); | ||
189 | } | ||
190 | else if (pid > 0) | ||
191 | exit (EXIT_SUCCESS); /* Parent exits. */ | ||
192 | |||
193 | setsid (); /* Become session leader. */ | ||
194 | 185 | ||
195 | signal (SIGHUP, SIG_IGN); /* Ignore SIGHUP. */ | 186 | /* Become a daemon. Take care to close inherited fds and to hold |
196 | 187 | first three one, in, out, err */ | |
197 | /* The second fork is to guarantee that the daemon cannot acquire a | 188 | if (daemon (0, 0) < 0) |
198 | controlling terminal. */ | ||
199 | pid = fork (); | ||
200 | if (pid == -1) | ||
201 | { | 189 | { |
202 | perror("fork failed:"); | 190 | perror ("failed to become a daemon:"); |
203 | exit (EXIT_FAILURE); | 191 | exit (EXIT_FAILURE); |
204 | } | 192 | } |
205 | else if (pid > 0) | ||
206 | exit (EXIT_SUCCESS); /* Parent exits. */ | ||
207 | |||
208 | /* Close inherited file descriptors. */ | ||
209 | { | ||
210 | size_t i; | ||
211 | #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) | ||
212 | size_t fdlimit = sysconf(_SC_OPEN_MAX); | ||
213 | #else | ||
214 | size_t fdlimit = 64; | ||
215 | #endif | ||
216 | for (i = 0; i < fdlimit; ++i) | ||
217 | close (i); | ||
218 | } | ||
219 | 193 | ||
220 | /* SIGCHLD is not ignore but rather use to do some simple load balancing. */ | 194 | /* SIGCHLD is not ignore but rather use to do some simple load balancing. */ |
221 | #ifdef HAVE_SIGACTION | 195 | #ifdef HAVE_SIGACTION | ... | ... |
-
Please register or sign in to post a comment