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