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