xref: /csrg-svn/bin/sh/trap.c (revision 69272)
147145Sbostic /*-
260698Sbostic  * Copyright (c) 1991, 1993
360698Sbostic  *	The Regents of the University of California.  All rights reserved.
447145Sbostic  *
547145Sbostic  * This code is derived from software contributed to Berkeley by
647145Sbostic  * Kenneth Almquist.
747145Sbostic  *
847145Sbostic  * %sccs.include.redist.c%
947145Sbostic  */
1047145Sbostic 
1147145Sbostic #ifndef lint
12*69272Schristos static char sccsid[] = "@(#)trap.c	8.3 (Berkeley) 05/04/95";
1347145Sbostic #endif /* not lint */
1447145Sbostic 
15*69272Schristos #include <signal.h>
16*69272Schristos #include <unistd.h>
17*69272Schristos #include <stdlib.h>
18*69272Schristos 
1947145Sbostic #include "shell.h"
2047145Sbostic #include "main.h"
2147145Sbostic #include "nodes.h"	/* for other headers */
2247145Sbostic #include "eval.h"
2347145Sbostic #include "jobs.h"
24*69272Schristos #include "show.h"
2547145Sbostic #include "options.h"
2647145Sbostic #include "syntax.h"
2747145Sbostic #include "output.h"
2847145Sbostic #include "memalloc.h"
2947145Sbostic #include "error.h"
3047145Sbostic #include "trap.h"
3147145Sbostic #include "mystring.h"
3247145Sbostic 
3347145Sbostic 
3447145Sbostic /*
3547145Sbostic  * Sigmode records the current value of the signal handlers for the various
3647145Sbostic  * modes.  A value of zero means that the current handler is not known.
3747145Sbostic  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
3847145Sbostic  */
3947145Sbostic 
4047145Sbostic #define S_DFL 1			/* default signal handling (SIG_DFL) */
4147145Sbostic #define S_CATCH 2		/* signal is caught */
4247145Sbostic #define S_IGN 3			/* signal is ignored (SIG_IGN) */
4347145Sbostic #define S_HARD_IGN 4		/* signal is ignored permenantly */
4454312Smarc #define S_RESET 5		/* temporary - to reset a hard ignored sig */
4547145Sbostic 
4647145Sbostic 
4747145Sbostic extern char nullstr[1];		/* null string */
4847145Sbostic 
4968935Sbostic char *trap[NSIG+1];		/* trap handler commands */
5068935Sbostic MKINIT char sigmode[NSIG];	/* current value of signal */
5168935Sbostic char gotsig[NSIG];		/* indicates specified signal received */
5247984Smarc int pendingsigs;			/* indicates some signal received */
5347145Sbostic 
5447145Sbostic /*
5547145Sbostic  * The trap builtin.
5647145Sbostic  */
5747145Sbostic 
58*69272Schristos int
59*69272Schristos trapcmd(argc, argv)
60*69272Schristos 	int argc;
61*69272Schristos 	char **argv;
62*69272Schristos {
6347145Sbostic 	char *action;
6447145Sbostic 	char **ap;
6547145Sbostic 	int signo;
6647145Sbostic 
6747145Sbostic 	if (argc <= 1) {
6868935Sbostic 		for (signo = 0 ; signo <= NSIG ; signo++) {
6947145Sbostic 			if (trap[signo] != NULL)
7047145Sbostic 				out1fmt("%d: %s\n", signo, trap[signo]);
7147145Sbostic 		}
7247145Sbostic 		return 0;
7347145Sbostic 	}
7447145Sbostic 	ap = argv + 1;
7547145Sbostic 	if (is_number(*ap))
7647145Sbostic 		action = NULL;
7747145Sbostic 	else
7847145Sbostic 		action = *ap++;
7947145Sbostic 	while (*ap) {
8068935Sbostic 		if ((signo = number(*ap)) < 0 || signo > NSIG)
8147145Sbostic 			error("%s: bad trap", *ap);
8247145Sbostic 		INTOFF;
8347145Sbostic 		if (action)
8447145Sbostic 			action = savestr(action);
8547145Sbostic 		if (trap[signo])
8647145Sbostic 			ckfree(trap[signo]);
8747145Sbostic 		trap[signo] = action;
8847145Sbostic 		if (signo != 0)
8947145Sbostic 			setsignal(signo);
9047145Sbostic 		INTON;
9147145Sbostic 		ap++;
9247145Sbostic 	}
9347145Sbostic 	return 0;
9447145Sbostic }
9547145Sbostic 
9647145Sbostic 
9747145Sbostic 
9847145Sbostic /*
9947145Sbostic  * Clear traps on a fork.
10047145Sbostic  */
10147145Sbostic 
10247145Sbostic void
10347145Sbostic clear_traps() {
10447145Sbostic 	char **tp;
10547145Sbostic 
10668935Sbostic 	for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
10747145Sbostic 		if (*tp && **tp) {	/* trap not NULL or SIG_IGN */
10847145Sbostic 			INTOFF;
10947145Sbostic 			ckfree(*tp);
11047145Sbostic 			*tp = NULL;
11147145Sbostic 			if (tp != &trap[0])
11247145Sbostic 				setsignal(tp - trap);
11347145Sbostic 			INTON;
11447145Sbostic 		}
11547145Sbostic 	}
11647145Sbostic }
11747145Sbostic 
11847145Sbostic 
11947145Sbostic 
12047145Sbostic /*
12147145Sbostic  * Set the signal handler for the specified signal.  The routine figures
12247145Sbostic  * out what it should be set to.
12347145Sbostic  */
12447145Sbostic 
125*69272Schristos long
126*69272Schristos setsignal(signo)
127*69272Schristos 	int signo;
128*69272Schristos {
12947145Sbostic 	int action;
130*69272Schristos 	sig_t sigact = SIG_DFL;
13147145Sbostic 	char *t;
13247145Sbostic 	extern void onsig();
13354312Smarc 	extern sig_t getsigaction();
13447145Sbostic 
13547145Sbostic 	if ((t = trap[signo]) == NULL)
13647145Sbostic 		action = S_DFL;
13747145Sbostic 	else if (*t != '\0')
13847145Sbostic 		action = S_CATCH;
13947145Sbostic 	else
14047145Sbostic 		action = S_IGN;
14147145Sbostic 	if (rootshell && action == S_DFL) {
14247145Sbostic 		switch (signo) {
14347145Sbostic 		case SIGINT:
14447145Sbostic 			if (iflag)
14547145Sbostic 				action = S_CATCH;
14647145Sbostic 			break;
14747145Sbostic 		case SIGQUIT:
14847984Smarc #ifdef DEBUG
14947984Smarc 			{
15047984Smarc 			extern int debug;
15147984Smarc 
15247984Smarc 			if (debug)
15347984Smarc 				break;
15447984Smarc 			}
15547145Sbostic #endif
15647984Smarc 			/* FALLTHROUGH */
15747145Sbostic 		case SIGTERM:
15847145Sbostic 			if (iflag)
15947145Sbostic 				action = S_IGN;
16047145Sbostic 			break;
16147145Sbostic #if JOBS
16247145Sbostic 		case SIGTSTP:
16347145Sbostic 		case SIGTTOU:
16455225Smarc 			if (mflag)
16547145Sbostic 				action = S_IGN;
16647145Sbostic 			break;
16747145Sbostic #endif
16847145Sbostic 		}
16947145Sbostic 	}
17047145Sbostic 	t = &sigmode[signo - 1];
17154312Smarc 	if (*t == 0) {
17254312Smarc 		/*
17354312Smarc 		 * current setting unknown
17447145Sbostic 		 */
17554312Smarc 		sigact = getsigaction(signo);
17647145Sbostic 		if (sigact == SIG_IGN) {
17755225Smarc 			if (mflag && (signo == SIGTSTP ||
17854312Smarc 			     signo == SIGTTIN || signo == SIGTTOU)) {
17954312Smarc 				*t = S_IGN;	/* don't hard ignore these */
18054312Smarc 			} else
18154312Smarc 				*t = S_HARD_IGN;
18247145Sbostic 		} else {
18354312Smarc 			*t = S_RESET;	/* force to be set */
18447145Sbostic 		}
18547145Sbostic 	}
18647145Sbostic 	if (*t == S_HARD_IGN || *t == action)
18747145Sbostic 		return 0;
18847145Sbostic 	switch (action) {
18947984Smarc 		case S_DFL:	sigact = SIG_DFL;	break;
19047984Smarc 		case S_CATCH:  	sigact = onsig;		break;
19147984Smarc 		case S_IGN:	sigact = SIG_IGN;	break;
19247145Sbostic 	}
19347145Sbostic 	*t = action;
194*69272Schristos 	return (long)signal(signo, sigact);
19547145Sbostic }
19647145Sbostic 
19754312Smarc /*
19854312Smarc  * Return the current setting for sig w/o changing it.
19954312Smarc  */
20054312Smarc sig_t
201*69272Schristos getsigaction(signo)
202*69272Schristos 	int signo;
203*69272Schristos {
20454312Smarc 	struct sigaction sa;
20547145Sbostic 
20654312Smarc 	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
20754312Smarc 		error("Sigaction system call failed");
20854312Smarc 
209*69272Schristos 	return (sig_t) sa.sa_handler;
21054312Smarc }
21154312Smarc 
21247145Sbostic /*
21347145Sbostic  * Ignore a signal.
21447145Sbostic  */
21547145Sbostic 
21647145Sbostic void
217*69272Schristos ignoresig(signo)
218*69272Schristos 	int signo;
219*69272Schristos {
22047145Sbostic 	if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
22147145Sbostic 		signal(signo, SIG_IGN);
22247145Sbostic 	}
22347145Sbostic 	sigmode[signo - 1] = S_HARD_IGN;
22447145Sbostic }
22547145Sbostic 
22647145Sbostic 
22747145Sbostic #ifdef mkinit
22868935Sbostic INCLUDE <signal.h>
22947145Sbostic INCLUDE "trap.h"
23047145Sbostic 
23147145Sbostic SHELLPROC {
23247145Sbostic 	char *sm;
23347145Sbostic 
23447145Sbostic 	clear_traps();
23568935Sbostic 	for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
23647145Sbostic 		if (*sm == S_IGN)
23747145Sbostic 			*sm = S_HARD_IGN;
23847145Sbostic 	}
23947145Sbostic }
24047145Sbostic #endif
24147145Sbostic 
24247145Sbostic 
24347145Sbostic 
24447145Sbostic /*
24547145Sbostic  * Signal handler.
24647145Sbostic  */
24747145Sbostic 
24847145Sbostic void
249*69272Schristos onsig(signo)
250*69272Schristos 	int signo;
251*69272Schristos {
25247145Sbostic 	signal(signo, onsig);
25347145Sbostic 	if (signo == SIGINT && trap[SIGINT] == NULL) {
25447145Sbostic 		onint();
25547145Sbostic 		return;
25647145Sbostic 	}
25747145Sbostic 	gotsig[signo - 1] = 1;
25847145Sbostic 	pendingsigs++;
25947145Sbostic }
26047145Sbostic 
26147145Sbostic 
26247145Sbostic 
26347145Sbostic /*
26447145Sbostic  * Called to execute a trap.  Perhaps we should avoid entering new trap
26547145Sbostic  * handlers while we are executing a trap handler.
26647145Sbostic  */
26747145Sbostic 
26847145Sbostic void
26947145Sbostic dotrap() {
27047145Sbostic 	int i;
27147984Smarc 	int savestatus;
27247145Sbostic 
27347145Sbostic 	for (;;) {
27447145Sbostic 		for (i = 1 ; ; i++) {
27547145Sbostic 			if (gotsig[i - 1])
27647145Sbostic 				break;
27768935Sbostic 			if (i >= NSIG)
27847145Sbostic 				goto done;
27947145Sbostic 		}
28047145Sbostic 		gotsig[i - 1] = 0;
28147984Smarc 		savestatus=exitstatus;
28247145Sbostic 		evalstring(trap[i]);
28347984Smarc 		exitstatus=savestatus;
28447145Sbostic 	}
28547145Sbostic done:
28647145Sbostic 	pendingsigs = 0;
28747145Sbostic }
28847145Sbostic 
28947145Sbostic 
29047145Sbostic 
29147145Sbostic /*
29247145Sbostic  * Controls whether the shell is interactive or not.
29347145Sbostic  */
29447145Sbostic 
29547145Sbostic 
29647145Sbostic void
297*69272Schristos setinteractive(on)
298*69272Schristos 	int on;
299*69272Schristos {
30055225Smarc 	static int is_interactive;
30155225Smarc 
30247145Sbostic 	if (on == is_interactive)
30347145Sbostic 		return;
30447145Sbostic 	setsignal(SIGINT);
30547145Sbostic 	setsignal(SIGQUIT);
30647145Sbostic 	setsignal(SIGTERM);
30747145Sbostic 	is_interactive = on;
30847145Sbostic }
30947145Sbostic 
31047145Sbostic 
31147145Sbostic 
31247145Sbostic /*
31347145Sbostic  * Called to exit the shell.
31447145Sbostic  */
31547145Sbostic 
31647145Sbostic void
317*69272Schristos exitshell(status)
318*69272Schristos 	int status;
319*69272Schristos {
32047145Sbostic 	struct jmploc loc1, loc2;
32147145Sbostic 	char *p;
32247145Sbostic 
32347145Sbostic 	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
32455225Smarc 	if (setjmp(loc1.loc)) {
32555225Smarc 		goto l1;
32655225Smarc 	}
32755225Smarc 	if (setjmp(loc2.loc)) {
32855225Smarc 		goto l2;
32955225Smarc 	}
33047145Sbostic 	handler = &loc1;
33147145Sbostic 	if ((p = trap[0]) != NULL && *p != '\0') {
33247145Sbostic 		trap[0] = NULL;
33347145Sbostic 		evalstring(p);
33447145Sbostic 	}
33547145Sbostic l1:   handler = &loc2;			/* probably unnecessary */
33647145Sbostic 	flushall();
33747145Sbostic #if JOBS
33847145Sbostic 	setjobctl(0);
33947145Sbostic #endif
34047145Sbostic l2:   _exit(status);
34147145Sbostic }
342