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