1a7c91847Schristos /* sighandle.c -- Library routines for manipulating chains of signal handlers
2a7c91847Schristos Copyright (C) 1992 Free Software Foundation, Inc.
3a7c91847Schristos
4a7c91847Schristos This program is free software; you can redistribute it and/or modify
5a7c91847Schristos it under the terms of the GNU General Public License as published by
6a7c91847Schristos the Free Software Foundation; either version 2, or (at your option)
7a7c91847Schristos any later version.
8a7c91847Schristos
9a7c91847Schristos This program is distributed in the hope that it will be useful,
10a7c91847Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
11a7c91847Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12a7c91847Schristos GNU General Public License for more details. */
13*5a6c14c8Schristos #include <sys/cdefs.h>
14*5a6c14c8Schristos __RCSID("$NetBSD: sighandle.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
15a7c91847Schristos
16a7c91847Schristos /* Written by Paul Sander, HaL Computer Systems, Inc. <paul@hal.com>
17a7c91847Schristos Brian Berliner <berliner@Sun.COM> added POSIX support */
18a7c91847Schristos
19a7c91847Schristos /*************************************************************************
20a7c91847Schristos *
21a7c91847Schristos * signal.c -- This file contains code that manipulates chains of signal
22a7c91847Schristos * handlers.
23a7c91847Schristos *
24a7c91847Schristos * Facilities are provided to register a signal handler for
25a7c91847Schristos * any specific signal. When a signal is received, all of the
26a7c91847Schristos * registered signal handlers are invoked in the reverse order
27a7c91847Schristos * in which they are registered. Note that the signal handlers
28a7c91847Schristos * must not themselves make calls to the signal handling
29a7c91847Schristos * facilities.
30a7c91847Schristos *
31a7c91847Schristos *************************************************************************/
32a7c91847Schristos
33a7c91847Schristos #ifdef HAVE_CONFIG_H
34a7c91847Schristos #include "config.h"
35a7c91847Schristos #endif
36a7c91847Schristos #include "system.h"
37a7c91847Schristos
38a7c91847Schristos #include <sys/types.h>
39a7c91847Schristos #include <stdio.h>
40a7c91847Schristos #include <signal.h>
41a7c91847Schristos
42a7c91847Schristos #ifdef STDC_HEADERS
43a7c91847Schristos #include <stdlib.h>
44a7c91847Schristos #else
45a7c91847Schristos #if __STDC__
46a7c91847Schristos char *calloc(unsigned nelem, unsigned size);
47a7c91847Schristos char *malloc(unsigned size);
48a7c91847Schristos #else
49a7c91847Schristos char *calloc();
50a7c91847Schristos char *malloc();
51a7c91847Schristos #endif /* __STDC__ */
52a7c91847Schristos #endif /* STDC_HEADERS */
53a7c91847Schristos
54a7c91847Schristos /* Define the highest signal number (usually) */
55a7c91847Schristos #ifndef SIGMAX
56a7c91847Schristos #define SIGMAX 64
57a7c91847Schristos #endif
58a7c91847Schristos
59a7c91847Schristos /* Define linked list of signal handlers structure */
60a7c91847Schristos struct SIG_hlist {
61a7c91847Schristos RETSIGTYPE (*handler)();
62a7c91847Schristos struct SIG_hlist *next;
63a7c91847Schristos };
64a7c91847Schristos
65a7c91847Schristos /*
66a7c91847Schristos * Define array of lists of signal handlers. Note that this depends on
67a7c91847Schristos * the implementation to initialize each element to a null pointer.
68a7c91847Schristos */
69a7c91847Schristos
70a7c91847Schristos static struct SIG_hlist **SIG_handlers;
71a7c91847Schristos
72a7c91847Schristos /* Define array of default signal vectors */
73a7c91847Schristos
74a7c91847Schristos #ifdef POSIX_SIGNALS
75a7c91847Schristos static struct sigaction *SIG_defaults;
76a7c91847Schristos #else
77a7c91847Schristos #ifdef BSD_SIGNALS
78a7c91847Schristos static struct sigvec *SIG_defaults;
79a7c91847Schristos #else
80a7c91847Schristos static RETSIGTYPE (**SIG_defaults) (int);
81a7c91847Schristos #endif
82a7c91847Schristos #endif
83a7c91847Schristos
84a7c91847Schristos /* Critical section housekeeping */
85a7c91847Schristos static int SIG_crSectNest = 0; /* Nesting level */
86a7c91847Schristos #ifdef POSIX_SIGNALS
87a7c91847Schristos static sigset_t SIG_crSectMask; /* Signal mask */
88a7c91847Schristos #else
89a7c91847Schristos static int SIG_crSectMask; /* Signal mask */
90a7c91847Schristos #endif
91a7c91847Schristos
92a7c91847Schristos /*
93a7c91847Schristos * Initialize the signal handler arrays
94a7c91847Schristos */
95a7c91847Schristos
SIG_init()96a7c91847Schristos static int SIG_init()
97a7c91847Schristos {
98a7c91847Schristos int i;
99a7c91847Schristos #ifdef POSIX_SIGNALS
100a7c91847Schristos sigset_t sigset_test;
101a7c91847Schristos #endif
102a7c91847Schristos
103a7c91847Schristos if (SIG_defaults && SIG_handlers) /* already allocated */
104a7c91847Schristos return (0);
105a7c91847Schristos
106a7c91847Schristos #ifdef POSIX_SIGNALS
107a7c91847Schristos (void) sigfillset(&sigset_test);
108a7c91847Schristos for (i = 1; i < SIGMAX && sigismember(&sigset_test, i) == 1; i++)
109a7c91847Schristos ;
110a7c91847Schristos if (i < SIGMAX)
111a7c91847Schristos i = SIGMAX;
112a7c91847Schristos i++;
113a7c91847Schristos if (!SIG_defaults)
114a7c91847Schristos SIG_defaults = (struct sigaction *)
115a7c91847Schristos calloc(i, sizeof(struct sigaction));
116a7c91847Schristos (void) sigemptyset(&SIG_crSectMask);
117a7c91847Schristos #else
118a7c91847Schristos i = SIGMAX+1;
119a7c91847Schristos #ifdef BSD_SIGNALS
120a7c91847Schristos if (!SIG_defaults)
121a7c91847Schristos SIG_defaults = (struct sigvec *)
122a7c91847Schristos calloc(i, sizeof(struct sigvec));
123a7c91847Schristos #else
124a7c91847Schristos if (!SIG_defaults)
125a7c91847Schristos SIG_defaults = ( RETSIGTYPE (**) (int) )
126a7c91847Schristos calloc( i, sizeof( RETSIGTYPE (**) (int) ) );
127a7c91847Schristos #endif
128a7c91847Schristos SIG_crSectMask = 0;
129a7c91847Schristos #endif
130a7c91847Schristos if (!SIG_handlers)
131a7c91847Schristos SIG_handlers = (struct SIG_hlist **)
132a7c91847Schristos calloc(i, sizeof(struct SIG_hlist *));
133a7c91847Schristos return (!SIG_defaults || !SIG_handlers);
134a7c91847Schristos }
135a7c91847Schristos
136a7c91847Schristos
137a7c91847Schristos
138a7c91847Schristos /*
139a7c91847Schristos * The following begins a critical section.
140a7c91847Schristos */
SIG_beginCrSect(void)141a7c91847Schristos void SIG_beginCrSect (void)
142a7c91847Schristos {
143a7c91847Schristos if (SIG_init() == 0)
144a7c91847Schristos {
145a7c91847Schristos if (SIG_crSectNest == 0)
146a7c91847Schristos {
147a7c91847Schristos #ifdef POSIX_SIGNALS
148a7c91847Schristos sigset_t sigset_mask;
149a7c91847Schristos
150a7c91847Schristos (void) sigfillset(&sigset_mask);
151a7c91847Schristos (void) sigprocmask(SIG_SETMASK,
152a7c91847Schristos &sigset_mask, &SIG_crSectMask);
153a7c91847Schristos #else
154a7c91847Schristos #ifdef BSD_SIGNALS
155a7c91847Schristos SIG_crSectMask = sigblock(~0);
156a7c91847Schristos #else
157a7c91847Schristos /* TBD */
158a7c91847Schristos #endif
159a7c91847Schristos #endif
160a7c91847Schristos }
161a7c91847Schristos SIG_crSectNest++;
162a7c91847Schristos }
163a7c91847Schristos }
164a7c91847Schristos
165a7c91847Schristos
166a7c91847Schristos
167a7c91847Schristos /*
168a7c91847Schristos * The following ends a critical section.
169a7c91847Schristos */
SIG_endCrSect(void)170a7c91847Schristos void SIG_endCrSect (void)
171a7c91847Schristos {
172a7c91847Schristos if (SIG_init() == 0)
173a7c91847Schristos {
174a7c91847Schristos SIG_crSectNest--;
175a7c91847Schristos if (SIG_crSectNest == 0)
176a7c91847Schristos {
177a7c91847Schristos #ifdef POSIX_SIGNALS
178a7c91847Schristos (void) sigprocmask(SIG_SETMASK, &SIG_crSectMask, NULL);
179a7c91847Schristos #else
180a7c91847Schristos #ifdef BSD_SIGNALS
181a7c91847Schristos (void) sigsetmask(SIG_crSectMask);
182a7c91847Schristos #else
183a7c91847Schristos /* TBD */
184a7c91847Schristos #endif
185a7c91847Schristos #endif
186a7c91847Schristos }
187a7c91847Schristos }
188a7c91847Schristos }
189a7c91847Schristos
190a7c91847Schristos
191a7c91847Schristos
192a7c91847Schristos /*
193a7c91847Schristos * The following invokes each signal handler in the reverse order in which
194a7c91847Schristos * they were registered.
195a7c91847Schristos */
SIG_handle(int sig)196a7c91847Schristos static RETSIGTYPE SIG_handle (int sig)
197a7c91847Schristos {
198a7c91847Schristos struct SIG_hlist *this;
199a7c91847Schristos
200a7c91847Schristos /* Dispatch signal handlers */
201a7c91847Schristos /* This crit section stuff is a CVSism - we know that our interrupt
202a7c91847Schristos * handlers will always end up exiting and we don't want them to be
203a7c91847Schristos * interrupted themselves.
204a7c91847Schristos */
205a7c91847Schristos SIG_beginCrSect();
206a7c91847Schristos this = SIG_handlers[sig];
207a7c91847Schristos while (this != (struct SIG_hlist *) NULL)
208a7c91847Schristos {
209a7c91847Schristos (*this->handler)(sig);
210a7c91847Schristos this = this->next;
211a7c91847Schristos }
212a7c91847Schristos SIG_endCrSect();
213a7c91847Schristos
214a7c91847Schristos return;
215a7c91847Schristos }
216a7c91847Schristos
217a7c91847Schristos /*
218a7c91847Schristos * The following registers a signal handler. If the handler is already
219a7c91847Schristos * registered, it is not registered twice, nor is the order in which signal
220a7c91847Schristos * handlers are invoked changed. If this is the first signal handler
221a7c91847Schristos * registered for a given signal, the old sigvec structure is saved for
222a7c91847Schristos * restoration later.
223a7c91847Schristos */
224a7c91847Schristos
SIG_register(int sig,RETSIGTYPE (* fn)())225a7c91847Schristos int SIG_register(int sig, RETSIGTYPE (*fn)())
226a7c91847Schristos {
227a7c91847Schristos int val;
228a7c91847Schristos struct SIG_hlist *this;
229a7c91847Schristos #ifdef POSIX_SIGNALS
230a7c91847Schristos struct sigaction act;
231a7c91847Schristos sigset_t sigset_mask, sigset_omask;
232a7c91847Schristos #else
233a7c91847Schristos #ifdef BSD_SIGNALS
234a7c91847Schristos struct sigvec vec;
235a7c91847Schristos int mask;
236a7c91847Schristos #endif
237a7c91847Schristos #endif
238a7c91847Schristos
239a7c91847Schristos /* Initialize */
240a7c91847Schristos if (SIG_init() != 0)
241a7c91847Schristos return (-1);
242a7c91847Schristos val = 0;
243a7c91847Schristos
244a7c91847Schristos /* Block this signal while we look at handler chain */
245a7c91847Schristos #ifdef POSIX_SIGNALS
246a7c91847Schristos (void) sigemptyset(&sigset_mask);
247a7c91847Schristos (void) sigaddset(&sigset_mask, sig);
248a7c91847Schristos (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
249a7c91847Schristos #else
250a7c91847Schristos #ifdef BSD_SIGNALS
251a7c91847Schristos mask = sigblock(sigmask(sig));
252a7c91847Schristos #endif
253a7c91847Schristos #endif
254a7c91847Schristos
255a7c91847Schristos /* See if this handler was already registered */
256a7c91847Schristos this = SIG_handlers[sig];
257a7c91847Schristos while (this != (struct SIG_hlist *) NULL)
258a7c91847Schristos {
259a7c91847Schristos if (this->handler == fn) break;
260a7c91847Schristos this = this->next;
261a7c91847Schristos }
262a7c91847Schristos
263a7c91847Schristos /* Register the new handler only if it is not already registered. */
264a7c91847Schristos if (this == (struct SIG_hlist *) NULL)
265a7c91847Schristos {
266a7c91847Schristos
267a7c91847Schristos /*
268a7c91847Schristos * If this is the first handler registered for this signal,
269a7c91847Schristos * set up the signal handler dispatcher
270a7c91847Schristos */
271a7c91847Schristos
272a7c91847Schristos if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
273a7c91847Schristos {
274a7c91847Schristos #ifdef POSIX_SIGNALS
275a7c91847Schristos act.sa_handler = SIG_handle;
276a7c91847Schristos (void) sigemptyset(&act.sa_mask);
277a7c91847Schristos act.sa_flags = 0;
278a7c91847Schristos val = sigaction(sig, &act, &SIG_defaults[sig]);
279a7c91847Schristos #else
280a7c91847Schristos #ifdef BSD_SIGNALS
281a7c91847Schristos memset (&vec, 0, sizeof (vec));
282a7c91847Schristos vec.sv_handler = SIG_handle;
283a7c91847Schristos val = sigvec(sig, &vec, &SIG_defaults[sig]);
284a7c91847Schristos #else
285a7c91847Schristos if ((SIG_defaults[sig] = signal(sig, SIG_handle)) == SIG_ERR)
286a7c91847Schristos val = -1;
287a7c91847Schristos #endif
288a7c91847Schristos #endif
289a7c91847Schristos }
290a7c91847Schristos
291a7c91847Schristos /* If not, register it */
292a7c91847Schristos if ((val == 0) && (this == (struct SIG_hlist *) NULL))
293a7c91847Schristos {
294a7c91847Schristos this = (struct SIG_hlist *)
295a7c91847Schristos malloc(sizeof(struct SIG_hlist));
296a7c91847Schristos if (this == NULL)
297a7c91847Schristos {
298a7c91847Schristos val = -1;
299a7c91847Schristos }
300a7c91847Schristos else
301a7c91847Schristos {
302a7c91847Schristos this->handler = fn;
303a7c91847Schristos this->next = SIG_handlers[sig];
304a7c91847Schristos SIG_handlers[sig] = this;
305a7c91847Schristos }
306a7c91847Schristos }
307a7c91847Schristos }
308a7c91847Schristos
309a7c91847Schristos /* Unblock the signal */
310a7c91847Schristos #ifdef POSIX_SIGNALS
311a7c91847Schristos (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
312a7c91847Schristos #else
313a7c91847Schristos #ifdef BSD_SIGNALS
314a7c91847Schristos (void) sigsetmask(mask);
315a7c91847Schristos #endif
316a7c91847Schristos #endif
317a7c91847Schristos
318a7c91847Schristos return val;
319a7c91847Schristos }
320a7c91847Schristos
321a7c91847Schristos
322a7c91847Schristos
323a7c91847Schristos /*
324a7c91847Schristos * The following deregisters a signal handler. If the last signal handler for
325a7c91847Schristos * a given signal is deregistered, the default sigvec information is restored.
326a7c91847Schristos */
327a7c91847Schristos
SIG_deregister(int sig,RETSIGTYPE (* fn)())328a7c91847Schristos int SIG_deregister(int sig, RETSIGTYPE (*fn)())
329a7c91847Schristos {
330a7c91847Schristos int val;
331a7c91847Schristos struct SIG_hlist *this;
332a7c91847Schristos struct SIG_hlist *last;
333a7c91847Schristos #ifdef POSIX_SIGNALS
334a7c91847Schristos sigset_t sigset_mask, sigset_omask;
335a7c91847Schristos #else
336a7c91847Schristos #ifdef BSD_SIGNALS
337a7c91847Schristos int mask;
338a7c91847Schristos #endif
339a7c91847Schristos #endif
340a7c91847Schristos
341a7c91847Schristos /* Initialize */
342a7c91847Schristos if (SIG_init() != 0)
343a7c91847Schristos return (-1);
344a7c91847Schristos val = 0;
345a7c91847Schristos last = (struct SIG_hlist *) NULL;
346a7c91847Schristos
347a7c91847Schristos /* Block this signal while we look at handler chain */
348a7c91847Schristos #ifdef POSIX_SIGNALS
349a7c91847Schristos (void) sigemptyset(&sigset_mask);
350a7c91847Schristos (void) sigaddset(&sigset_mask, sig);
351a7c91847Schristos (void) sigprocmask(SIG_BLOCK, &sigset_mask, &sigset_omask);
352a7c91847Schristos #else
353a7c91847Schristos #ifdef BSD_SIGNALS
354a7c91847Schristos mask = sigblock(sigmask(sig));
355a7c91847Schristos #endif
356a7c91847Schristos #endif
357a7c91847Schristos
358a7c91847Schristos /* Search for the signal handler */
359a7c91847Schristos this = SIG_handlers[sig];
360a7c91847Schristos while ((this != (struct SIG_hlist *) NULL) && (this->handler != fn))
361a7c91847Schristos {
362a7c91847Schristos last = this;
363a7c91847Schristos this = this->next;
364a7c91847Schristos }
365a7c91847Schristos
366a7c91847Schristos /* If it was registered, remove it */
367a7c91847Schristos if (this != (struct SIG_hlist *) NULL)
368a7c91847Schristos {
369a7c91847Schristos if (last == (struct SIG_hlist *) NULL)
370a7c91847Schristos {
371a7c91847Schristos SIG_handlers[sig] = this->next;
372a7c91847Schristos }
373a7c91847Schristos else
374a7c91847Schristos {
375a7c91847Schristos last->next = this->next;
376a7c91847Schristos }
377a7c91847Schristos free((char *) this);
378a7c91847Schristos }
379a7c91847Schristos
380a7c91847Schristos /* Restore default behavior if there are no registered handlers */
381a7c91847Schristos if (SIG_handlers[sig] == (struct SIG_hlist *) NULL)
382a7c91847Schristos {
383a7c91847Schristos #ifdef POSIX_SIGNALS
384a7c91847Schristos val = sigaction(sig, &SIG_defaults[sig],
385a7c91847Schristos (struct sigaction *) NULL);
386a7c91847Schristos #else
387a7c91847Schristos #ifdef BSD_SIGNALS
388a7c91847Schristos val = sigvec(sig, &SIG_defaults[sig], (struct sigvec *) NULL);
389a7c91847Schristos #else
390a7c91847Schristos if (signal(sig, SIG_defaults[sig]) == SIG_ERR)
391a7c91847Schristos val = -1;
392a7c91847Schristos #endif
393a7c91847Schristos #endif
394a7c91847Schristos }
395a7c91847Schristos
396a7c91847Schristos /* Unblock the signal */
397a7c91847Schristos #ifdef POSIX_SIGNALS
398a7c91847Schristos (void) sigprocmask(SIG_SETMASK, &sigset_omask, NULL);
399a7c91847Schristos #else
400a7c91847Schristos #ifdef BSD_SIGNALS
401a7c91847Schristos (void) sigsetmask(mask);
402a7c91847Schristos #endif
403a7c91847Schristos #endif
404a7c91847Schristos
405a7c91847Schristos return val;
406a7c91847Schristos }
407a7c91847Schristos
408a7c91847Schristos
409a7c91847Schristos
410a7c91847Schristos /*
411a7c91847Schristos * Return nonzero if currently in a critical section.
412a7c91847Schristos * Otherwise return zero.
413a7c91847Schristos */
414a7c91847Schristos
SIG_inCrSect(void)415a7c91847Schristos int SIG_inCrSect (void)
416a7c91847Schristos {
417a7c91847Schristos return SIG_crSectNest > 0;
418a7c91847Schristos }
419