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