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