trap.c revision 36150
192512Sphk/*-
292512Sphk * Copyright (c) 1991, 1993
392512Sphk *	The Regents of the University of California.  All rights reserved.
492512Sphk *
592512Sphk * This code is derived from software contributed to Berkeley by
692512Sphk * Kenneth Almquist.
792512Sphk *
892512Sphk * Redistribution and use in source and binary forms, with or without
992512Sphk * modification, are permitted provided that the following conditions
1092512Sphk * are met:
1192512Sphk * 1. Redistributions of source code must retain the above copyright
1292512Sphk *    notice, this list of conditions and the following disclaimer.
1392512Sphk * 2. Redistributions in binary form must reproduce the above copyright
1492512Sphk *    notice, this list of conditions and the following disclaimer in the
1592512Sphk *    documentation and/or other materials provided with the distribution.
1692512Sphk * 3. All advertising materials mentioning features or use of this software
1792512Sphk *    must display the following acknowledgement:
1892512Sphk *	This product includes software developed by the University of
1992512Sphk *	California, Berkeley and its contributors.
2092512Sphk * 4. Neither the name of the University nor the names of its contributors
2192512Sphk *    may be used to endorse or promote products derived from this software
2292512Sphk *    without specific prior written permission.
2392512Sphk *
2492512Sphk * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2592512Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2692512Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2792512Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2892512Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2992512Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3092512Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3192512Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3292512Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3392512Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3492512Sphk * SUCH DAMAGE.
3592512Sphk */
3692512Sphk
3792512Sphk#ifndef lint
3892512Sphk#if 0
3992512Sphkstatic char sccsid[] = "@(#)trap.c	8.5 (Berkeley) 6/5/95";
4092512Sphk#endif
4192512Sphkstatic const char rcsid[] =
4292512Sphk	"$Id$";
4392512Sphk#endif /* not lint */
4492512Sphk
4592512Sphk#include <signal.h>
4692512Sphk#include <unistd.h>
4792512Sphk#include <stdlib.h>
4892512Sphk
4992512Sphk#include "shell.h"
5092512Sphk#include "main.h"
5192512Sphk#include "nodes.h"	/* for other headers */
5292512Sphk#include "eval.h"
5392512Sphk#include "jobs.h"
5492512Sphk#include "show.h"
5592512Sphk#include "options.h"
5692512Sphk#include "syntax.h"
5792512Sphk#include "output.h"
5892512Sphk#include "memalloc.h"
5992512Sphk#include "error.h"
6092512Sphk#include "trap.h"
6192512Sphk#include "mystring.h"
6292512Sphk
6392512Sphk
6492512Sphk/*
6592512Sphk * Sigmode records the current value of the signal handlers for the various
6692512Sphk * modes.  A value of zero means that the current handler is not known.
6792512Sphk * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
6892512Sphk */
6992512Sphk
7092512Sphk#define S_DFL 1			/* default signal handling (SIG_DFL) */
7192512Sphk#define S_CATCH 2		/* signal is caught */
7292512Sphk#define S_IGN 3			/* signal is ignored (SIG_IGN) */
7392512Sphk#define S_HARD_IGN 4		/* signal is ignored permenantly */
7492512Sphk#define S_RESET 5		/* temporary - to reset a hard ignored sig */
7592512Sphk
7692512Sphk
7792512SphkMKINIT char sigmode[NSIG];	/* current value of signal */
7892512Sphkint pendingsigs;			/* indicates some signal received */
7992512Sphkstatic char *trap[NSIG];	/* trap handler commands */
8092512Sphkstatic char gotsig[NSIG];	/* indicates specified signal received */
8192512Sphkstatic int ignore_sigchld;	/* Used while handling SIGCHLD traps. */
8292512Sphk
8392512Sphkstatic int getsigaction __P((int, sig_t *));
8492512Sphk
8592512Sphk
8692512Sphk/*
8792512Sphk * Map a string to a signal number.
8892512Sphk */
8992512Sphkstatic int
9092512Sphksigstring_to_signum(sig)
9192512Sphk	char *sig;
9292512Sphk{
9392512Sphk
9492512Sphk	if (is_number(sig)) {
9592512Sphk		int signo;
9692512Sphk
9792512Sphk		signo = atoi(sig);
9892512Sphk		return ((signo >= 0 && signo < NSIG) ? signo : (-1));
9992512Sphk	} else if (strcasecmp(sig, "exit") == 0) {
10092512Sphk		return (0);
10192512Sphk	} else {
10292512Sphk		int n;
10392512Sphk
10492512Sphk		if (strncasecmp(sig, "sig", 3) == 0)
10592512Sphk			sig += 3;
10692512Sphk		for (n = 1; n < NSIG; n++)
10792512Sphk			if (strcasecmp(sys_signame[n], sig) == 0)
10892512Sphk				return (n);
10992512Sphk	}
11092512Sphk	return (-1);
11192512Sphk}
11292512Sphk
11392512Sphk
11492512Sphk/*
11592512Sphk * Print a list of valid signal names.
11692512Sphk */
11792512Sphkstatic void
11892512Sphkprintsignals()
11992512Sphk{
12092512Sphk	int n;
12192512Sphk
12292512Sphk	for (n = 1; n < NSIG; n++) {
12392512Sphk		out1fmt("%s", sys_signame[n]);
12492512Sphk		if (n == (NSIG / 2) || n == (NSIG - 1))
12592512Sphk			out1str("\n");
12692512Sphk		else
12792512Sphk			out1c(' ');
12892512Sphk	}
12992512Sphk}
13092512Sphk
13192512Sphk
13292512Sphk/*
13392512Sphk * The trap builtin.
13492512Sphk */
13592512Sphkint
13692512Sphktrapcmd(argc, argv)
13792512Sphk	int argc;
13892512Sphk	char **argv;
13992512Sphk{
14092512Sphk	char *action;
14192512Sphk	int signo;
14292512Sphk
14392512Sphk	if (argc <= 1) {
14492512Sphk		for (signo = 0 ; signo < NSIG ; signo++) {
14592512Sphk			if (trap[signo] != NULL)
14692512Sphk				out1fmt("trap -- '%s' %s\n", trap[signo],
14792512Sphk					(signo) ? sys_signame[signo] : "exit");
14892512Sphk		}
14992512Sphk		return 0;
15092512Sphk	}
15192512Sphk	action = NULL;
15292512Sphk	if (*++argv && strcmp(*argv, "--") == 0)
15392512Sphk		argv++;
15492512Sphk	if (*argv && sigstring_to_signum(*argv) == -1) {
15592512Sphk		if ((*argv)[0] != '-') {
15692512Sphk			action = *argv;
15792512Sphk			argv++;
15892512Sphk		} else if ((*argv)[1] == '\0') {
15992512Sphk			argv++;
16092512Sphk		} else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
16192512Sphk			printsignals();
16292512Sphk			return 0;
16392512Sphk		} else {
16492512Sphk			error("bad option %s", *argv);
16592512Sphk		}
16692512Sphk	}
16792512Sphk	while (*argv) {
16892512Sphk		if ((signo = sigstring_to_signum(*argv)) == -1)
16992512Sphk			error("bad signal %s", *argv);
17092512Sphk		INTOFF;
17192512Sphk		if (action)
17292512Sphk			action = savestr(action);
17392512Sphk		if (trap[signo])
17492512Sphk			ckfree(trap[signo]);
17592512Sphk		trap[signo] = action;
17692512Sphk		if (signo != 0)
17792512Sphk			setsignal(signo);
17892512Sphk		INTON;
17992512Sphk		argv++;
18092512Sphk	}
18192512Sphk	return 0;
18292512Sphk}
18392512Sphk
18492512Sphk
18592512Sphk/*
18692512Sphk * Clear traps on a fork.
18792512Sphk */
18892512Sphkvoid
18992512Sphkclear_traps()
19092512Sphk{
19192512Sphk	char **tp;
19292512Sphk
19392512Sphk	for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
19492512Sphk		if (*tp && **tp) {	/* trap not NULL or SIG_IGN */
19592512Sphk			INTOFF;
19692512Sphk			ckfree(*tp);
19792512Sphk			*tp = NULL;
19892512Sphk			if (tp != &trap[0])
19992512Sphk				setsignal(tp - trap);
20092512Sphk			INTON;
20192512Sphk		}
20292512Sphk	}
20392512Sphk}
20492512Sphk
20592512Sphk
20692512Sphk/*
20792512Sphk * Set the signal handler for the specified signal.  The routine figures
20892512Sphk * out what it should be set to.
20992512Sphk */
21092512Sphkvoid
21192512Sphksetsignal(signo)
21292512Sphk	int signo;
21392512Sphk{
21492512Sphk	int action;
21592512Sphk	sig_t sig, sigact = SIG_DFL;
21692512Sphk	char *t;
21792512Sphk
21892512Sphk	if ((t = trap[signo]) == NULL)
21992512Sphk		action = S_DFL;
22092512Sphk	else if (*t != '\0')
22192512Sphk		action = S_CATCH;
22292512Sphk	else
22392512Sphk		action = S_IGN;
22492512Sphk	if (rootshell && action == S_DFL) {
22592512Sphk		switch (signo) {
22692512Sphk		case SIGINT:
22792512Sphk			if (iflag)
22892512Sphk				action = S_CATCH;
22992512Sphk			break;
23092512Sphk		case SIGQUIT:
23192512Sphk#ifdef DEBUG
23292512Sphk			{
23392512Sphk			extern int debug;
23492512Sphk
23592512Sphk			if (debug)
23692512Sphk				break;
23792512Sphk			}
23892512Sphk#endif
23992512Sphk			/* FALLTHROUGH */
24092512Sphk		case SIGTERM:
24192512Sphk			if (iflag)
24292512Sphk				action = S_IGN;
24392512Sphk			break;
24492512Sphk#if JOBS
24592512Sphk		case SIGTSTP:
24692512Sphk		case SIGTTOU:
24792512Sphk			if (mflag)
24892512Sphk				action = S_IGN;
24992512Sphk			break;
25092512Sphk#endif
25192512Sphk		}
25292512Sphk	}
25392512Sphk
25492512Sphk	t = &sigmode[signo];
25592512Sphk	if (*t == 0) {
25692512Sphk		/*
25792512Sphk		 * current setting unknown
25892512Sphk		 */
25992512Sphk		if (!getsigaction(signo, &sigact)) {
26092512Sphk			/*
26192512Sphk			 * Pretend it worked; maybe we should give a warning
26292512Sphk			 * here, but other shells don't. We don't alter
26392512Sphk			 * sigmode, so that we retry every time.
26492512Sphk			 */
26592512Sphk			return;
26692512Sphk		}
26792512Sphk		if (sigact == SIG_IGN) {
26892512Sphk			if (mflag && (signo == SIGTSTP ||
26992512Sphk			     signo == SIGTTIN || signo == SIGTTOU)) {
27092512Sphk				*t = S_IGN;	/* don't hard ignore these */
27192512Sphk			} else
27292512Sphk				*t = S_HARD_IGN;
27392512Sphk		} else {
27492512Sphk			*t = S_RESET;	/* force to be set */
27592512Sphk		}
27692512Sphk	}
27792512Sphk	if (*t == S_HARD_IGN || *t == action)
27892512Sphk		return;
27992512Sphk	switch (action) {
28092512Sphk		case S_DFL:	sigact = SIG_DFL;	break;
28192512Sphk		case S_CATCH:  	sigact = onsig;		break;
28292512Sphk		case S_IGN:	sigact = SIG_IGN;	break;
28392512Sphk	}
28492512Sphk	*t = action;
28592512Sphk	sig = signal(signo, sigact);
28692512Sphk#ifdef BSD
28792512Sphk	if (sig != SIG_ERR && action == S_CATCH)
28892512Sphk		siginterrupt(signo, 1);
28992512Sphk#endif
29092512Sphk}
29192512Sphk
29292512Sphk
29392512Sphk/*
29492512Sphk * Return the current setting for sig w/o changing it.
29592512Sphk */
29692512Sphkstatic int
29792512Sphkgetsigaction(signo, sigact)
29892512Sphk	int signo;
29992512Sphk	sig_t *sigact;
30092512Sphk{
30192512Sphk	struct sigaction sa;
30292512Sphk
30392512Sphk	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
30492512Sphk		return 0;
30592512Sphk	*sigact = (sig_t) sa.sa_handler;
30692512Sphk	return 1;
30792512Sphk}
30892512Sphk
30992512Sphk
31092512Sphk/*
31192512Sphk * Ignore a signal.
31292512Sphk */
31392512Sphkvoid
31492512Sphkignoresig(signo)
31592512Sphk	int signo;
31692512Sphk{
31792512Sphk
31892512Sphk	if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
31992512Sphk		signal(signo, SIG_IGN);
32092512Sphk	}
32192512Sphk	sigmode[signo] = S_HARD_IGN;
32292512Sphk}
32392512Sphk
32492512Sphk
32592512Sphk#ifdef mkinit
32692512SphkINCLUDE <signal.h>
32792512SphkINCLUDE "trap.h"
32892512Sphk
32992512SphkSHELLPROC {
33092512Sphk	char *sm;
33192512Sphk
33292512Sphk	clear_traps();
33392512Sphk	for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
33492512Sphk		if (*sm == S_IGN)
33592512Sphk			*sm = S_HARD_IGN;
33692512Sphk	}
33792512Sphk}
33892512Sphk#endif
33992512Sphk
34092512Sphk
34192512Sphk/*
34292512Sphk * Signal handler.
34392512Sphk */
34492512Sphkvoid
34592512Sphkonsig(signo)
34692512Sphk	int signo;
34792512Sphk{
34892512Sphk
34992512Sphk#ifndef BSD
35092512Sphk	signal(signo, onsig);
35192512Sphk#endif
35292512Sphk	if (signo == SIGINT && trap[SIGINT] == NULL) {
35392512Sphk		onint();
35492512Sphk		return;
35592512Sphk	}
35692512Sphk	if (signo != SIGCHLD || !ignore_sigchld)
35792512Sphk		gotsig[signo] = 1;
35892512Sphk	pendingsigs++;
35992512Sphk}
36092512Sphk
36192512Sphk
36292512Sphk/*
36392512Sphk * Called to execute a trap.  Perhaps we should avoid entering new trap
36492512Sphk * handlers while we are executing a trap handler.
36592512Sphk */
36692512Sphkvoid
36792512Sphkdotrap()
36892512Sphk{
36992512Sphk	int i;
37092512Sphk	int savestatus;
37192512Sphk
37292512Sphk	for (;;) {
37392512Sphk		for (i = 1; i < NSIG; i++) {
37492512Sphk			if (gotsig[i]) {
37592512Sphk				gotsig[i] = 0;
37692512Sphk				if (trap[i]) {
37792512Sphk					/*
37892512Sphk					 * Ignore SIGCHLD to avoid infinite recursion
37992512Sphk					 * if the trap action does a fork.
38092512Sphk					 */
38192512Sphk					if (i == SIGCHLD)
38292512Sphk						ignore_sigchld++;
38392512Sphk					savestatus = exitstatus;
38492512Sphk					evalstring(trap[i]);
38592512Sphk					exitstatus = savestatus;
38692512Sphk					if (i == SIGCHLD)
38792512Sphk						ignore_sigchld--;
38892512Sphk				}
38992512Sphk				break;
39092512Sphk			}
39192512Sphk		}
39292512Sphk		if (i >= NSIG)
39392512Sphk			break;
39492512Sphk	}
39592512Sphk	pendingsigs = 0;
39692512Sphk}
39792512Sphk
39892512Sphk
39992512Sphk/*
40092512Sphk * Controls whether the shell is interactive or not.
40192512Sphk */
40292512Sphkvoid
40392512Sphksetinteractive(on)
40492512Sphk	int on;
40592512Sphk{
40692512Sphk	static int is_interactive = 0;
40792512Sphk
40892512Sphk	if (on == is_interactive)
40992512Sphk		return;
41092512Sphk	setsignal(SIGINT);
41192512Sphk	setsignal(SIGQUIT);
41292512Sphk	setsignal(SIGTERM);
41392512Sphk	is_interactive = on;
41492512Sphk}
415
416
417/*
418 * Called to exit the shell.
419 */
420void
421exitshell(status)
422	int status;
423{
424	struct jmploc loc1, loc2;
425	char *p;
426
427	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
428	if (setjmp(loc1.loc)) {
429		goto l1;
430	}
431	if (setjmp(loc2.loc)) {
432		goto l2;
433	}
434	handler = &loc1;
435	if ((p = trap[0]) != NULL && *p != '\0') {
436		trap[0] = NULL;
437		evalstring(p);
438	}
439l1:   handler = &loc2;			/* probably unnecessary */
440	flushall();
441#if JOBS
442	setjobctl(0);
443#endif
444l2:   _exit(status);
445}
446