xref: /csrg-svn/bin/sh/trap.c (revision 69807)
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*69807Schristos static char sccsid[] = "@(#)trap.c	8.5 (Berkeley) 06/05/95";
1347145Sbostic #endif /* not lint */
1447145Sbostic 
1569272Schristos #include <signal.h>
1669272Schristos #include <unistd.h>
1769272Schristos #include <stdlib.h>
1869272Schristos 
1947145Sbostic #include "shell.h"
2047145Sbostic #include "main.h"
2147145Sbostic #include "nodes.h"	/* for other headers */
2247145Sbostic #include "eval.h"
2347145Sbostic #include "jobs.h"
2469272Schristos #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 
54*69807Schristos static int getsigaction __P((int, sig_t *));
55*69807Schristos 
5647145Sbostic /*
5747145Sbostic  * The trap builtin.
5847145Sbostic  */
5947145Sbostic 
6069272Schristos int
trapcmd(argc,argv)6169272Schristos trapcmd(argc, argv)
6269272Schristos 	int argc;
6369272Schristos 	char **argv;
6469272Schristos {
6547145Sbostic 	char *action;
6647145Sbostic 	char **ap;
6747145Sbostic 	int signo;
6847145Sbostic 
6947145Sbostic 	if (argc <= 1) {
7068935Sbostic 		for (signo = 0 ; signo <= NSIG ; signo++) {
7147145Sbostic 			if (trap[signo] != NULL)
7247145Sbostic 				out1fmt("%d: %s\n", signo, trap[signo]);
7347145Sbostic 		}
7447145Sbostic 		return 0;
7547145Sbostic 	}
7647145Sbostic 	ap = argv + 1;
7747145Sbostic 	if (is_number(*ap))
7847145Sbostic 		action = NULL;
7947145Sbostic 	else
8047145Sbostic 		action = *ap++;
8147145Sbostic 	while (*ap) {
8268935Sbostic 		if ((signo = number(*ap)) < 0 || signo > NSIG)
8347145Sbostic 			error("%s: bad trap", *ap);
8447145Sbostic 		INTOFF;
8547145Sbostic 		if (action)
8647145Sbostic 			action = savestr(action);
8747145Sbostic 		if (trap[signo])
8847145Sbostic 			ckfree(trap[signo]);
8947145Sbostic 		trap[signo] = action;
9047145Sbostic 		if (signo != 0)
9147145Sbostic 			setsignal(signo);
9247145Sbostic 		INTON;
9347145Sbostic 		ap++;
9447145Sbostic 	}
9547145Sbostic 	return 0;
9647145Sbostic }
9747145Sbostic 
9847145Sbostic 
9947145Sbostic 
10047145Sbostic /*
10147145Sbostic  * Clear traps on a fork.
10247145Sbostic  */
10347145Sbostic 
10447145Sbostic void
clear_traps()10547145Sbostic clear_traps() {
10647145Sbostic 	char **tp;
10747145Sbostic 
10868935Sbostic 	for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
10947145Sbostic 		if (*tp && **tp) {	/* trap not NULL or SIG_IGN */
11047145Sbostic 			INTOFF;
11147145Sbostic 			ckfree(*tp);
11247145Sbostic 			*tp = NULL;
11347145Sbostic 			if (tp != &trap[0])
11447145Sbostic 				setsignal(tp - trap);
11547145Sbostic 			INTON;
11647145Sbostic 		}
11747145Sbostic 	}
11847145Sbostic }
11947145Sbostic 
12047145Sbostic 
12147145Sbostic 
12247145Sbostic /*
12347145Sbostic  * Set the signal handler for the specified signal.  The routine figures
12447145Sbostic  * out what it should be set to.
12547145Sbostic  */
12647145Sbostic 
12769272Schristos long
setsignal(signo)12869272Schristos setsignal(signo)
12969272Schristos 	int signo;
13069272Schristos {
13147145Sbostic 	int action;
13269272Schristos 	sig_t sigact = SIG_DFL;
13347145Sbostic 	char *t;
13447145Sbostic 	extern void onsig();
13547145Sbostic 
13647145Sbostic 	if ((t = trap[signo]) == NULL)
13747145Sbostic 		action = S_DFL;
13847145Sbostic 	else if (*t != '\0')
13947145Sbostic 		action = S_CATCH;
14047145Sbostic 	else
14147145Sbostic 		action = S_IGN;
14247145Sbostic 	if (rootshell && action == S_DFL) {
14347145Sbostic 		switch (signo) {
14447145Sbostic 		case SIGINT:
14547145Sbostic 			if (iflag)
14647145Sbostic 				action = S_CATCH;
14747145Sbostic 			break;
14847145Sbostic 		case SIGQUIT:
14947984Smarc #ifdef DEBUG
15047984Smarc 			{
15147984Smarc 			extern int debug;
15247984Smarc 
15347984Smarc 			if (debug)
15447984Smarc 				break;
15547984Smarc 			}
15647145Sbostic #endif
15747984Smarc 			/* FALLTHROUGH */
15847145Sbostic 		case SIGTERM:
15947145Sbostic 			if (iflag)
16047145Sbostic 				action = S_IGN;
16147145Sbostic 			break;
16247145Sbostic #if JOBS
16347145Sbostic 		case SIGTSTP:
16447145Sbostic 		case SIGTTOU:
16555225Smarc 			if (mflag)
16647145Sbostic 				action = S_IGN;
16747145Sbostic 			break;
16847145Sbostic #endif
16947145Sbostic 		}
17047145Sbostic 	}
17169806Schristos 
17247145Sbostic 	t = &sigmode[signo - 1];
17354312Smarc 	if (*t == 0) {
17454312Smarc 		/*
17554312Smarc 		 * current setting unknown
17647145Sbostic 		 */
177*69807Schristos 		if (!getsigaction(signo, &sigact)) {
178*69807Schristos 			/*
179*69807Schristos 			 * Pretend it worked; maybe we should give a warning
180*69807Schristos 			 * here, but other shells don't. We don't alter
181*69807Schristos 			 * sigmode, so that we retry every time.
182*69807Schristos 			 */
183*69807Schristos 			return 0;
184*69807Schristos 		}
18547145Sbostic 		if (sigact == SIG_IGN) {
18655225Smarc 			if (mflag && (signo == SIGTSTP ||
18754312Smarc 			     signo == SIGTTIN || signo == SIGTTOU)) {
18854312Smarc 				*t = S_IGN;	/* don't hard ignore these */
18954312Smarc 			} else
19054312Smarc 				*t = S_HARD_IGN;
19147145Sbostic 		} else {
19254312Smarc 			*t = S_RESET;	/* force to be set */
19347145Sbostic 		}
19447145Sbostic 	}
19547145Sbostic 	if (*t == S_HARD_IGN || *t == action)
19647145Sbostic 		return 0;
19747145Sbostic 	switch (action) {
19847984Smarc 		case S_DFL:	sigact = SIG_DFL;	break;
19947984Smarc 		case S_CATCH:  	sigact = onsig;		break;
20047984Smarc 		case S_IGN:	sigact = SIG_IGN;	break;
20147145Sbostic 	}
20247145Sbostic 	*t = action;
20369272Schristos 	return (long)signal(signo, sigact);
20447145Sbostic }
20547145Sbostic 
20654312Smarc /*
20754312Smarc  * Return the current setting for sig w/o changing it.
20854312Smarc  */
209*69807Schristos static int
getsigaction(signo,sigact)210*69807Schristos getsigaction(signo, sigact)
21169272Schristos 	int signo;
212*69807Schristos 	sig_t *sigact;
21369272Schristos {
21454312Smarc 	struct sigaction sa;
21547145Sbostic 
21654312Smarc 	if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
217*69807Schristos 		return 0;
218*69807Schristos 	*sigact = (sig_t) sa.sa_handler;
219*69807Schristos 	return 1;
22054312Smarc }
22154312Smarc 
22247145Sbostic /*
22347145Sbostic  * Ignore a signal.
22447145Sbostic  */
22547145Sbostic 
22647145Sbostic void
ignoresig(signo)22769272Schristos ignoresig(signo)
22869272Schristos 	int signo;
22969272Schristos {
23047145Sbostic 	if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
23147145Sbostic 		signal(signo, SIG_IGN);
23247145Sbostic 	}
23347145Sbostic 	sigmode[signo - 1] = S_HARD_IGN;
23447145Sbostic }
23547145Sbostic 
23647145Sbostic 
23747145Sbostic #ifdef mkinit
23868935Sbostic INCLUDE <signal.h>
23947145Sbostic INCLUDE "trap.h"
24047145Sbostic 
24147145Sbostic SHELLPROC {
24247145Sbostic 	char *sm;
24347145Sbostic 
24447145Sbostic 	clear_traps();
24568935Sbostic 	for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
24647145Sbostic 		if (*sm == S_IGN)
24747145Sbostic 			*sm = S_HARD_IGN;
24847145Sbostic 	}
24947145Sbostic }
25047145Sbostic #endif
25147145Sbostic 
25247145Sbostic 
25347145Sbostic 
25447145Sbostic /*
25547145Sbostic  * Signal handler.
25647145Sbostic  */
25747145Sbostic 
25847145Sbostic void
onsig(signo)25969272Schristos onsig(signo)
26069272Schristos 	int signo;
26169272Schristos {
26247145Sbostic 	signal(signo, onsig);
26347145Sbostic 	if (signo == SIGINT && trap[SIGINT] == NULL) {
26447145Sbostic 		onint();
26547145Sbostic 		return;
26647145Sbostic 	}
26747145Sbostic 	gotsig[signo - 1] = 1;
26847145Sbostic 	pendingsigs++;
26947145Sbostic }
27047145Sbostic 
27147145Sbostic 
27247145Sbostic 
27347145Sbostic /*
27447145Sbostic  * Called to execute a trap.  Perhaps we should avoid entering new trap
27547145Sbostic  * handlers while we are executing a trap handler.
27647145Sbostic  */
27747145Sbostic 
27847145Sbostic void
dotrap()27947145Sbostic dotrap() {
28047145Sbostic 	int i;
28147984Smarc 	int savestatus;
28247145Sbostic 
28347145Sbostic 	for (;;) {
28447145Sbostic 		for (i = 1 ; ; i++) {
28547145Sbostic 			if (gotsig[i - 1])
28647145Sbostic 				break;
28768935Sbostic 			if (i >= NSIG)
28847145Sbostic 				goto done;
28947145Sbostic 		}
29047145Sbostic 		gotsig[i - 1] = 0;
29147984Smarc 		savestatus=exitstatus;
29247145Sbostic 		evalstring(trap[i]);
29347984Smarc 		exitstatus=savestatus;
29447145Sbostic 	}
29547145Sbostic done:
29647145Sbostic 	pendingsigs = 0;
29747145Sbostic }
29847145Sbostic 
29947145Sbostic 
30047145Sbostic 
30147145Sbostic /*
30247145Sbostic  * Controls whether the shell is interactive or not.
30347145Sbostic  */
30447145Sbostic 
30547145Sbostic 
30647145Sbostic void
setinteractive(on)30769272Schristos setinteractive(on)
30869272Schristos 	int on;
30969272Schristos {
31055225Smarc 	static int is_interactive;
31155225Smarc 
31247145Sbostic 	if (on == is_interactive)
31347145Sbostic 		return;
31447145Sbostic 	setsignal(SIGINT);
31547145Sbostic 	setsignal(SIGQUIT);
31647145Sbostic 	setsignal(SIGTERM);
31747145Sbostic 	is_interactive = on;
31847145Sbostic }
31947145Sbostic 
32047145Sbostic 
32147145Sbostic 
32247145Sbostic /*
32347145Sbostic  * Called to exit the shell.
32447145Sbostic  */
32547145Sbostic 
32647145Sbostic void
exitshell(status)32769272Schristos exitshell(status)
32869272Schristos 	int status;
32969272Schristos {
33047145Sbostic 	struct jmploc loc1, loc2;
33147145Sbostic 	char *p;
33247145Sbostic 
33347145Sbostic 	TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
33455225Smarc 	if (setjmp(loc1.loc)) {
33555225Smarc 		goto l1;
33655225Smarc 	}
33755225Smarc 	if (setjmp(loc2.loc)) {
33855225Smarc 		goto l2;
33955225Smarc 	}
34047145Sbostic 	handler = &loc1;
34147145Sbostic 	if ((p = trap[0]) != NULL && *p != '\0') {
34247145Sbostic 		trap[0] = NULL;
34347145Sbostic 		evalstring(p);
34447145Sbostic 	}
34547145Sbostic l1:   handler = &loc2;			/* probably unnecessary */
34647145Sbostic 	flushall();
34747145Sbostic #if JOBS
34847145Sbostic 	setjobctl(0);
34947145Sbostic #endif
35047145Sbostic l2:   _exit(status);
35147145Sbostic }
352