xref: /netbsd-src/external/ibm-public/postfix/dist/src/master/master_sig.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
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