xref: /netbsd-src/external/ibm-public/postfix/dist/src/master/master_sig.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: master_sig.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	master_sig 3
6 /* SUMMARY
7 /*	Postfix master - signal processing
8 /* SYNOPSIS
9 /*	#include "master.h"
10 /*
11 /*	int	master_gotsighup;
12 /*	int	master_gotsigchld;
13 /*
14 /*	int	master_sigsetup()
15 /* DESCRIPTION
16 /*	This module implements the master process signal handling interface.
17 /*
18 /*	master_gotsighup (master_gotsigchld) is set to SIGHUP (SIGCHLD)
19 /*	when the process receives a hangup (child death) signal.
20 /*
21 /*	master_sigsetup() enables processing of hangup and child death signals.
22 /*	Receipt of SIGINT, SIGQUIT, SIGSEGV, SIGILL, or SIGTERM
23 /*	is interpreted as a request for termination.  Child processes are
24 /*	notified of the master\'s demise by sending them a SIGTERM signal.
25 /* DIAGNOSTICS
26 /* BUGS
27 /*	Need a way to register cleanup actions.
28 /* SEE ALSO
29 /* LICENSE
30 /* .ad
31 /* .fi
32 /*	The Secure Mailer license must be distributed with this software.
33 /* AUTHOR(S)
34 /*	Wietse Venema
35 /*	IBM T.J. Watson Research
36 /*	P.O. Box 704
37 /*	Yorktown Heights, NY 10598, USA
38 /*--*/
39 
40 /* System libraries. */
41 
42 #include <sys_defs.h>
43 #include <signal.h>
44 #include <unistd.h>
45 
46 /* Utility library. */
47 
48 #include <msg.h>
49 #include <posix_signals.h>
50 #include <killme_after.h>
51 
52 /* Application-specific. */
53 
54 #include "master.h"
55 
56 #ifdef USE_SIG_RETURN
57 #include <sys/syscall.h>
58 #undef USE_SIG_PIPE
59 #else
60 #define USE_SIG_PIPE
61 #endif
62 
63 /* Local stuff. */
64 
65 #ifdef USE_SIG_PIPE
66 #include <errno.h>
67 #include <fcntl.h>
68 #include <iostuff.h>
69 #include <events.h>
70 
71 int     master_sig_pipe[2];
72 
73 #define SIG_PIPE_WRITE_FD master_sig_pipe[1]
74 #define SIG_PIPE_READ_FD master_sig_pipe[0]
75 #endif
76 
77 int     master_gotsigchld;
78 int     master_gotsighup;
79 
80 #ifdef USE_SIG_RETURN
81 
82 /* master_sighup - register arrival of hangup signal */
83 
84 static void master_sighup(int sig)
85 {
86 
87     /*
88      * WARNING WARNING WARNING.
89      *
90      * This code runs at unpredictable moments, as a signal handler. Don't put
91      * any code here other than for setting a global flag.
92      */
93     master_gotsighup = sig;
94 }
95 
96 /* master_sigchld - register arrival of child death signal */
97 
98 static void master_sigchld(int sig, int code, struct sigcontext * scp)
99 {
100 
101     /*
102      * WARNING WARNING WARNING.
103      *
104      * This code runs at unpredictable moments, as a signal handler. Don't put
105      * any code here other than for setting a global flag, or code that is
106      * intended to be run within a signal handler.
107      */
108     master_gotsigchld = sig;
109     if (scp != NULL && scp->sc_syscall == SYS_select) {
110 	scp->sc_syscall_action = SIG_RETURN;
111 #ifndef SA_RESTART
112     } else if (scp != NULL) {
113 	scp->sc_syscall_action = SIG_RESTART;
114 #endif
115     }
116 }
117 
118 #else
119 
120 /* master_sighup - register arrival of hangup signal */
121 
122 static void master_sighup(int sig)
123 {
124     int     saved_errno = errno;
125 
126     /*
127      * WARNING WARNING WARNING.
128      *
129      * This code runs at unpredictable moments, as a signal handler. Don't put
130      * any code here other than for setting a global flag, or code that is
131      * intended to be run within a signal handler. Restore errno in case we
132      * are interrupting the epilog of a failed system call.
133      */
134     master_gotsighup = sig;
135     if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
136 	msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
137     errno = saved_errno;
138 }
139 
140 /* master_sigchld - force wakeup from select() */
141 
142 static void master_sigchld(int unused_sig)
143 {
144     int     saved_errno = errno;
145 
146     /*
147      * WARNING WARNING WARNING.
148      *
149      * This code runs at unpredictable moments, as a signal handler. Don't put
150      * any code here other than for setting a global flag, or code that is
151      * intended to be run within a signal handler. Restore errno in case we
152      * are interrupting the epilog of a failed system call.
153      */
154     master_gotsigchld = 1;
155     if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
156 	msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
157     errno = saved_errno;
158 }
159 
160 /* master_sig_event - called upon return from select() */
161 
162 static void master_sig_event(int unused_event, void *unused_context)
163 {
164     char    c[1];
165 
166     while (read(SIG_PIPE_READ_FD, c, 1) > 0)
167 	 /* void */ ;
168 }
169 
170 #endif
171 
172 /* master_sigdeath - die, women and children first */
173 
174 static void master_sigdeath(int sig)
175 {
176     const char *myname = "master_sigdeath";
177     struct sigaction action;
178     pid_t   pid = getpid();
179 
180     /*
181      * Set alarm clock here for suicide after 5s.
182      */
183     killme_after(5);
184 
185     /*
186      * Terminate all processes in our process group, except ourselves.
187      */
188     sigemptyset(&action.sa_mask);
189     action.sa_flags = 0;
190     action.sa_handler = SIG_IGN;
191     if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0)
192 	msg_fatal("%s: sigaction: %m", myname);
193     if (kill(-pid, SIGTERM) < 0)
194 	msg_fatal("%s: kill process group: %m", myname);
195 
196     /*
197      * XXX We're running from a signal handler, and should not call complex
198      * routines at all, but it would be even worse to silently terminate
199      * without informing the sysadmin. For this reason, msg(3) was made safe
200      * for usage by signal handlers that terminate the process.
201      */
202     msg_info("terminating on signal %d", sig);
203 
204     /*
205      * Deliver the signal to ourselves and clean up. XXX We're running as a
206      * signal handler and really should not be doing complicated things...
207      */
208     sigemptyset(&action.sa_mask);
209     action.sa_flags = 0;
210     action.sa_handler = SIG_DFL;
211     if (sigaction(sig, &action, (struct sigaction *) 0) < 0)
212 	msg_fatal("%s: sigaction: %m", myname);
213     if (kill(pid, sig) < 0)
214 	msg_fatal("%s: kill myself: %m", myname);
215 }
216 
217 /* master_sigsetup - set up signal handlers */
218 
219 void    master_sigsetup(void)
220 {
221     const char *myname = "master_sigsetup";
222     struct sigaction action;
223     static int sigs[] = {
224 	SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM,
225     };
226     unsigned i;
227 
228     sigemptyset(&action.sa_mask);
229     action.sa_flags = 0;
230 
231     /*
232      * Prepare to kill our children when we receive any of the above signals.
233      */
234     action.sa_handler = master_sigdeath;
235     for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
236 	if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0)
237 	    msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]);
238 
239 #ifdef USE_SIG_PIPE
240     if (pipe(master_sig_pipe))
241 	msg_fatal("pipe: %m");
242     non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING);
243     non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING);
244     close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC);
245     close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC);
246     event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (void *) 0);
247 #endif
248 
249     /*
250      * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit).
251      */
252 #ifdef SA_RESTART
253     action.sa_flags |= SA_RESTART;
254 #endif
255     action.sa_handler = master_sighup;
256     if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0)
257 	msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP);
258 
259     action.sa_flags |= SA_NOCLDSTOP;
260     action.sa_handler = master_sigchld;
261     if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0)
262 	msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD);
263 }
264