trap.c revision 125728
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 125728 2004-02-12 05:05:56Z njl $"); 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. */ 85100588Stjrvolatile sig_atomic_t gotwinch; 861556Srgrimes 8790111Simpstatic int getsigaction(int, sig_t *); 8817987Speter 8920902Ssteve 901556Srgrimes/* 9120902Ssteve * Map a string to a signal number. 92125727Snjl * 93125727Snjl * Note: the signal number may exceed NSIG. 9420902Ssteve */ 9520902Sstevestatic int 9690111Simpsigstring_to_signum(char *sig) 9720902Ssteve{ 9820902Ssteve 9920902Ssteve if (is_number(sig)) { 10020902Ssteve int signo; 10120902Ssteve 10220902Ssteve signo = atoi(sig); 10320902Ssteve return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 10420902Ssteve } else if (strcasecmp(sig, "exit") == 0) { 10520902Ssteve return (0); 10620902Ssteve } else { 10720902Ssteve int n; 10820902Ssteve 10920902Ssteve if (strncasecmp(sig, "sig", 3) == 0) 11020902Ssteve sig += 3; 111125155Snjl for (n = 1; n < sys_nsig; n++) 112125728Snjl if (sys_signame[n] && 113125728Snjl strcasecmp(sys_signame[n], sig) == 0) 11420902Ssteve return (n); 11520902Ssteve } 11620902Ssteve return (-1); 11720902Ssteve} 11820902Ssteve 11920902Ssteve 12020902Ssteve/* 12120902Ssteve * Print a list of valid signal names. 12220902Ssteve */ 12320902Sstevestatic void 12490111Simpprintsignals(void) 12520902Ssteve{ 126125727Snjl int n, outlen; 12720902Ssteve 128125727Snjl outlen = 0; 129125155Snjl for (n = 1; n < sys_nsig; n++) { 130125727Snjl if (sys_signame[n]) { 131125727Snjl out1fmt("%s", sys_signame[n]); 132125727Snjl outlen += strlen(sys_signame[n]); 133125727Snjl } else { 134125727Snjl out1fmt("%d", n); 135125727Snjl outlen += 3; /* good enough */ 136125727Snjl } 137125727Snjl ++outlen; 138125727Snjl if (outlen > 70 || n == sys_nsig - 1) { 13920902Ssteve out1str("\n"); 140125727Snjl outlen = 0; 141125727Snjl } else { 14220902Ssteve out1c(' '); 143125727Snjl } 14420902Ssteve } 14520902Ssteve} 14620902Ssteve 14720902Ssteve 14820902Ssteve/* 1491556Srgrimes * The trap builtin. 1501556Srgrimes */ 15117987Speterint 15290111Simptrapcmd(int argc, char **argv) 15317987Speter{ 1541556Srgrimes char *action; 1551556Srgrimes int signo; 1561556Srgrimes 1571556Srgrimes if (argc <= 1) { 158125155Snjl for (signo = 0 ; signo < sys_nsig ; signo++) { 159125727Snjl if (signo < NSIG && trap[signo] != NULL) { 160125727Snjl if (signo == 0) { 161125727Snjl out1fmt("trap -- '%s' %s\n", 162125727Snjl trap[signo], "exit"); 163125727Snjl } else if (sys_signame[signo]) { 164125727Snjl out1fmt("trap -- '%s' %s\n", 165125727Snjl trap[signo], sys_signame[signo]); 166125727Snjl } else { 167125727Snjl out1fmt("trap -- '%s' %d\n", 168125727Snjl trap[signo], signo); 169125727Snjl } 170125727Snjl } 1711556Srgrimes } 1721556Srgrimes return 0; 1731556Srgrimes } 17420902Ssteve action = NULL; 17520902Ssteve if (*++argv && strcmp(*argv, "--") == 0) 17620902Ssteve argv++; 17720902Ssteve if (*argv && sigstring_to_signum(*argv) == -1) { 17820902Ssteve if ((*argv)[0] != '-') { 17920902Ssteve action = *argv; 18020902Ssteve argv++; 18120902Ssteve } else if ((*argv)[1] == '\0') { 18220902Ssteve argv++; 18320902Ssteve } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 18420902Ssteve printsignals(); 18520902Ssteve return 0; 18620902Ssteve } else { 18720902Ssteve error("bad option %s", *argv); 18820902Ssteve } 18920902Ssteve } 19020902Ssteve while (*argv) { 19120902Ssteve if ((signo = sigstring_to_signum(*argv)) == -1) 19220902Ssteve error("bad signal %s", *argv); 1931556Srgrimes INTOFF; 1941556Srgrimes if (action) 1951556Srgrimes action = savestr(action); 1961556Srgrimes if (trap[signo]) 1971556Srgrimes ckfree(trap[signo]); 1981556Srgrimes trap[signo] = action; 1991556Srgrimes if (signo != 0) 2001556Srgrimes setsignal(signo); 2011556Srgrimes INTON; 20220902Ssteve argv++; 2031556Srgrimes } 2041556Srgrimes return 0; 2051556Srgrimes} 2061556Srgrimes 2071556Srgrimes 2081556Srgrimes/* 2091556Srgrimes * Clear traps on a fork. 2101556Srgrimes */ 2111556Srgrimesvoid 21290111Simpclear_traps(void) 21320902Ssteve{ 21438950Scracauer char *volatile *tp; 2151556Srgrimes 21620902Ssteve for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 2171556Srgrimes if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 2181556Srgrimes INTOFF; 2191556Srgrimes ckfree(*tp); 2201556Srgrimes *tp = NULL; 2211556Srgrimes if (tp != &trap[0]) 2221556Srgrimes setsignal(tp - trap); 2231556Srgrimes INTON; 2241556Srgrimes } 2251556Srgrimes } 2261556Srgrimes} 2271556Srgrimes 2281556Srgrimes 2291556Srgrimes/* 2301556Srgrimes * Set the signal handler for the specified signal. The routine figures 2311556Srgrimes * out what it should be set to. 2321556Srgrimes */ 23331098Sbdevoid 23490111Simpsetsignal(int signo) 23517987Speter{ 2361556Srgrimes int action; 23731098Sbde sig_t sig, sigact = SIG_DFL; 2381556Srgrimes char *t; 2391556Srgrimes 2401556Srgrimes if ((t = trap[signo]) == NULL) 2411556Srgrimes action = S_DFL; 2421556Srgrimes else if (*t != '\0') 2431556Srgrimes action = S_CATCH; 2441556Srgrimes else 2451556Srgrimes action = S_IGN; 24638521Scracauer if (action == S_DFL) { 2471556Srgrimes switch (signo) { 2481556Srgrimes case SIGINT: 24938521Scracauer action = S_CATCH; 2501556Srgrimes break; 2511556Srgrimes case SIGQUIT: 2521556Srgrimes#ifdef DEBUG 2531556Srgrimes { 2541556Srgrimes extern int debug; 2551556Srgrimes 2561556Srgrimes if (debug) 2571556Srgrimes break; 2581556Srgrimes } 2591556Srgrimes#endif 26038535Scracauer action = S_CATCH; 26138521Scracauer break; 2621556Srgrimes case SIGTERM: 26338521Scracauer if (rootshell && iflag) 2641556Srgrimes action = S_IGN; 2651556Srgrimes break; 2661556Srgrimes#if JOBS 2671556Srgrimes case SIGTSTP: 2681556Srgrimes case SIGTTOU: 26938521Scracauer if (rootshell && mflag) 2701556Srgrimes action = S_IGN; 2711556Srgrimes break; 2721556Srgrimes#endif 273100578Stjr#ifndef NO_HISTORY 274100578Stjr case SIGWINCH: 275100588Stjr if (rootshell && iflag) 276100578Stjr action = S_CATCH; 277100578Stjr break; 278100578Stjr#endif 2791556Srgrimes } 2801556Srgrimes } 28117987Speter 28220902Ssteve t = &sigmode[signo]; 2838855Srgrimes if (*t == 0) { 2848855Srgrimes /* 2858855Srgrimes * current setting unknown 2861556Srgrimes */ 28717987Speter if (!getsigaction(signo, &sigact)) { 28817987Speter /* 28917987Speter * Pretend it worked; maybe we should give a warning 29017987Speter * here, but other shells don't. We don't alter 29117987Speter * sigmode, so that we retry every time. 29217987Speter */ 29331098Sbde return; 29417987Speter } 2951556Srgrimes if (sigact == SIG_IGN) { 2968855Srgrimes if (mflag && (signo == SIGTSTP || 2971556Srgrimes signo == SIGTTIN || signo == SIGTTOU)) { 2981556Srgrimes *t = S_IGN; /* don't hard ignore these */ 2991556Srgrimes } else 3001556Srgrimes *t = S_HARD_IGN; 3011556Srgrimes } else { 3021556Srgrimes *t = S_RESET; /* force to be set */ 3031556Srgrimes } 3041556Srgrimes } 3051556Srgrimes if (*t == S_HARD_IGN || *t == action) 30631098Sbde return; 3071556Srgrimes switch (action) { 3081556Srgrimes case S_DFL: sigact = SIG_DFL; break; 3091556Srgrimes case S_CATCH: sigact = onsig; break; 3101556Srgrimes case S_IGN: sigact = SIG_IGN; break; 3111556Srgrimes } 3121556Srgrimes *t = action; 31331098Sbde sig = signal(signo, sigact); 31431098Sbde if (sig != SIG_ERR && action == S_CATCH) 31531098Sbde siginterrupt(signo, 1); 3161556Srgrimes} 3171556Srgrimes 31820902Ssteve 3191556Srgrimes/* 3201556Srgrimes * Return the current setting for sig w/o changing it. 3211556Srgrimes */ 32217987Speterstatic int 32390111Simpgetsigaction(int signo, sig_t *sigact) 32417987Speter{ 3251556Srgrimes struct sigaction sa; 3261556Srgrimes 3271556Srgrimes if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 32817987Speter return 0; 32917987Speter *sigact = (sig_t) sa.sa_handler; 33017987Speter return 1; 3311556Srgrimes} 3321556Srgrimes 33320902Ssteve 3341556Srgrimes/* 3351556Srgrimes * Ignore a signal. 3361556Srgrimes */ 3371556Srgrimesvoid 33890111Simpignoresig(int signo) 33917987Speter{ 34020902Ssteve 34120902Ssteve if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 3421556Srgrimes signal(signo, SIG_IGN); 3431556Srgrimes } 34420902Ssteve sigmode[signo] = S_HARD_IGN; 3451556Srgrimes} 3461556Srgrimes 3471556Srgrimes 3481556Srgrimes#ifdef mkinit 34917987SpeterINCLUDE <signal.h> 3501556SrgrimesINCLUDE "trap.h" 3511556Srgrimes 3521556SrgrimesSHELLPROC { 3531556Srgrimes char *sm; 3541556Srgrimes 3551556Srgrimes clear_traps(); 35617987Speter for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 3571556Srgrimes if (*sm == S_IGN) 3581556Srgrimes *sm = S_HARD_IGN; 3591556Srgrimes } 3601556Srgrimes} 3611556Srgrimes#endif 3621556Srgrimes 3631556Srgrimes 3641556Srgrimes/* 3651556Srgrimes * Signal handler. 3661556Srgrimes */ 3671556Srgrimesvoid 36890111Simponsig(int signo) 36917987Speter{ 37031098Sbde 3711556Srgrimes if (signo == SIGINT && trap[SIGINT] == NULL) { 3721556Srgrimes onint(); 3731556Srgrimes return; 3741556Srgrimes } 37538950Scracauer 37620902Ssteve if (signo != SIGCHLD || !ignore_sigchld) 37720902Ssteve gotsig[signo] = 1; 3781556Srgrimes pendingsigs++; 37938950Scracauer 38038950Scracauer /* If we are currently in a wait builtin, prepare to break it */ 38138950Scracauer if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 38238521Scracauer breakwaitcmd = 1; 38338950Scracauer /* 38439056Scracauer * If a trap is set, not ignored and not the null command, we need 38539056Scracauer * to make sure traps are executed even when a child blocks signals. 38638950Scracauer */ 38745221Scracauer if (Tflag && 38845221Scracauer trap[signo] != NULL && 38939056Scracauer ! trap[signo][0] == '\0' && 39039049Scracauer ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 39139049Scracauer breakwaitcmd = 1; 392100578Stjr 393100578Stjr#ifndef NO_HISTORY 394100578Stjr if (signo == SIGWINCH) 395100588Stjr gotwinch = 1; 396100578Stjr#endif 3971556Srgrimes} 3981556Srgrimes 3991556Srgrimes 4001556Srgrimes/* 4011556Srgrimes * Called to execute a trap. Perhaps we should avoid entering new trap 4021556Srgrimes * handlers while we are executing a trap handler. 4031556Srgrimes */ 4041556Srgrimesvoid 40590111Simpdotrap(void) 40620902Ssteve{ 4071556Srgrimes int i; 4081556Srgrimes int savestatus; 4091556Srgrimes 41038521Scracauer in_dotrap++; 4111556Srgrimes for (;;) { 41220902Ssteve for (i = 1; i < NSIG; i++) { 41320902Ssteve if (gotsig[i]) { 41420902Ssteve gotsig[i] = 0; 41520902Ssteve if (trap[i]) { 41620902Ssteve /* 417125728Snjl * Ignore SIGCHLD to avoid infinite 418125728Snjl * recursion if the trap action does 419125728Snjl * a fork. 42020902Ssteve */ 42120902Ssteve if (i == SIGCHLD) 42220902Ssteve ignore_sigchld++; 42320902Ssteve savestatus = exitstatus; 42420902Ssteve evalstring(trap[i]); 42520902Ssteve exitstatus = savestatus; 42620902Ssteve if (i == SIGCHLD) 42720902Ssteve ignore_sigchld--; 42820902Ssteve } 4291556Srgrimes break; 43020902Ssteve } 4311556Srgrimes } 43220902Ssteve if (i >= NSIG) 43320902Ssteve break; 4341556Srgrimes } 43538521Scracauer in_dotrap--; 4361556Srgrimes pendingsigs = 0; 4371556Srgrimes} 4381556Srgrimes 4391556Srgrimes 4401556Srgrimes/* 4411556Srgrimes * Controls whether the shell is interactive or not. 4421556Srgrimes */ 4431556Srgrimesvoid 44490111Simpsetinteractive(int on) 44517987Speter{ 44638521Scracauer static int is_interactive = -1; 4471556Srgrimes 4481556Srgrimes if (on == is_interactive) 4491556Srgrimes return; 4501556Srgrimes setsignal(SIGINT); 4511556Srgrimes setsignal(SIGQUIT); 4521556Srgrimes setsignal(SIGTERM); 453100578Stjr#ifndef NO_HISTORY 454100578Stjr setsignal(SIGWINCH); 455100578Stjr#endif 4561556Srgrimes is_interactive = on; 4571556Srgrimes} 4581556Srgrimes 4591556Srgrimes 4601556Srgrimes/* 4611556Srgrimes * Called to exit the shell. 4621556Srgrimes */ 4631556Srgrimesvoid 46490111Simpexitshell(int status) 46517987Speter{ 4661556Srgrimes struct jmploc loc1, loc2; 4671556Srgrimes char *p; 4681556Srgrimes 4691556Srgrimes TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 4701556Srgrimes if (setjmp(loc1.loc)) { 4711556Srgrimes goto l1; 4721556Srgrimes } 4731556Srgrimes if (setjmp(loc2.loc)) { 4741556Srgrimes goto l2; 4751556Srgrimes } 4761556Srgrimes handler = &loc1; 4771556Srgrimes if ((p = trap[0]) != NULL && *p != '\0') { 4781556Srgrimes trap[0] = NULL; 4791556Srgrimes evalstring(p); 4801556Srgrimes } 4811556Srgrimesl1: handler = &loc2; /* probably unnecessary */ 4821556Srgrimes flushall(); 4831556Srgrimes#if JOBS 4841556Srgrimes setjobctl(0); 4851556Srgrimes#endif 4861556Srgrimesl2: _exit(status); 4871556Srgrimes} 488