trap.c revision 217425
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 217425 2011-01-14 21:30:27Z jilles $"); 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 83217175Sjillesstatic int exiting; /* exitshell() has been called */ 84217175Sjillesstatic int exiting_exitstatus; /* value passed to exitshell() */ 85217175Sjilles 86213811Sobrienstatic int getsigaction(int, sig_t *); 8717987Speter 8820902Ssteve 891556Srgrimes/* 9020902Ssteve * Map a string to a signal number. 91125727Snjl * 92125727Snjl * Note: the signal number may exceed NSIG. 9320902Ssteve */ 94213811Sobrienstatic int 9590111Simpsigstring_to_signum(char *sig) 9620902Ssteve{ 9720902Ssteve 9820902Ssteve if (is_number(sig)) { 9920902Ssteve int signo; 10020902Ssteve 10120902Ssteve signo = atoi(sig); 10220902Ssteve return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 10320902Ssteve } else if (strcasecmp(sig, "exit") == 0) { 10420902Ssteve return (0); 10520902Ssteve } else { 10620902Ssteve int n; 10720902Ssteve 10820902Ssteve if (strncasecmp(sig, "sig", 3) == 0) 10920902Ssteve sig += 3; 110125155Snjl for (n = 1; n < sys_nsig; n++) 111125728Snjl if (sys_signame[n] && 112125728Snjl strcasecmp(sys_signame[n], sig) == 0) 11320902Ssteve return (n); 11420902Ssteve } 11520902Ssteve return (-1); 11620902Ssteve} 11720902Ssteve 11820902Ssteve 11920902Ssteve/* 12020902Ssteve * Print a list of valid signal names. 12120902Ssteve */ 122213811Sobrienstatic void 12390111Simpprintsignals(void) 12420902Ssteve{ 125125727Snjl int n, outlen; 12620902Ssteve 127125727Snjl outlen = 0; 128125155Snjl for (n = 1; n < sys_nsig; n++) { 129125727Snjl if (sys_signame[n]) { 130125727Snjl out1fmt("%s", sys_signame[n]); 131125727Snjl outlen += strlen(sys_signame[n]); 132125727Snjl } else { 133125727Snjl out1fmt("%d", n); 134125727Snjl outlen += 3; /* good enough */ 135125727Snjl } 136125727Snjl ++outlen; 137217425Sjilles if (outlen > 71 || n == sys_nsig - 1) { 13820902Ssteve out1str("\n"); 139125727Snjl outlen = 0; 140125727Snjl } else { 14120902Ssteve out1c(' '); 142125727Snjl } 14320902Ssteve } 14420902Ssteve} 14520902Ssteve 14620902Ssteve 14720902Ssteve/* 1481556Srgrimes * The trap builtin. 1491556Srgrimes */ 15017987Speterint 15190111Simptrapcmd(int argc, char **argv) 15217987Speter{ 1531556Srgrimes char *action; 1541556Srgrimes int signo; 155199641Sjilles int errors = 0; 1561556Srgrimes 1571556Srgrimes if (argc <= 1) { 158125155Snjl for (signo = 0 ; signo < sys_nsig ; signo++) { 159125727Snjl if (signo < NSIG && trap[signo] != NULL) { 160153244Sstefanf out1str("trap -- "); 161153244Sstefanf out1qstr(trap[signo]); 162125727Snjl if (signo == 0) { 163153244Sstefanf out1str(" exit\n"); 164125727Snjl } else if (sys_signame[signo]) { 165153244Sstefanf out1fmt(" %s\n", sys_signame[signo]); 166125727Snjl } else { 167153244Sstefanf out1fmt(" %d\n", signo); 168125727Snjl } 169125727Snjl } 1701556Srgrimes } 1711556Srgrimes return 0; 1721556Srgrimes } 17320902Ssteve action = NULL; 17420902Ssteve if (*++argv && strcmp(*argv, "--") == 0) 17520902Ssteve argv++; 17620902Ssteve if (*argv && sigstring_to_signum(*argv) == -1) { 17720902Ssteve if ((*argv)[0] != '-') { 17820902Ssteve action = *argv; 17920902Ssteve argv++; 18020902Ssteve } else if ((*argv)[1] == '\0') { 18120902Ssteve argv++; 18220902Ssteve } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 18320902Ssteve printsignals(); 18420902Ssteve return 0; 18520902Ssteve } else { 18620902Ssteve error("bad option %s", *argv); 18720902Ssteve } 18820902Ssteve } 18920902Ssteve while (*argv) { 190199641Sjilles if ((signo = sigstring_to_signum(*argv)) == -1) { 191216622Sjilles warning("bad signal %s", *argv); 192199641Sjilles errors = 1; 193199641Sjilles } 1941556Srgrimes INTOFF; 1951556Srgrimes if (action) 1961556Srgrimes action = savestr(action); 1971556Srgrimes if (trap[signo]) 1981556Srgrimes ckfree(trap[signo]); 1991556Srgrimes trap[signo] = action; 2001556Srgrimes if (signo != 0) 2011556Srgrimes setsignal(signo); 2021556Srgrimes INTON; 20320902Ssteve argv++; 2041556Srgrimes } 205199641Sjilles return errors; 2061556Srgrimes} 2071556Srgrimes 2081556Srgrimes 2091556Srgrimes/* 2101556Srgrimes * Clear traps on a fork. 2111556Srgrimes */ 2121556Srgrimesvoid 21390111Simpclear_traps(void) 21420902Ssteve{ 21538950Scracauer char *volatile *tp; 2161556Srgrimes 21720902Ssteve for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 2181556Srgrimes if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 2191556Srgrimes INTOFF; 2201556Srgrimes ckfree(*tp); 2211556Srgrimes *tp = NULL; 2221556Srgrimes if (tp != &trap[0]) 2231556Srgrimes setsignal(tp - trap); 2241556Srgrimes INTON; 2251556Srgrimes } 2261556Srgrimes } 2271556Srgrimes} 2281556Srgrimes 2291556Srgrimes 2301556Srgrimes/* 231194127Sjilles * Check if we have any traps enabled. 232194127Sjilles */ 233194127Sjillesint 234194127Sjilleshave_traps(void) 235194127Sjilles{ 236194127Sjilles char *volatile *tp; 237194127Sjilles 238194127Sjilles for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 239194127Sjilles if (*tp && **tp) /* trap not NULL or SIG_IGN */ 240194127Sjilles return 1; 241194127Sjilles } 242194127Sjilles return 0; 243194127Sjilles} 244194127Sjilles 245194127Sjilles/* 2461556Srgrimes * Set the signal handler for the specified signal. The routine figures 2471556Srgrimes * out what it should be set to. 2481556Srgrimes */ 24931098Sbdevoid 25090111Simpsetsignal(int signo) 25117987Speter{ 2521556Srgrimes int action; 253199205Sjilles sig_t sigact = SIG_DFL; 254199205Sjilles struct sigaction sa; 2551556Srgrimes char *t; 2561556Srgrimes 2571556Srgrimes if ((t = trap[signo]) == NULL) 2581556Srgrimes action = S_DFL; 2591556Srgrimes else if (*t != '\0') 2601556Srgrimes action = S_CATCH; 2611556Srgrimes else 2621556Srgrimes action = S_IGN; 26338521Scracauer if (action == S_DFL) { 2641556Srgrimes switch (signo) { 2651556Srgrimes case SIGINT: 26638521Scracauer action = S_CATCH; 2671556Srgrimes break; 2681556Srgrimes case SIGQUIT: 2691556Srgrimes#ifdef DEBUG 2701556Srgrimes { 2711556Srgrimes extern int debug; 2721556Srgrimes 2731556Srgrimes if (debug) 2741556Srgrimes break; 2751556Srgrimes } 2761556Srgrimes#endif 27738535Scracauer action = S_CATCH; 27838521Scracauer break; 2791556Srgrimes case SIGTERM: 28038521Scracauer if (rootshell && iflag) 2811556Srgrimes action = S_IGN; 2821556Srgrimes break; 2831556Srgrimes#if JOBS 2841556Srgrimes case SIGTSTP: 2851556Srgrimes case SIGTTOU: 28638521Scracauer if (rootshell && mflag) 2871556Srgrimes action = S_IGN; 2881556Srgrimes break; 2891556Srgrimes#endif 290100578Stjr#ifndef NO_HISTORY 291100578Stjr case SIGWINCH: 292100588Stjr if (rootshell && iflag) 293100578Stjr action = S_CATCH; 294100578Stjr break; 295100578Stjr#endif 2961556Srgrimes } 2971556Srgrimes } 29817987Speter 29920902Ssteve t = &sigmode[signo]; 3008855Srgrimes if (*t == 0) { 3018855Srgrimes /* 3028855Srgrimes * current setting unknown 3031556Srgrimes */ 30417987Speter if (!getsigaction(signo, &sigact)) { 30517987Speter /* 30617987Speter * Pretend it worked; maybe we should give a warning 30717987Speter * here, but other shells don't. We don't alter 30817987Speter * sigmode, so that we retry every time. 30917987Speter */ 31031098Sbde return; 31117987Speter } 3121556Srgrimes if (sigact == SIG_IGN) { 3138855Srgrimes if (mflag && (signo == SIGTSTP || 3141556Srgrimes signo == SIGTTIN || signo == SIGTTOU)) { 3151556Srgrimes *t = S_IGN; /* don't hard ignore these */ 3161556Srgrimes } else 3171556Srgrimes *t = S_HARD_IGN; 3181556Srgrimes } else { 3191556Srgrimes *t = S_RESET; /* force to be set */ 3201556Srgrimes } 3211556Srgrimes } 3221556Srgrimes if (*t == S_HARD_IGN || *t == action) 32331098Sbde return; 3241556Srgrimes switch (action) { 3251556Srgrimes case S_DFL: sigact = SIG_DFL; break; 3261556Srgrimes case S_CATCH: sigact = onsig; break; 3271556Srgrimes case S_IGN: sigact = SIG_IGN; break; 3281556Srgrimes } 3291556Srgrimes *t = action; 330199205Sjilles sa.sa_handler = sigact; 331199205Sjilles sa.sa_flags = 0; 332199205Sjilles sigemptyset(&sa.sa_mask); 333199205Sjilles sigaction(signo, &sa, NULL); 3341556Srgrimes} 3351556Srgrimes 33620902Ssteve 3371556Srgrimes/* 3381556Srgrimes * Return the current setting for sig w/o changing it. 3391556Srgrimes */ 340213811Sobrienstatic int 34190111Simpgetsigaction(int signo, sig_t *sigact) 34217987Speter{ 3431556Srgrimes struct sigaction sa; 3441556Srgrimes 3451556Srgrimes if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 34617987Speter return 0; 34717987Speter *sigact = (sig_t) sa.sa_handler; 34817987Speter return 1; 3491556Srgrimes} 3501556Srgrimes 35120902Ssteve 3521556Srgrimes/* 3531556Srgrimes * Ignore a signal. 3541556Srgrimes */ 3551556Srgrimesvoid 35690111Simpignoresig(int signo) 35717987Speter{ 35820902Ssteve 35920902Ssteve if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 3601556Srgrimes signal(signo, SIG_IGN); 3611556Srgrimes } 36220902Ssteve sigmode[signo] = S_HARD_IGN; 3631556Srgrimes} 3641556Srgrimes 3651556Srgrimes 3661556Srgrimes#ifdef mkinit 36717987SpeterINCLUDE <signal.h> 3681556SrgrimesINCLUDE "trap.h" 3691556Srgrimes 3701556SrgrimesSHELLPROC { 3711556Srgrimes char *sm; 3721556Srgrimes 3731556Srgrimes clear_traps(); 37417987Speter for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 3751556Srgrimes if (*sm == S_IGN) 3761556Srgrimes *sm = S_HARD_IGN; 3771556Srgrimes } 3781556Srgrimes} 3791556Srgrimes#endif 3801556Srgrimes 3811556Srgrimes 3821556Srgrimes/* 3831556Srgrimes * Signal handler. 3841556Srgrimes */ 3851556Srgrimesvoid 38690111Simponsig(int signo) 38717987Speter{ 38831098Sbde 3891556Srgrimes if (signo == SIGINT && trap[SIGINT] == NULL) { 3901556Srgrimes onint(); 3911556Srgrimes return; 3921556Srgrimes } 39338950Scracauer 39420902Ssteve if (signo != SIGCHLD || !ignore_sigchld) 39520902Ssteve gotsig[signo] = 1; 3961556Srgrimes pendingsigs++; 39738950Scracauer 39838950Scracauer /* If we are currently in a wait builtin, prepare to break it */ 39938950Scracauer if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 40038521Scracauer breakwaitcmd = 1; 401157811Sschweikh /* 402157811Sschweikh * If a trap is set, not ignored and not the null command, we need 40339056Scracauer * to make sure traps are executed even when a child blocks signals. 40438950Scracauer */ 40545221Scracauer if (Tflag && 406157811Sschweikh trap[signo] != NULL && 407149825Srse ! (trap[signo][0] == '\0') && 40839049Scracauer ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 40939049Scracauer breakwaitcmd = 1; 410100578Stjr 411100578Stjr#ifndef NO_HISTORY 412100578Stjr if (signo == SIGWINCH) 413100588Stjr gotwinch = 1; 414100578Stjr#endif 4151556Srgrimes} 4161556Srgrimes 4171556Srgrimes 4181556Srgrimes/* 4191556Srgrimes * Called to execute a trap. Perhaps we should avoid entering new trap 4201556Srgrimes * handlers while we are executing a trap handler. 4211556Srgrimes */ 4221556Srgrimesvoid 42390111Simpdotrap(void) 42420902Ssteve{ 4251556Srgrimes int i; 4261556Srgrimes int savestatus; 4271556Srgrimes 42838521Scracauer in_dotrap++; 4291556Srgrimes for (;;) { 43020902Ssteve for (i = 1; i < NSIG; i++) { 43120902Ssteve if (gotsig[i]) { 43220902Ssteve gotsig[i] = 0; 43320902Ssteve if (trap[i]) { 43420902Ssteve /* 435125728Snjl * Ignore SIGCHLD to avoid infinite 436125728Snjl * recursion if the trap action does 437125728Snjl * a fork. 43820902Ssteve */ 43920902Ssteve if (i == SIGCHLD) 44020902Ssteve ignore_sigchld++; 44120902Ssteve savestatus = exitstatus; 442193169Sstefanf evalstring(trap[i], 0); 44320902Ssteve exitstatus = savestatus; 44420902Ssteve if (i == SIGCHLD) 44520902Ssteve ignore_sigchld--; 44620902Ssteve } 4471556Srgrimes break; 44820902Ssteve } 4491556Srgrimes } 45020902Ssteve if (i >= NSIG) 45120902Ssteve break; 4521556Srgrimes } 45338521Scracauer in_dotrap--; 4541556Srgrimes pendingsigs = 0; 4551556Srgrimes} 4561556Srgrimes 4571556Srgrimes 4581556Srgrimes/* 4591556Srgrimes * Controls whether the shell is interactive or not. 4601556Srgrimes */ 4611556Srgrimesvoid 46290111Simpsetinteractive(int on) 46317987Speter{ 46438521Scracauer static int is_interactive = -1; 4651556Srgrimes 4661556Srgrimes if (on == is_interactive) 4671556Srgrimes return; 4681556Srgrimes setsignal(SIGINT); 4691556Srgrimes setsignal(SIGQUIT); 4701556Srgrimes setsignal(SIGTERM); 471100578Stjr#ifndef NO_HISTORY 472100578Stjr setsignal(SIGWINCH); 473100578Stjr#endif 4741556Srgrimes is_interactive = on; 4751556Srgrimes} 4761556Srgrimes 4771556Srgrimes 4781556Srgrimes/* 4791556Srgrimes * Called to exit the shell. 4801556Srgrimes */ 4811556Srgrimesvoid 48290111Simpexitshell(int status) 48317987Speter{ 484217175Sjilles TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 485217175Sjilles exiting = 1; 486217175Sjilles exiting_exitstatus = status; 487217175Sjilles exitshell_savedstatus(); 488217175Sjilles} 489217175Sjilles 490217175Sjillesvoid 491217175Sjillesexitshell_savedstatus(void) 492217175Sjilles{ 4931556Srgrimes struct jmploc loc1, loc2; 4941556Srgrimes char *p; 4951556Srgrimes 496217175Sjilles if (!exiting) 497217175Sjilles exiting_exitstatus = oexitstatus; 498217175Sjilles exitstatus = oexitstatus = exiting_exitstatus; 4991556Srgrimes if (setjmp(loc1.loc)) { 5001556Srgrimes goto l1; 5011556Srgrimes } 5021556Srgrimes if (setjmp(loc2.loc)) { 5031556Srgrimes goto l2; 5041556Srgrimes } 5051556Srgrimes handler = &loc1; 5061556Srgrimes if ((p = trap[0]) != NULL && *p != '\0') { 5071556Srgrimes trap[0] = NULL; 508193169Sstefanf evalstring(p, 0); 5091556Srgrimes } 5101556Srgrimesl1: handler = &loc2; /* probably unnecessary */ 5111556Srgrimes flushall(); 5121556Srgrimes#if JOBS 5131556Srgrimes setjobctl(0); 5141556Srgrimes#endif 515217175Sjillesl2: _exit(exiting_exitstatus); 5161556Srgrimes} 517