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#ifdef __APPLE_OS_X_SERVER__ 171#include <stdio.h> 172#include <string.h> 173 174static void sigusr1_handler(int sig) 175{ 176 char *myname = "sigusr1_handler"; 177 char pData[1024]; 178 int file_fd = -1; 179 180 file_fd = open( SRVR_MGR_COM_FILE, O_CREAT|O_TRUNC|O_RDWR, 0600 ); 181 if( file_fd == -1 ) 182 { 183 msg_fatal( "can't open com file: %s (%m)", SRVR_MGR_COM_FILE ); 184 } 185 else 186 { 187 snprintf( pData, sizeof pData, SRVR_MGR_DATA, smtp_count, smtpd_count ); 188 189 if ( lseek(file_fd, 0, SEEK_SET) == -1 || 190 ftruncate(file_fd, 0) == -1 || 191 write(file_fd, pData, strlen(pData)) == -1 ) 192 { 193 msg_fatal("%s: can't write to file: %m", myname); 194 } 195 close( file_fd ); 196 } 197} 198#endif 199 200/* master_sigdeath - die, women and children first */ 201 202static void master_sigdeath(int sig) 203{ 204 const char *myname = "master_sigdeath"; 205 struct sigaction action; 206 pid_t pid = getpid(); 207 208 /* 209 * Set alarm clock here for suicide after 5s. 210 */ 211 killme_after(5); 212 213 /* 214 * Terminate all processes in our process group, except ourselves. 215 */ 216 sigemptyset(&action.sa_mask); 217 action.sa_flags = 0; 218 action.sa_handler = SIG_IGN; 219 if (sigaction(SIGTERM, &action, (struct sigaction *) 0) < 0) 220 msg_fatal("%s: sigaction: %m", myname); 221 if (kill(-pid, SIGTERM) < 0) 222 msg_fatal("%s: kill process group: %m", myname); 223 224 /* 225 * XXX We're running from a signal handler, and should not call complex 226 * routines at all, but it would be even worse to silently terminate 227 * without informing the sysadmin. For this reason, msg(3) was made safe 228 * for usage by signal handlers that terminate the process. 229 */ 230 msg_info("terminating on signal %d", sig); 231 232 /* 233 * Deliver the signal to ourselves and clean up. XXX We're running as a 234 * signal handler and really should not be doing complicated things... 235 */ 236 sigemptyset(&action.sa_mask); 237 action.sa_flags = 0; 238 action.sa_handler = SIG_DFL; 239 if (sigaction(sig, &action, (struct sigaction *) 0) < 0) 240 msg_fatal("%s: sigaction: %m", myname); 241 if (kill(pid, sig) < 0) 242 msg_fatal("%s: kill myself: %m", myname); 243} 244 245/* master_sigsetup - set up signal handlers */ 246 247void master_sigsetup(void) 248{ 249 const char *myname = "master_sigsetup"; 250 struct sigaction action; 251 static int sigs[] = { 252 SIGINT, SIGQUIT, SIGILL, SIGBUS, SIGSEGV, SIGTERM, 253 }; 254 unsigned i; 255 256 sigemptyset(&action.sa_mask); 257 action.sa_flags = 0; 258 259 /* 260 * Prepare to kill our children when we receive any of the above signals. 261 */ 262 action.sa_handler = master_sigdeath; 263 for (i = 0; i < sizeof(sigs) / sizeof(sigs[0]); i++) 264 if (sigaction(sigs[i], &action, (struct sigaction *) 0) < 0) 265 msg_fatal("%s: sigaction(%d): %m", myname, sigs[i]); 266 267#ifdef USE_SIG_PIPE 268 if (pipe(master_sig_pipe)) 269 msg_fatal("pipe: %m"); 270 non_blocking(SIG_PIPE_WRITE_FD, NON_BLOCKING); 271 non_blocking(SIG_PIPE_READ_FD, NON_BLOCKING); 272 close_on_exec(SIG_PIPE_WRITE_FD, CLOSE_ON_EXEC); 273 close_on_exec(SIG_PIPE_READ_FD, CLOSE_ON_EXEC); 274 event_enable_read(SIG_PIPE_READ_FD, master_sig_event, (char *) 0); 275#endif 276 277 /* 278 * Intercept SIGHUP (re-read config file) and SIGCHLD (child exit). 279 */ 280#ifdef SA_RESTART 281 action.sa_flags |= SA_RESTART; 282#endif 283 action.sa_handler = master_sighup; 284 if (sigaction(SIGHUP, &action, (struct sigaction *) 0) < 0) 285 msg_fatal("%s: sigaction(%d): %m", myname, SIGHUP); 286 287 action.sa_flags |= SA_NOCLDSTOP; 288 action.sa_handler = master_sigchld; 289 if (sigaction(SIGCHLD, &action, (struct sigaction *) 0) < 0) 290 msg_fatal("%s: sigaction(%d): %m", myname, SIGCHLD); 291 292#ifdef __APPLE_OS_X_SERVER__ 293 action.sa_handler = sigusr1_handler; 294 if (sigaction(SIGUSR1, &action, (struct sigaction *) 0) < 0) 295 msg_fatal("%s: sigaction(%d): %m", myname, SIGUSR1); 296#endif 297} 298