Import sendmail 8.13.8
[dragonfly.git] / contrib / sendmail-8.13.8 / libmilter / signal.c
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
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
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
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 *
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
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
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 }