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