1*3c275423Schristos /*	$NetBSD: master_sig.c,v 1.3 2020/03/18 19:05:16 christos Exp $	*/
241fbaed0Stron 
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /*	master_sig 3
641fbaed0Stron /* SUMMARY
741fbaed0Stron /*	Postfix master - signal processing
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /*	#include "master.h"
1041fbaed0Stron /*
1141fbaed0Stron /*	int	master_gotsighup;
1241fbaed0Stron /*	int	master_gotsigchld;
1341fbaed0Stron /*
1441fbaed0Stron /*	int	master_sigsetup()
1541fbaed0Stron /* DESCRIPTION
1641fbaed0Stron /*	This module implements the master process signal handling interface.
1741fbaed0Stron /*
1841fbaed0Stron /*	master_gotsighup (master_gotsigchld) is set to SIGHUP (SIGCHLD)
1941fbaed0Stron /*	when the process receives a hangup (child death) signal.
2041fbaed0Stron /*
2141fbaed0Stron /*	master_sigsetup() enables processing of hangup and child death signals.
2241fbaed0Stron /*	Receipt of SIGINT, SIGQUIT, SIGSEGV, SIGILL, or SIGTERM
2341fbaed0Stron /*	is interpreted as a request for termination.  Child processes are
2441fbaed0Stron /*	notified of the master\'s demise by sending them a SIGTERM signal.
2541fbaed0Stron /* DIAGNOSTICS
2641fbaed0Stron /* BUGS
2741fbaed0Stron /*	Need a way to register cleanup actions.
2841fbaed0Stron /* SEE ALSO
2941fbaed0Stron /* LICENSE
3041fbaed0Stron /* .ad
3141fbaed0Stron /* .fi
3241fbaed0Stron /*	The Secure Mailer license must be distributed with this software.
3341fbaed0Stron /* AUTHOR(S)
3441fbaed0Stron /*	Wietse Venema
3541fbaed0Stron /*	IBM T.J. Watson Research
3641fbaed0Stron /*	P.O. Box 704
3741fbaed0Stron /*	Yorktown Heights, NY 10598, USA
38*3c275423Schristos /*
39*3c275423Schristos /*	Wietse Venema
40*3c275423Schristos /*	Google, Inc.
41*3c275423Schristos /*	111 8th Avenue
42*3c275423Schristos /*	New York, NY 10011, USA
4341fbaed0Stron /*--*/
4441fbaed0Stron 
4541fbaed0Stron /* System libraries. */
4641fbaed0Stron 
4741fbaed0Stron #include <sys_defs.h>
4841fbaed0Stron #include <signal.h>
4941fbaed0Stron #include <unistd.h>
5041fbaed0Stron 
5141fbaed0Stron /* Utility library. */
5241fbaed0Stron 
5341fbaed0Stron #include <msg.h>
5441fbaed0Stron #include <posix_signals.h>
5541fbaed0Stron #include <killme_after.h>
5641fbaed0Stron 
5741fbaed0Stron /* Application-specific. */
5841fbaed0Stron 
5941fbaed0Stron #include "master.h"
6041fbaed0Stron 
6141fbaed0Stron #ifdef USE_SIG_RETURN
6241fbaed0Stron #include <sys/syscall.h>
63e8314800Stron #undef USE_SIG_PIPE
64e8314800Stron #else
6541fbaed0Stron #define USE_SIG_PIPE
6641fbaed0Stron #endif
6741fbaed0Stron 
6841fbaed0Stron /* Local stuff. */
6941fbaed0Stron 
7041fbaed0Stron #ifdef USE_SIG_PIPE
7141fbaed0Stron #include <errno.h>
7241fbaed0Stron #include <fcntl.h>
7341fbaed0Stron #include <iostuff.h>
7441fbaed0Stron #include <events.h>
7541fbaed0Stron 
7641fbaed0Stron int     master_sig_pipe[2];
7741fbaed0Stron 
7841fbaed0Stron #define SIG_PIPE_WRITE_FD master_sig_pipe[1]
7941fbaed0Stron #define SIG_PIPE_READ_FD master_sig_pipe[0]
8041fbaed0Stron #endif
8141fbaed0Stron 
8241fbaed0Stron int     master_gotsigchld;
8341fbaed0Stron int     master_gotsighup;
8441fbaed0Stron 
85e8314800Stron #ifdef USE_SIG_RETURN
86e8314800Stron 
8741fbaed0Stron /* master_sighup - register arrival of hangup signal */
8841fbaed0Stron 
master_sighup(int sig)8941fbaed0Stron static void master_sighup(int sig)
9041fbaed0Stron {
9141fbaed0Stron 
9241fbaed0Stron     /*
9341fbaed0Stron      * WARNING WARNING WARNING.
9441fbaed0Stron      *
9541fbaed0Stron      * This code runs at unpredictable moments, as a signal handler. Don't put
9641fbaed0Stron      * any code here other than for setting a global flag.
9741fbaed0Stron      */
9841fbaed0Stron     master_gotsighup = sig;
9941fbaed0Stron }
10041fbaed0Stron 
10141fbaed0Stron /* master_sigchld - register arrival of child death signal */
10241fbaed0Stron 
master_sigchld(int sig,int code,struct sigcontext * scp)10341fbaed0Stron static void master_sigchld(int sig, int code, struct sigcontext * scp)
10441fbaed0Stron {
10541fbaed0Stron 
10641fbaed0Stron     /*
10741fbaed0Stron      * WARNING WARNING WARNING.
10841fbaed0Stron      *
10941fbaed0Stron      * This code runs at unpredictable moments, as a signal handler. Don't put
11041fbaed0Stron      * any code here other than for setting a global flag, or code that is
11141fbaed0Stron      * intended to be run within a signal handler.
11241fbaed0Stron      */
11341fbaed0Stron     master_gotsigchld = sig;
11441fbaed0Stron     if (scp != NULL && scp->sc_syscall == SYS_select) {
11541fbaed0Stron 	scp->sc_syscall_action = SIG_RETURN;
11641fbaed0Stron #ifndef SA_RESTART
11741fbaed0Stron     } else if (scp != NULL) {
11841fbaed0Stron 	scp->sc_syscall_action = SIG_RESTART;
11941fbaed0Stron #endif
12041fbaed0Stron     }
12141fbaed0Stron }
12241fbaed0Stron 
12341fbaed0Stron #else
12441fbaed0Stron 
125e8314800Stron /* master_sighup - register arrival of hangup signal */
126e8314800Stron 
master_sighup(int sig)127e8314800Stron static void master_sighup(int sig)
128e8314800Stron {
129e8314800Stron     int     saved_errno = errno;
130e8314800Stron 
131e8314800Stron     /*
132e8314800Stron      * WARNING WARNING WARNING.
133e8314800Stron      *
134e8314800Stron      * This code runs at unpredictable moments, as a signal handler. Don't put
135e8314800Stron      * any code here other than for setting a global flag, or code that is
136e8314800Stron      * intended to be run within a signal handler. Restore errno in case we
137e8314800Stron      * are interrupting the epilog of a failed system call.
138e8314800Stron      */
139e8314800Stron     master_gotsighup = sig;
140e8314800Stron     if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
141e8314800Stron 	msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
142e8314800Stron     errno = saved_errno;
143e8314800Stron }
14441fbaed0Stron 
14541fbaed0Stron /* master_sigchld - force wakeup from select() */
14641fbaed0Stron 
master_sigchld(int unused_sig)14741fbaed0Stron static void master_sigchld(int unused_sig)
14841fbaed0Stron {
14941fbaed0Stron     int     saved_errno = errno;
15041fbaed0Stron 
15141fbaed0Stron     /*
15241fbaed0Stron      * WARNING WARNING WARNING.
15341fbaed0Stron      *
15441fbaed0Stron      * This code runs at unpredictable moments, as a signal handler. Don't put
15541fbaed0Stron      * any code here other than for setting a global flag, or code that is
15641fbaed0Stron      * intended to be run within a signal handler. Restore errno in case we
15741fbaed0Stron      * are interrupting the epilog of a failed system call.
15841fbaed0Stron      */
159e8314800Stron     master_gotsigchld = 1;
16041fbaed0Stron     if (write(SIG_PIPE_WRITE_FD, "", 1) != 1)
16141fbaed0Stron 	msg_warn("write to SIG_PIPE_WRITE_FD failed: %m");
16241fbaed0Stron     errno = saved_errno;
16341fbaed0Stron }
16441fbaed0Stron 
16541fbaed0Stron /* master_sig_event - called upon return from select() */
16641fbaed0Stron 
master_sig_event(int unused_event,void * unused_context)167837e7c1aSchristos static void master_sig_event(int unused_event, void *unused_context)
16841fbaed0Stron {
16941fbaed0Stron     char    c[1];
17041fbaed0Stron 
17141fbaed0Stron     while (read(SIG_PIPE_READ_FD, c, 1) > 0)
17241fbaed0Stron 	 /* void */ ;
17341fbaed0Stron }
17441fbaed0Stron 
17541fbaed0Stron #endif
17641fbaed0Stron 
17741fbaed0Stron /* master_sigdeath - die, women and children first */
17841fbaed0Stron 
master_sigdeath(int sig)17941fbaed0Stron static void master_sigdeath(int sig)
18041fbaed0Stron {
18141fbaed0Stron     const char *myname = "master_sigdeath";
18241fbaed0Stron     struct sigaction action;
18341fbaed0Stron     pid_t   pid = getpid();
18441fbaed0Stron 
18541fbaed0Stron     /*
18641fbaed0Stron      * Set alarm clock here for suicide after 5s.
18741fbaed0Stron      */
18841fbaed0Stron     killme_after(5);
18941fbaed0Stron 
19041fbaed0Stron     /*
19141fbaed0Stron      * Terminate all processes in our process group, except ourselves.
19241fbaed0Stron      */
19341fbaed0Stron     sigemptyset(&action.sa_mask);
19441fbaed0Stron     action.sa_flags = 0;
19541fbaed0Stron     action.sa_handler = SIG_IGN;
19641fbaed0Stron     if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0)
19741fbaed0Stron 	msg_fatal("%s: sigaction: %m", myname);
19841fbaed0Stron     if (kill(-pid, SIGTERM) < 0)
19941fbaed0Stron 	msg_fatal("%s: kill process group: %m", myname);
20041fbaed0Stron 
20141fbaed0Stron     /*
20241fbaed0Stron      * XXX We're running from a signal handler, and should not call complex
20341fbaed0Stron      * routines at all, but it would be even worse to silently terminate
20441fbaed0Stron      * without informing the sysadmin. For this reason, msg(3) was made safe
20541fbaed0Stron      * for usage by signal handlers that terminate the process.
20641fbaed0Stron      */
20741fbaed0Stron     msg_info("terminating on signal %d", sig);
20841fbaed0Stron 
20941fbaed0Stron     /*
210*3c275423Schristos      * Undocumented: when a process runs with PID 1, Linux won't deliver a
211*3c275423Schristos      * signal unless the process specifies a handler (i.e. SIG_DFL is treated
212*3c275423Schristos      * as SIG_IGN).
213*3c275423Schristos      */
214*3c275423Schristos     if (init_mode)
215*3c275423Schristos 	/* Don't call exit() from a signal handler. */
216*3c275423Schristos 	_exit(0);
217*3c275423Schristos 
218*3c275423Schristos     /*
21941fbaed0Stron      * Deliver the signal to ourselves and clean up. XXX We're running as a
22041fbaed0Stron      * signal handler and really should not be doing complicated things...
22141fbaed0Stron      */
22241fbaed0Stron     sigemptyset(&action.sa_mask);
22341fbaed0Stron     action.sa_flags = 0;
22441fbaed0Stron     action.sa_handler = SIG_DFL;
22541fbaed0Stron     if (sigaction(sig, &action, (struct sigaction *) 0) < 0)
22641fbaed0Stron 	msg_fatal("%s: sigaction: %m", myname);
22741fbaed0Stron     if (kill(pid, sig) < 0)
22841fbaed0Stron 	msg_fatal("%s: kill myself: %m", myname);
22941fbaed0Stron }
23041fbaed0Stron 
23141fbaed0Stron /* master_sigsetup - set up signal handlers */
23241fbaed0Stron 
master_sigsetup(void)23341fbaed0Stron void    master_sigsetup(void)
23441fbaed0Stron {
23541fbaed0Stron     const char *myname = "master_sigsetup";
23641fbaed0Stron     struct sigaction action;
23741fbaed0Stron     static int sigs[] = {
23841fbaed0Stron 	SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM,
23941fbaed0Stron     };
24041fbaed0Stron     unsigned i;
24141fbaed0Stron 
24241fbaed0Stron     sigemptyset(&action.sa_mask);
24341fbaed0Stron     action.sa_flags = 0;
24441fbaed0Stron 
24541fbaed0Stron     /*
24641fbaed0Stron      * Prepare to kill our children when we receive any of the above signals.
24741fbaed0Stron      */
24841fbaed0Stron     action.sa_handler = master_sigdeath;
24941fbaed0Stron     for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++)
25041fbaed0Stron 	if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0)
25141fbaed0Stron 	    msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]);
25241fbaed0Stron 
25341fbaed0Stron #ifdef USE_SIG_PIPE
25441fbaed0Stron     if (pipe(master_sig_pipe))
25541fbaed0Stron 	msg_fatal("pipe: %m");
25641fbaed0Stron     non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING);
25741fbaed0Stron     non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING);
25841fbaed0Stron     close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC);
25941fbaed0Stron     close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC);
260837e7c1aSchristos     event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (void *) 0);
26141fbaed0Stron #endif
26241fbaed0Stron 
26341fbaed0Stron     /*
26441fbaed0Stron      * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit).
26541fbaed0Stron      */
26641fbaed0Stron #ifdef SA_RESTART
26741fbaed0Stron     action.sa_flags |= SA_RESTART;
26841fbaed0Stron #endif
26941fbaed0Stron     action.sa_handler = master_sighup;
27041fbaed0Stron     if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0)
27141fbaed0Stron 	msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP);
27241fbaed0Stron 
27341fbaed0Stron     action.sa_flags |= SA_NOCLDSTOP;
27441fbaed0Stron     action.sa_handler = master_sigchld;
27541fbaed0Stron     if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0)
27641fbaed0Stron 	msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD);
27741fbaed0Stron }
278