xref: /freebsd/contrib/sendmail/libmilter/signal.c (revision eacee0ff7ec955b32e09515246bd97b6edcd2b0f)
1 /*
2  *  Copyright (c) 1999-2001 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.35 2002/01/10 01:34:55 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 			smi_log(SMI_LOG_ERR,
111 				"%s: sigwait returned error: %d",
112 				(char *)name, errno);
113 			if (++errs > MAX_FAILS_T)
114 			{
115 				mi_stop_milters(MILTER_ABRT);
116 				return NULL;
117 			}
118 			continue;
119 		}
120 		errs = 0;
121 
122 		switch (sig)
123 		{
124 		  case SIGHUP:
125 		  case SIGTERM:
126 			mi_stop_milters(MILTER_STOP);
127 			return NULL;
128 		  case SIGINT:
129 			mi_stop_milters(MILTER_ABRT);
130 			return NULL;
131 		  default:
132 			smi_log(SMI_LOG_ERR,
133 				"%s: sigwait returned unmasked signal: %d",
134 				(char *)name, sig);
135 			break;
136 		}
137 	}
138 }
139 /*
140 **  MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
141 **
142 **	Parameters:
143 **		name -- name of milter
144 **
145 **	Returns:
146 **		MI_SUCCESS/MI_FAILURE
147 */
148 
149 static int
150 mi_spawn_signal_thread(name)
151 	char *name;
152 {
153 	sthread_t tid;
154 	int r;
155 	sigset_t set;
156 
157 	/* Mask HUP and KILL signals */
158 	sigemptyset(&set);
159 	sigaddset(&set, SIGHUP);
160 	sigaddset(&set, SIGTERM);
161 	sigaddset(&set, SIGINT);
162 
163 	if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
164 	{
165 		smi_log(SMI_LOG_ERR,
166 			"%s: Couldn't mask HUP and KILL signals", name);
167 		return MI_FAILURE;
168 	}
169 	r = thread_create(&tid, mi_signal_thread, (void *)name);
170 	if (r != 0)
171 	{
172 		smi_log(SMI_LOG_ERR,
173 			"%s: Couldn't start signal thread: %d",
174 			name, r);
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