1/* trap.c -- Not the trap command, but useful functions for manipulating 2 those objects. The trap command is in builtins/trap.def. */ 3 4/* Copyright (C) 1987-2006 Free Software Foundation, Inc. 5 6 This file is part of GNU Bash, the Bourne Again SHell. 7 8 Bash is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free 10 Software Foundation; either version 2, or (at your option) any later 11 version. 12 13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY 14 WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 for more details. 17 18 You should have received a copy of the GNU General Public License along 19 with Bash; see the file COPYING. If not, write to the Free Software 20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 21 22#include "config.h" 23 24#if defined (HAVE_UNISTD_H) 25# include <unistd.h> 26#endif 27 28#include "bashtypes.h" 29#include "bashansi.h" 30 31#include <stdio.h> 32#include <errno.h> 33 34#include "bashintl.h" 35 36#include "trap.h" 37 38#include "shell.h" 39#include "flags.h" 40#include "input.h" /* for save_token_state, restore_token_state */ 41#include "signames.h" 42#include "builtins.h" 43#include "builtins/common.h" 44#include "builtins/builtext.h" 45 46#ifndef errno 47extern int errno; 48#endif 49 50/* Flags which describe the current handling state of a signal. */ 51#define SIG_INHERITED 0x0 /* Value inherited from parent. */ 52#define SIG_TRAPPED 0x1 /* Currently trapped. */ 53#define SIG_HARD_IGNORE 0x2 /* Signal was ignored on shell entry. */ 54#define SIG_SPECIAL 0x4 /* Treat this signal specially. */ 55#define SIG_NO_TRAP 0x8 /* Signal cannot be trapped. */ 56#define SIG_INPROGRESS 0x10 /* Signal handler currently executing. */ 57#define SIG_CHANGED 0x20 /* Trap value changed in trap handler. */ 58#define SIG_IGNORED 0x40 /* The signal is currently being ignored. */ 59 60#define SPECIAL_TRAP(s) ((s) == EXIT_TRAP || (s) == DEBUG_TRAP || (s) == ERROR_TRAP || (s) == RETURN_TRAP) 61 62/* An array of such flags, one for each signal, describing what the 63 shell will do with a signal. DEBUG_TRAP == NSIG; some code below 64 assumes this. */ 65static int sigmodes[BASH_NSIG]; 66 67static void free_trap_command __P((int)); 68static void change_signal __P((int, char *)); 69 70static void get_original_signal __P((int)); 71 72static int _run_trap_internal __P((int, char *)); 73 74static void reset_signal __P((int)); 75static void restore_signal __P((int)); 76static void reset_or_restore_signal_handlers __P((sh_resetsig_func_t *)); 77 78/* Variables used here but defined in other files. */ 79extern int last_command_exit_value; 80extern int line_number; 81 82extern char *this_command_name; 83extern sh_builtin_func_t *this_shell_builtin; 84extern procenv_t wait_intr_buf; 85extern int return_catch_flag, return_catch_value; 86extern int subshell_level; 87 88/* The list of things to do originally, before we started trapping. */ 89SigHandler *original_signals[NSIG]; 90 91/* For each signal, a slot for a string, which is a command to be 92 executed when that signal is recieved. The slot can also contain 93 DEFAULT_SIG, which means do whatever you were going to do before 94 you were so rudely interrupted, or IGNORE_SIG, which says ignore 95 this signal. */ 96char *trap_list[BASH_NSIG]; 97 98/* A bitmap of signals received for which we have trap handlers. */ 99int pending_traps[NSIG]; 100 101/* Set to the number of the signal we're running the trap for + 1. 102 Used in execute_cmd.c and builtins/common.c to clean up when 103 parse_and_execute does not return normally after executing the 104 trap command (e.g., when `return' is executed in the trap command). */ 105int running_trap; 106 107/* Set to last_command_exit_value before running a trap. */ 108int trap_saved_exit_value; 109 110/* The (trapped) signal received while executing in the `wait' builtin */ 111int wait_signal_received; 112 113/* A value which can never be the target of a trap handler. */ 114#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps 115 116#define GETORIGSIG(sig) \ 117 do { \ 118 original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \ 119 set_signal_handler (sig, original_signals[sig]); \ 120 if (original_signals[sig] == SIG_IGN) \ 121 sigmodes[sig] |= SIG_HARD_IGNORE; \ 122 } while (0) 123 124#define GET_ORIGINAL_SIGNAL(sig) \ 125 if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \ 126 GETORIGSIG(sig) 127 128void 129initialize_traps () 130{ 131 register int i; 132 133 initialize_signames(); 134 135 trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; 136 sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = sigmodes[ERROR_TRAP] = sigmodes[RETURN_TRAP] = SIG_INHERITED; 137 original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER; 138 139 for (i = 1; i < NSIG; i++) 140 { 141 pending_traps[i] = 0; 142 trap_list[i] = (char *)DEFAULT_SIG; 143 sigmodes[i] = SIG_INHERITED; 144 original_signals[i] = IMPOSSIBLE_TRAP_HANDLER; 145 } 146 147 /* Show which signals are treated specially by the shell. */ 148#if defined (SIGCHLD) 149 GETORIGSIG (SIGCHLD); 150 sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP); 151#endif /* SIGCHLD */ 152 153 GETORIGSIG (SIGINT); 154 sigmodes[SIGINT] |= SIG_SPECIAL; 155 156#if defined (__BEOS__) 157 /* BeOS sets SIGINT to SIG_IGN! */ 158 original_signals[SIGINT] = SIG_DFL; 159 sigmodes[SIGINT] &= ~SIG_HARD_IGNORE; 160#endif 161 162 GETORIGSIG (SIGQUIT); 163 sigmodes[SIGQUIT] |= SIG_SPECIAL; 164 165 if (interactive) 166 { 167 GETORIGSIG (SIGTERM); 168 sigmodes[SIGTERM] |= SIG_SPECIAL; 169 } 170} 171 172#ifdef INCLUDE_UNUSED 173/* Return a printable representation of the trap handler for SIG. */ 174static char * 175trap_handler_string (sig) 176 int sig; 177{ 178 if (trap_list[sig] == (char *)DEFAULT_SIG) 179 return "DEFAULT_SIG"; 180 else if (trap_list[sig] == (char *)IGNORE_SIG) 181 return "IGNORE_SIG"; 182 else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) 183 return "IMPOSSIBLE_TRAP_HANDLER"; 184 else if (trap_list[sig]) 185 return trap_list[sig]; 186 else 187 return "NULL"; 188} 189#endif 190 191/* Return the print name of this signal. */ 192char * 193signal_name (sig) 194 int sig; 195{ 196 char *ret; 197 198 /* on cygwin32, signal_names[sig] could be null */ 199 ret = (sig >= BASH_NSIG || sig < 0 || signal_names[sig] == NULL) 200 ? _("invalid signal number") 201 : signal_names[sig]; 202 203 return ret; 204} 205 206/* Turn a string into a signal number, or a number into 207 a signal number. If STRING is "2", "SIGINT", or "INT", 208 then (int)2 is returned. Return NO_SIG if STRING doesn't 209 contain a valid signal descriptor. */ 210int 211decode_signal (string, flags) 212 char *string; 213 int flags; 214{ 215 intmax_t sig; 216 char *name; 217 218 if (legal_number (string, &sig)) 219 return ((sig >= 0 && sig < NSIG) ? (int)sig : NO_SIG); 220 221 /* A leading `SIG' may be omitted. */ 222 for (sig = 0; sig < BASH_NSIG; sig++) 223 { 224 name = signal_names[sig]; 225 if (name == 0 || name[0] == '\0') 226 continue; 227 228 /* Check name without the SIG prefix first case sensitivly or 229 insensitively depending on whether flags includes DSIG_NOCASE */ 230 if (STREQN (name, "SIG", 3)) 231 { 232 name += 3; 233 234 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) 235 return ((int)sig); 236 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) 237 return ((int)sig); 238 /* If we can't use the `SIG' prefix to match, punt on this 239 name now. */ 240 else if ((flags & DSIG_SIGPREFIX) == 0) 241 continue; 242 } 243 244 /* Check name with SIG prefix case sensitively or insensitively 245 depending on whether flags includes DSIG_NOCASE */ 246 name = signal_names[sig]; 247 if ((flags & DSIG_NOCASE) && strcasecmp (string, name) == 0) 248 return ((int)sig); 249 else if ((flags & DSIG_NOCASE) == 0 && strcmp (string, name) == 0) 250 return ((int)sig); 251 } 252 253 return (NO_SIG); 254} 255 256/* Non-zero when we catch a trapped signal. */ 257static int catch_flag; 258 259void 260run_pending_traps () 261{ 262 register int sig; 263 int old_exit_value, *token_state; 264 265 if (catch_flag == 0) /* simple optimization */ 266 return; 267 268 catch_flag = 0; 269 270 /* Preserve $? when running trap. */ 271 old_exit_value = last_command_exit_value; 272 273 for (sig = 1; sig < NSIG; sig++) 274 { 275 /* XXX this could be made into a counter by using 276 while (pending_traps[sig]--) instead of the if statement. */ 277 if (pending_traps[sig]) 278 { 279#if defined (HAVE_POSIX_SIGNALS) 280 sigset_t set, oset; 281 282 sigemptyset (&set); 283 sigemptyset (&oset); 284 285 sigaddset (&set, sig); 286 sigprocmask (SIG_BLOCK, &set, &oset); 287#else 288# if defined (HAVE_BSD_SIGNALS) 289 int oldmask = sigblock (sigmask (sig)); 290# endif 291#endif /* HAVE_POSIX_SIGNALS */ 292 293 if (sig == SIGINT) 294 { 295 run_interrupt_trap (); 296 CLRINTERRUPT; 297 } 298 else if (trap_list[sig] == (char *)DEFAULT_SIG || 299 trap_list[sig] == (char *)IGNORE_SIG || 300 trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) 301 { 302 /* This is possible due to a race condition. Say a bash 303 process has SIGTERM trapped. A subshell is spawned 304 using { list; } & and the parent does something and kills 305 the subshell with SIGTERM. It's possible for the subshell 306 to set pending_traps[SIGTERM] to 1 before the code in 307 execute_cmd.c eventually calls restore_original_signals 308 to reset the SIGTERM signal handler in the subshell. The 309 next time run_pending_traps is called, pending_traps[SIGTERM] 310 will be 1, but the trap handler in trap_list[SIGTERM] will 311 be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG). 312 Unless we catch this, the subshell will dump core when 313 trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is 314 usually 0x0. */ 315 internal_warning (_("run_pending_traps: bad value in trap_list[%d]: %p"), 316 sig, trap_list[sig]); 317 if (trap_list[sig] == (char *)DEFAULT_SIG) 318 { 319 internal_warning (_("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself"), sig, signal_name (sig)); 320 kill (getpid (), sig); 321 } 322 } 323 else 324 { 325 token_state = save_token_state (); 326 parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST); 327 restore_token_state (token_state); 328 free (token_state); 329 } 330 331 pending_traps[sig] = 0; 332 333#if defined (HAVE_POSIX_SIGNALS) 334 sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); 335#else 336# if defined (HAVE_BSD_SIGNALS) 337 sigsetmask (oldmask); 338# endif 339#endif /* POSIX_VERSION */ 340 } 341 } 342 343 last_command_exit_value = old_exit_value; 344} 345 346sighandler 347trap_handler (sig) 348 int sig; 349{ 350 int oerrno; 351 352 if ((sig >= NSIG) || 353 (trap_list[sig] == (char *)DEFAULT_SIG) || 354 (trap_list[sig] == (char *)IGNORE_SIG)) 355 programming_error (_("trap_handler: bad signal %d"), sig); 356 else 357 { 358 oerrno = errno; 359#if defined (MUST_REINSTALL_SIGHANDLERS) 360 set_signal_handler (sig, trap_handler); 361#endif /* MUST_REINSTALL_SIGHANDLERS */ 362 363 catch_flag = 1; 364 pending_traps[sig]++; 365 366 if (interrupt_immediately && this_shell_builtin && (this_shell_builtin == wait_builtin)) 367 { 368 wait_signal_received = sig; 369 longjmp (wait_intr_buf, 1); 370 } 371 372 if (interrupt_immediately) 373 run_pending_traps (); 374 375 errno = oerrno; 376 } 377 378 SIGRETURN (0); 379} 380 381#if defined (JOB_CONTROL) && defined (SIGCHLD) 382 383#ifdef INCLUDE_UNUSED 384/* Make COMMAND_STRING be executed when SIGCHLD is caught. */ 385void 386set_sigchld_trap (command_string) 387 char *command_string; 388{ 389 set_signal (SIGCHLD, command_string); 390} 391#endif 392 393/* Make COMMAND_STRING be executed when SIGCHLD is caught iff SIGCHLD 394 is not already trapped. */ 395void 396maybe_set_sigchld_trap (command_string) 397 char *command_string; 398{ 399 if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0) 400 set_signal (SIGCHLD, command_string); 401} 402#endif /* JOB_CONTROL && SIGCHLD */ 403 404void 405set_debug_trap (command) 406 char *command; 407{ 408 set_signal (DEBUG_TRAP, command); 409} 410 411void 412set_error_trap (command) 413 char *command; 414{ 415 set_signal (ERROR_TRAP, command); 416} 417 418void 419set_return_trap (command) 420 char *command; 421{ 422 set_signal (RETURN_TRAP, command); 423} 424 425#ifdef INCLUDE_UNUSED 426void 427set_sigint_trap (command) 428 char *command; 429{ 430 set_signal (SIGINT, command); 431} 432#endif 433 434/* Reset the SIGINT handler so that subshells that are doing `shellsy' 435 things, like waiting for command substitution or executing commands 436 in explicit subshells ( ( cmd ) ), can catch interrupts properly. */ 437SigHandler * 438set_sigint_handler () 439{ 440 if (sigmodes[SIGINT] & SIG_HARD_IGNORE) 441 return ((SigHandler *)SIG_IGN); 442 443 else if (sigmodes[SIGINT] & SIG_IGNORED) 444 return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */ 445 446 else if (sigmodes[SIGINT] & SIG_TRAPPED) 447 return ((SigHandler *)set_signal_handler (SIGINT, trap_handler)); 448 449 /* The signal is not trapped, so set the handler to the shell's special 450 interrupt handler. */ 451 else if (interactive) /* XXX - was interactive_shell */ 452 return (set_signal_handler (SIGINT, sigint_sighandler)); 453 else 454 return (set_signal_handler (SIGINT, termsig_sighandler)); 455} 456 457/* Return the correct handler for signal SIG according to the values in 458 sigmodes[SIG]. */ 459SigHandler * 460trap_to_sighandler (sig) 461 int sig; 462{ 463 if (sigmodes[sig] & (SIG_IGNORED|SIG_HARD_IGNORE)) 464 return (SIG_IGN); 465 else if (sigmodes[sig] & SIG_TRAPPED) 466 return (trap_handler); 467 else 468 return (SIG_DFL); 469} 470 471/* Set SIG to call STRING as a command. */ 472void 473set_signal (sig, string) 474 int sig; 475 char *string; 476{ 477 if (SPECIAL_TRAP (sig)) 478 { 479 change_signal (sig, savestring (string)); 480 if (sig == EXIT_TRAP && interactive == 0) 481 initialize_terminating_signals (); 482 return; 483 } 484 485 /* A signal ignored on entry to the shell cannot be trapped or reset, but 486 no error is reported when attempting to do so. -- Posix.2 */ 487 if (sigmodes[sig] & SIG_HARD_IGNORE) 488 return; 489 490 /* Make sure we have original_signals[sig] if the signal has not yet 491 been trapped. */ 492 if ((sigmodes[sig] & SIG_TRAPPED) == 0) 493 { 494 /* If we aren't sure of the original value, check it. */ 495 if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) 496 GETORIGSIG (sig); 497 if (original_signals[sig] == SIG_IGN) 498 return; 499 } 500 501 /* Only change the system signal handler if SIG_NO_TRAP is not set. 502 The trap command string is changed in either case. The shell signal 503 handlers for SIGINT and SIGCHLD run the user specified traps in an 504 environment in which it is safe to do so. */ 505 if ((sigmodes[sig] & SIG_NO_TRAP) == 0) 506 { 507 set_signal_handler (sig, SIG_IGN); 508 change_signal (sig, savestring (string)); 509 set_signal_handler (sig, trap_handler); 510 } 511 else 512 change_signal (sig, savestring (string)); 513} 514 515static void 516free_trap_command (sig) 517 int sig; 518{ 519 if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] && 520 (trap_list[sig] != (char *)IGNORE_SIG) && 521 (trap_list[sig] != (char *)DEFAULT_SIG) && 522 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER)) 523 free (trap_list[sig]); 524} 525 526/* If SIG has a string assigned to it, get rid of it. Then give it 527 VALUE. */ 528static void 529change_signal (sig, value) 530 int sig; 531 char *value; 532{ 533 if ((sigmodes[sig] & SIG_INPROGRESS) == 0) 534 free_trap_command (sig); 535 trap_list[sig] = value; 536 537 sigmodes[sig] |= SIG_TRAPPED; 538 if (value == (char *)IGNORE_SIG) 539 sigmodes[sig] |= SIG_IGNORED; 540 else 541 sigmodes[sig] &= ~SIG_IGNORED; 542 if (sigmodes[sig] & SIG_INPROGRESS) 543 sigmodes[sig] |= SIG_CHANGED; 544} 545 546static void 547get_original_signal (sig) 548 int sig; 549{ 550 /* If we aren't sure the of the original value, then get it. */ 551 if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER) 552 GETORIGSIG (sig); 553} 554 555/* Restore the default action for SIG; i.e., the action the shell 556 would have taken before you used the trap command. This is called 557 from trap_builtin (), which takes care to restore the handlers for 558 the signals the shell treats specially. */ 559void 560restore_default_signal (sig) 561 int sig; 562{ 563 if (SPECIAL_TRAP (sig)) 564 { 565 if ((sig != DEBUG_TRAP && sig != ERROR_TRAP && sig != RETURN_TRAP) || 566 (sigmodes[sig] & SIG_INPROGRESS) == 0) 567 free_trap_command (sig); 568 trap_list[sig] = (char *)NULL; 569 sigmodes[sig] &= ~SIG_TRAPPED; 570 if (sigmodes[sig] & SIG_INPROGRESS) 571 sigmodes[sig] |= SIG_CHANGED; 572 return; 573 } 574 575 GET_ORIGINAL_SIGNAL (sig); 576 577 /* A signal ignored on entry to the shell cannot be trapped or reset, but 578 no error is reported when attempting to do so. Thanks Posix.2. */ 579 if (sigmodes[sig] & SIG_HARD_IGNORE) 580 return; 581 582 /* If we aren't trapping this signal, don't bother doing anything else. */ 583 if ((sigmodes[sig] & SIG_TRAPPED) == 0) 584 return; 585 586 /* Only change the signal handler for SIG if it allows it. */ 587 if ((sigmodes[sig] & SIG_NO_TRAP) == 0) 588 set_signal_handler (sig, original_signals[sig]); 589 590 /* Change the trap command in either case. */ 591 change_signal (sig, (char *)DEFAULT_SIG); 592 593 /* Mark the signal as no longer trapped. */ 594 sigmodes[sig] &= ~SIG_TRAPPED; 595} 596 597/* Make this signal be ignored. */ 598void 599ignore_signal (sig) 600 int sig; 601{ 602 if (SPECIAL_TRAP (sig) && ((sigmodes[sig] & SIG_IGNORED) == 0)) 603 { 604 change_signal (sig, (char *)IGNORE_SIG); 605 return; 606 } 607 608 GET_ORIGINAL_SIGNAL (sig); 609 610 /* A signal ignored on entry to the shell cannot be trapped or reset. 611 No error is reported when the user attempts to do so. */ 612 if (sigmodes[sig] & SIG_HARD_IGNORE) 613 return; 614 615 /* If already trapped and ignored, no change necessary. */ 616 if (sigmodes[sig] & SIG_IGNORED) 617 return; 618 619 /* Only change the signal handler for SIG if it allows it. */ 620 if ((sigmodes[sig] & SIG_NO_TRAP) == 0) 621 set_signal_handler (sig, SIG_IGN); 622 623 /* Change the trap command in either case. */ 624 change_signal (sig, (char *)IGNORE_SIG); 625} 626 627/* Handle the calling of "trap 0". The only sticky situation is when 628 the command to be executed includes an "exit". This is why we have 629 to provide our own place for top_level to jump to. */ 630int 631run_exit_trap () 632{ 633 char *trap_command; 634 int code, function_code, retval; 635 636 trap_saved_exit_value = last_command_exit_value; 637 function_code = 0; 638 639 /* Run the trap only if signal 0 is trapped and not ignored, and we are not 640 currently running in the trap handler (call to exit in the list of 641 commands given to trap 0). */ 642 if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) && 643 (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0) 644 { 645 trap_command = savestring (trap_list[EXIT_TRAP]); 646 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; 647 sigmodes[EXIT_TRAP] |= SIG_INPROGRESS; 648 649 retval = trap_saved_exit_value; 650 running_trap = 1; 651 652 code = setjmp (top_level); 653 654 /* If we're in a function, make sure return longjmps come here, too. */ 655 if (return_catch_flag) 656 function_code = setjmp (return_catch); 657 658 if (code == 0 && function_code == 0) 659 { 660 reset_parser (); 661 parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); 662 } 663 else if (code == ERREXIT) 664 retval = last_command_exit_value; 665 else if (code == EXITPROG) 666 retval = last_command_exit_value; 667 else if (function_code != 0) 668 retval = return_catch_value; 669 else 670 retval = trap_saved_exit_value; 671 672 running_trap = 0; 673 return retval; 674 } 675 676 return (trap_saved_exit_value); 677} 678 679void 680run_trap_cleanup (sig) 681 int sig; 682{ 683 sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); 684} 685 686/* Run a trap command for SIG. SIG is one of the signals the shell treats 687 specially. Returns the exit status of the executed trap command list. */ 688static int 689_run_trap_internal (sig, tag) 690 int sig; 691 char *tag; 692{ 693 char *trap_command, *old_trap; 694 int trap_exit_value, *token_state; 695 int save_return_catch_flag, function_code; 696 procenv_t save_return_catch; 697 698 trap_exit_value = function_code = 0; 699 /* Run the trap only if SIG is trapped and not ignored, and we are not 700 currently executing in the trap handler. */ 701 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && 702 (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && 703 ((sigmodes[sig] & SIG_INPROGRESS) == 0)) 704 { 705 old_trap = trap_list[sig]; 706 sigmodes[sig] |= SIG_INPROGRESS; 707 sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ 708 trap_command = savestring (old_trap); 709 710 running_trap = sig + 1; 711 trap_saved_exit_value = last_command_exit_value; 712 713 token_state = save_token_state (); 714 715 /* If we're in a function, make sure return longjmps come here, too. */ 716 save_return_catch_flag = return_catch_flag; 717 if (return_catch_flag) 718 { 719 COPY_PROCENV (return_catch, save_return_catch); 720 function_code = setjmp (return_catch); 721 } 722 723 if (function_code == 0) 724 parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST); 725 726 restore_token_state (token_state); 727 free (token_state); 728 729 trap_exit_value = last_command_exit_value; 730 last_command_exit_value = trap_saved_exit_value; 731 running_trap = 0; 732 733 sigmodes[sig] &= ~SIG_INPROGRESS; 734 735 if (sigmodes[sig] & SIG_CHANGED) 736 { 737#if 0 738 /* Special traps like EXIT, DEBUG, RETURN are handled explicitly in 739 the places where they can be changed using unwind-protects. For 740 example, look at execute_cmd.c:execute_function(). */ 741 if (SPECIAL_TRAP (sig) == 0) 742#endif 743 free (old_trap); 744 sigmodes[sig] &= ~SIG_CHANGED; 745 } 746 747 if (save_return_catch_flag) 748 { 749 return_catch_flag = save_return_catch_flag; 750 return_catch_value = trap_exit_value; 751 COPY_PROCENV (save_return_catch, return_catch); 752 if (function_code) 753 longjmp (return_catch, 1); 754 } 755 } 756 757 return trap_exit_value; 758} 759 760int 761run_debug_trap () 762{ 763 int trap_exit_value; 764 765 /* XXX - question: should the DEBUG trap inherit the RETURN trap? */ 766 trap_exit_value = 0; 767 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && ((sigmodes[DEBUG_TRAP] & SIG_IGNORED) == 0) && ((sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)) 768 { 769 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap"); 770 771#if defined (DEBUGGER) 772 /* If we're in the debugger and the DEBUG trap returns 2 while we're in 773 a function or sourced script, we force a `return'. */ 774 if (debugging_mode && trap_exit_value == 2 && return_catch_flag) 775 { 776 return_catch_value = trap_exit_value; 777 longjmp (return_catch, 1); 778 } 779#endif 780 } 781 return trap_exit_value; 782} 783 784void 785run_error_trap () 786{ 787 if ((sigmodes[ERROR_TRAP] & SIG_TRAPPED) && ((sigmodes[ERROR_TRAP] & SIG_IGNORED) == 0) && (sigmodes[ERROR_TRAP] & SIG_INPROGRESS) == 0) 788 _run_trap_internal (ERROR_TRAP, "error trap"); 789} 790 791void 792run_return_trap () 793{ 794 int old_exit_value; 795 796#if 0 797 if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS)) 798 return; 799#endif 800 801 if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0) 802 { 803 old_exit_value = last_command_exit_value; 804 _run_trap_internal (RETURN_TRAP, "return trap"); 805 last_command_exit_value = old_exit_value; 806 } 807} 808 809/* Run a trap set on SIGINT. This is called from throw_to_top_level (), and 810 declared here to localize the trap functions. */ 811void 812run_interrupt_trap () 813{ 814 _run_trap_internal (SIGINT, "interrupt trap"); 815} 816 817#ifdef INCLUDE_UNUSED 818/* Free all the allocated strings in the list of traps and reset the trap 819 values to the default. */ 820void 821free_trap_strings () 822{ 823 register int i; 824 825 for (i = 0; i < BASH_NSIG; i++) 826 { 827 free_trap_command (i); 828 trap_list[i] = (char *)DEFAULT_SIG; 829 sigmodes[i] &= ~SIG_TRAPPED; 830 } 831 trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = trap_list[ERROR_TRAP] = trap_list[RETURN_TRAP] = (char *)NULL; 832} 833#endif 834 835/* Reset the handler for SIG to the original value. */ 836static void 837reset_signal (sig) 838 int sig; 839{ 840 set_signal_handler (sig, original_signals[sig]); 841 sigmodes[sig] &= ~SIG_TRAPPED; 842} 843 844/* Set the handler signal SIG to the original and free any trap 845 command associated with it. */ 846static void 847restore_signal (sig) 848 int sig; 849{ 850 set_signal_handler (sig, original_signals[sig]); 851 change_signal (sig, (char *)DEFAULT_SIG); 852 sigmodes[sig] &= ~SIG_TRAPPED; 853} 854 855static void 856reset_or_restore_signal_handlers (reset) 857 sh_resetsig_func_t *reset; 858{ 859 register int i; 860 861 /* Take care of the exit trap first */ 862 if (sigmodes[EXIT_TRAP] & SIG_TRAPPED) 863 { 864 sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED; 865 if (reset != reset_signal) 866 { 867 free_trap_command (EXIT_TRAP); 868 trap_list[EXIT_TRAP] = (char *)NULL; 869 } 870 } 871 872 for (i = 1; i < NSIG; i++) 873 { 874 if (sigmodes[i] & SIG_TRAPPED) 875 { 876 if (trap_list[i] == (char *)IGNORE_SIG) 877 set_signal_handler (i, SIG_IGN); 878 else 879 (*reset) (i); 880 } 881 else if (sigmodes[i] & SIG_SPECIAL) 882 (*reset) (i); 883 } 884 885 /* Command substitution and other child processes don't inherit the 886 debug, error, or return traps. If we're in the debugger, and the 887 `functrace' or `errtrace' options have been set, then let command 888 substitutions inherit them. Let command substitution inherit the 889 RETURN trap if we're in the debugger and tracing functions. */ 890 if (function_trace_mode == 0) 891 { 892 sigmodes[DEBUG_TRAP] &= ~SIG_TRAPPED; 893 sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED; 894 } 895 if (error_trace_mode == 0) 896 sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED; 897} 898 899/* Reset trapped signals to their original values, but don't free the 900 trap strings. Called by the command substitution code. */ 901void 902reset_signal_handlers () 903{ 904 reset_or_restore_signal_handlers (reset_signal); 905} 906 907/* Reset all trapped signals to their original values. Signals set to be 908 ignored with trap '' SIGNAL should be ignored, so we make sure that they 909 are. Called by child processes after they are forked. */ 910void 911restore_original_signals () 912{ 913 reset_or_restore_signal_handlers (restore_signal); 914} 915 916/* If a trap handler exists for signal SIG, then call it; otherwise just 917 return failure. */ 918int 919maybe_call_trap_handler (sig) 920 int sig; 921{ 922 /* Call the trap handler for SIG if the signal is trapped and not ignored. */ 923 if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0)) 924 { 925 switch (sig) 926 { 927 case SIGINT: 928 run_interrupt_trap (); 929 break; 930 case EXIT_TRAP: 931 run_exit_trap (); 932 break; 933 case DEBUG_TRAP: 934 run_debug_trap (); 935 break; 936 case ERROR_TRAP: 937 run_error_trap (); 938 break; 939 default: 940 trap_handler (sig); 941 break; 942 } 943 return (1); 944 } 945 else 946 return (0); 947} 948 949int 950signal_is_trapped (sig) 951 int sig; 952{ 953 return (sigmodes[sig] & SIG_TRAPPED); 954} 955 956int 957signal_is_special (sig) 958 int sig; 959{ 960 return (sigmodes[sig] & SIG_SPECIAL); 961} 962 963int 964signal_is_ignored (sig) 965 int sig; 966{ 967 return (sigmodes[sig] & SIG_IGNORED); 968} 969 970void 971set_signal_ignored (sig) 972 int sig; 973{ 974 sigmodes[sig] |= SIG_HARD_IGNORE; 975 original_signals[sig] = SIG_IGN; 976} 977 978int 979signal_in_progress (sig) 980 int sig; 981{ 982 return (sigmodes[sig] & SIG_INPROGRESS); 983} 984