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