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