xref: /netbsd-src/usr.bin/mail/sig.c (revision 1d6b489c6ecbe44de5cd5944470e3e2e40e4879d)
1*1d6b489cSrillig /*	$NetBSD: sig.c,v 1.4 2021/11/27 22:16:41 rillig Exp $	*/
2ca13337dSchristos 
3ca13337dSchristos /*
4ca13337dSchristos  * Copyright (c) 1980, 1993
5ca13337dSchristos  *	The Regents of the University of California.  All rights reserved.
6ca13337dSchristos  *
7ca13337dSchristos  * Redistribution and use in source and binary forms, with or without
8ca13337dSchristos  * modification, are permitted provided that the following conditions
9ca13337dSchristos  * are met:
10ca13337dSchristos  * 1. Redistributions of source code must retain the above copyright
11ca13337dSchristos  *    notice, this list of conditions and the following disclaimer.
12ca13337dSchristos  * 2. Redistributions in binary form must reproduce the above copyright
13ca13337dSchristos  *    notice, this list of conditions and the following disclaimer in the
14ca13337dSchristos  *    documentation and/or other materials provided with the distribution.
15ca13337dSchristos  * 3. Neither the name of the University nor the names of its contributors
16ca13337dSchristos  *    may be used to endorse or promote products derived from this software
17ca13337dSchristos  *    without specific prior written permission.
18ca13337dSchristos  *
19ca13337dSchristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20ca13337dSchristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ca13337dSchristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ca13337dSchristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23ca13337dSchristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24ca13337dSchristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25ca13337dSchristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26ca13337dSchristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27ca13337dSchristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28ca13337dSchristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29ca13337dSchristos  * SUCH DAMAGE.
30ca13337dSchristos  */
31ca13337dSchristos 
32ca13337dSchristos #include <sys/cdefs.h>
33ca13337dSchristos #ifndef lint
34*1d6b489cSrillig __RCSID("$NetBSD: sig.c,v 1.4 2021/11/27 22:16:41 rillig Exp $");
35ca13337dSchristos #endif /* not lint */
36ca13337dSchristos 
37ca13337dSchristos #include <assert.h>
38ca13337dSchristos #include <util.h>
39ca13337dSchristos #include <sys/queue.h>
40ca13337dSchristos 
41ca13337dSchristos #include "rcv.h"
42ca13337dSchristos #include "extern.h"
43ca13337dSchristos #include "sig.h"
44ca13337dSchristos 
45ca13337dSchristos /*
46ca13337dSchristos  * Mail -- a mail program
47ca13337dSchristos  *
48ca13337dSchristos  * Signal routines.
49ca13337dSchristos  */
50ca13337dSchristos 
51ca13337dSchristos static sig_t sigarray[NSIG];
52ca13337dSchristos 
53ca13337dSchristos typedef struct q_entry_s {
54ca13337dSchristos 	int qe_signo;
55ca13337dSchristos 	sig_t qe_handler;
56ca13337dSchristos 	struct q_entry_s *qe_next;
57ca13337dSchristos } q_entry_t;
58ca13337dSchristos 
59ca13337dSchristos static struct {
60ca13337dSchristos 	q_entry_t *qe_first;
61ca13337dSchristos 	q_entry_t **qe_last;
62c45c4e89Sdyoung } sigq = { NULL, &sigq.qe_first };
63ca13337dSchristos #define SIGQUEUE_INIT(p)  do {\
64ca13337dSchristos 	(p)->qe_first = NULL;\
65ca13337dSchristos 	(p)->qe_last = &((p)->qe_first);\
66*1d6b489cSrillig   } while (0)
67ca13337dSchristos 
68ca13337dSchristos /*
69ca13337dSchristos  * The routines alloc_entry() and free_entry() manage the queue
70ca13337dSchristos  * elements.
71ca13337dSchristos  *
72ca13337dSchristos  * Currently, they just assign one element per signo from a fix array
73ca13337dSchristos  * as we don't support POSIX signal queues.  We leave them as this may
74ca13337dSchristos  * change in the future and the modifications will be isolated.
75ca13337dSchristos  */
76ca13337dSchristos static q_entry_t *
alloc_entry(int signo)77ca13337dSchristos alloc_entry(int signo)
78ca13337dSchristos {
79ca13337dSchristos 	static q_entry_t entries[NSIG];
80ca13337dSchristos 	q_entry_t *e;
81ca13337dSchristos 
82ca13337dSchristos 	/*
83ca13337dSchristos 	 * We currently only post one signal per signal number, so
84ca13337dSchristos 	 * there is no need to make this complicated.
85ca13337dSchristos 	 */
86ca13337dSchristos 	e = &entries[signo];
87ca13337dSchristos 	if (e->qe_signo != 0)
88ca13337dSchristos 		return NULL;
89ca13337dSchristos 
90ca13337dSchristos 	e->qe_signo = signo;
91ca13337dSchristos 	e->qe_handler = sigarray[signo];
92ca13337dSchristos 	e->qe_next = NULL;
93ca13337dSchristos 
94ca13337dSchristos 	return e;
95ca13337dSchristos }
96ca13337dSchristos 
97ca13337dSchristos static void
free_entry(q_entry_t * e)98ca13337dSchristos free_entry(q_entry_t *e)
99ca13337dSchristos {
100ca13337dSchristos 
101ca13337dSchristos 	e->qe_signo = 0;
102ca13337dSchristos 	e->qe_handler = NULL;
103ca13337dSchristos 	e->qe_next = NULL;
104ca13337dSchristos }
105ca13337dSchristos 
106ca13337dSchristos /*
107c45c4e89Sdyoung  * Attempt to post a signal to the sigq.
108ca13337dSchristos  */
109ca13337dSchristos static void
sig_post(int signo)110ca13337dSchristos sig_post(int signo)
111ca13337dSchristos {
112ca13337dSchristos 	q_entry_t *e;
113ca13337dSchristos 
114ca13337dSchristos 	if (sigarray[signo] == SIG_DFL || sigarray[signo] == SIG_IGN)
115ca13337dSchristos 		return;
116ca13337dSchristos 
117ca13337dSchristos 	e = alloc_entry(signo);
118ca13337dSchristos 	if (e != NULL) {
119c45c4e89Sdyoung 		*sigq.qe_last = e;
120c45c4e89Sdyoung 		sigq.qe_last = &e->qe_next;
121ca13337dSchristos 	}
122ca13337dSchristos }
123ca13337dSchristos 
124ca13337dSchristos /*
125c45c4e89Sdyoung  * Check the sigq for any pending signals.  If any are found,
126ca13337dSchristos  * preform the required actions and remove them from the queue.
127ca13337dSchristos  */
128ca13337dSchristos PUBLIC void
sig_check(void)129ca13337dSchristos sig_check(void)
130ca13337dSchristos {
131ca13337dSchristos 	q_entry_t *e;
132ca13337dSchristos 	sigset_t nset;
133ca13337dSchristos 	sigset_t oset;
134ca13337dSchristos 	void (*handler)(int);
135ca13337dSchristos 	int signo;
136ca13337dSchristos 
137ca13337dSchristos 	(void)sigfillset(&nset);
138ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &nset, &oset);
139ca13337dSchristos 
140c45c4e89Sdyoung 	while ((e = sigq.qe_first) != NULL) {
141ca13337dSchristos 		signo = e->qe_signo;
142ca13337dSchristos 		handler = e->qe_handler;
143ca13337dSchristos 
144ca13337dSchristos 		/*
145ca13337dSchristos 		 * Remove the entry from the queue and free it.
146ca13337dSchristos 		 */
147c45c4e89Sdyoung 		sigq.qe_first = e->qe_next;
148c45c4e89Sdyoung 		if (sigq.qe_first == NULL)
149c45c4e89Sdyoung 			sigq.qe_last = &sigq.qe_first;
150ca13337dSchristos 		free_entry(e);
151ca13337dSchristos 
152ca13337dSchristos 		if (handler == SIG_DFL || handler == SIG_IGN) {
153ca13337dSchristos 			assert(/*CONSTCOND*/ 0);	/* These should not get posted. */
154ca13337dSchristos 		}
155ca13337dSchristos 		else {
156ca13337dSchristos 			(void)sigprocmask(SIG_SETMASK, &oset, NULL);
157ca13337dSchristos 			handler(signo);
158ca13337dSchristos 			(void)sigprocmask(SIG_SETMASK, &nset, NULL);
159ca13337dSchristos 		}
160ca13337dSchristos 	}
161ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
162ca13337dSchristos }
163ca13337dSchristos 
164ca13337dSchristos PUBLIC sig_t
sig_current(int signo)165a7879b44Schristos sig_current(int signo)
166a7879b44Schristos {
167a7879b44Schristos 	assert(signo > 0 && signo < NSIG);
168a7879b44Schristos 	return sigarray[signo];
169a7879b44Schristos }
170a7879b44Schristos 
171a7879b44Schristos PUBLIC sig_t
sig_signal(int signo,sig_t handler)172ca13337dSchristos sig_signal(int signo, sig_t handler)
173ca13337dSchristos {
174ca13337dSchristos 	sig_t old_handler;
175ca13337dSchristos 	sigset_t nset;
176ca13337dSchristos 	sigset_t oset;
177ca13337dSchristos 
178ca13337dSchristos 	assert(signo > 0 && signo < NSIG);
179ca13337dSchristos 
180ca13337dSchristos 	(void)sigemptyset(&nset);
181ca13337dSchristos 	(void)sigaddset(&nset, signo);
182ca13337dSchristos 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
183ca13337dSchristos 
184ca13337dSchristos 	old_handler = sigarray[signo];
185ca13337dSchristos 	sigarray[signo] = handler;
186ca13337dSchristos 
187ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
188ca13337dSchristos 
189ca13337dSchristos 	return old_handler;
190ca13337dSchristos }
191ca13337dSchristos 
192ca13337dSchristos static void
do_default_handler(int signo,int flags)193ca13337dSchristos do_default_handler(int signo, int flags)
194ca13337dSchristos {
195ca13337dSchristos 	struct sigaction nsa;
196ca13337dSchristos 	struct sigaction osa;
197ca13337dSchristos 	sigset_t nset;
198ca13337dSchristos 	sigset_t oset;
199ca13337dSchristos 	int save_errno;
200ca13337dSchristos 
201ca13337dSchristos 	save_errno = errno;
202ca13337dSchristos 	(void)sigemptyset(&nsa.sa_mask);
203ca13337dSchristos 	nsa.sa_flags = flags;
204ca13337dSchristos 	nsa.sa_handler = SIG_DFL;
205ca13337dSchristos 	(void)sigaction(signo, &nsa, &osa);
206ca13337dSchristos 
207ca13337dSchristos 	(void)sigemptyset(&nset);
208ca13337dSchristos 	(void)sigaddset(&nset, signo);
209ca13337dSchristos 	(void)sigprocmask(SIG_UNBLOCK, &nset, &oset);
210ca13337dSchristos 
211ca13337dSchristos 	(void)kill(0, signo);
212ca13337dSchristos 
213ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
214ca13337dSchristos 	(void)sigaction(signo, &osa, NULL);
215ca13337dSchristos 	errno = save_errno;
216ca13337dSchristos }
217ca13337dSchristos 
218ca13337dSchristos /*
219ca13337dSchristos  * Our generic signal handler.
220ca13337dSchristos  */
221ca13337dSchristos static void
sig_handler(int signo)222ca13337dSchristos sig_handler(int signo)
223ca13337dSchristos {
224ca13337dSchristos 	sigset_t nset;
225ca13337dSchristos 	sigset_t oset;
226ca13337dSchristos 
227ca13337dSchristos 	(void)sigfillset(&nset);
228ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &nset, &oset);
229ca13337dSchristos 
230ca13337dSchristos 	assert (signo > 0 && signo < NSIG);	/* Should be guaranteed. */
231ca13337dSchristos 
232ca13337dSchristos 	sig_post(signo);
233ca13337dSchristos 
234ca13337dSchristos 	switch (signo) {
235ca13337dSchristos 	case SIGCONT:
236ca13337dSchristos 		assert(/*CONSTCOND*/ 0);	/* We should not be seeing these. */
237ca13337dSchristos 		do_default_handler(signo, 0);
238ca13337dSchristos 		break;
239ca13337dSchristos 
240ca13337dSchristos 	case SIGTSTP:
241ca13337dSchristos 	case SIGTTIN:
242ca13337dSchristos 	case SIGTTOU:
243ca13337dSchristos 		do_default_handler(signo, 0);
244ca13337dSchristos 		break;
245ca13337dSchristos 
246ca13337dSchristos 	case SIGINT:
247ca13337dSchristos 	case SIGHUP:
248ca13337dSchristos 	case SIGQUIT:
249ca13337dSchristos 	case SIGPIPE:
250ca13337dSchristos 	default:
251ca13337dSchristos 		if (sigarray[signo] == SIG_DFL)
252ca13337dSchristos 			do_default_handler(signo, SA_RESTART);
253ca13337dSchristos 		break;
254ca13337dSchristos 	}
255ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
256ca13337dSchristos }
257ca13337dSchristos 
258ca13337dSchristos /*
259ca13337dSchristos  * Setup the signal handlers.
260ca13337dSchristos  */
261ca13337dSchristos PUBLIC void
sig_setup(void)262ca13337dSchristos sig_setup(void)
263ca13337dSchristos {
264ca13337dSchristos 	sigset_t nset;
265ca13337dSchristos 	sigset_t oset;
266ca13337dSchristos 	struct sigaction sa;
267ca13337dSchristos 	struct sigaction osa;
268ca13337dSchristos 
269ca13337dSchristos 	/* Block all signals while setting things. */
270ca13337dSchristos 	(void)sigfillset(&nset);
271ca13337dSchristos 	(void)sigprocmask(SIG_BLOCK, &nset, &oset);
272ca13337dSchristos 
273ca13337dSchristos 	/*
274ca13337dSchristos 	 * Flow Control - SIGTSTP, SIGTTIN, SIGTTOU, SIGCONT:
275ca13337dSchristos 	 *
276ca13337dSchristos 	 * We grab SIGTSTP, SIGTTIN, and SIGTTOU so that we post the
277ca13337dSchristos 	 * signals before suspending so that they are available when
278ca13337dSchristos 	 * we resume.  If we were to use SIGCONT instead, they will
279ca13337dSchristos 	 * not get posted until SIGCONT is unblocked, even though the
280ca13337dSchristos 	 * process has resumed.
281ca13337dSchristos 	 *
282ca13337dSchristos 	 * NOTE: We default these to SA_RESTART here, but we need to
283ca13337dSchristos 	 * change this in certain cases, e.g., when reading from a
284ca13337dSchristos 	 * tty.
285ca13337dSchristos 	 */
286ca13337dSchristos 	(void)sigemptyset(&sa.sa_mask);
287ca13337dSchristos 	sa.sa_flags = SA_RESTART;
288ca13337dSchristos 	sa.sa_handler = sig_handler;
289ca13337dSchristos 	(void)sigaction(SIGTSTP, &sa, NULL);
290ca13337dSchristos 	(void)sigaction(SIGTTIN, &sa, NULL);
291ca13337dSchristos 	(void)sigaction(SIGTTOU, &sa, NULL);
292ca13337dSchristos 
293ca13337dSchristos 	/*
294ca13337dSchristos 	 * SIGHUP, SIGINT, and SIGQUIT:
295ca13337dSchristos 	 *
296ca13337dSchristos 	 * SIGHUP and SIGINT are trapped unless they are being
297ca13337dSchristos 	 * ignored.
298ca13337dSchristos 	 *
299ca13337dSchristos 	 * Currently, we let the default handler deal with SIGQUIT.
300ca13337dSchristos 	 */
301ca13337dSchristos 	(void)sigemptyset(&sa.sa_mask);
302ca13337dSchristos 	sa.sa_flags = 0;
303ca13337dSchristos 	sa.sa_handler = sig_handler;
304ca13337dSchristos 
305ca13337dSchristos 	if (sigaction(SIGHUP, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN)
306ca13337dSchristos 		(void)signal(SIGHUP, SIG_IGN);
307ca13337dSchristos 
308ca13337dSchristos 	if (sigaction(SIGINT, &sa, &osa) != -1 && osa.sa_handler == SIG_IGN)
309ca13337dSchristos 		(void)signal(SIGINT, SIG_IGN);
310ca13337dSchristos #if 0
311ca13337dSchristos 	if (signal(SIGQUIT, SIG_DFL) == SIG_IGN)
312ca13337dSchristos 		(void)signal(SIGQUIT, SIG_IGN);
313ca13337dSchristos #endif
314ca13337dSchristos 	/*
315ca13337dSchristos 	 * SIGCHLD and SIGPIPE:
316ca13337dSchristos 	 *
317ca13337dSchristos 	 * SIGCHLD is setup early in main.  The handler lives in
318ca13337dSchristos 	 * popen.c as it uses internals of that module.
319ca13337dSchristos 	 *
320ca13337dSchristos 	 * SIGPIPE is grabbed here.  It is only used in
321ca13337dSchristos 	 * lex.c:setup_piping(), cmd1.c:type1(), and cmd1.c:pipecmd().
322ca13337dSchristos 	 */
323ca13337dSchristos 	(void)sigemptyset(&sa.sa_mask);
324ca13337dSchristos 	sa.sa_flags = 0;
325ca13337dSchristos 	sa.sa_handler = sig_handler;
326ca13337dSchristos 	(void)sigaction(SIGPIPE, &sa, NULL);
327ca13337dSchristos 
328ca13337dSchristos 	/*
329ca13337dSchristos 	 * Make sure our structures are initialized.
330ca13337dSchristos 	 * XXX: This should be unnecessary.
331ca13337dSchristos 	 */
332ca13337dSchristos 	(void)memset(sigarray, 0, sizeof(sigarray));
333c45c4e89Sdyoung 	SIGQUEUE_INIT(&sigq);
334ca13337dSchristos 
335ca13337dSchristos 	/* Restore the signal mask. */
336ca13337dSchristos 	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
337ca13337dSchristos }
338ca13337dSchristos 
339ca13337dSchristos static struct {		/* data shared by sig_hold() and sig_release() */
340ca13337dSchristos 	int depth;	/* depth of sig_hold() */
341ca13337dSchristos 	sigset_t oset;	/* old signal mask saved by sig_hold() */
342ca13337dSchristos } hold;
343ca13337dSchristos 
344ca13337dSchristos /*
345ca13337dSchristos  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
346ca13337dSchristos  */
347ca13337dSchristos PUBLIC void
sig_hold(void)348ca13337dSchristos sig_hold(void)
349ca13337dSchristos {
350ca13337dSchristos 	sigset_t nset;
351ca13337dSchristos 
352ca13337dSchristos 	if (hold.depth++ == 0) {
353ca13337dSchristos 		(void)sigemptyset(&nset);
354ca13337dSchristos 		(void)sigaddset(&nset, SIGHUP);
355ca13337dSchristos 		(void)sigaddset(&nset, SIGINT);
356ca13337dSchristos 		(void)sigaddset(&nset, SIGQUIT);
357ca13337dSchristos 		(void)sigprocmask(SIG_BLOCK, &nset, &hold.oset);
358ca13337dSchristos 	}
359ca13337dSchristos }
360ca13337dSchristos 
361ca13337dSchristos /*
362ca13337dSchristos  * Release signals SIGHUP, SIGINT, and SIGQUIT.
363ca13337dSchristos  */
364ca13337dSchristos PUBLIC void
sig_release(void)365ca13337dSchristos sig_release(void)
366ca13337dSchristos {
367ca13337dSchristos 
368ca13337dSchristos 	if (--hold.depth == 0)
369ca13337dSchristos 		(void)sigprocmask(SIG_SETMASK, &hold.oset, NULL);
370ca13337dSchristos }
371ca13337dSchristos 
372ca13337dSchristos /*
373ca13337dSchristos  * Unblock and ignore a signal.
374ca13337dSchristos  */
375ca13337dSchristos PUBLIC int
sig_ignore(int sig,struct sigaction * osa,sigset_t * oset)376ca13337dSchristos sig_ignore(int sig, struct sigaction *osa, sigset_t *oset)
377ca13337dSchristos {
378ca13337dSchristos 	struct sigaction act;
379ca13337dSchristos 	sigset_t nset;
380ca13337dSchristos 	int error;
381ca13337dSchristos 
382ca13337dSchristos 	(void)sigemptyset(&act.sa_mask);
383ca13337dSchristos 	act.sa_flags = SA_RESTART;
384ca13337dSchristos 	act.sa_handler = SIG_IGN;
385ca13337dSchristos 	error = sigaction(sig, &act, osa);
386ca13337dSchristos 
387ca13337dSchristos 	if (error != -1) {
388ca13337dSchristos 		(void)sigemptyset(&nset);
389ca13337dSchristos 		(void)sigaddset(&nset, sig);
390ca13337dSchristos 		(void)sigprocmask(SIG_UNBLOCK, &nset, oset);
391ca13337dSchristos 	} else if (oset != NULL)
392ca13337dSchristos 		(void)sigprocmask(SIG_UNBLOCK, NULL, oset);
393ca13337dSchristos 
394ca13337dSchristos 	return error;
395ca13337dSchristos }
396ca13337dSchristos 
397ca13337dSchristos /*
398ca13337dSchristos  * Restore a signal and the current signal mask.
399ca13337dSchristos  */
400ca13337dSchristos PUBLIC int
sig_restore(int sig,struct sigaction * osa,sigset_t * oset)401ca13337dSchristos sig_restore(int sig, struct sigaction *osa, sigset_t *oset)
402ca13337dSchristos {
403ca13337dSchristos 	int error;
404ca13337dSchristos 
405ca13337dSchristos 	error = 0;
406ca13337dSchristos 	if (oset)
407ca13337dSchristos 		error = sigprocmask(SIG_SETMASK, oset, NULL);
408ca13337dSchristos 	if (osa)
409ca13337dSchristos 		error = sigaction(sig, osa, NULL);
410ca13337dSchristos 
411ca13337dSchristos 	return error;
412ca13337dSchristos }
413ca13337dSchristos 
414ca13337dSchristos /*
415ca13337dSchristos  * Change the current flags and (optionally) return the old sigaction
416ca13337dSchristos  * structure so we can restore things later.  This is used to turn
417ca13337dSchristos  * SA_RESTART on or off.
418ca13337dSchristos  */
419ca13337dSchristos PUBLIC int
sig_setflags(int signo,int flags,struct sigaction * osa)420ca13337dSchristos sig_setflags(int signo, int flags, struct sigaction *osa)
421ca13337dSchristos {
422ca13337dSchristos 	struct sigaction sa;
423ca13337dSchristos 
424ca13337dSchristos 	if (sigaction(signo, NULL, &sa) == -1)
425ca13337dSchristos 		return -1;
426ca13337dSchristos 	if (osa)
427ca13337dSchristos 		*osa = sa;
428ca13337dSchristos 	sa.sa_flags = flags;
429ca13337dSchristos 	return sigaction(signo, &sa, NULL);
430ca13337dSchristos }
431ca13337dSchristos 
432