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