signal.c revision 132943
1/*
2 *  Copyright (c) 1999-2003 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.41 2003/11/19 00:25:20 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	(void) sigemptyset(&set);
94	(void) sigaddset(&set, SIGHUP);
95	(void) sigaddset(&set, SIGTERM);
96
97	/* Handle Ctrl-C gracefully for debugging */
98	(void) sigaddset(&set, SIGINT);
99	errs = 0;
100
101	for (;;)
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			/* this can happen on OSF/1 (at least) */
111			if (errno == EINTR)
112				continue;
113			smi_log(SMI_LOG_ERR,
114				"%s: sigwait returned error: %d",
115				(char *)name, errno);
116			if (++errs > MAX_FAILS_T)
117			{
118				mi_stop_milters(MILTER_ABRT);
119				return NULL;
120			}
121			continue;
122		}
123		errs = 0;
124
125		switch (sig)
126		{
127		  case SIGHUP:
128		  case SIGTERM:
129			mi_stop_milters(MILTER_STOP);
130			return NULL;
131		  case SIGINT:
132			mi_stop_milters(MILTER_ABRT);
133			return NULL;
134		  default:
135			smi_log(SMI_LOG_ERR,
136				"%s: sigwait returned unmasked signal: %d",
137				(char *)name, sig);
138			break;
139		}
140	}
141	/* NOTREACHED */
142}
143/*
144**  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
145**
146**	Parameters:
147**		name -- name of milter
148**
149**	Returns:
150**		MI_SUCCESS/MI_FAILURE
151*/
152
153static int
154mi_spawn_signal_thread(name)
155	char *name;
156{
157	sthread_t tid;
158	int r;
159	sigset_t set;
160
161	/* Mask HUP and KILL signals */
162	(void) sigemptyset(&set);
163	(void) sigaddset(&set, SIGHUP);
164	(void) sigaddset(&set, SIGTERM);
165	(void) sigaddset(&set, SIGINT);
166
167	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
168	{
169		smi_log(SMI_LOG_ERR,
170			"%s: Couldn't mask HUP and KILL signals", name);
171		return MI_FAILURE;
172	}
173	r = thread_create(&tid, mi_signal_thread, (void *)name);
174	if (r != 0)
175	{
176		smi_log(SMI_LOG_ERR,
177			"%s: Couldn't start signal thread: %d",
178			name, r);
179		return MI_FAILURE;
180	}
181	return MI_SUCCESS;
182}
183/*
184**  MI_CONTROL_STARTUP -- startup for thread to handle signals
185**
186**	Parameters:
187**		name -- name of milter
188**
189**	Returns:
190**		MI_SUCCESS/MI_FAILURE
191*/
192
193int
194mi_control_startup(name)
195	char *name;
196{
197
198	if (!smutex_init(&M_Mutex))
199	{
200		smi_log(SMI_LOG_ERR,
201			"%s: Couldn't initialize control pipe mutex", name);
202		return MI_FAILURE;
203	}
204
205	/*
206	**  spawn_signal_thread must happen before other threads are spawned
207	**  off so that it can mask the right signals and other threads
208	**  will inherit that mask.
209	*/
210	if (mi_spawn_signal_thread(name) == MI_FAILURE)
211	{
212		smi_log(SMI_LOG_ERR,
213			"%s: Couldn't spawn signal thread", name);
214		(void) smutex_destroy(&M_Mutex);
215		return MI_FAILURE;
216	}
217	return MI_SUCCESS;
218}
219