trap.c revision 149825
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3436150Scharnier#if 0 3536150Scharnierstatic char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; 3636150Scharnier#endif 371556Srgrimes#endif /* not lint */ 3899110Sobrien#include <sys/cdefs.h> 3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/trap.c 149825 2005-09-06 19:30:00Z rse $"); 401556Srgrimes 4117987Speter#include <signal.h> 4217987Speter#include <unistd.h> 4317987Speter#include <stdlib.h> 4417987Speter 451556Srgrimes#include "shell.h" 461556Srgrimes#include "main.h" 471556Srgrimes#include "nodes.h" /* for other headers */ 481556Srgrimes#include "eval.h" 491556Srgrimes#include "jobs.h" 5017987Speter#include "show.h" 511556Srgrimes#include "options.h" 521556Srgrimes#include "syntax.h" 531556Srgrimes#include "output.h" 541556Srgrimes#include "memalloc.h" 551556Srgrimes#include "error.h" 561556Srgrimes#include "trap.h" 571556Srgrimes#include "mystring.h" 58100578Stjr#include "myhistedit.h" 591556Srgrimes 601556Srgrimes 611556Srgrimes/* 621556Srgrimes * Sigmode records the current value of the signal handlers for the various 631556Srgrimes * modes. A value of zero means that the current handler is not known. 641556Srgrimes * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 651556Srgrimes */ 661556Srgrimes 671556Srgrimes#define S_DFL 1 /* default signal handling (SIG_DFL) */ 681556Srgrimes#define S_CATCH 2 /* signal is caught */ 691556Srgrimes#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 7046684Skris#define S_HARD_IGN 4 /* signal is ignored permanently */ 711556Srgrimes#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 721556Srgrimes 731556Srgrimes 7417987SpeterMKINIT char sigmode[NSIG]; /* current value of signal */ 7538521Scracauerint pendingsigs; /* indicates some signal received */ 7638536Scracauerint in_dotrap; /* do we execute in a trap handler? */ 7738950Scracauerstatic char *volatile trap[NSIG]; /* trap handler commands */ 7838521Scracauerstatic volatile sig_atomic_t gotsig[NSIG]; 7938521Scracauer /* indicates specified signal received */ 8020902Sstevestatic int ignore_sigchld; /* Used while handling SIGCHLD traps. */ 81100588Stjrvolatile sig_atomic_t gotwinch; 821556Srgrimes 8390111Simpstatic int getsigaction(int, sig_t *); 8417987Speter 8520902Ssteve 861556Srgrimes/* 8720902Ssteve * Map a string to a signal number. 88125727Snjl * 89125727Snjl * Note: the signal number may exceed NSIG. 9020902Ssteve */ 9120902Sstevestatic int 9290111Simpsigstring_to_signum(char *sig) 9320902Ssteve{ 9420902Ssteve 9520902Ssteve if (is_number(sig)) { 9620902Ssteve int signo; 9720902Ssteve 9820902Ssteve signo = atoi(sig); 9920902Ssteve return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 10020902Ssteve } else if (strcasecmp(sig, "exit") == 0) { 10120902Ssteve return (0); 10220902Ssteve } else { 10320902Ssteve int n; 10420902Ssteve 10520902Ssteve if (strncasecmp(sig, "sig", 3) == 0) 10620902Ssteve sig += 3; 107125155Snjl for (n = 1; n < sys_nsig; n++) 108125728Snjl if (sys_signame[n] && 109125728Snjl strcasecmp(sys_signame[n], sig) == 0) 11020902Ssteve return (n); 11120902Ssteve } 11220902Ssteve return (-1); 11320902Ssteve} 11420902Ssteve 11520902Ssteve 11620902Ssteve/* 11720902Ssteve * Print a list of valid signal names. 11820902Ssteve */ 11920902Sstevestatic void 12090111Simpprintsignals(void) 12120902Ssteve{ 122125727Snjl int n, outlen; 12320902Ssteve 124125727Snjl outlen = 0; 125125155Snjl for (n = 1; n < sys_nsig; n++) { 126125727Snjl if (sys_signame[n]) { 127125727Snjl out1fmt("%s", sys_signame[n]); 128125727Snjl outlen += strlen(sys_signame[n]); 129125727Snjl } else { 130125727Snjl out1fmt("%d", n); 131125727Snjl outlen += 3; /* good enough */ 132125727Snjl } 133125727Snjl ++outlen; 134125727Snjl if (outlen > 70 || n == sys_nsig - 1) { 13520902Ssteve out1str("\n"); 136125727Snjl outlen = 0; 137125727Snjl } else { 13820902Ssteve out1c(' '); 139125727Snjl } 14020902Ssteve } 14120902Ssteve} 14220902Ssteve 14320902Ssteve 14420902Ssteve/* 1451556Srgrimes * The trap builtin. 1461556Srgrimes */ 14717987Speterint 14890111Simptrapcmd(int argc, char **argv) 14917987Speter{ 1501556Srgrimes char *action; 1511556Srgrimes int signo; 1521556Srgrimes 1531556Srgrimes if (argc <= 1) { 154125155Snjl for (signo = 0 ; signo < sys_nsig ; signo++) { 155125727Snjl if (signo < NSIG && trap[signo] != NULL) { 156125727Snjl if (signo == 0) { 157125727Snjl out1fmt("trap -- '%s' %s\n", 158125727Snjl trap[signo], "exit"); 159125727Snjl } else if (sys_signame[signo]) { 160125727Snjl out1fmt("trap -- '%s' %s\n", 161125727Snjl trap[signo], sys_signame[signo]); 162125727Snjl } else { 163125727Snjl out1fmt("trap -- '%s' %d\n", 164125727Snjl trap[signo], signo); 165125727Snjl } 166125727Snjl } 1671556Srgrimes } 1681556Srgrimes return 0; 1691556Srgrimes } 17020902Ssteve action = NULL; 17120902Ssteve if (*++argv && strcmp(*argv, "--") == 0) 17220902Ssteve argv++; 17320902Ssteve if (*argv && sigstring_to_signum(*argv) == -1) { 17420902Ssteve if ((*argv)[0] != '-') { 17520902Ssteve action = *argv; 17620902Ssteve argv++; 17720902Ssteve } else if ((*argv)[1] == '\0') { 17820902Ssteve argv++; 17920902Ssteve } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 18020902Ssteve printsignals(); 18120902Ssteve return 0; 18220902Ssteve } else { 18320902Ssteve error("bad option %s", *argv); 18420902Ssteve } 18520902Ssteve } 18620902Ssteve while (*argv) { 18720902Ssteve if ((signo = sigstring_to_signum(*argv)) == -1) 18820902Ssteve error("bad signal %s", *argv); 1891556Srgrimes INTOFF; 1901556Srgrimes if (action) 1911556Srgrimes action = savestr(action); 1921556Srgrimes if (trap[signo]) 1931556Srgrimes ckfree(trap[signo]); 1941556Srgrimes trap[signo] = action; 1951556Srgrimes if (signo != 0) 1961556Srgrimes setsignal(signo); 1971556Srgrimes INTON; 19820902Ssteve argv++; 1991556Srgrimes } 2001556Srgrimes return 0; 2011556Srgrimes} 2021556Srgrimes 2031556Srgrimes 2041556Srgrimes/* 2051556Srgrimes * Clear traps on a fork. 2061556Srgrimes */ 2071556Srgrimesvoid 20890111Simpclear_traps(void) 20920902Ssteve{ 21038950Scracauer char *volatile *tp; 2111556Srgrimes 21220902Ssteve for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 2131556Srgrimes if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 2141556Srgrimes INTOFF; 2151556Srgrimes ckfree(*tp); 2161556Srgrimes *tp = NULL; 2171556Srgrimes if (tp != &trap[0]) 2181556Srgrimes setsignal(tp - trap); 2191556Srgrimes INTON; 2201556Srgrimes } 2211556Srgrimes } 2221556Srgrimes} 2231556Srgrimes 2241556Srgrimes 2251556Srgrimes/* 2261556Srgrimes * Set the signal handler for the specified signal. The routine figures 2271556Srgrimes * out what it should be set to. 2281556Srgrimes */ 22931098Sbdevoid 23090111Simpsetsignal(int signo) 23117987Speter{ 2321556Srgrimes int action; 23331098Sbde sig_t sig, sigact = SIG_DFL; 2341556Srgrimes char *t; 2351556Srgrimes 2361556Srgrimes if ((t = trap[signo]) == NULL) 2371556Srgrimes action = S_DFL; 2381556Srgrimes else if (*t != '\0') 2391556Srgrimes action = S_CATCH; 2401556Srgrimes else 2411556Srgrimes action = S_IGN; 24238521Scracauer if (action == S_DFL) { 2431556Srgrimes switch (signo) { 2441556Srgrimes case SIGINT: 24538521Scracauer action = S_CATCH; 2461556Srgrimes break; 2471556Srgrimes case SIGQUIT: 2481556Srgrimes#ifdef DEBUG 2491556Srgrimes { 2501556Srgrimes extern int debug; 2511556Srgrimes 2521556Srgrimes if (debug) 2531556Srgrimes break; 2541556Srgrimes } 2551556Srgrimes#endif 25638535Scracauer action = S_CATCH; 25738521Scracauer break; 2581556Srgrimes case SIGTERM: 25938521Scracauer if (rootshell && iflag) 2601556Srgrimes action = S_IGN; 2611556Srgrimes break; 2621556Srgrimes#if JOBS 2631556Srgrimes case SIGTSTP: 2641556Srgrimes case SIGTTOU: 26538521Scracauer if (rootshell && mflag) 2661556Srgrimes action = S_IGN; 2671556Srgrimes break; 2681556Srgrimes#endif 269100578Stjr#ifndef NO_HISTORY 270100578Stjr case SIGWINCH: 271100588Stjr if (rootshell && iflag) 272100578Stjr action = S_CATCH; 273100578Stjr break; 274100578Stjr#endif 2751556Srgrimes } 2761556Srgrimes } 27717987Speter 27820902Ssteve t = &sigmode[signo]; 2798855Srgrimes if (*t == 0) { 2808855Srgrimes /* 2818855Srgrimes * current setting unknown 2821556Srgrimes */ 28317987Speter if (!getsigaction(signo, &sigact)) { 28417987Speter /* 28517987Speter * Pretend it worked; maybe we should give a warning 28617987Speter * here, but other shells don't. We don't alter 28717987Speter * sigmode, so that we retry every time. 28817987Speter */ 28931098Sbde return; 29017987Speter } 2911556Srgrimes if (sigact == SIG_IGN) { 2928855Srgrimes if (mflag && (signo == SIGTSTP || 2931556Srgrimes signo == SIGTTIN || signo == SIGTTOU)) { 2941556Srgrimes *t = S_IGN; /* don't hard ignore these */ 2951556Srgrimes } else 2961556Srgrimes *t = S_HARD_IGN; 2971556Srgrimes } else { 2981556Srgrimes *t = S_RESET; /* force to be set */ 2991556Srgrimes } 3001556Srgrimes } 3011556Srgrimes if (*t == S_HARD_IGN || *t == action) 30231098Sbde return; 3031556Srgrimes switch (action) { 3041556Srgrimes case S_DFL: sigact = SIG_DFL; break; 3051556Srgrimes case S_CATCH: sigact = onsig; break; 3061556Srgrimes case S_IGN: sigact = SIG_IGN; break; 3071556Srgrimes } 3081556Srgrimes *t = action; 30931098Sbde sig = signal(signo, sigact); 31031098Sbde if (sig != SIG_ERR && action == S_CATCH) 31131098Sbde siginterrupt(signo, 1); 3121556Srgrimes} 3131556Srgrimes 31420902Ssteve 3151556Srgrimes/* 3161556Srgrimes * Return the current setting for sig w/o changing it. 3171556Srgrimes */ 31817987Speterstatic int 31990111Simpgetsigaction(int signo, sig_t *sigact) 32017987Speter{ 3211556Srgrimes struct sigaction sa; 3221556Srgrimes 3231556Srgrimes if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 32417987Speter return 0; 32517987Speter *sigact = (sig_t) sa.sa_handler; 32617987Speter return 1; 3271556Srgrimes} 3281556Srgrimes 32920902Ssteve 3301556Srgrimes/* 3311556Srgrimes * Ignore a signal. 3321556Srgrimes */ 3331556Srgrimesvoid 33490111Simpignoresig(int signo) 33517987Speter{ 33620902Ssteve 33720902Ssteve if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 3381556Srgrimes signal(signo, SIG_IGN); 3391556Srgrimes } 34020902Ssteve sigmode[signo] = S_HARD_IGN; 3411556Srgrimes} 3421556Srgrimes 3431556Srgrimes 3441556Srgrimes#ifdef mkinit 34517987SpeterINCLUDE <signal.h> 3461556SrgrimesINCLUDE "trap.h" 3471556Srgrimes 3481556SrgrimesSHELLPROC { 3491556Srgrimes char *sm; 3501556Srgrimes 3511556Srgrimes clear_traps(); 35217987Speter for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 3531556Srgrimes if (*sm == S_IGN) 3541556Srgrimes *sm = S_HARD_IGN; 3551556Srgrimes } 3561556Srgrimes} 3571556Srgrimes#endif 3581556Srgrimes 3591556Srgrimes 3601556Srgrimes/* 3611556Srgrimes * Signal handler. 3621556Srgrimes */ 3631556Srgrimesvoid 36490111Simponsig(int signo) 36517987Speter{ 36631098Sbde 3671556Srgrimes if (signo == SIGINT && trap[SIGINT] == NULL) { 3681556Srgrimes onint(); 3691556Srgrimes return; 3701556Srgrimes } 37138950Scracauer 37220902Ssteve if (signo != SIGCHLD || !ignore_sigchld) 37320902Ssteve gotsig[signo] = 1; 3741556Srgrimes pendingsigs++; 37538950Scracauer 37638950Scracauer /* If we are currently in a wait builtin, prepare to break it */ 37738950Scracauer if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 37838521Scracauer breakwaitcmd = 1; 37938950Scracauer /* 38039056Scracauer * If a trap is set, not ignored and not the null command, we need 38139056Scracauer * to make sure traps are executed even when a child blocks signals. 38238950Scracauer */ 38345221Scracauer if (Tflag && 38445221Scracauer trap[signo] != NULL && 385149825Srse ! (trap[signo][0] == '\0') && 38639049Scracauer ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 38739049Scracauer breakwaitcmd = 1; 388100578Stjr 389100578Stjr#ifndef NO_HISTORY 390100578Stjr if (signo == SIGWINCH) 391100588Stjr gotwinch = 1; 392100578Stjr#endif 3931556Srgrimes} 3941556Srgrimes 3951556Srgrimes 3961556Srgrimes/* 3971556Srgrimes * Called to execute a trap. Perhaps we should avoid entering new trap 3981556Srgrimes * handlers while we are executing a trap handler. 3991556Srgrimes */ 4001556Srgrimesvoid 40190111Simpdotrap(void) 40220902Ssteve{ 4031556Srgrimes int i; 4041556Srgrimes int savestatus; 4051556Srgrimes 40638521Scracauer in_dotrap++; 4071556Srgrimes for (;;) { 40820902Ssteve for (i = 1; i < NSIG; i++) { 40920902Ssteve if (gotsig[i]) { 41020902Ssteve gotsig[i] = 0; 41120902Ssteve if (trap[i]) { 41220902Ssteve /* 413125728Snjl * Ignore SIGCHLD to avoid infinite 414125728Snjl * recursion if the trap action does 415125728Snjl * a fork. 41620902Ssteve */ 41720902Ssteve if (i == SIGCHLD) 41820902Ssteve ignore_sigchld++; 41920902Ssteve savestatus = exitstatus; 42020902Ssteve evalstring(trap[i]); 42120902Ssteve exitstatus = savestatus; 42220902Ssteve if (i == SIGCHLD) 42320902Ssteve ignore_sigchld--; 42420902Ssteve } 4251556Srgrimes break; 42620902Ssteve } 4271556Srgrimes } 42820902Ssteve if (i >= NSIG) 42920902Ssteve break; 4301556Srgrimes } 43138521Scracauer in_dotrap--; 4321556Srgrimes pendingsigs = 0; 4331556Srgrimes} 4341556Srgrimes 4351556Srgrimes 4361556Srgrimes/* 4371556Srgrimes * Controls whether the shell is interactive or not. 4381556Srgrimes */ 4391556Srgrimesvoid 44090111Simpsetinteractive(int on) 44117987Speter{ 44238521Scracauer static int is_interactive = -1; 4431556Srgrimes 4441556Srgrimes if (on == is_interactive) 4451556Srgrimes return; 4461556Srgrimes setsignal(SIGINT); 4471556Srgrimes setsignal(SIGQUIT); 4481556Srgrimes setsignal(SIGTERM); 449100578Stjr#ifndef NO_HISTORY 450100578Stjr setsignal(SIGWINCH); 451100578Stjr#endif 4521556Srgrimes is_interactive = on; 4531556Srgrimes} 4541556Srgrimes 4551556Srgrimes 4561556Srgrimes/* 4571556Srgrimes * Called to exit the shell. 4581556Srgrimes */ 4591556Srgrimesvoid 46090111Simpexitshell(int status) 46117987Speter{ 4621556Srgrimes struct jmploc loc1, loc2; 4631556Srgrimes char *p; 4641556Srgrimes 4651556Srgrimes TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 4661556Srgrimes if (setjmp(loc1.loc)) { 4671556Srgrimes goto l1; 4681556Srgrimes } 4691556Srgrimes if (setjmp(loc2.loc)) { 4701556Srgrimes goto l2; 4711556Srgrimes } 4721556Srgrimes handler = &loc1; 4731556Srgrimes if ((p = trap[0]) != NULL && *p != '\0') { 4741556Srgrimes trap[0] = NULL; 4751556Srgrimes evalstring(p); 4761556Srgrimes } 4771556Srgrimesl1: handler = &loc2; /* probably unnecessary */ 4781556Srgrimes flushall(); 4791556Srgrimes#if JOBS 4801556Srgrimes setjobctl(0); 4811556Srgrimes#endif 4821556Srgrimesl2: _exit(status); 4831556Srgrimes} 484