1 /*
2 * Copyright (c) 1999-2004, 2006 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.44 2006/03/03 03:42:04 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 static void *mi_signal_thread __P((void *));
25 static int mi_spawn_signal_thread __P((char *));
26
27 /*
28 ** MI_STOP -- return value of MilterStop
29 **
30 ** Parameters:
31 ** none.
32 **
33 ** Returns:
34 ** value of MilterStop
35 */
36
37 int
mi_stop()38 mi_stop()
39 {
40 return MilterStop;
41 }
42 /*
43 ** MI_STOP_MILTERS -- set value of MilterStop
44 **
45 ** Parameters:
46 ** v -- new value for MilterStop.
47 **
48 ** Returns:
49 ** none.
50 */
51
52 void
mi_stop_milters(v)53 mi_stop_milters(v)
54 int v;
55 {
56 (void) smutex_lock(&M_Mutex);
57 if (MilterStop < v)
58 MilterStop = v;
59
60 /* close listen socket */
61 mi_closener();
62 (void) smutex_unlock(&M_Mutex);
63 }
64 /*
65 ** MI_CLEAN_SIGNALS -- clean up signal handler thread
66 **
67 ** Parameters:
68 ** none.
69 **
70 ** Returns:
71 ** none.
72 */
73
74 void
mi_clean_signals()75 mi_clean_signals()
76 {
77 (void) smutex_destroy(&M_Mutex);
78 }
79 /*
80 ** MI_SIGNAL_THREAD -- thread to deal with signals
81 **
82 ** Parameters:
83 ** name -- name of milter
84 **
85 ** Returns:
86 ** NULL
87 */
88
89 static void *
mi_signal_thread(name)90 mi_signal_thread(name)
91 void *name;
92 {
93 int sig, errs, sigerr;
94 sigset_t set;
95
96 (void) sigemptyset(&set);
97 (void) sigaddset(&set, SIGHUP);
98 (void) sigaddset(&set, SIGTERM);
99
100 /* Handle Ctrl-C gracefully for debugging */
101 (void) sigaddset(&set, SIGINT);
102 errs = 0;
103
104 for (;;)
105 {
106 sigerr = sig = 0;
107 #if defined(SOLARIS) || defined(__svr5__)
108 if ((sig = sigwait(&set)) < 0)
109 #else /* defined(SOLARIS) || defined(__svr5__) */
110 if ((sigerr = sigwait(&set, &sig)) != 0)
111 #endif /* defined(SOLARIS) || defined(__svr5__) */
112 {
113 /* some OS return -1 and set errno: copy it */
114 if (sigerr <= 0)
115 sigerr = errno;
116
117 /* this can happen on OSF/1 (at least) */
118 if (sigerr == EINTR)
119 continue;
120 smi_log(SMI_LOG_ERR,
121 "%s: sigwait returned error: %d",
122 (char *)name, sigerr);
123 if (++errs > MAX_FAILS_T)
124 {
125 mi_stop_milters(MILTER_ABRT);
126 return NULL;
127 }
128 continue;
129 }
130 errs = 0;
131
132 switch (sig)
133 {
134 case SIGHUP:
135 case SIGTERM:
136 mi_stop_milters(MILTER_STOP);
137 return NULL;
138 case SIGINT:
139 mi_stop_milters(MILTER_ABRT);
140 return NULL;
141 default:
142 smi_log(SMI_LOG_ERR,
143 "%s: sigwait returned unmasked signal: %d",
144 (char *)name, sig);
145 break;
146 }
147 }
148 /* NOTREACHED */
149 }
150 /*
151 ** MI_SPAWN_SIGNAL_THREAD -- spawn thread to handle signals
152 **
153 ** Parameters:
154 ** name -- name of milter
155 **
156 ** Returns:
157 ** MI_SUCCESS/MI_FAILURE
158 */
159
160 static int
mi_spawn_signal_thread(name)161 mi_spawn_signal_thread(name)
162 char *name;
163 {
164 sthread_t tid;
165 int r;
166 sigset_t set;
167
168 /* Mask HUP and KILL signals */
169 (void) sigemptyset(&set);
170 (void) sigaddset(&set, SIGHUP);
171 (void) sigaddset(&set, SIGTERM);
172 (void) sigaddset(&set, SIGINT);
173
174 if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0)
175 {
176 smi_log(SMI_LOG_ERR,
177 "%s: Couldn't mask HUP and KILL signals", name);
178 return MI_FAILURE;
179 }
180 r = thread_create(&tid, mi_signal_thread, (void *)name);
181 if (r != 0)
182 {
183 smi_log(SMI_LOG_ERR,
184 "%s: Couldn't start signal thread: %d",
185 name, r);
186 return MI_FAILURE;
187 }
188 return MI_SUCCESS;
189 }
190 /*
191 ** MI_CONTROL_STARTUP -- startup for thread to handle signals
192 **
193 ** Parameters:
194 ** name -- name of milter
195 **
196 ** Returns:
197 ** MI_SUCCESS/MI_FAILURE
198 */
199
200 int
mi_control_startup(name)201 mi_control_startup(name)
202 char *name;
203 {
204
205 if (!smutex_init(&M_Mutex))
206 {
207 smi_log(SMI_LOG_ERR,
208 "%s: Couldn't initialize control pipe mutex", name);
209 return MI_FAILURE;
210 }
211
212 /*
213 ** spawn_signal_thread must happen before other threads are spawned
214 ** off so that it can mask the right signals and other threads
215 ** will inherit that mask.
216 */
217 if (mi_spawn_signal_thread(name) == MI_FAILURE)
218 {
219 smi_log(SMI_LOG_ERR,
220 "%s: Couldn't spawn signal thread", name);
221 (void) smutex_destroy(&M_Mutex);
222 return MI_FAILURE;
223 }
224 return MI_SUCCESS;
225 }
226