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> 12SM_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 20static smutex_t M_Mutex; 21 22static int MilterStop = MILTER_CONT; 23 24static void *mi_signal_thread __P((void *)); 25static 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 37int 38mi_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 52void 53mi_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 74void 75mi_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 89static void * 90mi_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 160static int 161mi_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 200int 201mi_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