1 /*
2 * Copyright (c) 2000-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 #pragma ident "%Z%%M% %I% %E% SMI"
11
12 #include <sm/gen.h>
13 SM_RCSID("@(#)$Id: signal.c,v 1.17 2005/06/14 23:07:20 ca Exp $")
14
15 #if SM_CONF_SETITIMER
16 # include <sm/time.h>
17 #endif /* SM_CONF_SETITIMER */
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <time.h>
21 #include <unistd.h>
22 #include <sm/clock.h>
23 #include <sm/signal.h>
24 #include <signal.h>
25 #include <sm/string.h>
26
27 unsigned int volatile InCriticalSection; /* >0 if inside critical section */
28 int volatile PendingSignal; /* pending signal to resend */
29
30 /*
31 ** SM_SIGNAL -- set a signal handler
32 **
33 ** This is essentially old BSD "signal(3)".
34 **
35 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
36 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
37 ** DOING.
38 */
39
40 sigfunc_t
sm_signal(sig,handler)41 sm_signal(sig, handler)
42 int sig;
43 sigfunc_t handler;
44 {
45 # if defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3))
46 struct sigaction n, o;
47 # endif /* defined(SA_RESTART) || (!defined(SYS5SIGNALS) && !defined(BSD4_3)) */
48
49 /*
50 ** First, try for modern signal calls
51 ** and restartable syscalls
52 */
53
54 # ifdef SA_RESTART
55 (void) memset(&n, '\0', sizeof n);
56 # if USE_SA_SIGACTION
57 n.sa_sigaction = (void(*)(int, siginfo_t *, void *)) handler;
58 n.sa_flags = SA_RESTART|SA_SIGINFO;
59 # else /* USE_SA_SIGACTION */
60 n.sa_handler = handler;
61 n.sa_flags = SA_RESTART;
62 # endif /* USE_SA_SIGACTION */
63 if (sigaction(sig, &n, &o) < 0)
64 return SIG_ERR;
65 return o.sa_handler;
66 # else /* SA_RESTART */
67
68 /*
69 ** Else check for SYS5SIGNALS or
70 ** BSD4_3 signals
71 */
72
73 # if defined(SYS5SIGNALS) || defined(BSD4_3)
74 # ifdef BSD4_3
75 return signal(sig, handler);
76 # else /* BSD4_3 */
77 return sigset(sig, handler);
78 # endif /* BSD4_3 */
79 # else /* defined(SYS5SIGNALS) || defined(BSD4_3) */
80
81 /*
82 ** Finally, if nothing else is available,
83 ** go for a default
84 */
85
86 (void) memset(&n, '\0', sizeof n);
87 n.sa_handler = handler;
88 if (sigaction(sig, &n, &o) < 0)
89 return SIG_ERR;
90 return o.sa_handler;
91 # endif /* defined(SYS5SIGNALS) || defined(BSD4_3) */
92 # endif /* SA_RESTART */
93 }
94 /*
95 ** SM_BLOCKSIGNAL -- hold a signal to prevent delivery
96 **
97 ** Parameters:
98 ** sig -- the signal to block.
99 **
100 ** Returns:
101 ** 1 signal was previously blocked
102 ** 0 signal was not previously blocked
103 ** -1 on failure.
104 */
105
106 int
sm_blocksignal(sig)107 sm_blocksignal(sig)
108 int sig;
109 {
110 # ifdef BSD4_3
111 # ifndef sigmask
112 # define sigmask(s) (1 << ((s) - 1))
113 # endif /* ! sigmask */
114 return (sigblock(sigmask(sig)) & sigmask(sig)) != 0;
115 # else /* BSD4_3 */
116 # ifdef ALTOS_SYSTEM_V
117 sigfunc_t handler;
118
119 handler = sigset(sig, SIG_HOLD);
120 if (handler == SIG_ERR)
121 return -1;
122 else
123 return handler == SIG_HOLD;
124 # else /* ALTOS_SYSTEM_V */
125 sigset_t sset, oset;
126
127 (void) sigemptyset(&sset);
128 (void) sigaddset(&sset, sig);
129 if (sigprocmask(SIG_BLOCK, &sset, &oset) < 0)
130 return -1;
131 else
132 return sigismember(&oset, sig);
133 # endif /* ALTOS_SYSTEM_V */
134 # endif /* BSD4_3 */
135 }
136 /*
137 ** SM_RELEASESIGNAL -- release a held signal
138 **
139 ** Parameters:
140 ** sig -- the signal to release.
141 **
142 ** Returns:
143 ** 1 signal was previously blocked
144 ** 0 signal was not previously blocked
145 ** -1 on failure.
146 */
147
148 int
sm_releasesignal(sig)149 sm_releasesignal(sig)
150 int sig;
151 {
152 # ifdef BSD4_3
153 return (sigsetmask(sigblock(0) & ~sigmask(sig)) & sigmask(sig)) != 0;
154 # else /* BSD4_3 */
155 # ifdef ALTOS_SYSTEM_V
156 sigfunc_t handler;
157
158 handler = sigset(sig, SIG_HOLD);
159 if (sigrelse(sig) < 0)
160 return -1;
161 else
162 return handler == SIG_HOLD;
163 # else /* ALTOS_SYSTEM_V */
164 sigset_t sset, oset;
165
166 (void) sigemptyset(&sset);
167 (void) sigaddset(&sset, sig);
168 if (sigprocmask(SIG_UNBLOCK, &sset, &oset) < 0)
169 return -1;
170 else
171 return sigismember(&oset, sig);
172 # endif /* ALTOS_SYSTEM_V */
173 # endif /* BSD4_3 */
174 }
175 /*
176 ** PEND_SIGNAL -- Add a signal to the pending signal list
177 **
178 ** Parameters:
179 ** sig -- signal to add
180 **
181 ** Returns:
182 ** none.
183 **
184 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
185 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
186 ** DOING.
187 */
188
189 void
pend_signal(sig)190 pend_signal(sig)
191 int sig;
192 {
193 int sigbit;
194 int save_errno = errno;
195 #if SM_CONF_SETITIMER
196 struct itimerval clr;
197 #endif /* SM_CONF_SETITIMER */
198
199 /*
200 ** Don't want to interrupt something critical, hence delay
201 ** the alarm for one second. Hopefully, by then we
202 ** will be out of the critical section. If not, then
203 ** we will just delay again. The events to be run will
204 ** still all be run, maybe just a little bit late.
205 */
206
207 switch (sig)
208 {
209 case SIGHUP:
210 sigbit = PEND_SIGHUP;
211 break;
212
213 case SIGINT:
214 sigbit = PEND_SIGINT;
215 break;
216
217 case SIGTERM:
218 sigbit = PEND_SIGTERM;
219 break;
220
221 case SIGUSR1:
222 sigbit = PEND_SIGUSR1;
223 break;
224
225 case SIGALRM:
226 /* don't have to pend these */
227 sigbit = 0;
228 break;
229
230 default:
231 /* If we get here, we are in trouble */
232 abort();
233
234 /* NOTREACHED */
235 /* shut up stupid compiler warning on HP-UX 11 */
236 sigbit = 0;
237 break;
238 }
239
240 if (sigbit != 0)
241 PendingSignal |= sigbit;
242 (void) sm_signal(SIGALRM, sm_tick);
243 #if SM_CONF_SETITIMER
244 clr.it_interval.tv_sec = 0;
245 clr.it_interval.tv_usec = 0;
246 clr.it_value.tv_sec = 1;
247 clr.it_value.tv_usec = 0;
248 (void) setitimer(ITIMER_REAL, &clr, NULL);
249 #else /* SM_CONF_SETITIMER */
250 (void) alarm(1);
251 #endif /* SM_CONF_SETITIMER */
252 errno = save_errno;
253 }
254 /*
255 ** SM_ALLSIGNALS -- act on all signals
256 **
257 ** Parameters:
258 ** block -- whether to block or release all signals.
259 **
260 ** Returns:
261 ** none.
262 */
263
264 void
sm_allsignals(block)265 sm_allsignals(block)
266 bool block;
267 {
268 # ifdef BSD4_3
269 # ifndef sigmask
270 # define sigmask(s) (1 << ((s) - 1))
271 # endif /* ! sigmask */
272 if (block)
273 {
274 int mask = 0;
275
276 mask |= sigmask(SIGALRM);
277 mask |= sigmask(SIGCHLD);
278 mask |= sigmask(SIGHUP);
279 mask |= sigmask(SIGINT);
280 mask |= sigmask(SIGTERM);
281 mask |= sigmask(SIGUSR1);
282
283 (void) sigblock(mask);
284 }
285 else
286 sigsetmask(0);
287 # else /* BSD4_3 */
288 # ifdef ALTOS_SYSTEM_V
289 if (block)
290 {
291 (void) sigset(SIGALRM, SIG_HOLD);
292 (void) sigset(SIGCHLD, SIG_HOLD);
293 (void) sigset(SIGHUP, SIG_HOLD);
294 (void) sigset(SIGINT, SIG_HOLD);
295 (void) sigset(SIGTERM, SIG_HOLD);
296 (void) sigset(SIGUSR1, SIG_HOLD);
297 }
298 else
299 {
300 (void) sigset(SIGALRM, SIG_DFL);
301 (void) sigset(SIGCHLD, SIG_DFL);
302 (void) sigset(SIGHUP, SIG_DFL);
303 (void) sigset(SIGINT, SIG_DFL);
304 (void) sigset(SIGTERM, SIG_DFL);
305 (void) sigset(SIGUSR1, SIG_DFL);
306 }
307 # else /* ALTOS_SYSTEM_V */
308 sigset_t sset;
309
310 (void) sigemptyset(&sset);
311 (void) sigaddset(&sset, SIGALRM);
312 (void) sigaddset(&sset, SIGCHLD);
313 (void) sigaddset(&sset, SIGHUP);
314 (void) sigaddset(&sset, SIGINT);
315 (void) sigaddset(&sset, SIGTERM);
316 (void) sigaddset(&sset, SIGUSR1);
317 (void) sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sset, NULL);
318 # endif /* ALTOS_SYSTEM_V */
319 # endif /* BSD4_3 */
320 }
321 /*
322 ** SM_SIGNAL_NOOP -- A signal no-op function
323 **
324 ** Parameters:
325 ** sig -- signal received
326 **
327 ** Returns:
328 ** SIGFUNC_RETURN
329 */
330
331 /* ARGSUSED */
332 SIGFUNC_DECL
sm_signal_noop(sig)333 sm_signal_noop(sig)
334 int sig;
335 {
336 int save_errno = errno;
337
338 FIX_SYSV_SIGNAL(sig, sm_signal_noop);
339 errno = save_errno;
340 return SIGFUNC_RETURN;
341 }
342
343