1/*++
2/* NAME
3/*	master_sig 3
4/* SUMMARY
5/*	Postfix master - signal processing
6/* SYNOPSIS
7/*	#include "master.h"
8/*
9/*	int	master_gotsighup;
10/*	int	master_gotsigchld;
11/*
12/*	int	master_sigsetup()
13/* DESCRIPTION
14/*	This module implements the master process signal handling interface.
15/*
16/*	master_gotsighup (master_gotsigchld) is set to SIGHUP (SIGCHLD)
17/*	when the process receives a hangup (child death) signal.
18/*
19/*	master_sigsetup() enables processing of hangup and child death signals.
20/*	Receipt of SIGINT, SIGQUIT, SIGSEGV, SIGILL, or SIGTERM
21/*	is interpreted as a request for termination.  Child processes are
22/*	notified of the master\'s demise by sending them a SIGTERM signal.
23/* DIAGNOSTICS
24/* BUGS
25/*	Need a way to register cleanup actions.
26/* SEE ALSO
27/* LICENSE
28/* .ad
29/* .fi
30/*	The Secure Mailer license must be distributed with this software.
31/* AUTHOR(S)
32/*	Wietse Venema
33/*	IBM T.J. Watson Research
34/*	P.O. Box 704
35/*	Yorktown Heights, NY 10598, USA
36/*--*/
37
38/* System libraries. */
39
40#include <sys_defs.h>
41#include <signal.h>
42#include <unistd.h>
43
44/* Utility library. */
45
46#include <msg.h>
47#include <posix_signals.h>
48#include <killme_after.h>
49
50/* Application-specific. */
51
52#include "master.h"
53
54#ifdef USE_SIG_RETURN
55#include <sys/syscall.h>
56#undef USE_SIG_PIPE
57#else
58#define USE_SIG_PIPE
59#endif
60
61/* Local stuff. */
62
63#ifdef USE_SIG_PIPE
64#include <errno.h>
65#include <fcntl.h>
66#include <iostuff.h>
67#include <events.h>
68
69int     master_sig_pipe[2];
70
71#define SIG_PIPE_WRITE_FD master_sig_pipe[1]
72#define SIG_PIPE_READ_FD master_sig_pipe[0]
73#endif
74
75int     master_gotsigchld;
76int     master_gotsighup;
77
78#ifdef USE_SIG_RETURN
79
80/* master_sighup - register arrival of hangup signal */
81
82static void master_sighup(int sig)
83{
84
85    /*
86     * WARNING WARNING WARNING.
87     *
88     * This code runs at unpredictable moments, as a signal handler. Don't put
89     * any code here other than for setting a global flag.
90     */
91    master_gotsighup = sig;
92}
93
94/* master_sigchld - register arrival of child death signal */
95
96static void master_sigchld(int sig, int code, struct sigcontext * scp)
97{
98
99    /*
100     * WARNING WARNING WARNING.
101     *
102     * This code runs at unpredictable moments, as a signal handler. Don't put
103     * any code here other than for setting a global flag, or code that is
104     * intended to be run within a signal handler.
105     */
106    master_gotsigchld = sig;
107    if (scp != NULL && scp->sc_syscall == SYS_select) {
108	scp->sc_syscall_action = SIG_RETURN;
109#ifndef SA_RESTART
110    } else if (scp != NULL) {
111	scp->sc_syscall_action = SIG_RESTART;
112#endif
113    }
114}
115
116#else
117
118/* master_sighup - register arrival of hangup signal */
119
120static void master_sighup(int sig)
121{
122    int     saved_errno = errno;
123
124    /*
125     * WARNING WARNING WARNING.
126     *
127     * This code runs at unpredictable moments, as a signal handler. Don't put
128     * any code here other than for setting a global flag, or code that is
129     * intended to be run within a signal handler. Restore errno in case we
130     * are interrupting the epilog of a failed system call.
131     */
132    master_gotsighup = sig;
133    if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
134	msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
135    errno = saved_errno;
136}
137
138/* master_sigchld - force wakeup from select() */
139
140static void master_sigchld(int unused_sig)
141{
142    int     saved_errno = errno;
143
144    /*
145     * WARNING WARNING WARNING.
146     *
147     * This code runs at unpredictable moments, as a signal handler. Don't put
148     * any code here other than for setting a global flag, or code that is
149     * intended to be run within a signal handler. Restore errno in case we
150     * are interrupting the epilog of a failed system call.
151     */
152    master_gotsigchld = 1;
153    if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
154	msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
155    errno = saved_errno;
156}
157
158/* master_sig_event - called upon return from select() */
159
160static void master_sig_event(int unused_event, char *unused_context)
161{
162    char    c[1];
163
164    while (read(SIG_PIPE_READ_FD, c, 1) > 0)
165	 /* void */ ;
166}
167
168#endif
169
170/* master_sigdeath - die, women and children first */
171
172static 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
217void    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