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