trap.c revision 157811
1132744Skan/*- 290285Sobrien * Copyright (c) 1991, 1993 3169706Skan * The Regents of the University of California. All rights reserved. 418334Speter * 5132744Skan * This code is derived from software contributed to Berkeley by 618334Speter * Kenneth Almquist. 7132744Skan * 818334Speter * Redistribution and use in source and binary forms, with or without 918334Speter * modification, are permitted provided that the following conditions 1018334Speter * are met: 1118334Speter * 1. Redistributions of source code must retain the above copyright 12132744Skan * notice, this list of conditions and the following disclaimer. 1318334Speter * 2. Redistributions in binary form must reproduce the above copyright 1418334Speter * notice, this list of conditions and the following disclaimer in the 1518334Speter * documentation and/or other materials provided with the distribution. 1618334Speter * 4. Neither the name of the University nor the names of its contributors 1718334Speter * may be used to endorse or promote products derived from this software 18132744Skan * without specific prior written permission. 19169706Skan * 20169706Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2118334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2218334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2318334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2418334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2518334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2618334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2718334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2818334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2918334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3018334Speter * SUCH DAMAGE. 3118334Speter */ 3218334Speter 3390285Sobrien#ifndef lint 3490285Sobrien#if 0 3590285Sobrienstatic char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; 3618334Speter#endif 3750654Sobrien#endif /* not lint */ 3850654Sobrien#include <sys/cdefs.h> 3950654Sobrien__FBSDID("$FreeBSD: head/bin/sh/trap.c 157811 2006-04-17 17:55:11Z schweikh $"); 4090285Sobrien 4190285Sobrien#include <signal.h> 4290285Sobrien#include <unistd.h> 4390285Sobrien#include <stdlib.h> 44169706Skan 45132744Skan#include "shell.h" 4690285Sobrien#include "main.h" 47169706Skan#include "nodes.h" /* for other headers */ 48132744Skan#include "eval.h" 4990285Sobrien#include "jobs.h" 5090285Sobrien#include "show.h" 5190285Sobrien#include "options.h" 5290285Sobrien#include "syntax.h" 5390285Sobrien#include "output.h" 5490285Sobrien#include "memalloc.h" 5590285Sobrien#include "error.h" 5690285Sobrien#include "trap.h" 5790285Sobrien#include "mystring.h" 5890285Sobrien#include "myhistedit.h" 5990285Sobrien 6090285Sobrien 6190285Sobrien/* 6290285Sobrien * Sigmode records the current value of the signal handlers for the various 6390285Sobrien * modes. A value of zero means that the current handler is not known. 6490285Sobrien * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 6590285Sobrien */ 6690285Sobrien 6790285Sobrien#define S_DFL 1 /* default signal handling (SIG_DFL) */ 6890285Sobrien#define S_CATCH 2 /* signal is caught */ 6990285Sobrien#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 7090285Sobrien#define S_HARD_IGN 4 /* signal is ignored permanently */ 7190285Sobrien#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 7290285Sobrien 7390285Sobrien 7490285SobrienMKINIT char sigmode[NSIG]; /* current value of signal */ 7590285Sobrienint pendingsigs; /* indicates some signal received */ 7690285Sobrienint in_dotrap; /* do we execute in a trap handler? */ 7790285Sobrienstatic char *volatile trap[NSIG]; /* trap handler commands */ 7890285Sobrienstatic volatile sig_atomic_t gotsig[NSIG]; 7990285Sobrien /* indicates specified signal received */ 80132744Skanstatic int ignore_sigchld; /* Used while handling SIGCHLD traps. */ 81117407Skanvolatile sig_atomic_t gotwinch; 82117407Skan 83117407Skanstatic int getsigaction(int, sig_t *); 84117407Skan 85117407Skan 86117407Skan/* 8750654Sobrien * Map a string to a signal number. 8850654Sobrien * 8990285Sobrien * Note: the signal number may exceed NSIG. 9050654Sobrien */ 9118334Speterstatic int 9218334Spetersigstring_to_signum(char *sig) 9318334Speter{ 9490285Sobrien 9518334Speter if (is_number(sig)) { 96169706Skan int signo; 9718334Speter 98169706Skan signo = atoi(sig); 99169706Skan return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 100169706Skan } else if (strcasecmp(sig, "exit") == 0) { 101169706Skan return (0); 102132744Skan } else { 10318334Speter int n; 104169706Skan 105117407Skan if (strncasecmp(sig, "sig", 3) == 0) 106117407Skan sig += 3; 107117407Skan for (n = 1; n < sys_nsig; n++) 108117407Skan if (sys_signame[n] && 109169706Skan strcasecmp(sys_signame[n], sig) == 0) 110117407Skan return (n); 111117407Skan } 112117407Skan return (-1); 113117407Skan} 114117407Skan 115117407Skan 116169706Skan/* 117169706Skan * Print a list of valid signal names. 118117407Skan */ 11990285Sobrienstatic void 12090285Sobrienprintsignals(void) 12190285Sobrien{ 12290285Sobrien int n, outlen; 12390285Sobrien 124117407Skan outlen = 0; 12518334Speter for (n = 1; n < sys_nsig; n++) { 126169706Skan if (sys_signame[n]) { 127169706Skan out1fmt("%s", sys_signame[n]); 12852295Sobrien outlen += strlen(sys_signame[n]); 129132744Skan } else { 130132744Skan out1fmt("%d", n); 131132744Skan outlen += 3; /* good enough */ 132132744Skan } 133219374Smm ++outlen; 134132744Skan if (outlen > 70 || n == sys_nsig - 1) { 135132744Skan out1str("\n"); 136132744Skan outlen = 0; 137132744Skan } else { 138132744Skan out1c(' '); 139169706Skan } 140219374Smm } 141169706Skan} 142169706Skan 143169706Skan 144132744Skan/* 145132744Skan * The trap builtin. 14652295Sobrien */ 14752295Sobrienint 14890285Sobrientrapcmd(int argc, char **argv) 14990285Sobrien{ 150169706Skan char *action; 151169706Skan int signo; 15290285Sobrien 153117407Skan if (argc <= 1) { 15490285Sobrien for (signo = 0 ; signo < sys_nsig ; signo++) { 15590285Sobrien if (signo < NSIG && trap[signo] != NULL) { 15690285Sobrien out1str("trap -- "); 15790285Sobrien out1qstr(trap[signo]); 15890285Sobrien if (signo == 0) { 15990285Sobrien out1str(" exit\n"); 160117407Skan } else if (sys_signame[signo]) { 161169706Skan out1fmt(" %s\n", sys_signame[signo]); 162132744Skan } else { 163169706Skan out1fmt(" %d\n", signo); 164169706Skan } 165169706Skan } 166237021Spfg } 167169706Skan return 0; 168169706Skan } 169169706Skan action = NULL; 170237021Spfg if (*++argv && strcmp(*argv, "--") == 0) 17152295Sobrien argv++; 172132744Skan if (*argv && sigstring_to_signum(*argv) == -1) { 173132744Skan if ((*argv)[0] != '-') { 174132744Skan action = *argv; 175132744Skan argv++; 176132744Skan } else if ((*argv)[1] == '\0') { 17790285Sobrien argv++; 17890285Sobrien } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 17990285Sobrien printsignals(); 180169706Skan return 0; 181132744Skan } else { 182132744Skan error("bad option %s", *argv); 183132744Skan } 184132744Skan } 185132744Skan while (*argv) { 186132744Skan if ((signo = sigstring_to_signum(*argv)) == -1) 187169706Skan error("bad signal %s", *argv); 188169706Skan INTOFF; 189169706Skan if (action) 190132744Skan action = savestr(action); 191132744Skan if (trap[signo]) 192132744Skan ckfree(trap[signo]); 193132744Skan trap[signo] = action; 194132744Skan if (signo != 0) 195132744Skan setsignal(signo); 196132744Skan INTON; 197132744Skan argv++; 198132744Skan } 199132744Skan return 0; 200132744Skan} 201132744Skan 202132744Skan 203132744Skan/* 204132744Skan * Clear traps on a fork. 205132744Skan */ 206132744Skanvoid 207132744Skanclear_traps(void) 208132744Skan{ 209132744Skan char *volatile *tp; 210169706Skan 211132744Skan for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 212132744Skan if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 213132744Skan INTOFF; 214132744Skan ckfree(*tp); 215132744Skan *tp = NULL; 21690285Sobrien if (tp != &trap[0]) 217132744Skan setsignal(tp - trap); 218132744Skan INTON; 219132744Skan } 220132744Skan } 221169706Skan} 222169706Skan 223169706Skan 224169706Skan/* 225169706Skan * Set the signal handler for the specified signal. The routine figures 22652295Sobrien * out what it should be set to. 22790285Sobrien */ 22890285Sobrienvoid 22990285Sobriensetsignal(int signo) 23090285Sobrien{ 23190285Sobrien int action; 23290285Sobrien sig_t sig, sigact = SIG_DFL; 233117407Skan char *t; 234169706Skan 235169706Skan if ((t = trap[signo]) == NULL) 236117407Skan action = S_DFL; 237117407Skan else if (*t != '\0') 238169706Skan action = S_CATCH; 239169706Skan else 240237021Spfg action = S_IGN; 241169706Skan if (action == S_DFL) { 24296294Sobrien switch (signo) { 243117407Skan case SIGINT: 244117407Skan action = S_CATCH; 24590285Sobrien break; 246132744Skan case SIGQUIT: 247132744Skan#ifdef DEBUG 248132744Skan { 24990285Sobrien extern int debug; 250117407Skan 251117407Skan if (debug) 252117407Skan break; 253117407Skan } 25450654Sobrien#endif 255117407Skan action = S_CATCH; 256117407Skan break; 257117407Skan case SIGTERM: 258117407Skan if (rootshell && iflag) 25950654Sobrien action = S_IGN; 260146908Skan break; 261146908Skan#if JOBS 262146908Skan case SIGTSTP: 263146908Skan case SIGTTOU: 26418334Speter if (rootshell && mflag) 26518334Speter action = S_IGN; 26618334Speter break; 26718334Speter#endif 26818334Speter#ifndef NO_HISTORY 26918334Speter case SIGWINCH: 27018334Speter if (rootshell && iflag) 27118334Speter action = S_CATCH; 27218334Speter break; 27318334Speter#endif 27418334Speter } 27550654Sobrien } 27690285Sobrien 27790285Sobrien t = &sigmode[signo]; 27850654Sobrien if (*t == 0) { 279169706Skan /* 280169706Skan * current setting unknown 281169706Skan */ 282169706Skan if (!getsigaction(signo, &sigact)) { 283169706Skan /* 284169706Skan * Pretend it worked; maybe we should give a warning 285169706Skan * here, but other shells don't. We don't alter 286169706Skan * sigmode, so that we retry every time. 287169706Skan */ 288169706Skan return; 289169706Skan } 290169706Skan if (sigact == SIG_IGN) { 291169706Skan if (mflag && (signo == SIGTSTP || 292169706Skan signo == SIGTTIN || signo == SIGTTOU)) { 293132744Skan *t = S_IGN; /* don't hard ignore these */ 294132744Skan } else 295169706Skan *t = S_HARD_IGN; 296169706Skan } else { 297132744Skan *t = S_RESET; /* force to be set */ 29850654Sobrien } 29950654Sobrien } 30050654Sobrien if (*t == S_HARD_IGN || *t == action) 301169706Skan return; 302132744Skan switch (action) { 303132744Skan case S_DFL: sigact = SIG_DFL; break; 304132744Skan case S_CATCH: sigact = onsig; break; 305132744Skan case S_IGN: sigact = SIG_IGN; break; 306132744Skan } 307132744Skan *t = action; 308132744Skan sig = signal(signo, sigact); 309132744Skan if (sig != SIG_ERR && action == S_CATCH) 310132744Skan siginterrupt(signo, 1); 311132744Skan} 312132744Skan 313132744Skan 31490285Sobrien/* 31590285Sobrien * Return the current setting for sig w/o changing it. 31690285Sobrien */ 31790285Sobrienstatic int 318169706Skangetsigaction(int signo, sig_t *sigact) 319169706Skan{ 320169706Skan struct sigaction sa; 321169706Skan 322169706Skan if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 323169706Skan return 0; 324169706Skan *sigact = (sig_t) sa.sa_handler; 325169706Skan return 1; 32650654Sobrien} 327169706Skan 32818334Speter 329117407Skan/* 330117407Skan * Ignore a signal. 331117407Skan */ 332117407Skanvoid 333117407Skanignoresig(int signo) 334132744Skan{ 335117407Skan 336132744Skan if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 337117407Skan signal(signo, SIG_IGN); 338117407Skan } 339117407Skan sigmode[signo] = S_HARD_IGN; 340117407Skan} 341132744Skan 342132744Skan 343132744Skan#ifdef mkinit 344117407SkanINCLUDE <signal.h> 345117407SkanINCLUDE "trap.h" 346117407Skan 347117407SkanSHELLPROC { 348117407Skan char *sm; 349117407Skan 350117407Skan clear_traps(); 351117407Skan for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 352117407Skan if (*sm == S_IGN) 353117407Skan *sm = S_HARD_IGN; 354132744Skan } 355132744Skan} 356117407Skan#endif 357117407Skan 358117407Skan 359117407Skan/* 360117407Skan * Signal handler. 361117407Skan */ 362117407Skanvoid 363117407Skanonsig(int signo) 364132744Skan{ 365117407Skan 366117407Skan if (signo == SIGINT && trap[SIGINT] == NULL) { 367117407Skan onint(); 368117407Skan return; 369117407Skan } 370117407Skan 371132744Skan if (signo != SIGCHLD || !ignore_sigchld) 372117407Skan gotsig[signo] = 1; 373117407Skan pendingsigs++; 374117407Skan 375117407Skan /* If we are currently in a wait builtin, prepare to break it */ 376117407Skan if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 377117407Skan breakwaitcmd = 1; 378117407Skan /* 379117407Skan * If a trap is set, not ignored and not the null command, we need 380117407Skan * to make sure traps are executed even when a child blocks signals. 381219374Smm */ 382219374Smm if (Tflag && 383219374Smm trap[signo] != NULL && 384219374Smm ! (trap[signo][0] == '\0') && 385117407Skan ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 386117407Skan breakwaitcmd = 1; 387117407Skan 388132744Skan#ifndef NO_HISTORY 389117407Skan if (signo == SIGWINCH) 390132744Skan gotwinch = 1; 391117407Skan#endif 392117407Skan} 393117407Skan 394117407Skan 395117407Skan/* 396148163Sobrien * Called to execute a trap. Perhaps we should avoid entering new trap 397148163Sobrien * handlers while we are executing a trap handler. 398117407Skan */ 399117407Skanvoid 400132744Skandotrap(void) 401132744Skan{ 402117407Skan int i; 403117407Skan int savestatus; 404169706Skan 405169706Skan in_dotrap++; 406219374Smm for (;;) { 407219374Smm for (i = 1; i < NSIG; i++) { 408117407Skan if (gotsig[i]) { 409117407Skan gotsig[i] = 0; 410117407Skan if (trap[i]) { 411117407Skan /* 412117407Skan * Ignore SIGCHLD to avoid infinite 413117407Skan * recursion if the trap action does 414117407Skan * a fork. 415117407Skan */ 416117407Skan if (i == SIGCHLD) 417117407Skan ignore_sigchld++; 418117407Skan savestatus = exitstatus; 419132744Skan evalstring(trap[i]); 420169706Skan exitstatus = savestatus; 421219639Smm if (i == SIGCHLD) 422219639Smm ignore_sigchld--; 423117407Skan } 424117407Skan break; 425117407Skan } 426117407Skan } 427117407Skan if (i >= NSIG) 428117407Skan break; 429117407Skan } 430117407Skan in_dotrap--; 431117407Skan pendingsigs = 0; 432117407Skan} 433117407Skan 434117407Skan 435117407Skan/* 436117407Skan * Controls whether the shell is interactive or not. 437117407Skan */ 438117407Skanvoid 439117407Skansetinteractive(int on) 440117407Skan{ 441117407Skan static int is_interactive = -1; 442117407Skan 443117407Skan if (on == is_interactive) 444117407Skan return; 445117407Skan setsignal(SIGINT); 446117407Skan setsignal(SIGQUIT); 447117407Skan setsignal(SIGTERM); 448117407Skan#ifndef NO_HISTORY 449117407Skan setsignal(SIGWINCH); 450219374Smm#endif 451219374Smm is_interactive = on; 452219374Smm} 453219374Smm 454219374Smm 455117407Skan/* 456117407Skan * Called to exit the shell. 457117407Skan */ 458117407Skanvoid 459117407Skanexitshell(int status) 460117407Skan{ 461117407Skan struct jmploc loc1, loc2; 462117407Skan char *p; 463117407Skan 464117407Skan TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 465117407Skan if (setjmp(loc1.loc)) { 466117407Skan goto l1; 467117407Skan } 468117407Skan if (setjmp(loc2.loc)) { 469148163Sobrien goto l2; 470148163Sobrien } 471117407Skan handler = &loc1; 472117407Skan if ((p = trap[0]) != NULL && *p != '\0') { 473132744Skan trap[0] = NULL; 474132744Skan evalstring(p); 475132744Skan } 476132744Skanl1: handler = &loc2; /* probably unnecessary */ 477132744Skan flushall(); 478117407Skan#if JOBS 479117407Skan setjobctl(0); 480117407Skan#endif 481117407Skanl2: _exit(status); 482117407Skan} 483169706Skan