xref: /freebsd/contrib/sendmail/libmilter/signal.c (revision 2ef40764f06885f97d380ee8de0ced64930423db)
1 /*
2  *  Copyright (c) 1999-2002 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.37.2.2 2002/10/23 16:52:00 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 	sigemptyset(&set);
94 	sigaddset(&set, SIGHUP);
95 	sigaddset(&set, SIGTERM);
96 
97 	/* Handle Ctrl-C gracefully for debugging */
98 	sigaddset(&set, SIGINT);
99 	errs = 0;
100 
101 	while (true)
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 }
142 /*
143 **  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
144 **
145 **	Parameters:
146 **		name -- name of milter
147 **
148 **	Returns:
149 **		MI_SUCCESS/MI_FAILURE
150 */
151 
152 static int
153 mi_spawn_signal_thread(name)
154 	char *name;
155 {
156 	sthread_t tid;
157 	int r;
158 	sigset_t set;
159 
160 	/* Mask HUP and KILL signals */
161 	sigemptyset(&set);
162 	sigaddset(&set, SIGHUP);
163 	sigaddset(&set, SIGTERM);
164 	sigaddset(&set, SIGINT);
165 
166 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
167 	{
168 		smi_log(SMI_LOG_ERR,
169 			"%s: Couldn't mask HUP and KILL signals", name);
170 		return MI_FAILURE;
171 	}
172 	r = thread_create(&tid, mi_signal_thread, (void *)name);
173 	if (r != 0)
174 	{
175 		smi_log(SMI_LOG_ERR,
176 			"%s: Couldn't start signal thread: %d",
177 			name, r);
178 		return MI_FAILURE;
179 	}
180 	return MI_SUCCESS;
181 }
182 /*
183 **  MI_CONTROL_STARTUP -- startup for thread to handle signals
184 **
185 **	Parameters:
186 **		name -- name of milter
187 **
188 **	Returns:
189 **		MI_SUCCESS/MI_FAILURE
190 */
191 
192 int
193 mi_control_startup(name)
194 	char *name;
195 {
196 
197 	if (!smutex_init(&M_Mutex))
198 	{
199 		smi_log(SMI_LOG_ERR,
200 			"%s: Couldn't initialize control pipe mutex", name);
201 		return MI_FAILURE;
202 	}
203 
204 	/*
205 	**  spawn_signal_thread must happen before other threads are spawned
206 	**  off so that it can mask the right signals and other threads
207 	**  will inherit that mask.
208 	*/
209 	if (mi_spawn_signal_thread(name) == MI_FAILURE)
210 	{
211 		smi_log(SMI_LOG_ERR,
212 			"%s: Couldn't spawn signal thread", name);
213 		(void) smutex_destroy(&M_Mutex);
214 		return MI_FAILURE;
215 	}
216 	return MI_SUCCESS;
217 }
218