* Update Sendmail to version 8.12.10
[dragonfly.git] / contrib / sendmail / libmilter / signal.c
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.3 2003/08/04 18:14:33 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 }