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/* master_sigdeath - die, women and children first */ 171 172static void master_sigdeath(int sig) 173{ 174 const char *myname = "master_sigdeath"; 175 struct sigaction action; 176 pid_t pid = getpid(); 177 178 /* 179 * Set alarm clock here for suicide after 5s. 180 */ 181 killme_after(5); 182 183 /* 184 * Terminate all processes in our process group, except ourselves. 185 */ 186 sigemptyset(&action.sa_mask); 187 action.sa_flags = 0; 188 action.sa_handler = SIG_IGN; 189 if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0) 190 msg_fatal("%s: sigaction: %m", myname); 191 if (kill(-pid, SIGTERM) < 0) 192 msg_fatal("%s: kill process group: %m", myname); 193 194 /* 195 * XXX We're running from a signal handler, and should not call complex 196 * routines at all, but it would be even worse to silently terminate 197 * without informing the sysadmin. For this reason, msg(3) was made safe 198 * for usage by signal handlers that terminate the process. 199 */ 200 msg_info("terminating on signal %d", sig); 201 202 /* 203 * Deliver the signal to ourselves and clean up. XXX We're running as a 204 * signal handler and really should not be doing complicated things... 205 */ 206 sigemptyset(&action.sa_mask); 207 action.sa_flags = 0; 208 action.sa_handler = SIG_DFL; 209 if (sigaction(sig, &action, (struct sigaction *) 0) < 0) 210 msg_fatal("%s: sigaction: %m", myname); 211 if (kill(pid, sig) < 0) 212 msg_fatal("%s: kill myself: %m", myname); 213} 214 215/* master_sigsetup - set up signal handlers */ 216 217void master_sigsetup(void) 218{ 219 const char *myname = "master_sigsetup"; 220 struct sigaction action; 221 static int sigs[] = { 222 SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM, 223 }; 224 unsigned i; 225 226 sigemptyset(&action.sa_mask); 227 action.sa_flags = 0; 228 229 /* 230 * Prepare to kill our children when we receive any of the above signals. 231 */ 232 action.sa_handler = master_sigdeath; 233 for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) 234 if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0) 235 msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]); 236 237#ifdef USE_SIG_PIPE 238 if (pipe(master_sig_pipe)) 239 msg_fatal("pipe: %m"); 240 non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING); 241 non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING); 242 close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC); 243 close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC); 244 event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (char *) 0); 245#endif 246 247 /* 248 * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit). 249 */ 250#ifdef SA_RESTART 251 action.sa_flags |= SA_RESTART; 252#endif 253 action.sa_handler = master_sighup; 254 if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0) 255 msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP); 256 257 action.sa_flags |= SA_NOCLDSTOP; 258 action.sa_handler = master_sigchld; 259 if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0) 260 msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD); 261} 262