1 /*        $NetBSD: master_monitor.c,v 1.3 2022/10/08 16:12:46 christos Exp $    */
2 
3 /*++
4 /* NAME
5 /*        master_monitor 3
6 /* SUMMARY
7 /*        Postfix master - start-up monitoring
8 /* SYNOPSIS
9 /*        #include "master.h"
10 /*
11 /*        int     master_monitor(time_limit)
12 /*        int       time_limit;
13 /* DESCRIPTION
14 /*        master_monitor() forks off a background child process, and
15 /*        returns in the child. The result value is the file descriptor
16 /*        on which the child process must write one byte after it
17 /*        completes successful initialization as a daemon process.
18 /*
19 /*        The foreground process waits for the child's completion for
20 /*        a limited amount of time. It terminates with exit status 0
21 /*        in case of success, non-zero otherwise.
22 /* DIAGNOSTICS
23 /*        Fatal errors: system call failure.
24 /* BUGS
25 /* SEE ALSO
26 /* LICENSE
27 /* .ad
28 /* .fi
29 /*        The Secure Mailer license must be distributed with this software.
30 /* AUTHOR(S)
31 /*        Wietse Venema
32 /*        IBM T.J. Watson Research
33 /*        P.O. Box 704
34 /*        Yorktown Heights, NY 10598, USA
35 /*
36 /*        Wietse Venema
37 /*        Google, Inc.
38 /*        111 8th Avenue
39 /*        New York, NY 10011, USA
40 /*--*/
41 
42 /* System library. */
43 
44 #include <sys_defs.h>
45 #include <signal.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 
49 /* Utility library. */
50 
51 #include <msg.h>
52 #include <iostuff.h>
53 
54 /* Application-specific. */
55 
56 #include <master.h>
57 
58 /* master_monitor - fork off a foreground monitor process */
59 
master_monitor(int time_limit)60 int     master_monitor(int time_limit)
61 {
62     pid_t   pid;
63     int     pipes[2];
64     char    buf[1];
65 
66     /*
67      * Sanity check.
68      */
69     if (time_limit <= 0)
70           msg_panic("master_monitor: bad time limit: %d", time_limit);
71 
72     /*
73      * Set up the plumbing for child-to-parent communication.
74      */
75     if (pipe(pipes) < 0)
76           msg_fatal("pipe: %m");
77     close_on_exec(pipes[0], CLOSE_ON_EXEC);
78     close_on_exec(pipes[1], CLOSE_ON_EXEC);
79 
80     /*
81      * Fork the child, and wait for it to report successful initialization.
82      */
83     switch (pid = fork()) {
84     case -1:
85           /* Error. */
86           msg_fatal("fork: %m");
87     case 0:
88           /* Child. Initialize as daemon in the background. */
89           close(pipes[0]);
90           return (pipes[1]);
91     default:
92           /* Parent. Monitor the child in the foreground. */
93           close(pipes[1]);
94           switch (timed_read(pipes[0], buf, 1, time_limit, (void *) 0)) {
95           default:
96               msg_warn("%m while waiting for daemon initialization");
97               /* The child process still runs, but something is wrong. */
98               (void) kill(pid, SIGKILL);
99               /* FALLTHROUGH */
100           case 0:
101               /* The child process exited prematurely. */
102               msg_fatal("daemon initialization failure -- see logs for details");
103           case 1:
104               /* The child process initialized successfully. */
105               exit(0);
106           }
107     }
108 }
109