trap.c revision 193169
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 193169 2009-05-31 12:36:14Z stefanf $"); 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 */ 78157811Sschweikhstatic 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) { 156153244Sstefanf out1str("trap -- "); 157153244Sstefanf out1qstr(trap[signo]); 158125727Snjl if (signo == 0) { 159153244Sstefanf out1str(" exit\n"); 160125727Snjl } else if (sys_signame[signo]) { 161153244Sstefanf out1fmt(" %s\n", sys_signame[signo]); 162125727Snjl } else { 163153244Sstefanf out1fmt(" %d\n", signo); 164125727Snjl } 165125727Snjl } 1661556Srgrimes } 1671556Srgrimes return 0; 1681556Srgrimes } 16920902Ssteve action = NULL; 17020902Ssteve if (*++argv && strcmp(*argv, "--") == 0) 17120902Ssteve argv++; 17220902Ssteve if (*argv && sigstring_to_signum(*argv) == -1) { 17320902Ssteve if ((*argv)[0] != '-') { 17420902Ssteve action = *argv; 17520902Ssteve argv++; 17620902Ssteve } else if ((*argv)[1] == '\0') { 17720902Ssteve argv++; 17820902Ssteve } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 17920902Ssteve printsignals(); 18020902Ssteve return 0; 18120902Ssteve } else { 18220902Ssteve error("bad option %s", *argv); 18320902Ssteve } 18420902Ssteve } 18520902Ssteve while (*argv) { 18620902Ssteve if ((signo = sigstring_to_signum(*argv)) == -1) 18720902Ssteve error("bad signal %s", *argv); 1881556Srgrimes INTOFF; 1891556Srgrimes if (action) 1901556Srgrimes action = savestr(action); 1911556Srgrimes if (trap[signo]) 1921556Srgrimes ckfree(trap[signo]); 1931556Srgrimes trap[signo] = action; 1941556Srgrimes if (signo != 0) 1951556Srgrimes setsignal(signo); 1961556Srgrimes INTON; 19720902Ssteve argv++; 1981556Srgrimes } 1991556Srgrimes return 0; 2001556Srgrimes} 2011556Srgrimes 2021556Srgrimes 2031556Srgrimes/* 2041556Srgrimes * Clear traps on a fork. 2051556Srgrimes */ 2061556Srgrimesvoid 20790111Simpclear_traps(void) 20820902Ssteve{ 20938950Scracauer char *volatile *tp; 2101556Srgrimes 21120902Ssteve for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 2121556Srgrimes if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 2131556Srgrimes INTOFF; 2141556Srgrimes ckfree(*tp); 2151556Srgrimes *tp = NULL; 2161556Srgrimes if (tp != &trap[0]) 2171556Srgrimes setsignal(tp - trap); 2181556Srgrimes INTON; 2191556Srgrimes } 2201556Srgrimes } 2211556Srgrimes} 2221556Srgrimes 2231556Srgrimes 2241556Srgrimes/* 2251556Srgrimes * Set the signal handler for the specified signal. The routine figures 2261556Srgrimes * out what it should be set to. 2271556Srgrimes */ 22831098Sbdevoid 22990111Simpsetsignal(int signo) 23017987Speter{ 2311556Srgrimes int action; 23231098Sbde sig_t sig, sigact = SIG_DFL; 2331556Srgrimes char *t; 2341556Srgrimes 2351556Srgrimes if ((t = trap[signo]) == NULL) 2361556Srgrimes action = S_DFL; 2371556Srgrimes else if (*t != '\0') 2381556Srgrimes action = S_CATCH; 2391556Srgrimes else 2401556Srgrimes action = S_IGN; 24138521Scracauer if (action == S_DFL) { 2421556Srgrimes switch (signo) { 2431556Srgrimes case SIGINT: 24438521Scracauer action = S_CATCH; 2451556Srgrimes break; 2461556Srgrimes case SIGQUIT: 2471556Srgrimes#ifdef DEBUG 2481556Srgrimes { 2491556Srgrimes extern int debug; 2501556Srgrimes 2511556Srgrimes if (debug) 2521556Srgrimes break; 2531556Srgrimes } 2541556Srgrimes#endif 25538535Scracauer action = S_CATCH; 25638521Scracauer break; 2571556Srgrimes case SIGTERM: 25838521Scracauer if (rootshell && iflag) 2591556Srgrimes action = S_IGN; 2601556Srgrimes break; 2611556Srgrimes#if JOBS 2621556Srgrimes case SIGTSTP: 2631556Srgrimes case SIGTTOU: 26438521Scracauer if (rootshell && mflag) 2651556Srgrimes action = S_IGN; 2661556Srgrimes break; 2671556Srgrimes#endif 268100578Stjr#ifndef NO_HISTORY 269100578Stjr case SIGWINCH: 270100588Stjr if (rootshell && iflag) 271100578Stjr action = S_CATCH; 272100578Stjr break; 273100578Stjr#endif 2741556Srgrimes } 2751556Srgrimes } 27617987Speter 27720902Ssteve t = &sigmode[signo]; 2788855Srgrimes if (*t == 0) { 2798855Srgrimes /* 2808855Srgrimes * current setting unknown 2811556Srgrimes */ 28217987Speter if (!getsigaction(signo, &sigact)) { 28317987Speter /* 28417987Speter * Pretend it worked; maybe we should give a warning 28517987Speter * here, but other shells don't. We don't alter 28617987Speter * sigmode, so that we retry every time. 28717987Speter */ 28831098Sbde return; 28917987Speter } 2901556Srgrimes if (sigact == SIG_IGN) { 2918855Srgrimes if (mflag && (signo == SIGTSTP || 2921556Srgrimes signo == SIGTTIN || signo == SIGTTOU)) { 2931556Srgrimes *t = S_IGN; /* don't hard ignore these */ 2941556Srgrimes } else 2951556Srgrimes *t = S_HARD_IGN; 2961556Srgrimes } else { 2971556Srgrimes *t = S_RESET; /* force to be set */ 2981556Srgrimes } 2991556Srgrimes } 3001556Srgrimes if (*t == S_HARD_IGN || *t == action) 30131098Sbde return; 3021556Srgrimes switch (action) { 3031556Srgrimes case S_DFL: sigact = SIG_DFL; break; 3041556Srgrimes case S_CATCH: sigact = onsig; break; 3051556Srgrimes case S_IGN: sigact = SIG_IGN; break; 3061556Srgrimes } 3071556Srgrimes *t = action; 30831098Sbde sig = signal(signo, sigact); 30931098Sbde if (sig != SIG_ERR && action == S_CATCH) 31031098Sbde siginterrupt(signo, 1); 3111556Srgrimes} 3121556Srgrimes 31320902Ssteve 3141556Srgrimes/* 3151556Srgrimes * Return the current setting for sig w/o changing it. 3161556Srgrimes */ 31717987Speterstatic int 31890111Simpgetsigaction(int signo, sig_t *sigact) 31917987Speter{ 3201556Srgrimes struct sigaction sa; 3211556Srgrimes 3221556Srgrimes if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 32317987Speter return 0; 32417987Speter *sigact = (sig_t) sa.sa_handler; 32517987Speter return 1; 3261556Srgrimes} 3271556Srgrimes 32820902Ssteve 3291556Srgrimes/* 3301556Srgrimes * Ignore a signal. 3311556Srgrimes */ 3321556Srgrimesvoid 33390111Simpignoresig(int signo) 33417987Speter{ 33520902Ssteve 33620902Ssteve if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 3371556Srgrimes signal(signo, SIG_IGN); 3381556Srgrimes } 33920902Ssteve sigmode[signo] = S_HARD_IGN; 3401556Srgrimes} 3411556Srgrimes 3421556Srgrimes 3431556Srgrimes#ifdef mkinit 34417987SpeterINCLUDE <signal.h> 3451556SrgrimesINCLUDE "trap.h" 3461556Srgrimes 3471556SrgrimesSHELLPROC { 3481556Srgrimes char *sm; 3491556Srgrimes 3501556Srgrimes clear_traps(); 35117987Speter for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 3521556Srgrimes if (*sm == S_IGN) 3531556Srgrimes *sm = S_HARD_IGN; 3541556Srgrimes } 3551556Srgrimes} 3561556Srgrimes#endif 3571556Srgrimes 3581556Srgrimes 3591556Srgrimes/* 3601556Srgrimes * Signal handler. 3611556Srgrimes */ 3621556Srgrimesvoid 36390111Simponsig(int signo) 36417987Speter{ 36531098Sbde 3661556Srgrimes if (signo == SIGINT && trap[SIGINT] == NULL) { 3671556Srgrimes onint(); 3681556Srgrimes return; 3691556Srgrimes } 37038950Scracauer 37120902Ssteve if (signo != SIGCHLD || !ignore_sigchld) 37220902Ssteve gotsig[signo] = 1; 3731556Srgrimes pendingsigs++; 37438950Scracauer 37538950Scracauer /* If we are currently in a wait builtin, prepare to break it */ 37638950Scracauer if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 37738521Scracauer breakwaitcmd = 1; 378157811Sschweikh /* 379157811Sschweikh * If a trap is set, not ignored and not the null command, we need 38039056Scracauer * to make sure traps are executed even when a child blocks signals. 38138950Scracauer */ 38245221Scracauer if (Tflag && 383157811Sschweikh trap[signo] != NULL && 384149825Srse ! (trap[signo][0] == '\0') && 38539049Scracauer ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 38639049Scracauer breakwaitcmd = 1; 387100578Stjr 388100578Stjr#ifndef NO_HISTORY 389100578Stjr if (signo == SIGWINCH) 390100588Stjr gotwinch = 1; 391100578Stjr#endif 3921556Srgrimes} 3931556Srgrimes 3941556Srgrimes 3951556Srgrimes/* 3961556Srgrimes * Called to execute a trap. Perhaps we should avoid entering new trap 3971556Srgrimes * handlers while we are executing a trap handler. 3981556Srgrimes */ 3991556Srgrimesvoid 40090111Simpdotrap(void) 40120902Ssteve{ 4021556Srgrimes int i; 4031556Srgrimes int savestatus; 4041556Srgrimes 40538521Scracauer in_dotrap++; 4061556Srgrimes for (;;) { 40720902Ssteve for (i = 1; i < NSIG; i++) { 40820902Ssteve if (gotsig[i]) { 40920902Ssteve gotsig[i] = 0; 41020902Ssteve if (trap[i]) { 41120902Ssteve /* 412125728Snjl * Ignore SIGCHLD to avoid infinite 413125728Snjl * recursion if the trap action does 414125728Snjl * a fork. 41520902Ssteve */ 41620902Ssteve if (i == SIGCHLD) 41720902Ssteve ignore_sigchld++; 41820902Ssteve savestatus = exitstatus; 419193169Sstefanf evalstring(trap[i], 0); 42020902Ssteve exitstatus = savestatus; 42120902Ssteve if (i == SIGCHLD) 42220902Ssteve ignore_sigchld--; 42320902Ssteve } 4241556Srgrimes break; 42520902Ssteve } 4261556Srgrimes } 42720902Ssteve if (i >= NSIG) 42820902Ssteve break; 4291556Srgrimes } 43038521Scracauer in_dotrap--; 4311556Srgrimes pendingsigs = 0; 4321556Srgrimes} 4331556Srgrimes 4341556Srgrimes 4351556Srgrimes/* 4361556Srgrimes * Controls whether the shell is interactive or not. 4371556Srgrimes */ 4381556Srgrimesvoid 43990111Simpsetinteractive(int on) 44017987Speter{ 44138521Scracauer static int is_interactive = -1; 4421556Srgrimes 4431556Srgrimes if (on == is_interactive) 4441556Srgrimes return; 4451556Srgrimes setsignal(SIGINT); 4461556Srgrimes setsignal(SIGQUIT); 4471556Srgrimes setsignal(SIGTERM); 448100578Stjr#ifndef NO_HISTORY 449100578Stjr setsignal(SIGWINCH); 450100578Stjr#endif 4511556Srgrimes is_interactive = on; 4521556Srgrimes} 4531556Srgrimes 4541556Srgrimes 4551556Srgrimes/* 4561556Srgrimes * Called to exit the shell. 4571556Srgrimes */ 4581556Srgrimesvoid 45990111Simpexitshell(int status) 46017987Speter{ 4611556Srgrimes struct jmploc loc1, loc2; 4621556Srgrimes char *p; 4631556Srgrimes 4641556Srgrimes TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 4651556Srgrimes if (setjmp(loc1.loc)) { 4661556Srgrimes goto l1; 4671556Srgrimes } 4681556Srgrimes if (setjmp(loc2.loc)) { 4691556Srgrimes goto l2; 4701556Srgrimes } 4711556Srgrimes handler = &loc1; 4721556Srgrimes if ((p = trap[0]) != NULL && *p != '\0') { 4731556Srgrimes trap[0] = NULL; 474193169Sstefanf evalstring(p, 0); 4751556Srgrimes } 4761556Srgrimesl1: handler = &loc2; /* probably unnecessary */ 4771556Srgrimes flushall(); 4781556Srgrimes#if JOBS 4791556Srgrimes setjobctl(0); 4801556Srgrimes#endif 4811556Srgrimesl2: _exit(status); 4821556Srgrimes} 483