xref: /onnv-gate/usr/src/cmd/sendmail/libmilter/signal.c (revision 1658:e3b42aa6425a)
10Sstevel@tonic-gate /*
2*1658Sjbeck  *  Copyright (c) 1999-2004, 2006 Sendmail, Inc. and its suppliers.
30Sstevel@tonic-gate  *	All rights reserved.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
60Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
70Sstevel@tonic-gate  * the sendmail distribution.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  */
100Sstevel@tonic-gate 
110Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
120Sstevel@tonic-gate 
130Sstevel@tonic-gate #include <sm/gen.h>
14*1658Sjbeck SM_RCSID("@(#)$Id: signal.c,v 8.44 2006/03/03 03:42:04 ca Exp $")
150Sstevel@tonic-gate 
160Sstevel@tonic-gate #include "libmilter.h"
170Sstevel@tonic-gate 
180Sstevel@tonic-gate /*
190Sstevel@tonic-gate **  thread to handle signals
200Sstevel@tonic-gate */
210Sstevel@tonic-gate 
220Sstevel@tonic-gate static smutex_t M_Mutex;
230Sstevel@tonic-gate 
240Sstevel@tonic-gate static int MilterStop = MILTER_CONT;
250Sstevel@tonic-gate 
260Sstevel@tonic-gate static void	*mi_signal_thread __P((void *));
270Sstevel@tonic-gate static int	 mi_spawn_signal_thread __P((char *));
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate **  MI_STOP -- return value of MilterStop
310Sstevel@tonic-gate **
320Sstevel@tonic-gate **	Parameters:
330Sstevel@tonic-gate **		none.
340Sstevel@tonic-gate **
350Sstevel@tonic-gate **	Returns:
360Sstevel@tonic-gate **		value of MilterStop
370Sstevel@tonic-gate */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate int
mi_stop()400Sstevel@tonic-gate mi_stop()
410Sstevel@tonic-gate {
420Sstevel@tonic-gate 	return MilterStop;
430Sstevel@tonic-gate }
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate **  MI_STOP_MILTERS -- set value of MilterStop
460Sstevel@tonic-gate **
470Sstevel@tonic-gate **	Parameters:
480Sstevel@tonic-gate **		v -- new value for MilterStop.
490Sstevel@tonic-gate **
500Sstevel@tonic-gate **	Returns:
510Sstevel@tonic-gate **		none.
520Sstevel@tonic-gate */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate void
mi_stop_milters(v)550Sstevel@tonic-gate mi_stop_milters(v)
560Sstevel@tonic-gate 	int v;
570Sstevel@tonic-gate {
580Sstevel@tonic-gate 	(void) smutex_lock(&M_Mutex);
590Sstevel@tonic-gate 	if (MilterStop < v)
600Sstevel@tonic-gate 		MilterStop = v;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	/* close listen socket */
630Sstevel@tonic-gate 	mi_closener();
640Sstevel@tonic-gate 	(void) smutex_unlock(&M_Mutex);
650Sstevel@tonic-gate }
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate **  MI_CLEAN_SIGNALS -- clean up signal handler thread
680Sstevel@tonic-gate **
690Sstevel@tonic-gate **	Parameters:
700Sstevel@tonic-gate **		none.
710Sstevel@tonic-gate **
720Sstevel@tonic-gate **	Returns:
730Sstevel@tonic-gate **		none.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate 
760Sstevel@tonic-gate void
mi_clean_signals()770Sstevel@tonic-gate mi_clean_signals()
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 	(void) smutex_destroy(&M_Mutex);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate /*
820Sstevel@tonic-gate **  MI_SIGNAL_THREAD -- thread to deal with signals
830Sstevel@tonic-gate **
840Sstevel@tonic-gate **	Parameters:
850Sstevel@tonic-gate **		name -- name of milter
860Sstevel@tonic-gate **
870Sstevel@tonic-gate **	Returns:
880Sstevel@tonic-gate **		NULL
890Sstevel@tonic-gate */
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static void *
mi_signal_thread(name)920Sstevel@tonic-gate mi_signal_thread(name)
930Sstevel@tonic-gate 	void *name;
940Sstevel@tonic-gate {
95*1658Sjbeck 	int sig, errs, sigerr;
960Sstevel@tonic-gate 	sigset_t set;
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	(void) sigemptyset(&set);
990Sstevel@tonic-gate 	(void) sigaddset(&set, SIGHUP);
1000Sstevel@tonic-gate 	(void) sigaddset(&set, SIGTERM);
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	/* Handle Ctrl-C gracefully for debugging */
1030Sstevel@tonic-gate 	(void) sigaddset(&set, SIGINT);
1040Sstevel@tonic-gate 	errs = 0;
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	for (;;)
1070Sstevel@tonic-gate 	{
108*1658Sjbeck 		sigerr = sig = 0;
1090Sstevel@tonic-gate #if defined(SOLARIS) || defined(__svr5__)
1100Sstevel@tonic-gate 		if ((sig = sigwait(&set)) < 0)
1110Sstevel@tonic-gate #else /* defined(SOLARIS) || defined(__svr5__) */
112*1658Sjbeck 		if ((sigerr = sigwait(&set, &sig)) != 0)
1130Sstevel@tonic-gate #endif /* defined(SOLARIS) || defined(__svr5__) */
1140Sstevel@tonic-gate 		{
115*1658Sjbeck 			/* some OS return -1 and set errno: copy it */
116*1658Sjbeck 			if (sigerr <= 0)
117*1658Sjbeck 				sigerr = errno;
118*1658Sjbeck 
1190Sstevel@tonic-gate 			/* this can happen on OSF/1 (at least) */
120*1658Sjbeck 			if (sigerr == EINTR)
1210Sstevel@tonic-gate 				continue;
1220Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
1230Sstevel@tonic-gate 				"%s: sigwait returned error: %d",
124*1658Sjbeck 				(char *)name, sigerr);
1250Sstevel@tonic-gate 			if (++errs > MAX_FAILS_T)
1260Sstevel@tonic-gate 			{
1270Sstevel@tonic-gate 				mi_stop_milters(MILTER_ABRT);
1280Sstevel@tonic-gate 				return NULL;
1290Sstevel@tonic-gate 			}
1300Sstevel@tonic-gate 			continue;
1310Sstevel@tonic-gate 		}
1320Sstevel@tonic-gate 		errs = 0;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 		switch (sig)
1350Sstevel@tonic-gate 		{
1360Sstevel@tonic-gate 		  case SIGHUP:
1370Sstevel@tonic-gate 		  case SIGTERM:
1380Sstevel@tonic-gate 			mi_stop_milters(MILTER_STOP);
1390Sstevel@tonic-gate 			return NULL;
1400Sstevel@tonic-gate 		  case SIGINT:
1410Sstevel@tonic-gate 			mi_stop_milters(MILTER_ABRT);
1420Sstevel@tonic-gate 			return NULL;
1430Sstevel@tonic-gate 		  default:
1440Sstevel@tonic-gate 			smi_log(SMI_LOG_ERR,
1450Sstevel@tonic-gate 				"%s: sigwait returned unmasked signal: %d",
1460Sstevel@tonic-gate 				(char *)name, sig);
1470Sstevel@tonic-gate 			break;
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 	/* NOTREACHED */
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate **  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
1540Sstevel@tonic-gate **
1550Sstevel@tonic-gate **	Parameters:
1560Sstevel@tonic-gate **		name -- name of milter
1570Sstevel@tonic-gate **
1580Sstevel@tonic-gate **	Returns:
1590Sstevel@tonic-gate **		MI_SUCCESS/MI_FAILURE
1600Sstevel@tonic-gate */
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static int
mi_spawn_signal_thread(name)1630Sstevel@tonic-gate mi_spawn_signal_thread(name)
1640Sstevel@tonic-gate 	char *name;
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate 	sthread_t tid;
1670Sstevel@tonic-gate 	int r;
1680Sstevel@tonic-gate 	sigset_t set;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	/* Mask HUP and KILL signals */
1710Sstevel@tonic-gate 	(void) sigemptyset(&set);
1720Sstevel@tonic-gate 	(void) sigaddset(&set, SIGHUP);
1730Sstevel@tonic-gate 	(void) sigaddset(&set, SIGTERM);
1740Sstevel@tonic-gate 	(void) sigaddset(&set, SIGINT);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
1770Sstevel@tonic-gate 	{
1780Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
1790Sstevel@tonic-gate 			"%s: Couldn't mask HUP and KILL signals", name);
1800Sstevel@tonic-gate 		return MI_FAILURE;
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate 	r = thread_create(&tid, mi_signal_thread, (void *)name);
1830Sstevel@tonic-gate 	if (r != 0)
1840Sstevel@tonic-gate 	{
1850Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
1860Sstevel@tonic-gate 			"%s: Couldn't start signal thread: %d",
1870Sstevel@tonic-gate 			name, r);
1880Sstevel@tonic-gate 		return MI_FAILURE;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 	return MI_SUCCESS;
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate **  MI_CONTROL_STARTUP -- startup for thread to handle signals
1940Sstevel@tonic-gate **
1950Sstevel@tonic-gate **	Parameters:
1960Sstevel@tonic-gate **		name -- name of milter
1970Sstevel@tonic-gate **
1980Sstevel@tonic-gate **	Returns:
1990Sstevel@tonic-gate **		MI_SUCCESS/MI_FAILURE
2000Sstevel@tonic-gate */
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate int
mi_control_startup(name)2030Sstevel@tonic-gate mi_control_startup(name)
2040Sstevel@tonic-gate 	char *name;
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if (!smutex_init(&M_Mutex))
2080Sstevel@tonic-gate 	{
2090Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
2100Sstevel@tonic-gate 			"%s: Couldn't initialize control pipe mutex", name);
2110Sstevel@tonic-gate 		return MI_FAILURE;
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	/*
2150Sstevel@tonic-gate 	**  spawn_signal_thread must happen before other threads are spawned
2160Sstevel@tonic-gate 	**  off so that it can mask the right signals and other threads
2170Sstevel@tonic-gate 	**  will inherit that mask.
2180Sstevel@tonic-gate 	*/
2190Sstevel@tonic-gate 	if (mi_spawn_signal_thread(name) == MI_FAILURE)
2200Sstevel@tonic-gate 	{
2210Sstevel@tonic-gate 		smi_log(SMI_LOG_ERR,
2220Sstevel@tonic-gate 			"%s: Couldn't spawn signal thread", name);
2230Sstevel@tonic-gate 		(void) smutex_destroy(&M_Mutex);
2240Sstevel@tonic-gate 		return MI_FAILURE;
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 	return MI_SUCCESS;
2270Sstevel@tonic-gate }
228