1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * 5*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 6*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 7*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate */ 10*7c478bd9Sstevel@tonic-gate 11*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 14*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: signal.c,v 8.42 2004/08/20 21:10:30 ca Exp $") 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include "libmilter.h" 17*7c478bd9Sstevel@tonic-gate 18*7c478bd9Sstevel@tonic-gate /* 19*7c478bd9Sstevel@tonic-gate ** thread to handle signals 20*7c478bd9Sstevel@tonic-gate */ 21*7c478bd9Sstevel@tonic-gate 22*7c478bd9Sstevel@tonic-gate static smutex_t M_Mutex; 23*7c478bd9Sstevel@tonic-gate 24*7c478bd9Sstevel@tonic-gate static int MilterStop = MILTER_CONT; 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate static void *mi_signal_thread __P((void *)); 27*7c478bd9Sstevel@tonic-gate static int mi_spawn_signal_thread __P((char *)); 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate ** MI_STOP -- return value of MilterStop 31*7c478bd9Sstevel@tonic-gate ** 32*7c478bd9Sstevel@tonic-gate ** Parameters: 33*7c478bd9Sstevel@tonic-gate ** none. 34*7c478bd9Sstevel@tonic-gate ** 35*7c478bd9Sstevel@tonic-gate ** Returns: 36*7c478bd9Sstevel@tonic-gate ** value of MilterStop 37*7c478bd9Sstevel@tonic-gate */ 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate int 40*7c478bd9Sstevel@tonic-gate mi_stop() 41*7c478bd9Sstevel@tonic-gate { 42*7c478bd9Sstevel@tonic-gate return MilterStop; 43*7c478bd9Sstevel@tonic-gate } 44*7c478bd9Sstevel@tonic-gate /* 45*7c478bd9Sstevel@tonic-gate ** MI_STOP_MILTERS -- set value of MilterStop 46*7c478bd9Sstevel@tonic-gate ** 47*7c478bd9Sstevel@tonic-gate ** Parameters: 48*7c478bd9Sstevel@tonic-gate ** v -- new value for MilterStop. 49*7c478bd9Sstevel@tonic-gate ** 50*7c478bd9Sstevel@tonic-gate ** Returns: 51*7c478bd9Sstevel@tonic-gate ** none. 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate void 55*7c478bd9Sstevel@tonic-gate mi_stop_milters(v) 56*7c478bd9Sstevel@tonic-gate int v; 57*7c478bd9Sstevel@tonic-gate { 58*7c478bd9Sstevel@tonic-gate (void) smutex_lock(&M_Mutex); 59*7c478bd9Sstevel@tonic-gate if (MilterStop < v) 60*7c478bd9Sstevel@tonic-gate MilterStop = v; 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* close listen socket */ 63*7c478bd9Sstevel@tonic-gate mi_closener(); 64*7c478bd9Sstevel@tonic-gate (void) smutex_unlock(&M_Mutex); 65*7c478bd9Sstevel@tonic-gate } 66*7c478bd9Sstevel@tonic-gate /* 67*7c478bd9Sstevel@tonic-gate ** MI_CLEAN_SIGNALS -- clean up signal handler thread 68*7c478bd9Sstevel@tonic-gate ** 69*7c478bd9Sstevel@tonic-gate ** Parameters: 70*7c478bd9Sstevel@tonic-gate ** none. 71*7c478bd9Sstevel@tonic-gate ** 72*7c478bd9Sstevel@tonic-gate ** Returns: 73*7c478bd9Sstevel@tonic-gate ** none. 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate void 77*7c478bd9Sstevel@tonic-gate mi_clean_signals() 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate (void) smutex_destroy(&M_Mutex); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate ** MI_SIGNAL_THREAD -- thread to deal with signals 83*7c478bd9Sstevel@tonic-gate ** 84*7c478bd9Sstevel@tonic-gate ** Parameters: 85*7c478bd9Sstevel@tonic-gate ** name -- name of milter 86*7c478bd9Sstevel@tonic-gate ** 87*7c478bd9Sstevel@tonic-gate ** Returns: 88*7c478bd9Sstevel@tonic-gate ** NULL 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate static void * 92*7c478bd9Sstevel@tonic-gate mi_signal_thread(name) 93*7c478bd9Sstevel@tonic-gate void *name; 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate int sig, errs; 96*7c478bd9Sstevel@tonic-gate sigset_t set; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&set); 99*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGHUP); 100*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGTERM); 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* Handle Ctrl-C gracefully for debugging */ 103*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGINT); 104*7c478bd9Sstevel@tonic-gate errs = 0; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate for (;;) 107*7c478bd9Sstevel@tonic-gate { 108*7c478bd9Sstevel@tonic-gate sig = 0; 109*7c478bd9Sstevel@tonic-gate #if defined(SOLARIS) || defined(__svr5__) 110*7c478bd9Sstevel@tonic-gate if ((sig = sigwait(&set)) < 0) 111*7c478bd9Sstevel@tonic-gate #else /* defined(SOLARIS) || defined(__svr5__) */ 112*7c478bd9Sstevel@tonic-gate if (sigwait(&set, &sig) != 0) 113*7c478bd9Sstevel@tonic-gate #endif /* defined(SOLARIS) || defined(__svr5__) */ 114*7c478bd9Sstevel@tonic-gate { 115*7c478bd9Sstevel@tonic-gate /* this can happen on OSF/1 (at least) */ 116*7c478bd9Sstevel@tonic-gate if (errno == EINTR) 117*7c478bd9Sstevel@tonic-gate continue; 118*7c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 119*7c478bd9Sstevel@tonic-gate "%s: sigwait returned error: %d", 120*7c478bd9Sstevel@tonic-gate (char *)name, errno); 121*7c478bd9Sstevel@tonic-gate if (++errs > MAX_FAILS_T) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_ABRT); 124*7c478bd9Sstevel@tonic-gate return NULL; 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate continue; 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate errs = 0; 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate switch (sig) 131*7c478bd9Sstevel@tonic-gate { 132*7c478bd9Sstevel@tonic-gate case SIGHUP: 133*7c478bd9Sstevel@tonic-gate case SIGTERM: 134*7c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_STOP); 135*7c478bd9Sstevel@tonic-gate return NULL; 136*7c478bd9Sstevel@tonic-gate case SIGINT: 137*7c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_ABRT); 138*7c478bd9Sstevel@tonic-gate return NULL; 139*7c478bd9Sstevel@tonic-gate default: 140*7c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 141*7c478bd9Sstevel@tonic-gate "%s: sigwait returned unmasked signal: %d", 142*7c478bd9Sstevel@tonic-gate (char *)name, sig); 143*7c478bd9Sstevel@tonic-gate break; 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate /* 149*7c478bd9Sstevel@tonic-gate ** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals 150*7c478bd9Sstevel@tonic-gate ** 151*7c478bd9Sstevel@tonic-gate ** Parameters: 152*7c478bd9Sstevel@tonic-gate ** name -- name of milter 153*7c478bd9Sstevel@tonic-gate ** 154*7c478bd9Sstevel@tonic-gate ** Returns: 155*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 156*7c478bd9Sstevel@tonic-gate */ 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate static int 159*7c478bd9Sstevel@tonic-gate mi_spawn_signal_thread(name) 160*7c478bd9Sstevel@tonic-gate char *name; 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate sthread_t tid; 163*7c478bd9Sstevel@tonic-gate int r; 164*7c478bd9Sstevel@tonic-gate sigset_t set; 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate /* Mask HUP and KILL signals */ 167*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&set); 168*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGHUP); 169*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGTERM); 170*7c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGINT); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) 173*7c478bd9Sstevel@tonic-gate { 174*7c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 175*7c478bd9Sstevel@tonic-gate "%s: Couldn't mask HUP and KILL signals", name); 176*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate r = thread_create(&tid, mi_signal_thread, (void *)name); 179*7c478bd9Sstevel@tonic-gate if (r != 0) 180*7c478bd9Sstevel@tonic-gate { 181*7c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 182*7c478bd9Sstevel@tonic-gate "%s: Couldn't start signal thread: %d", 183*7c478bd9Sstevel@tonic-gate name, r); 184*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 185*7c478bd9Sstevel@tonic-gate } 186*7c478bd9Sstevel@tonic-gate return MI_SUCCESS; 187*7c478bd9Sstevel@tonic-gate } 188*7c478bd9Sstevel@tonic-gate /* 189*7c478bd9Sstevel@tonic-gate ** MI_CONTROL_STARTUP -- startup for thread to handle signals 190*7c478bd9Sstevel@tonic-gate ** 191*7c478bd9Sstevel@tonic-gate ** Parameters: 192*7c478bd9Sstevel@tonic-gate ** name -- name of milter 193*7c478bd9Sstevel@tonic-gate ** 194*7c478bd9Sstevel@tonic-gate ** Returns: 195*7c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate int 199*7c478bd9Sstevel@tonic-gate mi_control_startup(name) 200*7c478bd9Sstevel@tonic-gate char *name; 201*7c478bd9Sstevel@tonic-gate { 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate if (!smutex_init(&M_Mutex)) 204*7c478bd9Sstevel@tonic-gate { 205*7c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 206*7c478bd9Sstevel@tonic-gate "%s: Couldn't initialize control pipe mutex", name); 207*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate /* 211*7c478bd9Sstevel@tonic-gate ** spawn_signal_thread must happen before other threads are spawned 212*7c478bd9Sstevel@tonic-gate ** off so that it can mask the right signals and other threads 213*7c478bd9Sstevel@tonic-gate ** will inherit that mask. 214*7c478bd9Sstevel@tonic-gate */ 215*7c478bd9Sstevel@tonic-gate if (mi_spawn_signal_thread(name) == MI_FAILURE) 216*7c478bd9Sstevel@tonic-gate { 217*7c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR, 218*7c478bd9Sstevel@tonic-gate "%s: Couldn't spawn signal thread", name); 219*7c478bd9Sstevel@tonic-gate (void) smutex_destroy(&M_Mutex); 220*7c478bd9Sstevel@tonic-gate return MI_FAILURE; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate return MI_SUCCESS; 223*7c478bd9Sstevel@tonic-gate } 224