xref: /freebsd/contrib/sendmail/libmilter/signal.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
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>
12 SM_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 
20 static smutex_t M_Mutex;
21 
22 static 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 
34 int
35 mi_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 
49 void
50 mi_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 
71 void
72 mi_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 
86 static void *
87 mi_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 
153 static int
154 mi_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 
193 int
194 mi_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