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