xref: /freebsd/contrib/bmake/sigaction.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /* NAME:
2  *      sigact.c - fake sigaction(2)
3  *
4  * SYNOPSIS:
5  *      #include "sigact.h"
6  *
7  *      int sigaction(int sig, struct sigaction *act,
8  *                      struct sigaction *oact);
9  *      int sigaddset(sigset_t *mask, int sig);
10  *      int sigdelset(sigset_t *mask, int sig);
11  *      int sigemptyset(sigset_t *mask);
12  *      int sigfillset(sigset_t *mask);
13  *      int sigismember(sigset_t *mask, int sig);
14  *      int sigpending(sigset_t *set);
15  *      int sigprocmask(int how, sigset_t *set, sigset_t *oset);
16  *      int sigsuspend(sigset_t *mask);
17  *
18  *      SIG_HDLR (*Signal(int sig, SIG_HDLR (*disp)(int)))(int);
19  *
20  * DESCRIPTION:
21  *      This is a fake sigaction implementation.  It uses
22  *      sigsetmask(2) et al or sigset(2) and friends if
23  *      available, otherwise it just uses signal(2).  If it
24  *      thinks sigaction(2) really exists it compiles to "almost"
25  *      nothing.
26  *
27  *      In any case it provides a Signal() function that is
28  *      implemented in terms of sigaction().
29  *      If not using signal(2) as part of the underlying
30  *      implementation (USE_SIGNAL or USE_SIGMASK), and
31  *      NO_SIGNAL is not defined, it also provides a signal()
32  *      function that calls Signal().
33  *
34  *      The need for all this mucking about is the problems
35  *      caused by mixing various signal handling mechanisms in
36  *      the one process.  This module allows for a consistent
37  *      POSIX compliant interface to whatever is actually
38  *      available.
39  *
40  *      sigaction() allows the caller to examine and/or set the
41  *      action to be associated with a given signal. "act" and
42  *      "oact" are pointers to 'sigaction structs':
43  *.nf
44  *
45  *      struct sigaction
46  *      {
47  *             SIG_HDLR  (*sa_handler)();
48  *             sigset_t  sa_mask;
49  *             int       sa_flags;
50  *      };
51  *.fi
52  *
53  *      SIG_HDLR is normally 'void' in the POSIX implementation
54  *      and for most current systems.  On some older UNIX
55  *      systems, signal handlers do not return 'void', so
56  *      this implementation keeps 'sa_handler' inline with the
57  *      hosts normal signal handling conventions.
58  *      'sa_mask' controls which signals will be blocked while
59  *      the selected signal handler is active.  It is not used
60  *      in this implementation.
61  *      'sa_flags' controls various semantics such as whether
62  *      system calls should be automagically restarted
63  *      (SA_RESTART) etc.  It is not used in this
64  *      implementation.
65  *      Either "act" or "oact" may be NULL in which case the
66  *      appropriate operation is skipped.
67  *
68  *      sigaddset() adds "sig" to the sigset_t pointed to by "mask".
69  *
70  *      sigdelset() removes "sig" from the sigset_t pointed to
71  *      by "mask".
72  *
73  *      sigemptyset() makes the sigset_t pointed to by "mask" empty.
74  *
75  *      sigfillset() makes the sigset_t pointed to by "mask"
76  *      full ie. match all signals.
77  *
78  *      sigismember() returns true if "sig" is found in "*mask".
79  *
80  *      sigpending() is supposed to return "set" loaded with the
81  *      set of signals that are blocked and pending for the
82  *      calling process.  It does nothing in this impementation.
83  *
84  *      sigprocmask() is used to examine and/or change the
85  *      signal mask for the calling process.  Either "set" or
86  *      "oset" may be NULL in which case the appropriate
87  *      operation is skipped.  "how" may be one of SIG_BLOCK,
88  *      SIG_UNBLOCK or SIG_SETMASK.  If this package is built
89  *      with USE_SIGNAL, then this routine achieves nothing.
90  *
91  *      sigsuspend() sets the signal mask to "*mask" and waits
92  *      for a signal to be delivered after which the previous
93  *      mask is restored.
94  *
95  *
96  * RETURN VALUE:
97  *      0==success, -1==failure
98  *
99  * BUGS:
100  *      Since we fake most of this, don't expect fancy usage to
101  *      work.
102  *
103  * AUTHOR:
104  *      Simon J. Gerraty <sjg@crufty.net>
105  */
106 /* COPYRIGHT:
107  *      @(#)Copyright (c) 1992-2021, Simon J. Gerraty
108  *
109  *      This is free software.  It comes with NO WARRANTY.
110  *      Permission to use, modify and distribute this source code
111  *      is granted subject to the following conditions.
112  *      1/ that that the above copyright notice and this notice
113  *      are preserved in all copies and that due credit be given
114  *      to the author.
115  *      2/ that any changes to this code are clearly commented
116  *      as such so that the author does get blamed for bugs
117  *      other than his own.
118  *
119  *      Please send copies of changes and bug-fixes to:
120  *      sjg@crufty.net
121  *
122  */
123 #ifndef lint
124 static char *RCSid = "$Id: sigact.c,v 1.8 2021/10/14 19:39:17 sjg Exp $";
125 #endif
126 
127 #undef _ANSI_SOURCE		/* causes problems */
128 
129 #include <signal.h>
130 #include <sys/cdefs.h>
131 
132 #ifdef HAVE_CONFIG_H
133 # include "config.h"
134 # ifdef NO_SIGSET
135 #   undef HAVE_SIGSET
136 # endif
137 # ifndef HAVE_SIGACTION
138 #   ifdef HAVE_SIGSETMASK
139 #     define USE_SIGMASK
140 #   else
141 #     ifdef HAVE_SIGSET
142 #       define USE_SIGSET
143 #     else
144 #       define USE_SIGNAL
145 #     endif
146 #   endif
147 # endif
148 #endif
149 
150 /*
151  * some systems have a faulty sigaction() implementation!
152  * Allow us to bypass it.
153  * Or they may have installed sigact.h as signal.h which is why
154  * we have SA_NOCLDSTOP defined.
155  */
156 #if !defined(SA_NOCLDSTOP) || defined(_SIGACT_H) || defined(USE_SIGNAL) || defined(USE_SIGSET) || defined(USE_SIGMASK)
157 
158 /*
159  * if we haven't been told,
160  * try and guess what we should implement with.
161  */
162 #if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
163 # if defined(sigmask) || defined(BSD) || defined(_BSD) && !defined(BSD41)
164 #   define USE_SIGMASK
165 # else
166 #   ifndef NO_SIGSET
167 #     define USE_SIGSET
168 #   else
169 #     define USE_SIGNAL
170 #   endif
171 # endif
172 #endif
173 /*
174  * if we still don't know, we're in trouble
175  */
176 #if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL)
177 error must know what to implement with
178 #endif
179 
180 #include "sigact.h"
181 
182 /*
183  * in case signal() has been mapped to our Signal().
184  */
185 #undef signal
186 
187 
188 int
189 sigaction(int sig,
190     const struct sigaction *act,
191     struct sigaction *oact)
192 {
193 	SIG_HDLR(*oldh) ();
194 
195 	if (act) {
196 #ifdef USE_SIGSET
197 		oldh = sigset(sig, act->sa_handler);
198 #else
199 		oldh = signal(sig, act->sa_handler);
200 #endif
201 	} else {
202 		if (oact) {
203 #ifdef USE_SIGSET
204 			oldh = sigset(sig, SIG_IGN);
205 #else
206 			oldh = signal(sig, SIG_IGN);
207 #endif
208 			if (oldh != SIG_IGN && oldh != SIG_ERR) {
209 #ifdef USE_SIGSET
210 				(void) sigset(sig, oldh);
211 #else
212 				(void) signal(sig, oldh);
213 #endif
214 			}
215 		}
216 	}
217 	if (oact) {
218 		oact->sa_handler = oldh;
219 	}
220 	return 0;		/* hey we're faking it */
221 }
222 
223 #ifndef HAVE_SIGADDSET
224 int
225 sigaddset(sigset_t *mask, int sig)
226 {
227 	*mask |= sigmask(sig);
228 	return 0;
229 }
230 
231 
232 int
233 sigdelset(sigset_t *mask, int sig)
234 {
235 	*mask &= ~(sigmask(sig));
236 	return 0;
237 }
238 
239 
240 int
241 sigemptyset(sigset_t *mask)
242 {
243 	*mask = 0;
244 	return 0;
245 }
246 
247 
248 int
249 sigfillset(sigset_t *mask)
250 {
251 	*mask = ~0;
252 	return 0;
253 }
254 
255 
256 int
257 sigismember(const sigset_t *mask, int sig)
258 {
259 	return ((*mask) & sigmask(sig));
260 }
261 #endif
262 
263 #ifndef HAVE_SIGPENDING
264 int
265 sigpending(sigset_t *set)
266 {
267 	return 0;		/* faking it! */
268 }
269 #endif
270 
271 #ifndef HAVE_SIGPROCMASK
272 int
273 sigprocmask(int how, const sigset_t *set, sigset_t *oset)
274 {
275 #ifdef USE_SIGSET
276 	int i;
277 #endif
278 	static sigset_t sm;
279 	static int once = 0;
280 
281 	if (!once) {
282 		/*
283 	         * initally we clear sm,
284 	         * there after, it represents the last
285 	         * thing we did.
286 	         */
287 		once++;
288 #ifdef USE_SIGMASK
289 		sm = sigblock(0);
290 #else
291 		sm = 0;
292 #endif
293 	}
294 	if (oset)
295 		*oset = sm;
296 	if (set) {
297 		switch (how) {
298 		case SIG_BLOCK:
299 			sm |= *set;
300 			break;
301 		case SIG_UNBLOCK:
302 			sm &= ~(*set);
303 			break;
304 		case SIG_SETMASK:
305 			sm = *set;
306 			break;
307 		}
308 #ifdef USE_SIGMASK
309 		(void) sigsetmask(sm);
310 #else
311 #ifdef USE_SIGSET
312 		for (i = 1; i < NSIG; i++) {
313 			if (how == SIG_UNBLOCK) {
314 				if (*set & sigmask(i))
315 					sigrelse(i);
316 			} else
317 				if (sm & sigmask(i)) {
318 					sighold(i);
319 				}
320 		}
321 #endif
322 #endif
323 	}
324 	return 0;
325 }
326 #endif
327 
328 #ifndef HAVE_SIGSUSPEND
329 int
330 sigsuspend(sigset_t *mask)
331 {
332 #ifdef USE_SIGMASK
333 	sigpause(*mask);
334 #else
335 	int i;
336 
337 #ifdef USE_SIGSET
338 
339 	for (i = 1; i < NSIG; i++) {
340 		if (*mask & sigmask(i)) {
341 			/* not the same sigpause() as above! */
342 			sigpause(i);
343 			break;
344 		}
345 	}
346 #else				/* signal(2) only */
347 	SIG_HDLR(*oldh) ();
348 
349 	/*
350          * make sure that signals in mask will not
351          * be ignored.
352          */
353 	for (i = 1; i < NSIG; i++) {
354 		if (*mask & sigmask(i)) {
355 			if ((oldh = signal(i, SIG_DFL)) != SIG_ERR &&
356 			    oldh != SIG_IGN &&
357 			    oldh != SIG_DFL)
358 				(void) signal(i, oldh);	/* restore handler */
359 		}
360 	}
361 	pause();		/* wait for a signal */
362 #endif
363 #endif
364 	return 0;
365 }
366 #endif
367 #endif				/* ! SA_NOCLDSTOP */
368 
369 #if 0
370 #if !defined(SIG_HDLR)
371 #define SIG_HDLR void
372 #endif
373 #if !defined(SIG_ERR)
374 #define SIG_ERR	(SIG_HDLR (*)())-1
375 #endif
376 
377 #if !defined(USE_SIGNAL) && !defined(USE_SIGMASK) && !defined(NO_SIGNAL)
378 /*
379  * ensure we avoid signal mayhem
380  */
381 
382 extern void (*Signal (int sig, void (*handler) (int)))(int);
383 
384 SIG_HDLR(*signal(int sig, SIG_HDLR(*handler)(int))
385 {
386 	return (Signal(sig, handler));
387 }
388 #endif
389 #endif
390 
391 /* This lot (for GNU-Emacs) goes at the end of the file. */
392 /*
393  * Local Variables:
394  * version-control:t
395  * comment-column:40
396  * End:
397  */
398