1 /* $NetBSD: trap.c,v 1.58 2024/10/09 13:43:33 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.58 2024/10/09 13:43:33 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. 440 */ 441 void 442 clear_traps(int vforked) 443 { 444 char * volatile *tp; 445 446 VTRACE(DBG_TRAP, ("clear_traps(%d)\n", vforked)); 447 if (!vforked) 448 traps_invalid = 1; 449 450 for (tp = &trap[1] ; tp < &trap[NSIG] ; tp++) { 451 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 452 INTOFF; 453 setsignal(tp - trap, vforked == 1); 454 INTON; 455 } 456 } 457 if (vforked == 2) 458 free_traps(); 459 } 460 461 void 462 free_traps(void) 463 { 464 char * volatile *tp; 465 466 VTRACE(DBG_TRAP, ("free_traps%s\n", traps_invalid ? "(invalid)" : "")); 467 INTOFF; 468 for (tp = trap ; tp < &trap[NSIG] ; tp++) 469 if (*tp && **tp) { 470 ckfree(*tp); 471 *tp = NULL; 472 } 473 traps_invalid = 0; 474 INTON; 475 } 476 477 /* 478 * See if there are any defined traps 479 */ 480 int 481 have_traps(void) 482 { 483 char * volatile *tp; 484 485 if (traps_invalid) 486 return 0; 487 488 for (tp = trap ; tp < &trap[NSIG] ; tp++) 489 if (*tp && **tp) /* trap not NULL or SIG_IGN */ 490 return 1; 491 return 0; 492 } 493 494 /* 495 * Set the signal handler for the specified signal. The routine figures 496 * out what it should be set to. 497 */ 498 void 499 setsignal(int signo, int vforked) 500 { 501 int action; 502 sig_t sigact = SIG_DFL, sig; 503 char *t, tsig; 504 505 if (traps_invalid || (t = trap[signo]) == NULL) 506 action = S_DFL; 507 else if (*t != '\0') 508 action = S_CATCH; 509 else 510 action = S_IGN; 511 512 VTRACE(DBG_TRAP, ("setsignal(%d%s) -> %d", signo, 513 vforked ? ", VF" : "", action)); 514 if (rootshell && !vforked && action == S_DFL) { 515 switch (signo) { 516 case SIGINT: 517 if (iflag || minusc || sflag == 0) 518 action = S_CATCH; 519 break; 520 case SIGQUIT: 521 #ifdef DEBUG 522 if (debug) 523 break; 524 #endif 525 /* FALLTHROUGH */ 526 case SIGTERM: 527 if (rootshell && iflag) 528 action = S_IGN; 529 break; 530 #if JOBS 531 case SIGTSTP: 532 case SIGTTOU: 533 if (rootshell && mflag) 534 action = S_IGN; 535 break; 536 #endif 537 } 538 } 539 540 /* 541 * Never let users futz with SIGCHLD 542 * instead we will give them pseudo SIGCHLD's 543 * when background jobs complete. 544 */ 545 if (signo == SIGCHLD) 546 action = S_DFL; 547 548 VTRACE(DBG_TRAP, (" -> %d", action)); 549 550 t = &sigmode[signo]; 551 tsig = *t; 552 if (tsig == 0) { 553 /* 554 * current setting unknown 555 */ 556 if (!getsigaction(signo, &sigact)) { 557 /* 558 * Pretend it worked; maybe we should give a warning 559 * here, but other shells don't. We don't alter 560 * sigmode, so that we retry every time. 561 */ 562 VTRACE(DBG_TRAP, (" getsigaction (%d)\n", errno)); 563 return; 564 } 565 VTRACE(DBG_TRAP, (" [%s]%s%s", sigact==SIG_IGN ? "IGN" : 566 sigact==SIG_DFL ? "DFL" : "caught", 567 iflag ? "i" : "", mflag ? "m" : "")); 568 569 if (sigact == SIG_IGN) { 570 /* 571 * POSIX 3.14.13 states that non-interactive shells 572 * should ignore trap commands for signals that were 573 * ignored upon entry, and leaves the behavior 574 * unspecified for interactive shells. On interactive 575 * shells, or if job control is on, and we have a job 576 * control related signal, we allow the trap to work. 577 * 578 * This change allows us to be POSIX compliant, and 579 * at the same time override the default behavior if 580 * we need to by setting the interactive flag. 581 */ 582 if ((mflag && (signo == SIGTSTP || 583 signo == SIGTTIN || signo == SIGTTOU)) || iflag) { 584 tsig = S_IGN; 585 } else 586 tsig = S_HARD_IGN; 587 } else { 588 tsig = S_RESET; /* force to be set */ 589 } 590 } 591 VTRACE(DBG_TRAP, (" tsig=%d\n", tsig)); 592 593 if (tsig == S_HARD_IGN || tsig == action) 594 return; 595 596 switch (action) { 597 case S_DFL: sigact = SIG_DFL; break; 598 case S_CATCH: sigact = onsig; break; 599 case S_IGN: sigact = SIG_IGN; break; 600 } 601 602 sig = signal(signo, sigact); 603 604 if (sig != SIG_ERR) { 605 sigset_t ss; 606 607 if (!vforked) 608 *t = action; 609 610 if (action == S_CATCH) 611 (void)siginterrupt(signo, 1); 612 /* 613 * If our parent accidentally blocked signals for 614 * us make sure we unblock them 615 */ 616 (void)sigemptyset(&ss); 617 (void)sigaddset(&ss, signo); 618 (void)sigprocmask(SIG_UNBLOCK, &ss, NULL); 619 } 620 return; 621 } 622 623 /* 624 * Return the current setting for sig w/o changing it. 625 */ 626 static int 627 getsigaction(int signo, sig_t *sigact) 628 { 629 struct sigaction sa; 630 631 if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 632 return 0; 633 *sigact = (sig_t) sa.sa_handler; 634 return 1; 635 } 636 637 /* 638 * Ignore a signal. 639 */ 640 641 void 642 ignoresig(int signo, int vforked) 643 { 644 if (sigmode[signo] == 0) 645 setsignal(signo, vforked); 646 647 VTRACE(DBG_TRAP, ("ignoresig(%d%s)\n", signo, vforked ? ", VF" : "")); 648 if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 649 signal(signo, SIG_IGN); 650 if (!vforked) 651 sigmode[signo] = S_IGN; 652 } 653 } 654 655 char * 656 child_trap(void) 657 { 658 char * p; 659 660 p = trap[SIGCHLD]; 661 662 if (traps_invalid || (p != NULL && *p == '\0')) 663 p = NULL; 664 665 return p; 666 } 667 668 669 #ifdef mkinit 670 INCLUDE <signal.h> 671 INCLUDE "trap.h" 672 INCLUDE "shell.h" 673 INCLUDE "show.h" 674 675 SHELLPROC { 676 char *sm; 677 678 INTOFF; 679 clear_traps(2); 680 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 681 if (*sm == S_IGN) { 682 *sm = S_HARD_IGN; 683 VTRACE(DBG_TRAP, ("SHELLPROC: %d -> hard_ign\n", 684 (sm - sigmode))); 685 } 686 } 687 INTON; 688 } 689 #endif 690 691 692 693 /* 694 * Signal handler. 695 */ 696 697 void 698 onsig(int signo) 699 { 700 int sav_err = errno; 701 702 CTRACE(DBG_SIG, ("onsig(%d), had: pendingsigs %d%s, gotsig[%d]=%d\n", 703 signo, pendingsigs, intpending ? " (SIGINT-pending)" : "", 704 signo, gotsig[signo])); 705 706 /* This should not be needed. 707 signal(signo, onsig); 708 */ 709 710 if (signo == SIGINT && (traps_invalid || trap[SIGINT] == NULL)) { 711 VTRACE(DBG_SIG, ("onsig(SIGINT), doing it now\n")); 712 if (suppressint && !in_dotrap) 713 intpending = 1; 714 else 715 onint(); 716 errno = sav_err; 717 return; 718 } 719 720 /* 721 * if the signal will do nothing, no point reporting it 722 */ 723 if (!traps_invalid && trap[signo] != NULL && trap[signo][0] != '\0' && 724 signo != SIGCHLD) { 725 gotsig[signo] = 1; 726 pendingsigs++; 727 if (iflag && signo == SIGINT) { 728 if (!suppressint) { 729 VTRACE(DBG_SIG, 730 ("onsig: -i gotsig[INT]->%d pendingsigs->%d BANG\n", 731 gotsig[SIGINT], pendingsigs)); 732 onint(); 733 errno = sav_err; 734 return; 735 } 736 intpending = 1; 737 } 738 VTRACE(DBG_SIG, ("onsig: gotsig[%d]->%d pendingsigs->%d%s\n", 739 signo, gotsig[signo], pendingsigs, 740 intpending ? " (SIGINT pending)":"")); 741 } 742 errno = sav_err; 743 } 744 745 746 747 /* 748 * Called to execute a trap. Perhaps we should avoid entering new trap 749 * handlers while we are executing a trap handler. 750 */ 751 752 void 753 dotrap(void) 754 { 755 int i; 756 char *tr; 757 int savestatus; 758 struct skipsave saveskip; 759 760 CTRACE(DBG_TRAP|DBG_SIG, ("dotrap[%d]: %d pending, traps %sinvalid\n", 761 in_dotrap, pendingsigs, traps_invalid ? "" : "not ")); 762 763 in_dotrap++; 764 for (;;) { 765 pendingsigs = 0; 766 for (i = 1 ; ; i++) { 767 if (i >= NSIG) { 768 in_dotrap--; 769 VTRACE(DBG_TRAP|DBG_SIG, ("dotrap[%d] done\n", 770 in_dotrap)); 771 return; 772 } 773 if (gotsig[i]) 774 break; 775 } 776 gotsig[i] = 0; 777 778 if (traps_invalid) 779 continue; 780 781 tr = trap[i]; 782 783 CTRACE(DBG_TRAP|DBG_SIG, ("dotrap %d: %s%s%s\n", i, 784 tr ? "\"" : "", tr ? tr : "NULL", tr ? "\"" : "")); 785 786 if (tr != NULL) { 787 last_trapsig = i; 788 save_skipstate(&saveskip); 789 savestatus = exitstatus; 790 791 tr = savestr(tr); /* trap code may free trap[i] */ 792 evalstring(tr, 0); 793 ckfree(tr); 794 795 if (current_skipstate() == SKIPNONE || 796 saveskip.state != SKIPNONE) { 797 restore_skipstate(&saveskip); 798 exitstatus = savestatus; 799 } 800 } 801 } 802 } 803 804 int 805 lastsig(void) 806 { 807 int i; 808 809 for (i = NSIG; --i > 0; ) 810 if (gotsig[i]) 811 return i; 812 return SIGINT; /* XXX */ 813 } 814 815 /* 816 * Controls whether the shell is interactive or not. 817 */ 818 819 820 void 821 setinteractive(int on) 822 { 823 static int is_interactive; 824 825 if (on == is_interactive) 826 return; 827 setsignal(SIGINT, 0); 828 setsignal(SIGQUIT, 0); 829 setsignal(SIGTERM, 0); 830 is_interactive = on; 831 } 832 833 834 835 /* 836 * Called to exit the shell. 837 */ 838 void 839 exitshell(int status) 840 { 841 CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 842 ("pid %d: exitshell(%d)\n", getpid(), status)); 843 844 exiting = 1; 845 exiting_status = status; 846 exitshell_savedstatus(); 847 } 848 849 void 850 exitshell_savedstatus(void) 851 { 852 struct jmploc loc; 853 char *p; 854 volatile int sig = 0; 855 int s; 856 sigset_t sigs; 857 858 CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 859 ("pid %d: exitshell_savedstatus()%s $?=%d xs=%d dt=%d ts=%d\n", 860 getpid(), exiting ? " exiting" : "", exitstatus, 861 exiting_status, in_dotrap, last_trapsig)); 862 863 if (!exiting) { 864 if (in_dotrap && last_trapsig) { 865 sig = last_trapsig; 866 exiting_status = sig + 128; 867 } else 868 exiting_status = exitstatus; 869 } 870 exitstatus = exiting_status; 871 872 if (pendingsigs && !setjmp(loc.loc)) { 873 handler = &loc; 874 875 dotrap(); 876 } 877 878 if (!setjmp(loc.loc)) { 879 handler = &loc; 880 881 if (!traps_invalid && (p = trap[0]) != NULL && *p != '\0') { 882 reset_eval(); 883 trap[0] = NULL; 884 VTRACE(DBG_TRAP, ("exit trap: \"%s\"\n", p)); 885 evalstring(p, 0); 886 } 887 } 888 889 INTOFF; /* we're done, no more interrupts. */ 890 891 #ifndef SMALL 892 if (rootshell) 893 save_sh_history(); 894 #endif 895 896 if (!setjmp(loc.loc)) { 897 handler = &loc; /* probably unnecessary */ 898 flushall(); 899 #if JOBS 900 setjobctl(0); 901 #endif 902 } 903 904 if ((s = sig) != 0 && s != SIGSTOP && s != SIGTSTP && s != SIGTTIN && 905 s != SIGTTOU) { 906 struct rlimit nocore; 907 908 /* 909 * if the signal is of the core dump variety, don't... 910 */ 911 nocore.rlim_cur = nocore.rlim_max = 0; 912 (void) setrlimit(RLIMIT_CORE, &nocore); 913 914 signal(s, SIG_DFL); 915 sigemptyset(&sigs); 916 sigaddset(&sigs, s); 917 sigprocmask(SIG_UNBLOCK, &sigs, NULL); 918 919 VTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 920 ("exitshell_savedstatus(): pid %d Death by signal %d\n", 921 getpid(), s)); 922 kill(getpid(), s); 923 } 924 VTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 925 ("exitshell_savedstatus(): pid %d exiting(%d)\n", 926 getpid(), exiting_status)); 927 _exit(exiting_status); 928 /* NOTREACHED */ 929 } 930