diff options
Diffstat (limited to 'sendmail/libmilter/signal.c')
-rw-r--r-- | sendmail/libmilter/signal.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/sendmail/libmilter/signal.c b/sendmail/libmilter/signal.c new file mode 100644 index 0000000..ad68469 --- /dev/null +++ b/sendmail/libmilter/signal.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +SM_RCSID("@(#)$Id: signal.c,v 8.44 2006/03/03 03:42:04 ca Exp $") + +#include "libmilter.h" + +/* +** thread to handle signals +*/ + +static smutex_t M_Mutex; + +static int MilterStop = MILTER_CONT; + +static void *mi_signal_thread __P((void *)); +static int mi_spawn_signal_thread __P((char *)); + +/* +** MI_STOP -- return value of MilterStop +** +** Parameters: +** none. +** +** Returns: +** value of MilterStop +*/ + +int +mi_stop() +{ + return MilterStop; +} +/* +** MI_STOP_MILTERS -- set value of MilterStop +** +** Parameters: +** v -- new value for MilterStop. +** +** Returns: +** none. +*/ + +void +mi_stop_milters(v) + int v; +{ + (void) smutex_lock(&M_Mutex); + if (MilterStop < v) + MilterStop = v; + + /* close listen socket */ + mi_closener(); + (void) smutex_unlock(&M_Mutex); +} +/* +** MI_CLEAN_SIGNALS -- clean up signal handler thread +** +** Parameters: +** none. +** +** Returns: +** none. +*/ + +void +mi_clean_signals() +{ + (void) smutex_destroy(&M_Mutex); +} +/* +** MI_SIGNAL_THREAD -- thread to deal with signals +** +** Parameters: +** name -- name of milter +** +** Returns: +** NULL +*/ + +static void * +mi_signal_thread(name) + void *name; +{ + int sig, errs, sigerr; + sigset_t set; + + (void) sigemptyset(&set); + (void) sigaddset(&set, SIGHUP); + (void) sigaddset(&set, SIGTERM); + + /* Handle Ctrl-C gracefully for debugging */ + (void) sigaddset(&set, SIGINT); + errs = 0; + + for (;;) + { + sigerr = sig = 0; +#if defined(SOLARIS) || defined(__svr5__) + if ((sig = sigwait(&set)) < 0) +#else /* defined(SOLARIS) || defined(__svr5__) */ + if ((sigerr = sigwait(&set, &sig)) != 0) +#endif /* defined(SOLARIS) || defined(__svr5__) */ + { + /* some OS return -1 and set errno: copy it */ + if (sigerr <= 0) + sigerr = errno; + + /* this can happen on OSF/1 (at least) */ + if (sigerr == EINTR) + continue; + smi_log(SMI_LOG_ERR, + "%s: sigwait returned error: %d", + (char *)name, sigerr); + if (++errs > MAX_FAILS_T) + { + mi_stop_milters(MILTER_ABRT); + return NULL; + } + continue; + } + errs = 0; + + switch (sig) + { + case SIGHUP: + case SIGTERM: + mi_stop_milters(MILTER_STOP); + return NULL; + case SIGINT: + mi_stop_milters(MILTER_ABRT); + return NULL; + default: + smi_log(SMI_LOG_ERR, + "%s: sigwait returned unmasked signal: %d", + (char *)name, sig); + break; + } + } + /* NOTREACHED */ +} +/* +** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals +** +** Parameters: +** name -- name of milter +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +static int +mi_spawn_signal_thread(name) + char *name; +{ + sthread_t tid; + int r; + sigset_t set; + + /* Mask HUP and KILL signals */ + (void) sigemptyset(&set); + (void) sigaddset(&set, SIGHUP); + (void) sigaddset(&set, SIGTERM); + (void) sigaddset(&set, SIGINT); + + if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't mask HUP and KILL signals", name); + return MI_FAILURE; + } + r = thread_create(&tid, mi_signal_thread, (void *)name); + if (r != 0) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't start signal thread: %d", + name, r); + return MI_FAILURE; + } + return MI_SUCCESS; +} +/* +** MI_CONTROL_STARTUP -- startup for thread to handle signals +** +** Parameters: +** name -- name of milter +** +** Returns: +** MI_SUCCESS/MI_FAILURE +*/ + +int +mi_control_startup(name) + char *name; +{ + + if (!smutex_init(&M_Mutex)) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't initialize control pipe mutex", name); + return MI_FAILURE; + } + + /* + ** spawn_signal_thread must happen before other threads are spawned + ** off so that it can mask the right signals and other threads + ** will inherit that mask. + */ + if (mi_spawn_signal_thread(name) == MI_FAILURE) + { + smi_log(SMI_LOG_ERR, + "%s: Couldn't spawn signal thread", name); + (void) smutex_destroy(&M_Mutex); + return MI_FAILURE; + } + return MI_SUCCESS; +} |