1 /* 2 * Copyright (c) 1999-2000 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 #ifndef lint 12 static char id[] = "@(#)$Id: signal.c,v 8.10.4.7 2000/09/01 00:49:04 ca Exp $"; 13 #endif /* ! lint */ 14 15 #if _FFR_MILTER 16 #include "libmilter.h" 17 18 typedef pthread_mutex_t smutex_t; 19 # define smutex_init(mp) (pthread_mutex_init(mp, NULL) == 0) 20 # define smutex_destroy(mp) (pthread_mutex_destroy(mp) == 0) 21 # define smutex_lock(mp) (pthread_mutex_lock(mp) == 0) 22 # define smutex_unlock(mp) (pthread_mutex_unlock(mp) == 0) 23 # define smutex_trylock(mp) (pthread_mutex_trylock(mp) == 0) 24 25 /* 26 ** thread to handle signals 27 */ 28 29 static smutex_t M_Mutex; 30 31 static int MilterStop = MILTER_CONT; 32 33 /* 34 ** MI_STOP -- return value of MilterStop 35 ** 36 ** Parameters: 37 ** none. 38 ** 39 ** Returns: 40 ** value of MilterStop 41 */ 42 43 int 44 mi_stop() 45 { 46 return MilterStop; 47 } 48 /* 49 ** MI_STOP_MILTERS -- set value of MilterStop 50 ** 51 ** Parameters: 52 ** v -- new value for MilterStop. 53 ** 54 ** Returns: 55 ** none. 56 */ 57 58 void 59 mi_stop_milters(v) 60 int v; 61 { 62 (void) smutex_lock(&M_Mutex); 63 if (MilterStop < v) 64 MilterStop = v; 65 66 /* close listen socket */ 67 mi_closener(); 68 (void) smutex_unlock(&M_Mutex); 69 } 70 /* 71 ** MI_CLEAN_SIGNALS -- clean up signal handler thread 72 ** 73 ** Parameters: 74 ** none. 75 ** 76 ** Returns: 77 ** none. 78 */ 79 80 void 81 mi_clean_signals() 82 { 83 (void) smutex_destroy(&M_Mutex); 84 } 85 /* 86 ** MI_SIGNAL_THREAD -- thread to deal with signals 87 ** 88 ** Parameters: 89 ** name -- name of milter 90 ** 91 ** Returns: 92 ** NULL 93 */ 94 95 static void * 96 mi_signal_thread(name) 97 void *name; 98 { 99 int sig, errs; 100 sigset_t set; 101 102 sigemptyset(&set); 103 sigaddset(&set, SIGHUP); 104 sigaddset(&set, SIGTERM); 105 106 /* Handle Ctrl-C gracefully for debugging */ 107 sigaddset(&set, SIGINT); 108 errs = 0; 109 110 while (TRUE) 111 { 112 sig = 0; 113 #ifdef SOLARIS 114 if ((sig = sigwait(&set)) < 0) 115 #else /* SOLARIS */ 116 if (sigwait(&set, &sig) != 0) 117 #endif /* SOLARIS */ 118 { 119 smi_log(SMI_LOG_ERR, 120 "%s: sigwait returned error: %s", 121 (char *)name, strerror(errno)); 122 if (++errs > MAX_FAILS_T) 123 { 124 mi_stop_milters(MILTER_ABRT); 125 return NULL; 126 } 127 continue; 128 } 129 errs = 0; 130 131 switch (sig) 132 { 133 case SIGHUP: 134 case SIGTERM: 135 mi_stop_milters(MILTER_STOP); 136 return NULL; 137 case SIGINT: 138 mi_stop_milters(MILTER_ABRT); 139 return NULL; 140 default: 141 smi_log(SMI_LOG_ERR, 142 "%s: sigwait returned unmasked signal: %d", 143 (char *)name, sig); 144 break; 145 } 146 } 147 } 148 /* 149 ** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals 150 ** 151 ** Parameters: 152 ** name -- name of milter 153 ** 154 ** Returns: 155 ** MI_SUCCESS/MI_FAILURE 156 */ 157 158 static int 159 mi_spawn_signal_thread(name) 160 char *name; 161 { 162 sthread_t tid; 163 sigset_t set; 164 165 /* Mask HUP and KILL signals */ 166 sigemptyset(&set); 167 sigaddset(&set, SIGHUP); 168 sigaddset(&set, SIGTERM); 169 sigaddset(&set, SIGINT); 170 171 if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) 172 { 173 smi_log(SMI_LOG_ERR, 174 "%s: Couldn't mask HUP and KILL signals", name); 175 return MI_FAILURE; 176 } 177 if (thread_create(&tid, mi_signal_thread, 178 (void *)name) != MI_SUCCESS) 179 { 180 smi_log(SMI_LOG_ERR, 181 "%s: Couldn't start signal thread", name); 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 #endif /* _FFR_MILTER */ 223