xref: /netbsd-src/external/gpl2/xcvs/dist/lib/sighandle.c (revision 5a6c14c844c4c665da5632061aebde7bb2cb5766)
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