signal.c revision 90792
1/*
2 *  Copyright (c) 1999-2001 Sendmail, 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.35 2002/01/10 01:34:55 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
24/*
25**  MI_STOP -- return value of MilterStop
26**
27**	Parameters:
28**		none.
29**
30**	Returns:
31**		value of MilterStop
32*/
33
34int
35mi_stop()
36{
37	return MilterStop;
38}
39/*
40**  MI_STOP_MILTERS -- set value of MilterStop
41**
42**	Parameters:
43**		v -- new value for MilterStop.
44**
45**	Returns:
46**		none.
47*/
48
49void
50mi_stop_milters(v)
51	int v;
52{
53	(void) smutex_lock(&M_Mutex);
54	if (MilterStop < v)
55		MilterStop = v;
56
57	/* close listen socket */
58	mi_closener();
59	(void) smutex_unlock(&M_Mutex);
60}
61/*
62**  MI_CLEAN_SIGNALS -- clean up signal handler thread
63**
64**	Parameters:
65**		none.
66**
67**	Returns:
68**		none.
69*/
70
71void
72mi_clean_signals()
73{
74	(void) smutex_destroy(&M_Mutex);
75}
76/*
77**  MI_SIGNAL_THREAD -- thread to deal with signals
78**
79**	Parameters:
80**		name -- name of milter
81**
82**	Returns:
83**		NULL
84*/
85
86static void *
87mi_signal_thread(name)
88	void *name;
89{
90	int sig, errs;
91	sigset_t set;
92
93	sigemptyset(&set);
94	sigaddset(&set, SIGHUP);
95	sigaddset(&set, SIGTERM);
96
97	/* Handle Ctrl-C gracefully for debugging */
98	sigaddset(&set, SIGINT);
99	errs = 0;
100
101	while (true)
102	{
103		sig = 0;
104#if defined(SOLARIS) || defined(__svr5__)
105		if ((sig = sigwait(&set)) < 0)
106#else /* defined(SOLARIS) || defined(__svr5__) */
107		if (sigwait(&set, &sig) != 0)
108#endif /* defined(SOLARIS) || defined(__svr5__) */
109		{
110			smi_log(SMI_LOG_ERR,
111				"%s: sigwait returned error: %d",
112				(char *)name, errno);
113			if (++errs > MAX_FAILS_T)
114			{
115				mi_stop_milters(MILTER_ABRT);
116				return NULL;
117			}
118			continue;
119		}
120		errs = 0;
121
122		switch (sig)
123		{
124		  case SIGHUP:
125		  case SIGTERM:
126			mi_stop_milters(MILTER_STOP);
127			return NULL;
128		  case SIGINT:
129			mi_stop_milters(MILTER_ABRT);
130			return NULL;
131		  default:
132			smi_log(SMI_LOG_ERR,
133				"%s: sigwait returned unmasked signal: %d",
134				(char *)name, sig);
135			break;
136		}
137	}
138}
139/*
140**  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
141**
142**	Parameters:
143**		name -- name of milter
144**
145**	Returns:
146**		MI_SUCCESS/MI_FAILURE
147*/
148
149static int
150mi_spawn_signal_thread(name)
151	char *name;
152{
153	sthread_t tid;
154	int r;
155	sigset_t set;
156
157	/* Mask HUP and KILL signals */
158	sigemptyset(&set);
159	sigaddset(&set, SIGHUP);
160	sigaddset(&set, SIGTERM);
161	sigaddset(&set, SIGINT);
162
163	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
164	{
165		smi_log(SMI_LOG_ERR,
166			"%s: Couldn't mask HUP and KILL signals", name);
167		return MI_FAILURE;
168	}
169	r = thread_create(&tid, mi_signal_thread, (void *)name);
170	if (r != 0)
171	{
172		smi_log(SMI_LOG_ERR,
173			"%s: Couldn't start signal thread: %d",
174			name, r);
175		return MI_FAILURE;
176	}
177	return MI_SUCCESS;
178}
179/*
180**  MI_CONTROL_STARTUP -- startup for thread to handle signals
181**
182**	Parameters:
183**		name -- name of milter
184**
185**	Returns:
186**		MI_SUCCESS/MI_FAILURE
187*/
188
189int
190mi_control_startup(name)
191	char *name;
192{
193
194	if (!smutex_init(&M_Mutex))
195	{
196		smi_log(SMI_LOG_ERR,
197			"%s: Couldn't initialize control pipe mutex", name);
198		return MI_FAILURE;
199	}
200
201	/*
202	**  spawn_signal_thread must happen before other threads are spawned
203	**  off so that it can mask the right signals and other threads
204	**  will inherit that mask.
205	*/
206	if (mi_spawn_signal_thread(name) == MI_FAILURE)
207	{
208		smi_log(SMI_LOG_ERR,
209			"%s: Couldn't spawn signal thread", name);
210		(void) smutex_destroy(&M_Mutex);
211		return MI_FAILURE;
212	}
213	return MI_SUCCESS;
214}
215