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