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