trap.c revision 30969
133965Sjdp/*- 2218822Sdim * Copyright (c) 1991, 1993 3130561Sobrien * The Regents of the University of California. All rights reserved. 477298Sobrien * 533965Sjdp * This code is derived from software contributed to Berkeley by 633965Sjdp * Kenneth Almquist. 733965Sjdp * 833965Sjdp * Redistribution and use in source and binary forms, with or without 933965Sjdp * modification, are permitted provided that the following conditions 1033965Sjdp * are met: 1133965Sjdp * 1. Redistributions of source code must retain the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer. 1333965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1433965Sjdp * notice, this list of conditions and the following disclaimer in the 1533965Sjdp * documentation and/or other materials provided with the distribution. 1633965Sjdp * 3. All advertising materials mentioning features or use of this software 1733965Sjdp * must display the following acknowledgement: 1833965Sjdp * This product includes software developed by the University of 1933965Sjdp * California, Berkeley and its contributors. 20218822Sdim * 4. Neither the name of the University nor the names of its contributors 2133965Sjdp * may be used to endorse or promote products derived from this software 2277298Sobrien * without specific prior written permission. 2333965Sjdp * 24104834Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27104834Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2833965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2933965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3033965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32218822Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3433965Sjdp * SUCH DAMAGE. 3533965Sjdp * 3633965Sjdp * $Id: trap.c,v 1.8 1997/02/22 13:58:46 peter Exp $ 3733965Sjdp */ 3833965Sjdp 39218822Sdim#ifndef lint 40130561Sobrienstatic char const sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; 41130561Sobrien#endif /* not lint */ 42130561Sobrien 4333965Sjdp#include <signal.h> 4433965Sjdp#include <unistd.h> 4533965Sjdp#include <stdlib.h> 4633965Sjdp 4733965Sjdp#include "shell.h" 4833965Sjdp#include "main.h" 4933965Sjdp#include "nodes.h" /* for other headers */ 5033965Sjdp#include "eval.h" 5133965Sjdp#include "jobs.h" 5277298Sobrien#include "show.h" 5333965Sjdp#include "options.h" 5433965Sjdp#include "syntax.h" 55218822Sdim#include "output.h" 56218822Sdim#include "memalloc.h" 5733965Sjdp#include "error.h" 5833965Sjdp#include "trap.h" 5933965Sjdp#include "mystring.h" 6033965Sjdp 6133965Sjdp 6233965Sjdp/* 63130561Sobrien * Sigmode records the current value of the signal handlers for the various 64130561Sobrien * modes. A value of zero means that the current handler is not known. 65130561Sobrien * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 66218822Sdim */ 67218822Sdim 6833965Sjdp#define S_DFL 1 /* default signal handling (SIG_DFL) */ 6933965Sjdp#define S_CATCH 2 /* signal is caught */ 7033965Sjdp#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 7133965Sjdp#define S_HARD_IGN 4 /* signal is ignored permenantly */ 72130561Sobrien#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 7333965Sjdp 7489857Sobrien 7589857SobrienMKINIT char sigmode[NSIG]; /* current value of signal */ 7689857Sobrienint pendingsigs; /* indicates some signal received */ 7789857Sobrienstatic char *trap[NSIG]; /* trap handler commands */ 78218822Sdimstatic char gotsig[NSIG]; /* indicates specified signal received */ 7989857Sobrienstatic int ignore_sigchld; /* Used while handling SIGCHLD traps. */ 8089857Sobrien 81218822Sdimstatic int getsigaction __P((int, sig_t *)); 82218822Sdim 8389857Sobrien 8489857Sobrien/* 8589857Sobrien * Map a string to a signal number. 8689857Sobrien */ 8789857Sobrienstatic int 8889857Sobriensigstring_to_signum(sig) 8989857Sobrien char *sig; 9033965Sjdp{ 91218822Sdim 9260484Sobrien if (is_number(sig)) { 9333965Sjdp int signo; 9433965Sjdp 9533965Sjdp signo = atoi(sig); 9633965Sjdp return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 9733965Sjdp } else if (strcasecmp(sig, "exit") == 0) { 9833965Sjdp return (0); 99130561Sobrien } else { 10033965Sjdp int n; 10133965Sjdp 102130561Sobrien if (strncasecmp(sig, "sig", 3) == 0) 10333965Sjdp sig += 3; 10433965Sjdp for (n = 1; n < NSIG; n++) 10533965Sjdp if (strcasecmp(sys_signame[n], sig) == 0) 10633965Sjdp return (n); 107130561Sobrien } 108130561Sobrien return (-1); 109130561Sobrien} 11033965Sjdp 11133965Sjdp 11233965Sjdp/* 11333965Sjdp * Print a list of valid signal names. 11433965Sjdp */ 11533965Sjdpstatic void 11633965Sjdpprintsignals() 11733965Sjdp{ 11833965Sjdp int n; 11933965Sjdp 12033965Sjdp for (n = 1; n < NSIG; n++) { 12133965Sjdp out1fmt("%s", sys_signame[n]); 122130561Sobrien if (n == (NSIG / 2) || n == (NSIG - 1)) 12333965Sjdp out1str("\n"); 12433965Sjdp else 12533965Sjdp out1c(' '); 12633965Sjdp } 12733965Sjdp} 128130561Sobrien 129130561Sobrien 13033965Sjdp/* 13133965Sjdp * The trap builtin. 13260484Sobrien */ 13333965Sjdpint 13433965Sjdptrapcmd(argc, argv) 13533965Sjdp int argc; 13633965Sjdp char **argv; 13733965Sjdp{ 13833965Sjdp char *action; 13933965Sjdp int signo; 14033965Sjdp 14133965Sjdp if (argc <= 1) { 14233965Sjdp for (signo = 0 ; signo < NSIG ; signo++) { 14333965Sjdp if (trap[signo] != NULL) 144218822Sdim out1fmt("trap -- '%s' %s\n", trap[signo], 14560484Sobrien (signo) ? sys_signame[signo] : "exit"); 14660484Sobrien } 14760484Sobrien return 0; 14833965Sjdp } 14933965Sjdp action = NULL; 15033965Sjdp if (*++argv && strcmp(*argv, "--") == 0) 15133965Sjdp argv++; 152218822Sdim if (*argv && sigstring_to_signum(*argv) == -1) { 153218822Sdim if ((*argv)[0] != '-') { 154218822Sdim action = *argv; 155218822Sdim argv++; 156218822Sdim } else if ((*argv)[1] == '\0') { 157218822Sdim argv++; 158218822Sdim } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 159218822Sdim printsignals(); 160218822Sdim return 0; 161218822Sdim } else { 162218822Sdim error("bad option %s", *argv); 163218822Sdim } 164218822Sdim } 165218822Sdim while (*argv) { 166218822Sdim if ((signo = sigstring_to_signum(*argv)) == -1) 167218822Sdim error("bad signal %s", *argv); 168218822Sdim INTOFF; 169218822Sdim if (action) 170218822Sdim action = savestr(action); 171218822Sdim if (trap[signo]) 172218822Sdim ckfree(trap[signo]); 17333965Sjdp trap[signo] = action; 17433965Sjdp if (signo != 0) 17533965Sjdp setsignal(signo); 17633965Sjdp INTON; 177218822Sdim argv++; 17833965Sjdp } 17933965Sjdp return 0; 18033965Sjdp} 18133965Sjdp 18233965Sjdp 18333965Sjdp/* 18433965Sjdp * Clear traps on a fork. 18533965Sjdp */ 18633965Sjdpvoid 18733965Sjdpclear_traps() 18833965Sjdp{ 18938889Sjdp char **tp; 19033965Sjdp 19133965Sjdp for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 19233965Sjdp if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 19333965Sjdp INTOFF; 19433965Sjdp ckfree(*tp); 19533965Sjdp *tp = NULL; 19638889Sjdp if (tp != &trap[0]) 19733965Sjdp setsignal(tp - trap); 19833965Sjdp INTON; 199130561Sobrien } 200218822Sdim } 201218822Sdim} 202218822Sdim 203218822Sdim 20433965Sjdp/* 20533965Sjdp * Set the signal handler for the specified signal. The routine figures 20633965Sjdp * out what it should be set to. 20733965Sjdp */ 20833965Sjdplong 20933965Sjdpsetsignal(signo) 21033965Sjdp int signo; 21133965Sjdp{ 21233965Sjdp int action; 213218822Sdim sig_t sigact = SIG_DFL; 214218822Sdim char *t; 215218822Sdim long sig; 216218822Sdim 217218822Sdim if ((t = trap[signo]) == NULL) 218104834Sobrien action = S_DFL; 219218822Sdim else if (*t != '\0') 220218822Sdim action = S_CATCH; 221218822Sdim else 222218822Sdim action = S_IGN; 223218822Sdim if (rootshell && action == S_DFL) { 224218822Sdim switch (signo) { 225218822Sdim case SIGINT: 226218822Sdim if (iflag) 227218822Sdim action = S_CATCH; 22833965Sjdp break; 229218822Sdim case SIGQUIT: 230104834Sobrien#ifdef DEBUG 231218822Sdim { 232218822Sdim extern int debug; 233218822Sdim 23433965Sjdp if (debug) 235218822Sdim break; 236218822Sdim } 237218822Sdim#endif 23833965Sjdp /* FALLTHROUGH */ 239218822Sdim case SIGTERM: 240218822Sdim if (iflag) 241218822Sdim action = S_IGN; 242218822Sdim break; 24333965Sjdp#if JOBS 244218822Sdim case SIGTSTP: 245218822Sdim case SIGTTOU: 246218822Sdim if (mflag) 247218822Sdim action = S_IGN; 248218822Sdim break; 249218822Sdim#endif 250218822Sdim } 25133965Sjdp } 25233965Sjdp 25333965Sjdp t = &sigmode[signo]; 25433965Sjdp if (*t == 0) { 25533965Sjdp /* 25633965Sjdp * current setting unknown 25733965Sjdp */ 25833965Sjdp if (!getsigaction(signo, &sigact)) { 25933965Sjdp /* 26033965Sjdp * Pretend it worked; maybe we should give a warning 261218822Sdim * here, but other shells don't. We don't alter 26233965Sjdp * sigmode, so that we retry every time. 263218822Sdim */ 264218822Sdim return 0; 265218822Sdim } 26633965Sjdp if (sigact == SIG_IGN) { 26733965Sjdp if (mflag && (signo == SIGTSTP || 268218822Sdim signo == SIGTTIN || signo == SIGTTOU)) { 26933965Sjdp *t = S_IGN; /* don't hard ignore these */ 27033965Sjdp } else 271130561Sobrien *t = S_HARD_IGN; 272218822Sdim } else { 273130561Sobrien *t = S_RESET; /* force to be set */ 274104834Sobrien } 27533965Sjdp } 276104834Sobrien if (*t == S_HARD_IGN || *t == action) 27733965Sjdp return 0; 27833965Sjdp switch (action) { 279218822Sdim case S_DFL: sigact = SIG_DFL; break; 28033965Sjdp case S_CATCH: sigact = onsig; break; 28133965Sjdp case S_IGN: sigact = SIG_IGN; break; 28233965Sjdp } 28333965Sjdp *t = action; 28433965Sjdp sig = (long)signal(signo, sigact); 28533965Sjdp#ifdef BSD 28633965Sjdp if (sig != -1 && action == S_CATCH) 28733965Sjdp sig = siginterrupt(signo, 1); 28833965Sjdp#endif 28933965Sjdp return sig; 29033965Sjdp} 29133965Sjdp 292218822Sdim 293218822Sdim/* 294218822Sdim * Return the current setting for sig w/o changing it. 295218822Sdim */ 296218822Sdimstatic int 297218822Sdimgetsigaction(signo, sigact) 298218822Sdim int signo; 299218822Sdim sig_t *sigact; 300218822Sdim{ 30133965Sjdp struct sigaction sa; 30233965Sjdp 303218822Sdim if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 30433965Sjdp return 0; 30533965Sjdp *sigact = (sig_t) sa.sa_handler; 30633965Sjdp return 1; 30733965Sjdp} 30833965Sjdp 30933965Sjdp 31033965Sjdp/* 31133965Sjdp * Ignore a signal. 312218822Sdim */ 313218822Sdimvoid 31433965Sjdpignoresig(signo) 31533965Sjdp int signo; 31633965Sjdp{ 317130561Sobrien 31833965Sjdp if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 319104834Sobrien signal(signo, SIG_IGN); 320218822Sdim } 32133965Sjdp sigmode[signo] = S_HARD_IGN; 32233965Sjdp} 32333965Sjdp 32460484Sobrien 32560484Sobrien#ifdef mkinit 32660484SobrienINCLUDE <signal.h> 32789857SobrienINCLUDE "trap.h" 32889857Sobrien 32989857SobrienSHELLPROC { 33060484Sobrien char *sm; 33160484Sobrien 33260484Sobrien clear_traps(); 33333965Sjdp for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 33433965Sjdp if (*sm == S_IGN) 33533965Sjdp *sm = S_HARD_IGN; 336218822Sdim } 337218822Sdim} 33833965Sjdp#endif 33933965Sjdp 34033965Sjdp 341104834Sobrien/* 342218822Sdim * Signal handler. 34333965Sjdp */ 344218822Sdimvoid 34533965Sjdponsig(signo) 34633965Sjdp int signo; 34733965Sjdp{ 34833965Sjdp#ifndef BSD 34933965Sjdp signal(signo, onsig); 35089857Sobrien#endif 35133965Sjdp if (signo == SIGINT && trap[SIGINT] == NULL) { 35233965Sjdp onint(); 35333965Sjdp return; 35433965Sjdp } 355130561Sobrien if (signo != SIGCHLD || !ignore_sigchld) 35677298Sobrien gotsig[signo] = 1; 35777298Sobrien pendingsigs++; 35877298Sobrien} 359104834Sobrien 36077298Sobrien 361104834Sobrien/* 36277298Sobrien * Called to execute a trap. Perhaps we should avoid entering new trap 36377298Sobrien * handlers while we are executing a trap handler. 364104834Sobrien */ 36577298Sobrienvoid 366104834Sobriendotrap() 36733965Sjdp{ 36833965Sjdp int i; 369104834Sobrien int savestatus; 37033965Sjdp 37133965Sjdp for (;;) { 372130561Sobrien for (i = 1; i < NSIG; i++) { 37333965Sjdp if (gotsig[i]) { 37433965Sjdp gotsig[i] = 0; 375130561Sobrien if (trap[i]) { 37633965Sjdp /* 37789857Sobrien * Ignore SIGCHLD to avoid infinite recursion 37833965Sjdp * if the trap action does a fork. 37933965Sjdp */ 38033965Sjdp if (i == SIGCHLD) 38189857Sobrien ignore_sigchld++; 38233965Sjdp savestatus = exitstatus; 38333965Sjdp evalstring(trap[i]); 38433965Sjdp exitstatus = savestatus; 385218822Sdim if (i == SIGCHLD) 386218822Sdim ignore_sigchld--; 387218822Sdim } 388218822Sdim break; 389218822Sdim } 390218822Sdim } 39133965Sjdp if (i >= NSIG) 39233965Sjdp break; 39333965Sjdp } 39433965Sjdp pendingsigs = 0; 39533965Sjdp} 39633965Sjdp 397104834Sobrien 398104834Sobrien/* 39933965Sjdp * Controls whether the shell is interactive or not. 40033965Sjdp */ 40133965Sjdpvoid 40233965Sjdpsetinteractive(on) 403218822Sdim int on; 40433965Sjdp{ 405 static int is_interactive = 0; 406 407 if (on == is_interactive) 408 return; 409 setsignal(SIGINT); 410 setsignal(SIGQUIT); 411 setsignal(SIGTERM); 412 is_interactive = on; 413} 414 415 416/* 417 * Called to exit the shell. 418 */ 419void 420exitshell(status) 421 int status; 422{ 423 struct jmploc loc1, loc2; 424 char *p; 425 426 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 427 if (setjmp(loc1.loc)) { 428 goto l1; 429 } 430 if (setjmp(loc2.loc)) { 431 goto l2; 432 } 433 handler = &loc1; 434 if ((p = trap[0]) != NULL && *p != '\0') { 435 trap[0] = NULL; 436 evalstring(p); 437 } 438l1: handler = &loc2; /* probably unnecessary */ 439 flushall(); 440#if JOBS 441 setjobctl(0); 442#endif 443l2: _exit(status); 444} 445