diff options
Diffstat (limited to 'trap.c')
-rw-r--r-- | trap.c | 98 |
1 files changed, 79 insertions, 19 deletions
@@ -1,7 +1,7 @@ /* trap.c -- Not the trap command, but useful functions for manipulating those objects. The trap command is in builtins/trap.def. */ -/* Copyright (C) 1987-2018 Free Software Foundation, Inc. +/* Copyright (C) 1987-2020 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -90,6 +90,7 @@ static void trap_if_untrapped (int, char *); extern procenv_t alrmbuf; extern volatile int from_return_trap; +extern int waiting_for_child; extern WORD_LIST *subst_assign_varlist; @@ -120,6 +121,9 @@ int wait_signal_received; int trapped_signal_received; +/* Set to 1 to suppress the effect of `set v' in the DEBUG trap. */ +int suppress_debug_trap_verbose = 0; + #define GETORIGSIG(sig) \ do { \ original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL); \ @@ -294,6 +298,7 @@ run_pending_traps () { register int sig; int old_exit_value, x; + int old_running; WORD_LIST *save_subst_varlist; HASH_TABLE *save_tempenv; sh_parser_state_t pstate; @@ -330,6 +335,7 @@ run_pending_traps () #if defined (ARRAY_VARS) ps = save_pipestatus_array (); #endif + old_running = running_trap; for (sig = 1; sig < NSIG; sig++) { @@ -440,7 +446,7 @@ run_pending_traps () } pending_traps[sig] = 0; /* XXX - move before evalstring? */ - running_trap = 0; + running_trap = old_running; } } @@ -450,6 +456,17 @@ run_pending_traps () last_command_exit_value = old_exit_value; } +/* Set the private state variables noting that we received a signal SIG + for which we have a trap set. */ +void +set_trap_state (sig) + int sig; +{ + catch_flag = 1; + pending_traps[sig]++; + trapped_signal_received = sig; +} + sighandler trap_handler (sig) int sig; @@ -478,14 +495,12 @@ trap_handler (sig) set_signal_handler (sig, trap_handler); #endif /* MUST_REINSTALL_SIGHANDLERS */ - catch_flag = 1; - pending_traps[sig]++; - trapped_signal_received = sig; + set_trap_state (sig); if (this_shell_builtin && (this_shell_builtin == wait_builtin)) { wait_signal_received = sig; - if (interrupt_immediately && wait_intr_flag) + if (waiting_for_child && wait_intr_flag) sh_longjmp (wait_intr_buf, 1); } @@ -493,13 +508,10 @@ trap_handler (sig) /* Set the event hook so readline will call it after the signal handlers finish executing, so if this interrupted character input we can get quick response. */ - if (RL_ISSTATE (RL_STATE_SIGHANDLER) && interrupt_immediately == 0) + if (RL_ISSTATE (RL_STATE_SIGHANDLER)) bashline_set_event_hook (); #endif - if (interrupt_immediately) - run_pending_traps (); - errno = oerrno; } @@ -507,16 +519,23 @@ trap_handler (sig) } int -first_pending_trap () +next_pending_trap (start) + int start; { register int i; - for (i = 1; i < NSIG; i++) + for (i = start; i < NSIG; i++) if (pending_traps[i]) return i; return -1; } +int +first_pending_trap () +{ + return (next_pending_trap (1)); +} + /* Return > 0 if any of the "real" signals (not fake signals like EXIT) are trapped. */ int @@ -531,6 +550,15 @@ any_signals_trapped () } void +clear_pending_traps () +{ + register int i; + + for (i = 1; i < NSIG; i++) + pending_traps[i] = 0; +} + +void check_signals () { CHECK_ALRM; /* set by the read builtin */ @@ -952,6 +980,7 @@ void run_trap_cleanup (sig) int sig; { + /* XXX - should we clean up trap_list[sig] == IMPOSSIBLE_TRAP_HANDLER? */ sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED); } @@ -966,7 +995,8 @@ _run_trap_internal (sig, tag) { char *trap_command, *old_trap; int trap_exit_value; - volatile int save_return_catch_flag, function_code, old_int; + volatile int save_return_catch_flag, function_code; + int old_modes, old_running, old_int; int flags; procenv_t save_return_catch; WORD_LIST *save_subst_varlist; @@ -976,13 +1006,15 @@ _run_trap_internal (sig, tag) ARRAY *ps; #endif + old_modes = old_running = -1; + trap_exit_value = function_code = 0; trap_saved_exit_value = last_command_exit_value; /* Run the trap only if SIG is trapped and not ignored, and we are not currently executing in the trap handler. */ if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) && (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) && -#if 0 +#if 1 /* Uncomment this to allow some special signals to recursively execute trap handlers. */ (RECURSIVE_SIG (sig) || (sigmodes[sig] & SIG_INPROGRESS) == 0)) @@ -991,6 +1023,9 @@ _run_trap_internal (sig, tag) #endif { old_trap = trap_list[sig]; + old_modes = sigmodes[sig]; + old_running = running_trap; + sigmodes[sig] |= SIG_INPROGRESS; sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */ trap_command = savestring (old_trap); @@ -1050,8 +1085,10 @@ _run_trap_internal (sig, tag) temporary_env = save_tempenv; - sigmodes[sig] &= ~SIG_INPROGRESS; - running_trap = 0; + if ((old_modes & SIG_INPROGRESS) == 0) + sigmodes[sig] &= ~SIG_INPROGRESS; + + running_trap = old_running; interrupt_state = old_int; if (sigmodes[sig] & SIG_CHANGED) @@ -1110,9 +1147,7 @@ run_debug_trap () #endif old_verbose = echo_input_at_read; -#if 0 /* not yet */ - echo_input_at_read = 0; -#endif + echo_input_at_read = suppress_debug_trap_verbose ? 0 : echo_input_at_read; trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap"); @@ -1177,6 +1212,8 @@ run_interrupt_trap (will_throw) { if (will_throw && running_trap > 0) run_trap_cleanup (running_trap - 1); + pending_traps[SIGINT] = 0; /* run_pending_traps does this */ + catch_flag = 0; _run_trap_internal (SIGINT, "interrupt trap"); } @@ -1391,3 +1428,26 @@ signal_in_progress (sig) { return (sigmodes[sig] & SIG_INPROGRESS); } + +#if 0 /* TAG: bash-5.2 */ +int +block_trapped_signals (maskp, omaskp) + sigset_t *maskp; + sigset_t *omaskp; +{ + int i; + + sigemptyset (maskp); + for (i = 1; i < NSIG; i++) + if (sigmodes[i] & SIG_TRAPPED) + sigaddset (maskp, i); + return (sigprocmask (SIG_BLOCK, maskp, omaskp)); +} + +int +unblock_trapped_signals (maskp) + sigset_t *maskp; +{ + return (sigprocmask (SIG_SETMASK, maskp, 0)); +} +#endif |