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