xref: /freebsd/contrib/sendmail/libmilter/signal.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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
12 static 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 
18 typedef 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 
29 static smutex_t M_Mutex;
30 
31 static 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 
43 int
44 mi_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 
58 void
59 mi_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 
80 void
81 mi_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 
95 static void *
96 mi_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 
158 static int
159 mi_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 
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 #endif /* _FFR_MILTER */
223