trap.c revision 1.52 1 1.52 kre /* $NetBSD: trap.c,v 1.52 2019/04/25 03:54:10 kre Exp $ */
2 1.12 cgd
3 1.1 cgd /*-
4 1.6 jtc * Copyright (c) 1991, 1993
5 1.6 jtc * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * This code is derived from software contributed to Berkeley by
8 1.1 cgd * Kenneth Almquist.
9 1.1 cgd *
10 1.1 cgd * Redistribution and use in source and binary forms, with or without
11 1.1 cgd * modification, are permitted provided that the following conditions
12 1.1 cgd * are met:
13 1.1 cgd * 1. Redistributions of source code must retain the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer.
15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 cgd * notice, this list of conditions and the following disclaimer in the
17 1.1 cgd * documentation and/or other materials provided with the distribution.
18 1.29 agc * 3. Neither the name of the University nor the names of its contributors
19 1.1 cgd * may be used to endorse or promote products derived from this software
20 1.1 cgd * without specific prior written permission.
21 1.1 cgd *
22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 cgd * SUCH DAMAGE.
33 1.1 cgd */
34 1.1 cgd
35 1.17 christos #include <sys/cdefs.h>
36 1.1 cgd #ifndef lint
37 1.12 cgd #if 0
38 1.15 christos static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
39 1.12 cgd #else
40 1.52 kre __RCSID("$NetBSD: trap.c,v 1.52 2019/04/25 03:54:10 kre Exp $");
41 1.12 cgd #endif
42 1.1 cgd #endif /* not lint */
43 1.1 cgd
44 1.13 christos #include <signal.h>
45 1.13 christos #include <unistd.h>
46 1.13 christos #include <stdlib.h>
47 1.40 kre #include <stdio.h>
48 1.47 kre #include <errno.h>
49 1.52 kre #include <limits.h>
50 1.50 kre #include <termios.h>
51 1.47 kre
52 1.50 kre #undef CEOF /* from <termios.h> but concflicts with sh use */
53 1.50 kre
54 1.50 kre #include <sys/ioctl.h>
55 1.47 kre #include <sys/resource.h>
56 1.13 christos
57 1.1 cgd #include "shell.h"
58 1.1 cgd #include "main.h"
59 1.1 cgd #include "nodes.h" /* for other headers */
60 1.1 cgd #include "eval.h"
61 1.1 cgd #include "jobs.h"
62 1.13 christos #include "show.h"
63 1.1 cgd #include "options.h"
64 1.35 christos #include "builtins.h"
65 1.1 cgd #include "syntax.h"
66 1.1 cgd #include "output.h"
67 1.1 cgd #include "memalloc.h"
68 1.1 cgd #include "error.h"
69 1.1 cgd #include "trap.h"
70 1.1 cgd #include "mystring.h"
71 1.31 christos #include "var.h"
72 1.1 cgd
73 1.1 cgd
74 1.1 cgd /*
75 1.1 cgd * Sigmode records the current value of the signal handlers for the various
76 1.1 cgd * modes. A value of zero means that the current handler is not known.
77 1.1 cgd * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
78 1.1 cgd */
79 1.1 cgd
80 1.1 cgd #define S_DFL 1 /* default signal handling (SIG_DFL) */
81 1.1 cgd #define S_CATCH 2 /* signal is caught */
82 1.1 cgd #define S_IGN 3 /* signal is ignored (SIG_IGN) */
83 1.1 cgd #define S_HARD_IGN 4 /* signal is ignored permenantly */
84 1.6 jtc #define S_RESET 5 /* temporary - to reset a hard ignored sig */
85 1.1 cgd
86 1.1 cgd
87 1.8 jtc MKINIT char sigmode[NSIG]; /* current value of signal */
88 1.47 kre static volatile sig_atomic_t gotsig[NSIG];/* indicates specified signal received */
89 1.47 kre volatile sig_atomic_t pendingsigs; /* indicates some signal received */
90 1.47 kre
91 1.47 kre int traps_invalid; /* in a subshell, but trap[] not yet cleared */
92 1.47 kre static char * volatile trap[NSIG]; /* trap handler commands */
93 1.47 kre static int in_dotrap;
94 1.47 kre static int last_trapsig;
95 1.47 kre
96 1.47 kre static int exiting; /* exitshell() has been done */
97 1.47 kre static int exiting_status; /* the status to use for exit() */
98 1.1 cgd
99 1.28 christos static int getsigaction(int, sig_t *);
100 1.40 kre STATIC const char *trap_signame(int);
101 1.46 kre void printsignals(struct output *, int);
102 1.26 wulf
103 1.26 wulf /*
104 1.26 wulf * return the signal number described by `p' (as a number or a name)
105 1.26 wulf * or -1 if it isn't one
106 1.26 wulf */
107 1.26 wulf
108 1.26 wulf static int
109 1.28 christos signame_to_signum(const char *p)
110 1.26 wulf {
111 1.26 wulf int i;
112 1.26 wulf
113 1.26 wulf if (is_number(p))
114 1.26 wulf return number(p);
115 1.26 wulf
116 1.26 wulf if (strcasecmp(p, "exit") == 0 )
117 1.26 wulf return 0;
118 1.26 wulf
119 1.46 kre i = signalnumber(p);
120 1.46 kre if (i == 0)
121 1.46 kre i = -1;
122 1.46 kre return i;
123 1.26 wulf }
124 1.26 wulf
125 1.26 wulf /*
126 1.40 kre * return the name of a signal used by the "trap" command
127 1.40 kre */
128 1.40 kre STATIC const char *
129 1.40 kre trap_signame(int signo)
130 1.40 kre {
131 1.40 kre static char nbuf[12];
132 1.46 kre const char *p;
133 1.40 kre
134 1.40 kre if (signo == 0)
135 1.40 kre return "EXIT";
136 1.46 kre p = signalname(signo);
137 1.40 kre if (p != NULL)
138 1.40 kre return p;
139 1.40 kre (void)snprintf(nbuf, sizeof nbuf, "%d", signo);
140 1.40 kre return nbuf;
141 1.40 kre }
142 1.40 kre
143 1.50 kre #ifdef SMALL
144 1.40 kre /*
145 1.26 wulf * Print a list of valid signal names
146 1.26 wulf */
147 1.46 kre void
148 1.46 kre printsignals(struct output *out, int len)
149 1.26 wulf {
150 1.26 wulf int n;
151 1.26 wulf
152 1.46 kre if (len != 0)
153 1.46 kre outc(' ', out);
154 1.26 wulf for (n = 1; n < NSIG; n++) {
155 1.46 kre outfmt(out, "%s", trap_signame(n));
156 1.26 wulf if ((n == NSIG/2) || n == (NSIG - 1))
157 1.46 kre outstr("\n", out);
158 1.26 wulf else
159 1.46 kre outc(' ', out);
160 1.26 wulf }
161 1.26 wulf }
162 1.50 kre #else /* !SMALL */
163 1.50 kre /*
164 1.50 kre * Print the names of all the signals (neatly) to fp
165 1.50 kre * "len" gives the number of chars already printed to
166 1.50 kre * the current output line (in kill.c, always 0)
167 1.50 kre */
168 1.50 kre void
169 1.50 kre printsignals(struct output *out, int len)
170 1.50 kre {
171 1.50 kre int sig;
172 1.50 kre int nl, pad;
173 1.50 kre const char *name;
174 1.50 kre int termwidth = 80;
175 1.50 kre
176 1.50 kre if ((name = bltinlookup("COLUMNS", 1)) != NULL)
177 1.50 kre termwidth = (int)strtol(name, NULL, 10);
178 1.50 kre else if (isatty(1)) {
179 1.50 kre struct winsize win;
180 1.50 kre
181 1.50 kre if (ioctl(1, TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
182 1.50 kre termwidth = win.ws_col;
183 1.50 kre }
184 1.50 kre
185 1.50 kre if (posix)
186 1.50 kre pad = 1;
187 1.50 kre else
188 1.50 kre pad = (len | 7) + 1 - len;
189 1.50 kre
190 1.50 kre for (sig = 0; (sig = signalnext(sig)) != 0; ) {
191 1.50 kre name = signalname(sig);
192 1.50 kre if (name == NULL)
193 1.50 kre continue;
194 1.50 kre
195 1.50 kre nl = strlen(name);
196 1.50 kre
197 1.50 kre if (len > 0 && nl + len + pad >= termwidth) {
198 1.50 kre outc('\n', out);
199 1.50 kre len = 0;
200 1.50 kre pad = 0;
201 1.50 kre } else if (pad > 0 && len != 0)
202 1.50 kre outfmt(out, "%*s", pad, "");
203 1.50 kre else
204 1.50 kre pad = 0;
205 1.50 kre
206 1.50 kre len += nl + pad;
207 1.50 kre if (!posix)
208 1.50 kre pad = (nl | 7) + 1 - nl;
209 1.50 kre else
210 1.50 kre pad = 1;
211 1.50 kre
212 1.50 kre outstr(name, out);
213 1.50 kre }
214 1.50 kre if (len != 0)
215 1.50 kre outc('\n', out);
216 1.50 kre }
217 1.50 kre #endif /* SMALL */
218 1.15 christos
219 1.1 cgd /*
220 1.1 cgd * The trap builtin.
221 1.1 cgd */
222 1.1 cgd
223 1.10 cgd int
224 1.28 christos trapcmd(int argc, char **argv)
225 1.10 cgd {
226 1.1 cgd char *action;
227 1.1 cgd char **ap;
228 1.1 cgd int signo;
229 1.39 kre int errs = 0;
230 1.40 kre int printonly = 0;
231 1.39 kre
232 1.39 kre ap = argv + 1;
233 1.39 kre
234 1.47 kre CTRACE(DBG_TRAP, ("trapcmd: "));
235 1.39 kre if (argc == 2 && strcmp(*ap, "-l") == 0) {
236 1.47 kre CTRACE(DBG_TRAP, ("-l\n"));
237 1.46 kre out1str("EXIT");
238 1.46 kre printsignals(out1, 4);
239 1.39 kre return 0;
240 1.39 kre }
241 1.40 kre if (argc == 2 && strcmp(*ap, "-") == 0) {
242 1.47 kre CTRACE(DBG_TRAP, ("-\n"));
243 1.40 kre for (signo = 0; signo < NSIG; signo++) {
244 1.40 kre if (trap[signo] == NULL)
245 1.40 kre continue;
246 1.40 kre INTOFF;
247 1.40 kre ckfree(trap[signo]);
248 1.40 kre trap[signo] = NULL;
249 1.40 kre if (signo != 0)
250 1.40 kre setsignal(signo, 0);
251 1.40 kre INTON;
252 1.40 kre }
253 1.47 kre traps_invalid = 0;
254 1.40 kre return 0;
255 1.40 kre }
256 1.40 kre if (argc >= 2 && strcmp(*ap, "-p") == 0) {
257 1.47 kre CTRACE(DBG_TRAP, ("-p "));
258 1.40 kre printonly = 1;
259 1.40 kre ap++;
260 1.40 kre argc--;
261 1.40 kre }
262 1.39 kre
263 1.39 kre if (argc > 1 && strcmp(*ap, "--") == 0) {
264 1.39 kre argc--;
265 1.39 kre ap++;
266 1.39 kre }
267 1.1 cgd
268 1.1 cgd if (argc <= 1) {
269 1.40 kre int count;
270 1.40 kre
271 1.47 kre CTRACE(DBG_TRAP, ("*all*\n"));
272 1.40 kre if (printonly) {
273 1.52 kre for (count = 0, signo = 0 ; signo < NSIG ; signo++) {
274 1.52 kre if (signo == SIGKILL || signo == SIGSTOP)
275 1.52 kre continue;
276 1.40 kre if (trap[signo] == NULL) {
277 1.40 kre if (count == 0)
278 1.40 kre out1str("trap -- -");
279 1.40 kre out1fmt(" %s", trap_signame(signo));
280 1.40 kre /* oh! unlucky 13 */
281 1.40 kre if (++count >= 13) {
282 1.40 kre out1str("\n");
283 1.40 kre count = 0;
284 1.40 kre }
285 1.40 kre }
286 1.52 kre }
287 1.40 kre if (count)
288 1.40 kre out1str("\n");
289 1.40 kre }
290 1.40 kre
291 1.52 kre /*
292 1.52 kre * We don't need do deal with SIGSTOP or SIGKILL as a
293 1.52 kre * special case anywhere here, as they cannot be
294 1.52 kre * ignored or caught - the only possibility is default
295 1.52 kre */
296 1.40 kre for (count = 0, signo = 0 ; signo < NSIG ; signo++)
297 1.40 kre if (trap[signo] != NULL && trap[signo][0] == '\0') {
298 1.40 kre if (count == 0)
299 1.40 kre out1str("trap -- ''");
300 1.40 kre out1fmt(" %s", trap_signame(signo));
301 1.40 kre /*
302 1.40 kre * the prefix is 10 bytes, with 4 byte
303 1.40 kre * signal names (common) we have room in
304 1.40 kre * the 70 bytes left on a normal line for
305 1.40 kre * 70/(4+1) signals, that's 14, but to
306 1.40 kre * allow for the occasional longer sig name
307 1.40 kre * we output one less...
308 1.40 kre */
309 1.40 kre if (++count >= 13) {
310 1.40 kre out1str("\n");
311 1.40 kre count = 0;
312 1.40 kre }
313 1.40 kre }
314 1.40 kre if (count)
315 1.40 kre out1str("\n");
316 1.40 kre
317 1.40 kre for (signo = 0 ; signo < NSIG ; signo++)
318 1.40 kre if (trap[signo] != NULL && trap[signo][0] != '\0') {
319 1.40 kre out1str("trap -- ");
320 1.31 christos print_quoted(trap[signo]);
321 1.40 kre out1fmt(" %s\n", trap_signame(signo));
322 1.31 christos }
323 1.40 kre
324 1.1 cgd return 0;
325 1.1 cgd }
326 1.47 kre CTRACE(DBG_TRAP, ("\n"));
327 1.26 wulf
328 1.26 wulf action = NULL;
329 1.26 wulf
330 1.47 kre if (!printonly && traps_invalid)
331 1.47 kre free_traps();
332 1.47 kre
333 1.40 kre if (!printonly && !is_number(*ap)) {
334 1.39 kre if ((*ap)[0] == '-' && (*ap)[1] == '\0')
335 1.39 kre ap++; /* reset to default */
336 1.39 kre else
337 1.39 kre action = *ap++; /* can be '' for "ignore" */
338 1.39 kre argc--;
339 1.39 kre }
340 1.26 wulf
341 1.39 kre if (argc < 2) { /* there must be at least 1 condition */
342 1.39 kre out2str("Usage: trap [-l]\n"
343 1.40 kre " trap -p [condition ...]\n"
344 1.39 kre " trap action condition ...\n"
345 1.39 kre " trap N condition ...\n");
346 1.39 kre return 2;
347 1.26 wulf }
348 1.26 wulf
349 1.39 kre
350 1.1 cgd while (*ap) {
351 1.39 kre signo = signame_to_signum(*ap);
352 1.26 wulf
353 1.40 kre if (signo < 0 || signo >= NSIG) {
354 1.39 kre /* This is not a fatal error, so sayeth posix */
355 1.39 kre outfmt(out2, "trap: '%s' bad condition\n", *ap);
356 1.39 kre errs = 1;
357 1.40 kre ap++;
358 1.40 kre continue;
359 1.40 kre }
360 1.40 kre ap++;
361 1.40 kre
362 1.40 kre if (printonly) {
363 1.52 kre /*
364 1.52 kre * we allow SIGSTOP and SIGKILL to be obtained
365 1.52 kre * (action will always be "-") here, if someone
366 1.52 kre * really wants to get that particular output
367 1.52 kre */
368 1.40 kre out1str("trap -- ");
369 1.40 kre if (trap[signo] == NULL)
370 1.40 kre out1str("-");
371 1.40 kre else
372 1.40 kre print_quoted(trap[signo]);
373 1.40 kre out1fmt(" %s\n", trap_signame(signo));
374 1.40 kre continue;
375 1.39 kre }
376 1.26 wulf
377 1.52 kre if ((signo == SIGKILL || signo == SIGSTOP) && action != NULL) {
378 1.52 kre #ifndef SMALL
379 1.52 kre /*
380 1.52 kre * Don't bother with the error message in a SMALL shell
381 1.52 kre * just ignore req and return error status silently
382 1.52 kre * (POSIX says this is an "undefined" operation so
383 1.52 kre * whatever we do is OK!)
384 1.52 kre *
385 1.52 kre * When we do generate an error, make it attempt match
386 1.52 kre * the user's operand, as best we can reasonably.
387 1.52 kre */
388 1.52 kre outfmt(out2, "trap: '%s%s' cannot be %s\n",
389 1.52 kre (!is_alpha(ap[-1][0]) ||
390 1.52 kre strncasecmp(ap[-1], "sig", 3) == 0) ? "" :
391 1.52 kre is_upper(ap[-1][0]) ? "SIG" : "sig",
392 1.52 kre ap[-1], *action ? "caught" : "ignored");
393 1.52 kre #endif
394 1.52 kre errs = 1;
395 1.52 kre continue;
396 1.52 kre }
397 1.52 kre
398 1.1 cgd INTOFF;
399 1.1 cgd if (action)
400 1.1 cgd action = savestr(action);
401 1.26 wulf
402 1.47 kre VTRACE(DBG_TRAP, ("trap for %d from %s%s%s to %s%s%s\n", signo,
403 1.47 kre trap[signo] ? "'" : "", trap[signo] ? trap[signo] : "-",
404 1.47 kre trap[signo] ? "'" : "", action ? "'" : "",
405 1.47 kre action ? action : "-", action ? "'" : ""));
406 1.47 kre
407 1.1 cgd if (trap[signo])
408 1.1 cgd ckfree(trap[signo]);
409 1.26 wulf
410 1.1 cgd trap[signo] = action;
411 1.26 wulf
412 1.1 cgd if (signo != 0)
413 1.27 christos setsignal(signo, 0);
414 1.1 cgd INTON;
415 1.1 cgd }
416 1.39 kre return errs;
417 1.1 cgd }
418 1.1 cgd
419 1.1 cgd
420 1.1 cgd
421 1.1 cgd /*
422 1.27 christos * Clear traps on a fork or vfork.
423 1.27 christos * Takes one arg vfork, to tell it to not be destructive of
424 1.27 christos * the parents variables.
425 1.1 cgd */
426 1.1 cgd void
427 1.28 christos clear_traps(int vforked)
428 1.27 christos {
429 1.47 kre char * volatile *tp;
430 1.47 kre
431 1.47 kre VTRACE(DBG_TRAP, ("clear_traps(%d)\n", vforked));
432 1.47 kre if (!vforked)
433 1.47 kre traps_invalid = 1;
434 1.1 cgd
435 1.47 kre for (tp = &trap[1] ; tp < &trap[NSIG] ; tp++) {
436 1.1 cgd if (*tp && **tp) { /* trap not NULL or SIG_IGN */
437 1.1 cgd INTOFF;
438 1.47 kre setsignal(tp - trap, vforked == 1);
439 1.1 cgd INTON;
440 1.1 cgd }
441 1.1 cgd }
442 1.47 kre if (vforked == 2)
443 1.47 kre free_traps();
444 1.47 kre }
445 1.47 kre
446 1.47 kre void
447 1.47 kre free_traps(void)
448 1.47 kre {
449 1.47 kre char * volatile *tp;
450 1.47 kre
451 1.47 kre VTRACE(DBG_TRAP, ("free_traps%s\n", traps_invalid ? "(invalid)" : ""));
452 1.47 kre INTOFF;
453 1.47 kre for (tp = trap ; tp < &trap[NSIG] ; tp++)
454 1.47 kre if (*tp && **tp) {
455 1.47 kre ckfree(*tp);
456 1.47 kre *tp = NULL;
457 1.47 kre }
458 1.47 kre traps_invalid = 0;
459 1.47 kre INTON;
460 1.1 cgd }
461 1.1 cgd
462 1.45 kre /*
463 1.45 kre * See if there are any defined traps
464 1.45 kre */
465 1.45 kre int
466 1.45 kre have_traps(void)
467 1.45 kre {
468 1.47 kre char * volatile *tp;
469 1.47 kre
470 1.47 kre if (traps_invalid)
471 1.47 kre return 0;
472 1.1 cgd
473 1.45 kre for (tp = trap ; tp < &trap[NSIG] ; tp++)
474 1.45 kre if (*tp && **tp) /* trap not NULL or SIG_IGN */
475 1.45 kre return 1;
476 1.45 kre return 0;
477 1.45 kre }
478 1.1 cgd
479 1.1 cgd /*
480 1.1 cgd * Set the signal handler for the specified signal. The routine figures
481 1.1 cgd * out what it should be set to.
482 1.1 cgd */
483 1.47 kre void
484 1.28 christos setsignal(int signo, int vforked)
485 1.10 cgd {
486 1.1 cgd int action;
487 1.32 christos sig_t sigact = SIG_DFL, sig;
488 1.27 christos char *t, tsig;
489 1.1 cgd
490 1.51 kre if (traps_invalid || (t = trap[signo]) == NULL)
491 1.1 cgd action = S_DFL;
492 1.1 cgd else if (*t != '\0')
493 1.1 cgd action = S_CATCH;
494 1.1 cgd else
495 1.1 cgd action = S_IGN;
496 1.47 kre
497 1.47 kre VTRACE(DBG_TRAP, ("setsignal(%d%s) -> %d", signo,
498 1.47 kre vforked ? ", VF" : "", action));
499 1.27 christos if (rootshell && !vforked && action == S_DFL) {
500 1.1 cgd switch (signo) {
501 1.1 cgd case SIGINT:
502 1.21 christos if (iflag || minusc || sflag == 0)
503 1.1 cgd action = S_CATCH;
504 1.1 cgd break;
505 1.1 cgd case SIGQUIT:
506 1.1 cgd #ifdef DEBUG
507 1.1 cgd if (debug)
508 1.1 cgd break;
509 1.1 cgd #endif
510 1.1 cgd /* FALLTHROUGH */
511 1.1 cgd case SIGTERM:
512 1.47 kre if (rootshell && iflag)
513 1.1 cgd action = S_IGN;
514 1.1 cgd break;
515 1.1 cgd #if JOBS
516 1.1 cgd case SIGTSTP:
517 1.1 cgd case SIGTTOU:
518 1.47 kre if (rootshell && mflag)
519 1.1 cgd action = S_IGN;
520 1.1 cgd break;
521 1.1 cgd #endif
522 1.1 cgd }
523 1.1 cgd }
524 1.14 christos
525 1.47 kre /*
526 1.47 kre * Never let users futz with SIGCHLD
527 1.47 kre * instead we will give them pseudo SIGCHLD's
528 1.47 kre * when background jobs complete.
529 1.47 kre */
530 1.47 kre if (signo == SIGCHLD)
531 1.47 kre action = S_DFL;
532 1.47 kre
533 1.47 kre VTRACE(DBG_TRAP, (" -> %d", action));
534 1.47 kre
535 1.47 kre t = &sigmode[signo];
536 1.27 christos tsig = *t;
537 1.27 christos if (tsig == 0) {
538 1.16 christos /*
539 1.16 christos * current setting unknown
540 1.1 cgd */
541 1.15 christos if (!getsigaction(signo, &sigact)) {
542 1.15 christos /*
543 1.15 christos * Pretend it worked; maybe we should give a warning
544 1.15 christos * here, but other shells don't. We don't alter
545 1.15 christos * sigmode, so that we retry every time.
546 1.15 christos */
547 1.47 kre VTRACE(DBG_TRAP, (" getsigaction (%d)\n", errno));
548 1.47 kre return;
549 1.15 christos }
550 1.47 kre VTRACE(DBG_TRAP, (" [%s]%s%s", sigact==SIG_IGN ? "IGN" :
551 1.47 kre sigact==SIG_DFL ? "DFL" : "caught",
552 1.47 kre iflag ? "i" : "", mflag ? "m" : ""));
553 1.47 kre
554 1.1 cgd if (sigact == SIG_IGN) {
555 1.32 christos /*
556 1.33 christos * POSIX 3.14.13 states that non-interactive shells
557 1.33 christos * should ignore trap commands for signals that were
558 1.33 christos * ignored upon entry, and leaves the behavior
559 1.33 christos * unspecified for interactive shells. On interactive
560 1.33 christos * shells, or if job control is on, and we have a job
561 1.33 christos * control related signal, we allow the trap to work.
562 1.33 christos *
563 1.33 christos * This change allows us to be POSIX compliant, and
564 1.33 christos * at the same time override the default behavior if
565 1.33 christos * we need to by setting the interactive flag.
566 1.32 christos */
567 1.33 christos if ((mflag && (signo == SIGTSTP ||
568 1.33 christos signo == SIGTTIN || signo == SIGTTOU)) || iflag) {
569 1.33 christos tsig = S_IGN;
570 1.33 christos } else
571 1.33 christos tsig = S_HARD_IGN;
572 1.1 cgd } else {
573 1.27 christos tsig = S_RESET; /* force to be set */
574 1.1 cgd }
575 1.1 cgd }
576 1.47 kre VTRACE(DBG_TRAP, (" tsig=%d\n", tsig));
577 1.47 kre
578 1.27 christos if (tsig == S_HARD_IGN || tsig == action)
579 1.47 kre return;
580 1.47 kre
581 1.1 cgd switch (action) {
582 1.1 cgd case S_DFL: sigact = SIG_DFL; break;
583 1.1 cgd case S_CATCH: sigact = onsig; break;
584 1.1 cgd case S_IGN: sigact = SIG_IGN; break;
585 1.1 cgd }
586 1.47 kre
587 1.32 christos sig = signal(signo, sigact);
588 1.47 kre
589 1.32 christos if (sig != SIG_ERR) {
590 1.32 christos sigset_t ss;
591 1.47 kre
592 1.32 christos if (!vforked)
593 1.32 christos *t = action;
594 1.47 kre
595 1.32 christos if (action == S_CATCH)
596 1.32 christos (void)siginterrupt(signo, 1);
597 1.32 christos /*
598 1.32 christos * If our parent accidentally blocked signals for
599 1.32 christos * us make sure we unblock them
600 1.32 christos */
601 1.32 christos (void)sigemptyset(&ss);
602 1.32 christos (void)sigaddset(&ss, signo);
603 1.32 christos (void)sigprocmask(SIG_UNBLOCK, &ss, NULL);
604 1.32 christos }
605 1.47 kre return;
606 1.1 cgd }
607 1.1 cgd
608 1.6 jtc /*
609 1.6 jtc * Return the current setting for sig w/o changing it.
610 1.6 jtc */
611 1.15 christos static int
612 1.28 christos getsigaction(int signo, sig_t *sigact)
613 1.10 cgd {
614 1.6 jtc struct sigaction sa;
615 1.6 jtc
616 1.6 jtc if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
617 1.15 christos return 0;
618 1.15 christos *sigact = (sig_t) sa.sa_handler;
619 1.15 christos return 1;
620 1.6 jtc }
621 1.1 cgd
622 1.1 cgd /*
623 1.1 cgd * Ignore a signal.
624 1.1 cgd */
625 1.1 cgd
626 1.1 cgd void
627 1.28 christos ignoresig(int signo, int vforked)
628 1.10 cgd {
629 1.47 kre if (sigmode[signo] == 0)
630 1.47 kre setsignal(signo, vforked);
631 1.47 kre
632 1.47 kre VTRACE(DBG_TRAP, ("ignoresig(%d%s)\n", signo, vforked ? ", VF" : ""));
633 1.47 kre if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
634 1.1 cgd signal(signo, SIG_IGN);
635 1.47 kre if (!vforked)
636 1.47 kre sigmode[signo] = S_IGN;
637 1.1 cgd }
638 1.47 kre }
639 1.47 kre
640 1.47 kre char *
641 1.47 kre child_trap(void)
642 1.47 kre {
643 1.47 kre char * p;
644 1.47 kre
645 1.47 kre p = trap[SIGCHLD];
646 1.47 kre
647 1.51 kre if (traps_invalid || (p != NULL && *p == '\0'))
648 1.47 kre p = NULL;
649 1.47 kre
650 1.47 kre return p;
651 1.1 cgd }
652 1.1 cgd
653 1.1 cgd
654 1.1 cgd #ifdef mkinit
655 1.8 jtc INCLUDE <signal.h>
656 1.1 cgd INCLUDE "trap.h"
657 1.47 kre INCLUDE "shell.h"
658 1.47 kre INCLUDE "show.h"
659 1.1 cgd
660 1.1 cgd SHELLPROC {
661 1.1 cgd char *sm;
662 1.1 cgd
663 1.47 kre INTOFF;
664 1.47 kre clear_traps(2);
665 1.8 jtc for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
666 1.47 kre if (*sm == S_IGN) {
667 1.1 cgd *sm = S_HARD_IGN;
668 1.49 kre VTRACE(DBG_TRAP, ("SHELLPROC: %d -> hard_ign\n",
669 1.49 kre (sm - sigmode)));
670 1.47 kre }
671 1.1 cgd }
672 1.47 kre INTON;
673 1.1 cgd }
674 1.1 cgd #endif
675 1.1 cgd
676 1.1 cgd
677 1.1 cgd
678 1.1 cgd /*
679 1.1 cgd * Signal handler.
680 1.1 cgd */
681 1.1 cgd
682 1.1 cgd void
683 1.28 christos onsig(int signo)
684 1.10 cgd {
685 1.52 kre int sav_err = errno;
686 1.52 kre
687 1.52 kre CTRACE(DBG_SIG, ("onsig(%d), had: pendingsigs %d%s, gotsig[%d]=%d\n",
688 1.52 kre signo, pendingsigs, intpending ? " (SIGINT-pending)" : "",
689 1.52 kre signo, gotsig[signo]));
690 1.41 kre
691 1.47 kre /* This should not be needed.
692 1.1 cgd signal(signo, onsig);
693 1.47 kre */
694 1.47 kre
695 1.51 kre if (signo == SIGINT && (traps_invalid || trap[SIGINT] == NULL)) {
696 1.52 kre VTRACE(DBG_SIG, ("onsig(SIGINT), doing it now\n"));
697 1.52 kre if (suppressint && !in_dotrap)
698 1.52 kre intpending = 1;
699 1.52 kre else
700 1.52 kre onint();
701 1.52 kre errno = sav_err;
702 1.1 cgd return;
703 1.1 cgd }
704 1.47 kre
705 1.47 kre /*
706 1.47 kre * if the signal will do nothing, no point reporting it
707 1.47 kre */
708 1.51 kre if (!traps_invalid && trap[signo] != NULL && trap[signo][0] != '\0' &&
709 1.47 kre signo != SIGCHLD) {
710 1.47 kre gotsig[signo] = 1;
711 1.47 kre pendingsigs++;
712 1.52 kre if (iflag && signo == SIGINT) {
713 1.52 kre if (!suppressint) {
714 1.52 kre VTRACE(DBG_SIG,
715 1.52 kre ("onsig: -i gotsig[INT]->%d pendingsigs->%d BANG\n",
716 1.52 kre gotsig[SIGINT], pendingsigs));
717 1.52 kre onint();
718 1.52 kre errno = sav_err;
719 1.52 kre return;
720 1.52 kre }
721 1.52 kre intpending = 1;
722 1.52 kre }
723 1.52 kre VTRACE(DBG_SIG, ("onsig: gotsig[%d]->%d pendingsigs->%d%s\n",
724 1.52 kre signo, gotsig[signo], pendingsigs,
725 1.52 kre intpending ? " (SIGINT pending)":""));
726 1.47 kre }
727 1.52 kre errno = sav_err;
728 1.1 cgd }
729 1.1 cgd
730 1.1 cgd
731 1.1 cgd
732 1.1 cgd /*
733 1.1 cgd * Called to execute a trap. Perhaps we should avoid entering new trap
734 1.1 cgd * handlers while we are executing a trap handler.
735 1.1 cgd */
736 1.1 cgd
737 1.1 cgd void
738 1.28 christos dotrap(void)
739 1.28 christos {
740 1.1 cgd int i;
741 1.47 kre char *tr;
742 1.1 cgd int savestatus;
743 1.47 kre struct skipsave saveskip;
744 1.47 kre
745 1.52 kre CTRACE(DBG_TRAP|DBG_SIG, ("dotrap[%d]: %d pending, traps %sinvalid\n",
746 1.52 kre in_dotrap, pendingsigs, traps_invalid ? "" : "not "));
747 1.52 kre
748 1.47 kre in_dotrap++;
749 1.1 cgd for (;;) {
750 1.47 kre pendingsigs = 0;
751 1.1 cgd for (i = 1 ; ; i++) {
752 1.52 kre if (i >= NSIG) {
753 1.52 kre in_dotrap--;
754 1.52 kre VTRACE(DBG_TRAP|DBG_SIG, ("dotrap[%d] done\n",
755 1.52 kre in_dotrap));
756 1.40 kre return;
757 1.52 kre }
758 1.40 kre if (gotsig[i])
759 1.6 jtc break;
760 1.1 cgd }
761 1.40 kre gotsig[i] = 0;
762 1.47 kre
763 1.47 kre if (traps_invalid)
764 1.47 kre continue;
765 1.47 kre
766 1.47 kre tr = trap[i];
767 1.47 kre
768 1.47 kre CTRACE(DBG_TRAP|DBG_SIG, ("dotrap %d: %s%s%s\n", i,
769 1.47 kre tr ? "\"" : "", tr ? tr : "NULL", tr ? "\"" : ""));
770 1.47 kre
771 1.47 kre if (tr != NULL) {
772 1.47 kre last_trapsig = i;
773 1.47 kre save_skipstate(&saveskip);
774 1.47 kre savestatus = exitstatus;
775 1.47 kre
776 1.44 kre tr = savestr(tr); /* trap code may free trap[i] */
777 1.44 kre evalstring(tr, 0);
778 1.44 kre ckfree(tr);
779 1.47 kre
780 1.47 kre if (current_skipstate() == SKIPNONE ||
781 1.47 kre saveskip.state != SKIPNONE) {
782 1.47 kre restore_skipstate(&saveskip);
783 1.47 kre exitstatus = savestatus;
784 1.47 kre }
785 1.44 kre }
786 1.1 cgd }
787 1.1 cgd }
788 1.1 cgd
789 1.37 christos int
790 1.37 christos lastsig(void)
791 1.37 christos {
792 1.37 christos int i;
793 1.1 cgd
794 1.40 kre for (i = NSIG; --i > 0; )
795 1.40 kre if (gotsig[i])
796 1.37 christos return i;
797 1.37 christos return SIGINT; /* XXX */
798 1.37 christos }
799 1.1 cgd
800 1.1 cgd /*
801 1.1 cgd * Controls whether the shell is interactive or not.
802 1.1 cgd */
803 1.1 cgd
804 1.1 cgd
805 1.1 cgd void
806 1.28 christos setinteractive(int on)
807 1.10 cgd {
808 1.6 jtc static int is_interactive;
809 1.6 jtc
810 1.1 cgd if (on == is_interactive)
811 1.1 cgd return;
812 1.27 christos setsignal(SIGINT, 0);
813 1.27 christos setsignal(SIGQUIT, 0);
814 1.27 christos setsignal(SIGTERM, 0);
815 1.1 cgd is_interactive = on;
816 1.1 cgd }
817 1.1 cgd
818 1.1 cgd
819 1.1 cgd
820 1.1 cgd /*
821 1.1 cgd * Called to exit the shell.
822 1.1 cgd */
823 1.47 kre void
824 1.47 kre exitshell(int status)
825 1.47 kre {
826 1.47 kre CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP,
827 1.47 kre ("pid %d: exitshell(%d)\n", getpid(), status));
828 1.47 kre
829 1.47 kre exiting = 1;
830 1.47 kre exiting_status = status;
831 1.47 kre exitshell_savedstatus();
832 1.47 kre }
833 1.1 cgd
834 1.1 cgd void
835 1.47 kre exitshell_savedstatus(void)
836 1.10 cgd {
837 1.47 kre struct jmploc loc;
838 1.1 cgd char *p;
839 1.47 kre volatile int sig = 0;
840 1.47 kre int s;
841 1.47 kre sigset_t sigs;
842 1.1 cgd
843 1.41 kre CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP,
844 1.47 kre ("pid %d: exitshell_savedstatus()%s $?=%d xs=%d dt=%d ts=%d\n",
845 1.47 kre getpid(), exiting ? " exiting" : "", exitstatus,
846 1.47 kre exiting_status, in_dotrap, last_trapsig));
847 1.47 kre
848 1.47 kre if (!exiting) {
849 1.47 kre if (in_dotrap && last_trapsig) {
850 1.47 kre sig = last_trapsig;
851 1.47 kre exiting_status = sig + 128;
852 1.47 kre } else
853 1.47 kre exiting_status = exitstatus;
854 1.47 kre }
855 1.47 kre exitstatus = exiting_status;
856 1.47 kre
857 1.47 kre if (!setjmp(loc.loc)) {
858 1.47 kre handler = &loc;
859 1.47 kre
860 1.47 kre if (!traps_invalid && (p = trap[0]) != NULL && *p != '\0') {
861 1.47 kre reset_eval();
862 1.47 kre trap[0] = NULL;
863 1.47 kre VTRACE(DBG_TRAP, ("exit trap: \"%s\"\n", p));
864 1.47 kre evalstring(p, 0);
865 1.47 kre }
866 1.47 kre }
867 1.41 kre
868 1.47 kre INTOFF; /* we're done, no more interrupts. */
869 1.47 kre
870 1.47 kre if (!setjmp(loc.loc)) {
871 1.47 kre handler = &loc; /* probably unnecessary */
872 1.47 kre flushall();
873 1.47 kre #if JOBS
874 1.47 kre setjobctl(0);
875 1.47 kre #endif
876 1.6 jtc }
877 1.47 kre
878 1.47 kre if ((s = sig) != 0 && s != SIGSTOP && s != SIGTSTP && s != SIGTTIN &&
879 1.47 kre s != SIGTTOU) {
880 1.47 kre struct rlimit nocore;
881 1.47 kre
882 1.47 kre /*
883 1.47 kre * if the signal is of the core dump variety, don't...
884 1.47 kre */
885 1.47 kre nocore.rlim_cur = nocore.rlim_max = 0;
886 1.47 kre (void) setrlimit(RLIMIT_CORE, &nocore);
887 1.47 kre
888 1.47 kre signal(s, SIG_DFL);
889 1.47 kre sigemptyset(&sigs);
890 1.47 kre sigaddset(&sigs, s);
891 1.47 kre sigprocmask(SIG_UNBLOCK, &sigs, NULL);
892 1.47 kre
893 1.47 kre kill(getpid(), s);
894 1.1 cgd }
895 1.47 kre _exit(exiting_status);
896 1.18 mycroft /* NOTREACHED */
897 1.1 cgd }
898