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