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