trap.c revision 100578
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 * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 371556Srgrimes#ifndef lint 3836150Scharnier#if 0 3936150Scharnierstatic char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; 4036150Scharnier#endif 411556Srgrimes#endif /* not lint */ 4299110Sobrien#include <sys/cdefs.h> 4399110Sobrien__FBSDID("$FreeBSD: head/bin/sh/trap.c 100578 2002-07-23 15:05:00Z tjr $"); 441556Srgrimes 4517987Speter#include <signal.h> 4617987Speter#include <unistd.h> 4717987Speter#include <stdlib.h> 4817987Speter 491556Srgrimes#include "shell.h" 501556Srgrimes#include "main.h" 511556Srgrimes#include "nodes.h" /* for other headers */ 521556Srgrimes#include "eval.h" 531556Srgrimes#include "jobs.h" 5417987Speter#include "show.h" 551556Srgrimes#include "options.h" 561556Srgrimes#include "syntax.h" 571556Srgrimes#include "output.h" 581556Srgrimes#include "memalloc.h" 591556Srgrimes#include "error.h" 601556Srgrimes#include "trap.h" 611556Srgrimes#include "mystring.h" 62100578Stjr#include "myhistedit.h" 631556Srgrimes 641556Srgrimes 651556Srgrimes/* 661556Srgrimes * Sigmode records the current value of the signal handlers for the various 671556Srgrimes * modes. A value of zero means that the current handler is not known. 681556Srgrimes * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 691556Srgrimes */ 701556Srgrimes 711556Srgrimes#define S_DFL 1 /* default signal handling (SIG_DFL) */ 721556Srgrimes#define S_CATCH 2 /* signal is caught */ 731556Srgrimes#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 7446684Skris#define S_HARD_IGN 4 /* signal is ignored permanently */ 751556Srgrimes#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 761556Srgrimes 771556Srgrimes 7817987SpeterMKINIT char sigmode[NSIG]; /* current value of signal */ 7938521Scracauerint pendingsigs; /* indicates some signal received */ 8038536Scracauerint in_dotrap; /* do we execute in a trap handler? */ 8138950Scracauerstatic char *volatile trap[NSIG]; /* trap handler commands */ 8238521Scracauerstatic volatile sig_atomic_t gotsig[NSIG]; 8338521Scracauer /* indicates specified signal received */ 8420902Sstevestatic int ignore_sigchld; /* Used while handling SIGCHLD traps. */ 851556Srgrimes 8690111Simpstatic int getsigaction(int, sig_t *); 8717987Speter 8820902Ssteve 891556Srgrimes/* 9020902Ssteve * Map a string to a signal number. 9120902Ssteve */ 9220902Sstevestatic int 9390111Simpsigstring_to_signum(char *sig) 9420902Ssteve{ 9520902Ssteve 9620902Ssteve if (is_number(sig)) { 9720902Ssteve int signo; 9820902Ssteve 9920902Ssteve signo = atoi(sig); 10020902Ssteve return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 10120902Ssteve } else if (strcasecmp(sig, "exit") == 0) { 10220902Ssteve return (0); 10320902Ssteve } else { 10420902Ssteve int n; 10520902Ssteve 10620902Ssteve if (strncasecmp(sig, "sig", 3) == 0) 10720902Ssteve sig += 3; 10820902Ssteve for (n = 1; n < NSIG; n++) 10920902Ssteve if (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{ 12220902Ssteve int n; 12320902Ssteve 12420902Ssteve for (n = 1; n < NSIG; n++) { 12520902Ssteve out1fmt("%s", sys_signame[n]); 12620902Ssteve if (n == (NSIG / 2) || n == (NSIG - 1)) 12720902Ssteve out1str("\n"); 12820902Ssteve else 12920902Ssteve out1c(' '); 13020902Ssteve } 13120902Ssteve} 13220902Ssteve 13320902Ssteve 13420902Ssteve/* 1351556Srgrimes * The trap builtin. 1361556Srgrimes */ 13717987Speterint 13890111Simptrapcmd(int argc, char **argv) 13917987Speter{ 1401556Srgrimes char *action; 1411556Srgrimes int signo; 1421556Srgrimes 1431556Srgrimes if (argc <= 1) { 14420902Ssteve for (signo = 0 ; signo < NSIG ; signo++) { 1451556Srgrimes if (trap[signo] != NULL) 14620902Ssteve out1fmt("trap -- '%s' %s\n", trap[signo], 14720902Ssteve (signo) ? sys_signame[signo] : "exit"); 1481556Srgrimes } 1491556Srgrimes return 0; 1501556Srgrimes } 15120902Ssteve action = NULL; 15220902Ssteve if (*++argv && strcmp(*argv, "--") == 0) 15320902Ssteve argv++; 15420902Ssteve if (*argv && sigstring_to_signum(*argv) == -1) { 15520902Ssteve if ((*argv)[0] != '-') { 15620902Ssteve action = *argv; 15720902Ssteve argv++; 15820902Ssteve } else if ((*argv)[1] == '\0') { 15920902Ssteve argv++; 16020902Ssteve } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 16120902Ssteve printsignals(); 16220902Ssteve return 0; 16320902Ssteve } else { 16420902Ssteve error("bad option %s", *argv); 16520902Ssteve } 16620902Ssteve } 16720902Ssteve while (*argv) { 16820902Ssteve if ((signo = sigstring_to_signum(*argv)) == -1) 16920902Ssteve error("bad signal %s", *argv); 1701556Srgrimes INTOFF; 1711556Srgrimes if (action) 1721556Srgrimes action = savestr(action); 1731556Srgrimes if (trap[signo]) 1741556Srgrimes ckfree(trap[signo]); 1751556Srgrimes trap[signo] = action; 1761556Srgrimes if (signo != 0) 1771556Srgrimes setsignal(signo); 1781556Srgrimes INTON; 17920902Ssteve argv++; 1801556Srgrimes } 1811556Srgrimes return 0; 1821556Srgrimes} 1831556Srgrimes 1841556Srgrimes 1851556Srgrimes/* 1861556Srgrimes * Clear traps on a fork. 1871556Srgrimes */ 1881556Srgrimesvoid 18990111Simpclear_traps(void) 19020902Ssteve{ 19138950Scracauer char *volatile *tp; 1921556Srgrimes 19320902Ssteve for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 1941556Srgrimes if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 1951556Srgrimes INTOFF; 1961556Srgrimes ckfree(*tp); 1971556Srgrimes *tp = NULL; 1981556Srgrimes if (tp != &trap[0]) 1991556Srgrimes setsignal(tp - trap); 2001556Srgrimes INTON; 2011556Srgrimes } 2021556Srgrimes } 2031556Srgrimes} 2041556Srgrimes 2051556Srgrimes 2061556Srgrimes/* 2071556Srgrimes * Set the signal handler for the specified signal. The routine figures 2081556Srgrimes * out what it should be set to. 2091556Srgrimes */ 21031098Sbdevoid 21190111Simpsetsignal(int signo) 21217987Speter{ 2131556Srgrimes int action; 21431098Sbde sig_t sig, sigact = SIG_DFL; 2151556Srgrimes char *t; 2161556Srgrimes 2171556Srgrimes if ((t = trap[signo]) == NULL) 2181556Srgrimes action = S_DFL; 2191556Srgrimes else if (*t != '\0') 2201556Srgrimes action = S_CATCH; 2211556Srgrimes else 2221556Srgrimes action = S_IGN; 22338521Scracauer if (action == S_DFL) { 2241556Srgrimes switch (signo) { 2251556Srgrimes case SIGINT: 22638521Scracauer action = S_CATCH; 2271556Srgrimes break; 2281556Srgrimes case SIGQUIT: 2291556Srgrimes#ifdef DEBUG 2301556Srgrimes { 2311556Srgrimes extern int debug; 2321556Srgrimes 2331556Srgrimes if (debug) 2341556Srgrimes break; 2351556Srgrimes } 2361556Srgrimes#endif 23738535Scracauer action = S_CATCH; 23838521Scracauer break; 2391556Srgrimes case SIGTERM: 24038521Scracauer if (rootshell && iflag) 2411556Srgrimes action = S_IGN; 2421556Srgrimes break; 2431556Srgrimes#if JOBS 2441556Srgrimes case SIGTSTP: 2451556Srgrimes case SIGTTOU: 24638521Scracauer if (rootshell && mflag) 2471556Srgrimes action = S_IGN; 2481556Srgrimes break; 2491556Srgrimes#endif 250100578Stjr#ifndef NO_HISTORY 251100578Stjr case SIGWINCH: 252100578Stjr if (rootshell && iflag && el != NULL) 253100578Stjr action = S_CATCH; 254100578Stjr break; 255100578Stjr#endif 2561556Srgrimes } 2571556Srgrimes } 25817987Speter 25920902Ssteve t = &sigmode[signo]; 2608855Srgrimes if (*t == 0) { 2618855Srgrimes /* 2628855Srgrimes * current setting unknown 2631556Srgrimes */ 26417987Speter if (!getsigaction(signo, &sigact)) { 26517987Speter /* 26617987Speter * Pretend it worked; maybe we should give a warning 26717987Speter * here, but other shells don't. We don't alter 26817987Speter * sigmode, so that we retry every time. 26917987Speter */ 27031098Sbde return; 27117987Speter } 2721556Srgrimes if (sigact == SIG_IGN) { 2738855Srgrimes if (mflag && (signo == SIGTSTP || 2741556Srgrimes signo == SIGTTIN || signo == SIGTTOU)) { 2751556Srgrimes *t = S_IGN; /* don't hard ignore these */ 2761556Srgrimes } else 2771556Srgrimes *t = S_HARD_IGN; 2781556Srgrimes } else { 2791556Srgrimes *t = S_RESET; /* force to be set */ 2801556Srgrimes } 2811556Srgrimes } 2821556Srgrimes if (*t == S_HARD_IGN || *t == action) 28331098Sbde return; 2841556Srgrimes switch (action) { 2851556Srgrimes case S_DFL: sigact = SIG_DFL; break; 2861556Srgrimes case S_CATCH: sigact = onsig; break; 2871556Srgrimes case S_IGN: sigact = SIG_IGN; break; 2881556Srgrimes } 2891556Srgrimes *t = action; 29031098Sbde sig = signal(signo, sigact); 29131098Sbde if (sig != SIG_ERR && action == S_CATCH) 29231098Sbde siginterrupt(signo, 1); 2931556Srgrimes} 2941556Srgrimes 29520902Ssteve 2961556Srgrimes/* 2971556Srgrimes * Return the current setting for sig w/o changing it. 2981556Srgrimes */ 29917987Speterstatic int 30090111Simpgetsigaction(int signo, sig_t *sigact) 30117987Speter{ 3021556Srgrimes struct sigaction sa; 3031556Srgrimes 3041556Srgrimes if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 30517987Speter return 0; 30617987Speter *sigact = (sig_t) sa.sa_handler; 30717987Speter return 1; 3081556Srgrimes} 3091556Srgrimes 31020902Ssteve 3111556Srgrimes/* 3121556Srgrimes * Ignore a signal. 3131556Srgrimes */ 3141556Srgrimesvoid 31590111Simpignoresig(int signo) 31617987Speter{ 31720902Ssteve 31820902Ssteve if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 3191556Srgrimes signal(signo, SIG_IGN); 3201556Srgrimes } 32120902Ssteve sigmode[signo] = S_HARD_IGN; 3221556Srgrimes} 3231556Srgrimes 3241556Srgrimes 3251556Srgrimes#ifdef mkinit 32617987SpeterINCLUDE <signal.h> 3271556SrgrimesINCLUDE "trap.h" 3281556Srgrimes 3291556SrgrimesSHELLPROC { 3301556Srgrimes char *sm; 3311556Srgrimes 3321556Srgrimes clear_traps(); 33317987Speter for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 3341556Srgrimes if (*sm == S_IGN) 3351556Srgrimes *sm = S_HARD_IGN; 3361556Srgrimes } 3371556Srgrimes} 3381556Srgrimes#endif 3391556Srgrimes 3401556Srgrimes 3411556Srgrimes/* 3421556Srgrimes * Signal handler. 3431556Srgrimes */ 3441556Srgrimesvoid 34590111Simponsig(int signo) 34617987Speter{ 34731098Sbde 3481556Srgrimes if (signo == SIGINT && trap[SIGINT] == NULL) { 3491556Srgrimes onint(); 3501556Srgrimes return; 3511556Srgrimes } 35238950Scracauer 35320902Ssteve if (signo != SIGCHLD || !ignore_sigchld) 35420902Ssteve gotsig[signo] = 1; 3551556Srgrimes pendingsigs++; 35638950Scracauer 35738950Scracauer /* If we are currently in a wait builtin, prepare to break it */ 35838950Scracauer if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 35938521Scracauer breakwaitcmd = 1; 36038950Scracauer /* 36139056Scracauer * If a trap is set, not ignored and not the null command, we need 36239056Scracauer * to make sure traps are executed even when a child blocks signals. 36338950Scracauer */ 36445221Scracauer if (Tflag && 36545221Scracauer trap[signo] != NULL && 36639056Scracauer ! trap[signo][0] == '\0' && 36739049Scracauer ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 36839049Scracauer breakwaitcmd = 1; 369100578Stjr 370100578Stjr#ifndef NO_HISTORY 371100578Stjr if (signo == SIGWINCH) 372100578Stjr el_resize(el); 373100578Stjr#endif 3741556Srgrimes} 3751556Srgrimes 3761556Srgrimes 3771556Srgrimes/* 3781556Srgrimes * Called to execute a trap. Perhaps we should avoid entering new trap 3791556Srgrimes * handlers while we are executing a trap handler. 3801556Srgrimes */ 3811556Srgrimesvoid 38290111Simpdotrap(void) 38320902Ssteve{ 3841556Srgrimes int i; 3851556Srgrimes int savestatus; 3861556Srgrimes 38738521Scracauer in_dotrap++; 3881556Srgrimes for (;;) { 38920902Ssteve for (i = 1; i < NSIG; i++) { 39020902Ssteve if (gotsig[i]) { 39120902Ssteve gotsig[i] = 0; 39220902Ssteve if (trap[i]) { 39320902Ssteve /* 39420902Ssteve * Ignore SIGCHLD to avoid infinite recursion 39520902Ssteve * if the trap action does a fork. 39620902Ssteve */ 39720902Ssteve if (i == SIGCHLD) 39820902Ssteve ignore_sigchld++; 39920902Ssteve savestatus = exitstatus; 40020902Ssteve evalstring(trap[i]); 40120902Ssteve exitstatus = savestatus; 40220902Ssteve if (i == SIGCHLD) 40320902Ssteve ignore_sigchld--; 40420902Ssteve } 4051556Srgrimes break; 40620902Ssteve } 4071556Srgrimes } 40820902Ssteve if (i >= NSIG) 40920902Ssteve break; 4101556Srgrimes } 41138521Scracauer in_dotrap--; 4121556Srgrimes pendingsigs = 0; 4131556Srgrimes} 4141556Srgrimes 4151556Srgrimes 4161556Srgrimes/* 4171556Srgrimes * Controls whether the shell is interactive or not. 4181556Srgrimes */ 4191556Srgrimesvoid 42090111Simpsetinteractive(int on) 42117987Speter{ 42238521Scracauer static int is_interactive = -1; 4231556Srgrimes 4241556Srgrimes if (on == is_interactive) 4251556Srgrimes return; 4261556Srgrimes setsignal(SIGINT); 4271556Srgrimes setsignal(SIGQUIT); 4281556Srgrimes setsignal(SIGTERM); 429100578Stjr#ifndef NO_HISTORY 430100578Stjr setsignal(SIGWINCH); 431100578Stjr#endif 4321556Srgrimes is_interactive = on; 4331556Srgrimes} 4341556Srgrimes 4351556Srgrimes 4361556Srgrimes/* 4371556Srgrimes * Called to exit the shell. 4381556Srgrimes */ 4391556Srgrimesvoid 44090111Simpexitshell(int status) 44117987Speter{ 4421556Srgrimes struct jmploc loc1, loc2; 4431556Srgrimes char *p; 4441556Srgrimes 4451556Srgrimes TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 4461556Srgrimes if (setjmp(loc1.loc)) { 4471556Srgrimes goto l1; 4481556Srgrimes } 4491556Srgrimes if (setjmp(loc2.loc)) { 4501556Srgrimes goto l2; 4511556Srgrimes } 4521556Srgrimes handler = &loc1; 4531556Srgrimes if ((p = trap[0]) != NULL && *p != '\0') { 4541556Srgrimes trap[0] = NULL; 4551556Srgrimes evalstring(p); 4561556Srgrimes } 4571556Srgrimesl1: handler = &loc2; /* probably unnecessary */ 4581556Srgrimes flushall(); 4591556Srgrimes#if JOBS 4601556Srgrimes setjobctl(0); 4611556Srgrimes#endif 4621556Srgrimesl2: _exit(status); 4631556Srgrimes} 464