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