17c478bd9Sstevel@tonic-gate /*
2*445f2479Sjbeck * Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate *
57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate * the sendmail distribution.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate */
107c478bd9Sstevel@tonic-gate
117c478bd9Sstevel@tonic-gate #include <sm/gen.h>
12*445f2479Sjbeck SM_RCSID("@(#)$Id: signal.c,v 8.44 2006/03/03 03:42:04 ca Exp $")
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #include "libmilter.h"
157c478bd9Sstevel@tonic-gate
167c478bd9Sstevel@tonic-gate /*
177c478bd9Sstevel@tonic-gate ** thread to handle signals
187c478bd9Sstevel@tonic-gate */
197c478bd9Sstevel@tonic-gate
207c478bd9Sstevel@tonic-gate static smutex_t M_Mutex;
217c478bd9Sstevel@tonic-gate
227c478bd9Sstevel@tonic-gate static int MilterStop = MILTER_CONT;
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate static void *mi_signal_thread __P((void *));
257c478bd9Sstevel@tonic-gate static int mi_spawn_signal_thread __P((char *));
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate ** MI_STOP -- return value of MilterStop
297c478bd9Sstevel@tonic-gate **
307c478bd9Sstevel@tonic-gate ** Parameters:
317c478bd9Sstevel@tonic-gate ** none.
327c478bd9Sstevel@tonic-gate **
337c478bd9Sstevel@tonic-gate ** Returns:
347c478bd9Sstevel@tonic-gate ** value of MilterStop
357c478bd9Sstevel@tonic-gate */
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate int
mi_stop()387c478bd9Sstevel@tonic-gate mi_stop()
397c478bd9Sstevel@tonic-gate {
407c478bd9Sstevel@tonic-gate return MilterStop;
417c478bd9Sstevel@tonic-gate }
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate ** MI_STOP_MILTERS -- set value of MilterStop
447c478bd9Sstevel@tonic-gate **
457c478bd9Sstevel@tonic-gate ** Parameters:
467c478bd9Sstevel@tonic-gate ** v -- new value for MilterStop.
477c478bd9Sstevel@tonic-gate **
487c478bd9Sstevel@tonic-gate ** Returns:
497c478bd9Sstevel@tonic-gate ** none.
507c478bd9Sstevel@tonic-gate */
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate void
mi_stop_milters(v)537c478bd9Sstevel@tonic-gate mi_stop_milters(v)
547c478bd9Sstevel@tonic-gate int v;
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate (void) smutex_lock(&M_Mutex);
577c478bd9Sstevel@tonic-gate if (MilterStop < v)
587c478bd9Sstevel@tonic-gate MilterStop = v;
597c478bd9Sstevel@tonic-gate
607c478bd9Sstevel@tonic-gate /* close listen socket */
617c478bd9Sstevel@tonic-gate mi_closener();
627c478bd9Sstevel@tonic-gate (void) smutex_unlock(&M_Mutex);
637c478bd9Sstevel@tonic-gate }
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate ** MI_CLEAN_SIGNALS -- clean up signal handler thread
667c478bd9Sstevel@tonic-gate **
677c478bd9Sstevel@tonic-gate ** Parameters:
687c478bd9Sstevel@tonic-gate ** none.
697c478bd9Sstevel@tonic-gate **
707c478bd9Sstevel@tonic-gate ** Returns:
717c478bd9Sstevel@tonic-gate ** none.
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate void
mi_clean_signals()757c478bd9Sstevel@tonic-gate mi_clean_signals()
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate (void) smutex_destroy(&M_Mutex);
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate ** MI_SIGNAL_THREAD -- thread to deal with signals
817c478bd9Sstevel@tonic-gate **
827c478bd9Sstevel@tonic-gate ** Parameters:
837c478bd9Sstevel@tonic-gate ** name -- name of milter
847c478bd9Sstevel@tonic-gate **
857c478bd9Sstevel@tonic-gate ** Returns:
867c478bd9Sstevel@tonic-gate ** NULL
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate static void *
mi_signal_thread(name)907c478bd9Sstevel@tonic-gate mi_signal_thread(name)
917c478bd9Sstevel@tonic-gate void *name;
927c478bd9Sstevel@tonic-gate {
93*445f2479Sjbeck int sig, errs, sigerr;
947c478bd9Sstevel@tonic-gate sigset_t set;
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate (void) sigemptyset(&set);
977c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGHUP);
987c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGTERM);
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /* Handle Ctrl-C gracefully for debugging */
1017c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGINT);
1027c478bd9Sstevel@tonic-gate errs = 0;
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate for (;;)
1057c478bd9Sstevel@tonic-gate {
106*445f2479Sjbeck sigerr = sig = 0;
1077c478bd9Sstevel@tonic-gate #if defined(SOLARIS) || defined(__svr5__)
1087c478bd9Sstevel@tonic-gate if ((sig = sigwait(&set)) < 0)
1097c478bd9Sstevel@tonic-gate #else /* defined(SOLARIS) || defined(__svr5__) */
110*445f2479Sjbeck if ((sigerr = sigwait(&set, &sig)) != 0)
1117c478bd9Sstevel@tonic-gate #endif /* defined(SOLARIS) || defined(__svr5__) */
1127c478bd9Sstevel@tonic-gate {
113*445f2479Sjbeck /* some OS return -1 and set errno: copy it */
114*445f2479Sjbeck if (sigerr <= 0)
115*445f2479Sjbeck sigerr = errno;
116*445f2479Sjbeck
1177c478bd9Sstevel@tonic-gate /* this can happen on OSF/1 (at least) */
118*445f2479Sjbeck if (sigerr == EINTR)
1197c478bd9Sstevel@tonic-gate continue;
1207c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
1217c478bd9Sstevel@tonic-gate "%s: sigwait returned error: %d",
122*445f2479Sjbeck (char *)name, sigerr);
1237c478bd9Sstevel@tonic-gate if (++errs > MAX_FAILS_T)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_ABRT);
1267c478bd9Sstevel@tonic-gate return NULL;
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate continue;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate errs = 0;
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate switch (sig)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate case SIGHUP:
1357c478bd9Sstevel@tonic-gate case SIGTERM:
1367c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_STOP);
1377c478bd9Sstevel@tonic-gate return NULL;
1387c478bd9Sstevel@tonic-gate case SIGINT:
1397c478bd9Sstevel@tonic-gate mi_stop_milters(MILTER_ABRT);
1407c478bd9Sstevel@tonic-gate return NULL;
1417c478bd9Sstevel@tonic-gate default:
1427c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
1437c478bd9Sstevel@tonic-gate "%s: sigwait returned unmasked signal: %d",
1447c478bd9Sstevel@tonic-gate (char *)name, sig);
1457c478bd9Sstevel@tonic-gate break;
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate /* NOTREACHED */
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate ** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
1527c478bd9Sstevel@tonic-gate **
1537c478bd9Sstevel@tonic-gate ** Parameters:
1547c478bd9Sstevel@tonic-gate ** name -- name of milter
1557c478bd9Sstevel@tonic-gate **
1567c478bd9Sstevel@tonic-gate ** Returns:
1577c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
1587c478bd9Sstevel@tonic-gate */
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate static int
mi_spawn_signal_thread(name)1617c478bd9Sstevel@tonic-gate mi_spawn_signal_thread(name)
1627c478bd9Sstevel@tonic-gate char *name;
1637c478bd9Sstevel@tonic-gate {
1647c478bd9Sstevel@tonic-gate sthread_t tid;
1657c478bd9Sstevel@tonic-gate int r;
1667c478bd9Sstevel@tonic-gate sigset_t set;
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /* Mask HUP and KILL signals */
1697c478bd9Sstevel@tonic-gate (void) sigemptyset(&set);
1707c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGHUP);
1717c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGTERM);
1727c478bd9Sstevel@tonic-gate (void) sigaddset(&set, SIGINT);
1737c478bd9Sstevel@tonic-gate
1747c478bd9Sstevel@tonic-gate if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
1777c478bd9Sstevel@tonic-gate "%s: Couldn't mask HUP and KILL signals", name);
1787c478bd9Sstevel@tonic-gate return MI_FAILURE;
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate r = thread_create(&tid, mi_signal_thread, (void *)name);
1817c478bd9Sstevel@tonic-gate if (r != 0)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
1847c478bd9Sstevel@tonic-gate "%s: Couldn't start signal thread: %d",
1857c478bd9Sstevel@tonic-gate name, r);
1867c478bd9Sstevel@tonic-gate return MI_FAILURE;
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate return MI_SUCCESS;
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate ** MI_CONTROL_STARTUP -- startup for thread to handle signals
1927c478bd9Sstevel@tonic-gate **
1937c478bd9Sstevel@tonic-gate ** Parameters:
1947c478bd9Sstevel@tonic-gate ** name -- name of milter
1957c478bd9Sstevel@tonic-gate **
1967c478bd9Sstevel@tonic-gate ** Returns:
1977c478bd9Sstevel@tonic-gate ** MI_SUCCESS/MI_FAILURE
1987c478bd9Sstevel@tonic-gate */
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate int
mi_control_startup(name)2017c478bd9Sstevel@tonic-gate mi_control_startup(name)
2027c478bd9Sstevel@tonic-gate char *name;
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate if (!smutex_init(&M_Mutex))
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
2087c478bd9Sstevel@tonic-gate "%s: Couldn't initialize control pipe mutex", name);
2097c478bd9Sstevel@tonic-gate return MI_FAILURE;
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate ** spawn_signal_thread must happen before other threads are spawned
2147c478bd9Sstevel@tonic-gate ** off so that it can mask the right signals and other threads
2157c478bd9Sstevel@tonic-gate ** will inherit that mask.
2167c478bd9Sstevel@tonic-gate */
2177c478bd9Sstevel@tonic-gate if (mi_spawn_signal_thread(name) == MI_FAILURE)
2187c478bd9Sstevel@tonic-gate {
2197c478bd9Sstevel@tonic-gate smi_log(SMI_LOG_ERR,
2207c478bd9Sstevel@tonic-gate "%s: Couldn't spawn signal thread", name);
2217c478bd9Sstevel@tonic-gate (void) smutex_destroy(&M_Mutex);
2227c478bd9Sstevel@tonic-gate return MI_FAILURE;
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate return MI_SUCCESS;
2257c478bd9Sstevel@tonic-gate }
226