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#ifdef __APPLE_OS_X_SERVER__
171#include <stdio.h>
172#include <string.h>
173
174static void sigusr1_handler(int sig)
175{
176    char   *myname = "sigusr1_handler";
177	char	pData[1024];
178	int file_fd = -1;
179
180	file_fd = open( SRVR_MGR_COM_FILE, O_CREAT|O_TRUNC|O_RDWR, 0600 );
181	if( file_fd == -1 )
182	{
183	    msg_fatal( "can't open com file: %s (%m)", SRVR_MGR_COM_FILE );
184	}
185	else
186	{
187		snprintf( pData, sizeof pData, SRVR_MGR_DATA, smtp_count, smtpd_count );
188
189		if ( lseek(file_fd, 0, SEEK_SET) == -1 ||
190			ftruncate(file_fd, 0) == -1 ||
191			write(file_fd, pData, strlen(pData)) == -1 )
192		{
193			msg_fatal("%s: can't write to file: %m", myname);
194		}
195		close( file_fd );
196	}
197}
198#endif
199
200/* master_sigdeath - die, women and children first */
201
202static void master_sigdeath(int sig)
203{
204    const char *myname = "master_sigdeath";
205    struct sigaction action;
206    pid_t   pid = getpid();
207
208    /*
209     * Set alarm clock here for suicide after 5s.
210     */
211    killme_after(5);
212
213    /*
214     * Terminate all processes in our process group, except ourselves.
215     */
216    sigemptyset(&action.sa_mask);
217    action.sa_flags = 0;
218    action.sa_handler = SIG_IGN;
219    if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0)
220	msg_fatal("%s: sigaction: %m", myname);
221    if (kill(-pid, SIGTERM) < 0)
222	msg_fatal("%s: kill process group: %m", myname);
223
224    /*
225     * XXX We're running from a signal handler, and should not call complex
226     * routines at all, but it would be even worse to silently terminate
227     * without informing the sysadmin. For this reason, msg(3) was made safe
228     * for usage by signal handlers that terminate the process.
229     */
230    msg_info("terminating on signal %d", sig);
231
232    /*
233     * Deliver the signal to ourselves and clean up. XXX We're running as a
234     * signal handler and really should not be doing complicated things...
235     */
236    sigemptyset(&action.sa_mask);
237    action.sa_flags = 0;
238    action.sa_handler = SIG_DFL;
239    if (sigaction(sig, &action, (struct sigaction *) 0) < 0)
240	msg_fatal("%s: sigaction: %m", myname);
241    if (kill(pid, sig) < 0)
242	msg_fatal("%s: kill myself: %m", myname);
243}
244
245/* master_sigsetup - set up signal handlers */
246
247void    master_sigsetup(void)
248{
249    const char *myname = "master_sigsetup";
250    struct sigaction action;
251    static int sigs[] = {
252	SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM,
253    };
254    unsigned i;
255
256    sigemptyset(&action.sa_mask);
257    action.sa_flags = 0;
258
259    /*
260     * Prepare to kill our children when we receive any of the above signals.
261     */
262    action.sa_handler = master_sigdeath;
263    for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
264	if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0)
265	    msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]);
266
267#ifdef USE_SIG_PIPE
268    if (pipe(master_sig_pipe))
269	msg_fatal("pipe: %m");
270    non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING);
271    non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING);
272    close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC);
273    close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC);
274    event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (char *) 0);
275#endif
276
277    /*
278     * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit).
279     */
280#ifdef SA_RESTART
281    action.sa_flags |= SA_RESTART;
282#endif
283    action.sa_handler = master_sighup;
284    if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0)
285	msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP);
286
287    action.sa_flags |= SA_NOCLDSTOP;
288    action.sa_handler = master_sigchld;
289    if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0)
290	msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD);
291
292#ifdef __APPLE_OS_X_SERVER__
293    action.sa_handler = sigusr1_handler;
294    if (sigaction(SIGUSR1, &action, (struct sigaction *) 0) < 0)
295	msg_fatal("%s: sigaction(%d): %m", myname, SIGUSR1);
296#endif
297}
298