trap.c revision 194127
1159307Spjd/*- 2220922Spjd * Copyright (c) 1991, 1993 3159307Spjd * The Regents of the University of California. All rights reserved. 4159307Spjd * 5159307Spjd * This code is derived from software contributed to Berkeley by 6159307Spjd * Kenneth Almquist. 7159307Spjd * 8159307Spjd * Redistribution and use in source and binary forms, with or without 9159307Spjd * modification, are permitted provided that the following conditions 10159307Spjd * are met: 11159307Spjd * 1. Redistributions of source code must retain the above copyright 12159307Spjd * notice, this list of conditions and the following disclaimer. 13159307Spjd * 2. Redistributions in binary form must reproduce the above copyright 14159307Spjd * notice, this list of conditions and the following disclaimer in the 15159307Spjd * documentation and/or other materials provided with the distribution. 16159307Spjd * 4. Neither the name of the University nor the names of its contributors 17159307Spjd * may be used to endorse or promote products derived from this software 18159307Spjd * without specific prior written permission. 19159307Spjd * 20159307Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21159307Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22159307Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23159307Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24159307Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25159307Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26159307Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27159307Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28159307Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29159307Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30159307Spjd * SUCH DAMAGE. 31159307Spjd */ 32159307Spjd 33159307Spjd#ifndef lint 34159307Spjd#if 0 35159307Spjdstatic char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; 36159307Spjd#endif 37159307Spjd#endif /* not lint */ 38159307Spjd#include <sys/cdefs.h> 39159307Spjd__FBSDID("$FreeBSD: head/bin/sh/trap.c 194127 2009-06-13 21:10:41Z jilles $"); 40159307Spjd 41159307Spjd#include <signal.h> 42159307Spjd#include <unistd.h> 43159307Spjd#include <stdlib.h> 44159307Spjd 45159307Spjd#include "shell.h" 46159307Spjd#include "main.h" 47159307Spjd#include "nodes.h" /* for other headers */ 48159307Spjd#include "eval.h" 49159307Spjd#include "jobs.h" 50159307Spjd#include "show.h" 51159307Spjd#include "options.h" 52159307Spjd#include "syntax.h" 53159307Spjd#include "output.h" 54159307Spjd#include "memalloc.h" 55159307Spjd#include "error.h" 56159307Spjd#include "trap.h" 57159307Spjd#include "mystring.h" 58159307Spjd#include "myhistedit.h" 59159307Spjd 60159307Spjd 61159307Spjd/* 62159307Spjd * Sigmode records the current value of the signal handlers for the various 63159307Spjd * modes. A value of zero means that the current handler is not known. 64159307Spjd * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 65159307Spjd */ 66159307Spjd 67159307Spjd#define S_DFL 1 /* default signal handling (SIG_DFL) */ 68159307Spjd#define S_CATCH 2 /* signal is caught */ 69159307Spjd#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 70159307Spjd#define S_HARD_IGN 4 /* signal is ignored permanently */ 71159307Spjd#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 72159307Spjd 73159307Spjd 74159307SpjdMKINIT char sigmode[NSIG]; /* current value of signal */ 75159307Spjdint pendingsigs; /* indicates some signal received */ 76159307Spjdint in_dotrap; /* do we execute in a trap handler? */ 77159307Spjdstatic char *volatile trap[NSIG]; /* trap handler commands */ 78159307Spjdstatic volatile sig_atomic_t gotsig[NSIG]; 79159307Spjd /* indicates specified signal received */ 80159307Spjdstatic int ignore_sigchld; /* Used while handling SIGCHLD traps. */ 81159307Spjdvolatile sig_atomic_t gotwinch; 82159307Spjd 83159307Spjdstatic int getsigaction(int, sig_t *); 84159307Spjd 85159307Spjd 86159307Spjd/* 87159307Spjd * Map a string to a signal number. 88159307Spjd * 89159307Spjd * Note: the signal number may exceed NSIG. 90159307Spjd */ 91159307Spjdstatic int 92159307Spjdsigstring_to_signum(char *sig) 93159307Spjd{ 94159307Spjd 95159307Spjd if (is_number(sig)) { 96159307Spjd int signo; 97159307Spjd 98159307Spjd signo = atoi(sig); 99159307Spjd return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 100159307Spjd } else if (strcasecmp(sig, "exit") == 0) { 101159307Spjd return (0); 102159307Spjd } else { 103159307Spjd int n; 104159307Spjd 105159307Spjd if (strncasecmp(sig, "sig", 3) == 0) 106159307Spjd sig += 3; 107159307Spjd for (n = 1; n < sys_nsig; n++) 108159307Spjd if (sys_signame[n] && 109159307Spjd strcasecmp(sys_signame[n], sig) == 0) 110159307Spjd return (n); 111159307Spjd } 112159307Spjd return (-1); 113159307Spjd} 114159307Spjd 115159307Spjd 116159307Spjd/* 117159307Spjd * Print a list of valid signal names. 118159307Spjd */ 119159307Spjdstatic void 120159307Spjdprintsignals(void) 121159307Spjd{ 122159307Spjd int n, outlen; 123159307Spjd 124159307Spjd outlen = 0; 125159307Spjd for (n = 1; n < sys_nsig; n++) { 126159307Spjd if (sys_signame[n]) { 127159307Spjd out1fmt("%s", sys_signame[n]); 128159307Spjd outlen += strlen(sys_signame[n]); 129159307Spjd } else { 130159307Spjd out1fmt("%d", n); 131159307Spjd outlen += 3; /* good enough */ 132214118Spjd } 133159307Spjd ++outlen; 134159307Spjd if (outlen > 70 || n == sys_nsig - 1) { 135159307Spjd out1str("\n"); 136159307Spjd outlen = 0; 137159307Spjd } else { 138159307Spjd out1c(' '); 139159307Spjd } 140159307Spjd } 141159307Spjd} 142159307Spjd 143159307Spjd 144159307Spjd/* 145159307Spjd * The trap builtin. 146159307Spjd */ 147159307Spjdint 148159307Spjdtrapcmd(int argc, char **argv) 149159307Spjd{ 150159307Spjd char *action; 151220922Spjd int signo; 152221625Spjd 153159307Spjd if (argc <= 1) { 154159307Spjd for (signo = 0 ; signo < sys_nsig ; signo++) { 155159307Spjd if (signo < NSIG && trap[signo] != NULL) { 156159307Spjd out1str("trap -- "); 157159307Spjd out1qstr(trap[signo]); 158159307Spjd if (signo == 0) { 159159307Spjd out1str(" exit\n"); 160159307Spjd } else if (sys_signame[signo]) { 161159307Spjd out1fmt(" %s\n", sys_signame[signo]); 162159307Spjd } else { 163159307Spjd out1fmt(" %d\n", signo); 164159307Spjd } 165159307Spjd } 166159307Spjd } 167159307Spjd return 0; 168159307Spjd } 169159307Spjd action = NULL; 170159307Spjd if (*++argv && strcmp(*argv, "--") == 0) 171159307Spjd argv++; 172159307Spjd if (*argv && sigstring_to_signum(*argv) == -1) { 173159307Spjd if ((*argv)[0] != '-') { 174159307Spjd action = *argv; 175159307Spjd argv++; 176159307Spjd } else if ((*argv)[1] == '\0') { 177159307Spjd argv++; 178159307Spjd } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { 179159307Spjd printsignals(); 180159307Spjd return 0; 181159307Spjd } else { 182159307Spjd error("bad option %s", *argv); 183159307Spjd } 184159307Spjd } 185159307Spjd while (*argv) { 186159307Spjd if ((signo = sigstring_to_signum(*argv)) == -1) 187159307Spjd error("bad signal %s", *argv); 188159307Spjd INTOFF; 189159307Spjd if (action) 190159307Spjd action = savestr(action); 191159307Spjd if (trap[signo]) 192159307Spjd ckfree(trap[signo]); 193159307Spjd trap[signo] = action; 194159307Spjd if (signo != 0) 195159307Spjd setsignal(signo); 196159307Spjd INTON; 197159307Spjd argv++; 198159307Spjd } 199159307Spjd return 0; 200159307Spjd} 201159307Spjd 202159307Spjd 203159307Spjd/* 204159307Spjd * Clear traps on a fork. 205159307Spjd */ 206159307Spjdvoid 207159307Spjdclear_traps(void) 208235201Seadler{ 209235419Seadler char *volatile *tp; 210159307Spjd 211159307Spjd for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 212159307Spjd if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 213159307Spjd INTOFF; 214159307Spjd ckfree(*tp); 215159307Spjd *tp = NULL; 216159307Spjd if (tp != &trap[0]) 217159307Spjd setsignal(tp - trap); 218159307Spjd INTON; 219159307Spjd } 220159307Spjd } 221159307Spjd} 222159307Spjd 223159307Spjd 224235201Seadler/* 225235419Seadler * Check if we have any traps enabled. 226159307Spjd */ 227159307Spjdint 228159307Spjdhave_traps(void) 229159307Spjd{ 230159307Spjd char *volatile *tp; 231159307Spjd 232159307Spjd for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 233159307Spjd if (*tp && **tp) /* trap not NULL or SIG_IGN */ 234159307Spjd return 1; 235159307Spjd } 236159307Spjd return 0; 237159307Spjd} 238159307Spjd 239159307Spjd/* 240159307Spjd * Set the signal handler for the specified signal. The routine figures 241159307Spjd * out what it should be set to. 242159307Spjd */ 243159307Spjdvoid 244159307Spjdsetsignal(int signo) 245214118Spjd{ 246159307Spjd int action; 247159307Spjd sig_t sig, sigact = SIG_DFL; 248159307Spjd char *t; 249159307Spjd 250159307Spjd if ((t = trap[signo]) == NULL) 251159307Spjd action = S_DFL; 252159307Spjd else if (*t != '\0') 253159307Spjd action = S_CATCH; 254159307Spjd else 255159307Spjd action = S_IGN; 256159307Spjd if (action == S_DFL) { 257159307Spjd switch (signo) { 258159307Spjd case SIGINT: 259159307Spjd action = S_CATCH; 260159307Spjd break; 261159307Spjd case SIGQUIT: 262159307Spjd#ifdef DEBUG 263159307Spjd { 264159307Spjd extern int debug; 265159307Spjd 266159307Spjd if (debug) 267159307Spjd break; 268159307Spjd } 269159307Spjd#endif 270159307Spjd action = S_CATCH; 271159307Spjd break; 272159307Spjd case SIGTERM: 273159307Spjd if (rootshell && iflag) 274159307Spjd action = S_IGN; 275159307Spjd break; 276159307Spjd#if JOBS 277220922Spjd case SIGTSTP: 278220922Spjd case SIGTTOU: 279159307Spjd if (rootshell && mflag) 280159307Spjd action = S_IGN; 281159307Spjd break; 282159307Spjd#endif 283159307Spjd#ifndef NO_HISTORY 284159307Spjd case SIGWINCH: 285159307Spjd if (rootshell && iflag) 286159307Spjd action = S_CATCH; 287159307Spjd break; 288159307Spjd#endif 289159307Spjd } 290159307Spjd } 291159307Spjd 292159307Spjd t = &sigmode[signo]; 293214118Spjd if (*t == 0) { 294159307Spjd /* 295159307Spjd * current setting unknown 296159307Spjd */ 297159307Spjd if (!getsigaction(signo, &sigact)) { 298159307Spjd /* 299159307Spjd * Pretend it worked; maybe we should give a warning 300159307Spjd * here, but other shells don't. We don't alter 301159307Spjd * sigmode, so that we retry every time. 302159307Spjd */ 303159307Spjd return; 304159307Spjd } 305159307Spjd if (sigact == SIG_IGN) { 306159307Spjd if (mflag && (signo == SIGTSTP || 307159307Spjd signo == SIGTTIN || signo == SIGTTOU)) { 308159307Spjd *t = S_IGN; /* don't hard ignore these */ 309159307Spjd } else 310159307Spjd *t = S_HARD_IGN; 311159307Spjd } else { 312159307Spjd *t = S_RESET; /* force to be set */ 313159307Spjd } 314159307Spjd } 315159307Spjd if (*t == S_HARD_IGN || *t == action) 316159307Spjd return; 317159307Spjd switch (action) { 318159307Spjd case S_DFL: sigact = SIG_DFL; break; 319159307Spjd case S_CATCH: sigact = onsig; break; 320159307Spjd case S_IGN: sigact = SIG_IGN; break; 321159307Spjd } 322159307Spjd *t = action; 323159307Spjd sig = signal(signo, sigact); 324159307Spjd if (sig != SIG_ERR && action == S_CATCH) 325159307Spjd siginterrupt(signo, 1); 326159307Spjd} 327159307Spjd 328159307Spjd 329159307Spjd/* 330159307Spjd * Return the current setting for sig w/o changing it. 331159307Spjd */ 332159307Spjdstatic int 333159307Spjdgetsigaction(int signo, sig_t *sigact) 334159307Spjd{ 335159307Spjd struct sigaction sa; 336159307Spjd 337159307Spjd if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 338159307Spjd return 0; 339159307Spjd *sigact = (sig_t) sa.sa_handler; 340159307Spjd return 1; 341159307Spjd} 342159307Spjd 343159307Spjd 344159307Spjd/* 345159307Spjd * Ignore a signal. 346159307Spjd */ 347159307Spjdvoid 348159307Spjdignoresig(int signo) 349159307Spjd{ 350159307Spjd 351159307Spjd if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 352159307Spjd signal(signo, SIG_IGN); 353159307Spjd } 354159307Spjd sigmode[signo] = S_HARD_IGN; 355159307Spjd} 356159307Spjd 357159307Spjd 358159307Spjd#ifdef mkinit 359159307SpjdINCLUDE <signal.h> 360159307SpjdINCLUDE "trap.h" 361159307Spjd 362159307SpjdSHELLPROC { 363159307Spjd char *sm; 364159307Spjd 365159307Spjd clear_traps(); 366159307Spjd for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 367159307Spjd if (*sm == S_IGN) 368159307Spjd *sm = S_HARD_IGN; 369159307Spjd } 370159307Spjd} 371159307Spjd#endif 372159307Spjd 373159307Spjd 374159307Spjd/* 375159307Spjd * Signal handler. 376159307Spjd */ 377159307Spjdvoid 378159307Spjdonsig(int signo) 379159307Spjd{ 380159307Spjd 381159307Spjd if (signo == SIGINT && trap[SIGINT] == NULL) { 382159307Spjd onint(); 383159307Spjd return; 384159307Spjd } 385159307Spjd 386159307Spjd if (signo != SIGCHLD || !ignore_sigchld) 387159307Spjd gotsig[signo] = 1; 388159307Spjd pendingsigs++; 389159307Spjd 390159307Spjd /* If we are currently in a wait builtin, prepare to break it */ 391159307Spjd if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) 392159307Spjd breakwaitcmd = 1; 393159307Spjd /* 394159307Spjd * If a trap is set, not ignored and not the null command, we need 395159307Spjd * to make sure traps are executed even when a child blocks signals. 396159307Spjd */ 397159307Spjd if (Tflag && 398159307Spjd trap[signo] != NULL && 399159307Spjd ! (trap[signo][0] == '\0') && 400214116Spjd ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) 401214116Spjd breakwaitcmd = 1; 402214116Spjd 403214116Spjd#ifndef NO_HISTORY 404214116Spjd if (signo == SIGWINCH) 405159307Spjd gotwinch = 1; 406159307Spjd#endif 407159307Spjd} 408159307Spjd 409159307Spjd 410159307Spjd/* 411159307Spjd * Called to execute a trap. Perhaps we should avoid entering new trap 412159307Spjd * handlers while we are executing a trap handler. 413159307Spjd */ 414159307Spjdvoid 415159307Spjddotrap(void) 416159307Spjd{ 417159307Spjd int i; 418159307Spjd int savestatus; 419159307Spjd 420159307Spjd in_dotrap++; 421159307Spjd for (;;) { 422159307Spjd for (i = 1; i < NSIG; i++) { 423159307Spjd if (gotsig[i]) { 424159307Spjd gotsig[i] = 0; 425159307Spjd if (trap[i]) { 426159307Spjd /* 427159307Spjd * Ignore SIGCHLD to avoid infinite 428159307Spjd * recursion if the trap action does 429159307Spjd * a fork. 430159307Spjd */ 431159307Spjd if (i == SIGCHLD) 432159307Spjd ignore_sigchld++; 433159307Spjd savestatus = exitstatus; 434159307Spjd evalstring(trap[i], 0); 435159307Spjd exitstatus = savestatus; 436159307Spjd if (i == SIGCHLD) 437159307Spjd ignore_sigchld--; 438159343Spjd } 439159307Spjd break; 440159307Spjd } 441159307Spjd } 442159307Spjd if (i >= NSIG) 443159307Spjd break; 444159307Spjd } 445159307Spjd in_dotrap--; 446159307Spjd pendingsigs = 0; 447159307Spjd} 448159307Spjd 449159307Spjd 450159307Spjd/* 451159307Spjd * Controls whether the shell is interactive or not. 452159307Spjd */ 453159307Spjdvoid 454159307Spjdsetinteractive(int on) 455159307Spjd{ 456159307Spjd static int is_interactive = -1; 457159307Spjd 458159307Spjd if (on == is_interactive) 459159307Spjd return; 460159307Spjd setsignal(SIGINT); 461159307Spjd setsignal(SIGQUIT); 462159307Spjd setsignal(SIGTERM); 463159307Spjd#ifndef NO_HISTORY 464159307Spjd setsignal(SIGWINCH); 465159307Spjd#endif 466159307Spjd is_interactive = on; 467159307Spjd} 468159307Spjd 469159307Spjd 470159307Spjd/* 471159307Spjd * Called to exit the shell. 472159307Spjd */ 473159307Spjdvoid 474159307Spjdexitshell(int status) 475159307Spjd{ 476159307Spjd struct jmploc loc1, loc2; 477159307Spjd char *p; 478159307Spjd 479159307Spjd TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 480159307Spjd if (setjmp(loc1.loc)) { 481159307Spjd goto l1; 482159307Spjd } 483159307Spjd if (setjmp(loc2.loc)) { 484159307Spjd goto l2; 485159307Spjd } 486159307Spjd handler = &loc1; 487159307Spjd if ((p = trap[0]) != NULL && *p != '\0') { 488159307Spjd trap[0] = NULL; 489159307Spjd evalstring(p, 0); 490159307Spjd } 491159307Spjdl1: handler = &loc2; /* probably unnecessary */ 492159307Spjd flushall(); 493159307Spjd#if JOBS 494159307Spjd setjobctl(0); 495159343Spjd#endif 496160569Spjdl2: _exit(status); 497159307Spjd} 498159307Spjd