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