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