xref: /freebsd/contrib/sendmail/libmilter/signal.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
1 /*
2  *  Copyright (c) 1999-2004 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>
12 SM_RCSID("@(#)$Id: signal.c,v 8.42 2004/08/20 21:10:30 ca Exp $")
13 
14 #include "libmilter.h"
15 
16 /*
17 **  thread to handle signals
18 */
19 
20 static smutex_t M_Mutex;
21 
22 static int MilterStop = MILTER_CONT;
23 
24 static void	*mi_signal_thread __P((void *));
25 static int	 mi_spawn_signal_thread __P((char *));
26 
27 /*
28 **  MI_STOP -- return value of MilterStop
29 **
30 **	Parameters:
31 **		none.
32 **
33 **	Returns:
34 **		value of MilterStop
35 */
36 
37 int
38 mi_stop()
39 {
40 	return MilterStop;
41 }
42 /*
43 **  MI_STOP_MILTERS -- set value of MilterStop
44 **
45 **	Parameters:
46 **		v -- new value for MilterStop.
47 **
48 **	Returns:
49 **		none.
50 */
51 
52 void
53 mi_stop_milters(v)
54 	int v;
55 {
56 	(void) smutex_lock(&M_Mutex);
57 	if (MilterStop < v)
58 		MilterStop = v;
59 
60 	/* close listen socket */
61 	mi_closener();
62 	(void) smutex_unlock(&M_Mutex);
63 }
64 /*
65 **  MI_CLEAN_SIGNALS -- clean up signal handler thread
66 **
67 **	Parameters:
68 **		none.
69 **
70 **	Returns:
71 **		none.
72 */
73 
74 void
75 mi_clean_signals()
76 {
77 	(void) smutex_destroy(&M_Mutex);
78 }
79 /*
80 **  MI_SIGNAL_THREAD -- thread to deal with signals
81 **
82 **	Parameters:
83 **		name -- name of milter
84 **
85 **	Returns:
86 **		NULL
87 */
88 
89 static void *
90 mi_signal_thread(name)
91 	void *name;
92 {
93 	int sig, errs;
94 	sigset_t set;
95 
96 	(void) sigemptyset(&set);
97 	(void) sigaddset(&set, SIGHUP);
98 	(void) sigaddset(&set, SIGTERM);
99 
100 	/* Handle Ctrl-C gracefully for debugging */
101 	(void) sigaddset(&set, SIGINT);
102 	errs = 0;
103 
104 	for (;;)
105 	{
106 		sig = 0;
107 #if defined(SOLARIS) || defined(__svr5__)
108 		if ((sig = sigwait(&set)) < 0)
109 #else /* defined(SOLARIS) || defined(__svr5__) */
110 		if (sigwait(&set, &sig) != 0)
111 #endif /* defined(SOLARIS) || defined(__svr5__) */
112 		{
113 			/* this can happen on OSF/1 (at least) */
114 			if (errno == EINTR)
115 				continue;
116 			smi_log(SMI_LOG_ERR,
117 				"%s: sigwait returned error: %d",
118 				(char *)name, errno);
119 			if (++errs > MAX_FAILS_T)
120 			{
121 				mi_stop_milters(MILTER_ABRT);
122 				return NULL;
123 			}
124 			continue;
125 		}
126 		errs = 0;
127 
128 		switch (sig)
129 		{
130 		  case SIGHUP:
131 		  case SIGTERM:
132 			mi_stop_milters(MILTER_STOP);
133 			return NULL;
134 		  case SIGINT:
135 			mi_stop_milters(MILTER_ABRT);
136 			return NULL;
137 		  default:
138 			smi_log(SMI_LOG_ERR,
139 				"%s: sigwait returned unmasked signal: %d",
140 				(char *)name, sig);
141 			break;
142 		}
143 	}
144 	/* NOTREACHED */
145 }
146 /*
147 **  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
148 **
149 **	Parameters:
150 **		name -- name of milter
151 **
152 **	Returns:
153 **		MI_SUCCESS/MI_FAILURE
154 */
155 
156 static int
157 mi_spawn_signal_thread(name)
158 	char *name;
159 {
160 	sthread_t tid;
161 	int r;
162 	sigset_t set;
163 
164 	/* Mask HUP and KILL signals */
165 	(void) sigemptyset(&set);
166 	(void) sigaddset(&set, SIGHUP);
167 	(void) sigaddset(&set, SIGTERM);
168 	(void) sigaddset(&set, SIGINT);
169 
170 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
171 	{
172 		smi_log(SMI_LOG_ERR,
173 			"%s: Couldn't mask HUP and KILL signals", name);
174 		return MI_FAILURE;
175 	}
176 	r = thread_create(&tid, mi_signal_thread, (void *)name);
177 	if (r != 0)
178 	{
179 		smi_log(SMI_LOG_ERR,
180 			"%s: Couldn't start signal thread: %d",
181 			name, r);
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 
196 int
197 mi_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