1 /* 2 * Copyright (c) 1999-2003 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.41 2003/11/19 00:25:20 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 (void) sigemptyset(&set); 94 (void) sigaddset(&set, SIGHUP); 95 (void) sigaddset(&set, SIGTERM); 96 97 /* Handle Ctrl-C gracefully for debugging */ 98 (void) sigaddset(&set, SIGINT); 99 errs = 0; 100 101 for (;;) 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 /* this can happen on OSF/1 (at least) */ 111 if (errno == EINTR) 112 continue; 113 smi_log(SMI_LOG_ERR, 114 "%s: sigwait returned error: %d", 115 (char *)name, errno); 116 if (++errs > MAX_FAILS_T) 117 { 118 mi_stop_milters(MILTER_ABRT); 119 return NULL; 120 } 121 continue; 122 } 123 errs = 0; 124 125 switch (sig) 126 { 127 case SIGHUP: 128 case SIGTERM: 129 mi_stop_milters(MILTER_STOP); 130 return NULL; 131 case SIGINT: 132 mi_stop_milters(MILTER_ABRT); 133 return NULL; 134 default: 135 smi_log(SMI_LOG_ERR, 136 "%s: sigwait returned unmasked signal: %d", 137 (char *)name, sig); 138 break; 139 } 140 } 141 /* NOTREACHED */ 142 } 143 /* 144 ** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals 145 ** 146 ** Parameters: 147 ** name -- name of milter 148 ** 149 ** Returns: 150 ** MI_SUCCESS/MI_FAILURE 151 */ 152 153 static int 154 mi_spawn_signal_thread(name) 155 char *name; 156 { 157 sthread_t tid; 158 int r; 159 sigset_t set; 160 161 /* Mask HUP and KILL signals */ 162 (void) sigemptyset(&set); 163 (void) sigaddset(&set, SIGHUP); 164 (void) sigaddset(&set, SIGTERM); 165 (void) sigaddset(&set, SIGINT); 166 167 if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) 168 { 169 smi_log(SMI_LOG_ERR, 170 "%s: Couldn't mask HUP and KILL signals", name); 171 return MI_FAILURE; 172 } 173 r = thread_create(&tid, mi_signal_thread, (void *)name); 174 if (r != 0) 175 { 176 smi_log(SMI_LOG_ERR, 177 "%s: Couldn't start signal thread: %d", 178 name, r); 179 return MI_FAILURE; 180 } 181 return MI_SUCCESS; 182 } 183 /* 184 ** MI_CONTROL_STARTUP -- startup for thread to handle signals 185 ** 186 ** Parameters: 187 ** name -- name of milter 188 ** 189 ** Returns: 190 ** MI_SUCCESS/MI_FAILURE 191 */ 192 193 int 194 mi_control_startup(name) 195 char *name; 196 { 197 198 if (!smutex_init(&M_Mutex)) 199 { 200 smi_log(SMI_LOG_ERR, 201 "%s: Couldn't initialize control pipe mutex", name); 202 return MI_FAILURE; 203 } 204 205 /* 206 ** spawn_signal_thread must happen before other threads are spawned 207 ** off so that it can mask the right signals and other threads 208 ** will inherit that mask. 209 */ 210 if (mi_spawn_signal_thread(name) == MI_FAILURE) 211 { 212 smi_log(SMI_LOG_ERR, 213 "%s: Couldn't spawn signal thread", name); 214 (void) smutex_destroy(&M_Mutex); 215 return MI_FAILURE; 216 } 217 return MI_SUCCESS; 218 } 219