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