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