1 /* $NetBSD: master_sig.c,v 1.3 2020/03/18 19:05:16 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 /* Wietse Venema
40 /* Google, Inc.
41 /* 111 8th Avenue
42 /* New York, NY 10011, USA
43 /*--*/
44
45 /* System libraries. */
46
47 #include <sys_defs.h>
48 #include <signal.h>
49 #include <unistd.h>
50
51 /* Utility library. */
52
53 #include <msg.h>
54 #include <posix_signals.h>
55 #include <killme_after.h>
56
57 /* Application-specific. */
58
59 #include "master.h"
60
61 #ifdef USE_SIG_RETURN
62 #include <sys/syscall.h>
63 #undef USE_SIG_PIPE
64 #else
65 #define USE_SIG_PIPE
66 #endif
67
68 /* Local stuff. */
69
70 #ifdef USE_SIG_PIPE
71 #include <errno.h>
72 #include <fcntl.h>
73 #include <iostuff.h>
74 #include <events.h>
75
76 int master_sig_pipe[2];
77
78 #define SIG_PIPE_WRITE_FD master_sig_pipe[1]
79 #define SIG_PIPE_READ_FD master_sig_pipe[0]
80 #endif
81
82 int master_gotsigchld;
83 int master_gotsighup;
84
85 #ifdef USE_SIG_RETURN
86
87 /* master_sighup - register arrival of hangup signal */
88
master_sighup(int sig)89 static void master_sighup(int sig)
90 {
91
92 /*
93 * WARNING WARNING WARNING.
94 *
95 * This code runs at unpredictable moments, as a signal handler. Don't put
96 * any code here other than for setting a global flag.
97 */
98 master_gotsighup = sig;
99 }
100
101 /* master_sigchld - register arrival of child death signal */
102
master_sigchld(int sig,int code,struct sigcontext * scp)103 static void master_sigchld(int sig, int code, struct sigcontext * scp)
104 {
105
106 /*
107 * WARNING WARNING WARNING.
108 *
109 * This code runs at unpredictable moments, as a signal handler. Don't put
110 * any code here other than for setting a global flag, or code that is
111 * intended to be run within a signal handler.
112 */
113 master_gotsigchld = sig;
114 if (scp != NULL && scp->sc_syscall == SYS_select) {
115 scp->sc_syscall_action = SIG_RETURN;
116 #ifndef SA_RESTART
117 } else if (scp != NULL) {
118 scp->sc_syscall_action = SIG_RESTART;
119 #endif
120 }
121 }
122
123 #else
124
125 /* master_sighup - register arrival of hangup signal */
126
master_sighup(int sig)127 static void master_sighup(int sig)
128 {
129 int saved_errno = errno;
130
131 /*
132 * WARNING WARNING WARNING.
133 *
134 * This code runs at unpredictable moments, as a signal handler. Don't put
135 * any code here other than for setting a global flag, or code that is
136 * intended to be run within a signal handler. Restore errno in case we
137 * are interrupting the epilog of a failed system call.
138 */
139 master_gotsighup = sig;
140 if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
141 msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
142 errno = saved_errno;
143 }
144
145 /* master_sigchld - force wakeup from select() */
146
master_sigchld(int unused_sig)147 static void master_sigchld(int unused_sig)
148 {
149 int saved_errno = errno;
150
151 /*
152 * WARNING WARNING WARNING.
153 *
154 * This code runs at unpredictable moments, as a signal handler. Don't put
155 * any code here other than for setting a global flag, or code that is
156 * intended to be run within a signal handler. Restore errno in case we
157 * are interrupting the epilog of a failed system call.
158 */
159 master_gotsigchld = 1;
160 if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
161 msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
162 errno = saved_errno;
163 }
164
165 /* master_sig_event - called upon return from select() */
166
master_sig_event(int unused_event,void * unused_context)167 static void master_sig_event(int unused_event, void *unused_context)
168 {
169 char c[1];
170
171 while (read(SIG_PIPE_READ_FD, c, 1) > 0)
172 /* void */ ;
173 }
174
175 #endif
176
177 /* master_sigdeath - die, women and children first */
178
master_sigdeath(int sig)179 static void master_sigdeath(int sig)
180 {
181 const char *myname = "master_sigdeath";
182 struct sigaction action;
183 pid_t pid = getpid();
184
185 /*
186 * Set alarm clock here for suicide after 5s.
187 */
188 killme_after(5);
189
190 /*
191 * Terminate all processes in our process group, except ourselves.
192 */
193 sigemptyset(&action.sa_mask);
194 action.sa_flags = 0;
195 action.sa_handler = SIG_IGN;
196 if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0)
197 msg_fatal("%s: sigaction: %m", myname);
198 if (kill(-pid, SIGTERM) < 0)
199 msg_fatal("%s: kill process group: %m", myname);
200
201 /*
202 * XXX We're running from a signal handler, and should not call complex
203 * routines at all, but it would be even worse to silently terminate
204 * without informing the sysadmin. For this reason, msg(3) was made safe
205 * for usage by signal handlers that terminate the process.
206 */
207 msg_info("terminating on signal %d", sig);
208
209 /*
210 * Undocumented: when a process runs with PID 1, Linux won't deliver a
211 * signal unless the process specifies a handler (i.e. SIG_DFL is treated
212 * as SIG_IGN).
213 */
214 if (init_mode)
215 /* Don't call exit() from a signal handler. */
216 _exit(0);
217
218 /*
219 * Deliver the signal to ourselves and clean up. XXX We're running as a
220 * signal handler and really should not be doing complicated things...
221 */
222 sigemptyset(&action.sa_mask);
223 action.sa_flags = 0;
224 action.sa_handler = SIG_DFL;
225 if (sigaction(sig, &action, (struct sigaction *) 0) < 0)
226 msg_fatal("%s: sigaction: %m", myname);
227 if (kill(pid, sig) < 0)
228 msg_fatal("%s: kill myself: %m", myname);
229 }
230
231 /* master_sigsetup - set up signal handlers */
232
master_sigsetup(void)233 void master_sigsetup(void)
234 {
235 const char *myname = "master_sigsetup";
236 struct sigaction action;
237 static int sigs[] = {
238 SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM,
239 };
240 unsigned i;
241
242 sigemptyset(&action.sa_mask);
243 action.sa_flags = 0;
244
245 /*
246 * Prepare to kill our children when we receive any of the above signals.
247 */
248 action.sa_handler = master_sigdeath;
249 for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
250 if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0)
251 msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]);
252
253 #ifdef USE_SIG_PIPE
254 if (pipe(master_sig_pipe))
255 msg_fatal("pipe: %m");
256 non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING);
257 non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING);
258 close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC);
259 close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC);
260 event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (void *) 0);
261 #endif
262
263 /*
264 * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit).
265 */
266 #ifdef SA_RESTART
267 action.sa_flags |= SA_RESTART;
268 #endif
269 action.sa_handler = master_sighup;
270 if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0)
271 msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP);
272
273 action.sa_flags |= SA_NOCLDSTOP;
274 action.sa_handler = master_sigchld;
275 if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0)
276 msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD);
277 }
278