X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=trap.c;h=a24130f4b9cc984d5861df657035aff2ca4a6046;hb=28ef6c316f1aff914bb95ac09787a3c83c1815fd;hp=ab59ad784b078ef1843f0e64b216b13372c5b7f9;hpb=e8ce775db824de329b81293b4e5d8fbd65624528;p=platform%2Fupstream%2Fbash.git diff --git a/trap.c b/trap.c index ab59ad7..a24130f 100644 --- a/trap.c +++ b/trap.c @@ -7,7 +7,7 @@ Bash is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free - Software Foundation; either version 1, or (at your option) any later + Software Foundation; either version 2, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY @@ -17,25 +17,31 @@ You should have received a copy of the GNU General Public License along with Bash; see the file COPYING. If not, write to the Free Software - Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #include "config.h" -#include - #if defined (HAVE_UNISTD_H) # include #endif #include "bashtypes.h" -#include "trap.h" - #include "bashansi.h" +#include +#include + +#include "trap.h" + #include "shell.h" +#include "input.h" /* for save_token_state, restore_token_state */ #include "signames.h" #include "builtins/common.h" +#ifndef errno +extern int errno; +#endif + /* Flags which describe the current handling state of a signal. */ #define SIG_INHERITED 0x0 /* Value inherited from parent. */ #define SIG_TRAPPED 0x1 /* Currently trapped. */ @@ -116,6 +122,11 @@ initialize_traps () set_signal_handler (SIGINT, original_signals[SIGINT]); sigmodes[SIGINT] |= SIG_SPECIAL; +#if defined (__BEOS__) + /* BeOS sets SIGINT to SIG_IGN! */ + original_signals[SIGINT] = SIG_DFL; +#endif + original_signals[SIGQUIT] = (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL); set_signal_handler (SIGQUIT, original_signals[SIGQUIT]); @@ -130,12 +141,37 @@ initialize_traps () } } +#ifdef INCLUDE_UNUSED +/* Return a printable representation of the trap handler for SIG. */ +static char * +trap_handler_string (sig) + int sig; +{ + if (trap_list[sig] == (char *)DEFAULT_SIG) + return "DEFAULT_SIG"; + else if (trap_list[sig] == (char *)IGNORE_SIG) + return "IGNORE_SIG"; + else if (trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) + return "IMPOSSIBLE_TRAP_HANDLER"; + else if (trap_list[sig]) + return trap_list[sig]; + else + return "NULL"; +} +#endif + /* Return the print name of this signal. */ char * signal_name (sig) int sig; { - return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]); + char *ret; + + /* on cygwin32, signal_names[sig] could be null */ + ret = (sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]; + if (ret == NULL) + ret = "unrecognized signal number"; + return ret; } /* Turn a string into a signal number, or a number into @@ -153,10 +189,14 @@ decode_signal (string) /* A leading `SIG' may be omitted. */ for (sig = 0; sig <= NSIG; sig++) - if (strcasecmp (string, signal_names[sig]) == 0 || - (STREQN (signal_names[sig], "SIG", 3) && - strcasecmp (string, &(signal_names[sig])[3]) == 0)) - return ((int)sig); + { + if (signal_names[sig] == 0 || signal_names[sig][0] == '\0') + continue; + if (strcasecmp (string, signal_names[sig]) == 0 || + (STREQN (signal_names[sig], "SIG", 3) && + strcasecmp (string, &(signal_names[sig])[3]) == 0)) + return ((int)sig); + } return (NO_SIG); } @@ -168,7 +208,7 @@ void run_pending_traps () { register int sig; - int old_exit_value; + int old_exit_value, *token_state; if (catch_flag == 0) /* simple optimization */ return; @@ -181,7 +221,7 @@ run_pending_traps () for (sig = 1; sig < NSIG; sig++) { /* XXX this could be made into a counter by using - while (pending_traps[sig]--) instead of the if statement. */ + while (pending_traps[sig]--) instead of the if statement. */ if (pending_traps[sig]) { #if defined (HAVE_POSIX_SIGNALS) @@ -203,8 +243,38 @@ run_pending_traps () run_interrupt_trap (); CLRINTERRUPT; } + else if (trap_list[sig] == (char *)DEFAULT_SIG || + trap_list[sig] == (char *)IGNORE_SIG || + trap_list[sig] == (char *)IMPOSSIBLE_TRAP_HANDLER) + { + /* This is possible due to a race condition. Say a bash + process has SIGTERM trapped. A subshell is spawned + using { list; } & and the parent does something and kills + the subshell with SIGTERM. It's possible for the subshell + to set pending_traps[SIGTERM] to 1 before the code in + execute_cmd.c eventually calls restore_original_signals + to reset the SIGTERM signal handler in the subshell. The + next time run_pending_traps is called, pending_traps[SIGTERM] + will be 1, but the trap handler in trap_list[SIGTERM] will + be invalid (probably DEFAULT_SIG, but it could be IGNORE_SIG). + Unless we catch this, the subshell will dump core when + trap_list[SIGTERM] == DEFAULT_SIG, because DEFAULT_SIG is + usually 0x0. */ + internal_warning ("run_pending_traps: bad value in trap_list[%d]: 0x%x", + sig, (int)trap_list[sig]); + if (trap_list[sig] == (char *)DEFAULT_SIG) + { + internal_warning ("run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself", sig, signal_name (sig)); + kill (getpid (), sig); + } + } else - parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST); + { + token_state = save_token_state (); + parse_and_execute (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST); + restore_token_state (token_state); + free (token_state); + } pending_traps[sig] = 0; @@ -225,12 +295,15 @@ sighandler trap_handler (sig) int sig; { + int oerrno; + if ((sig >= NSIG) || (trap_list[sig] == (char *)DEFAULT_SIG) || (trap_list[sig] == (char *)IGNORE_SIG)) programming_error ("trap_handler: bad signal %d", sig); else { + oerrno = errno; #if defined (MUST_REINSTALL_SIGHANDLERS) set_signal_handler (sig, trap_handler); #endif /* MUST_REINSTALL_SIGHANDLERS */ @@ -240,12 +313,16 @@ trap_handler (sig) if (interrupt_immediately) run_pending_traps (); + + errno = oerrno; } SIGRETURN (0); } #if defined (JOB_CONTROL) && defined (SIGCHLD) + +#ifdef INCLUDE_UNUSED /* Make COMMAND_STRING be executed when SIGCHLD is caught. */ void set_sigchld_trap (command_string) @@ -253,6 +330,7 @@ set_sigchld_trap (command_string) { set_signal (SIGCHLD, command_string); } +#endif /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current SIGCHLD trap handler is DEFAULT_SIG. */ @@ -272,12 +350,14 @@ set_debug_trap (command) set_signal (DEBUG_TRAP, command); } +#ifdef INCLUDE_UNUSED void set_sigint_trap (command) char *command; { set_signal (SIGINT, command); } +#endif /* Reset the SIGINT handler so that subshells that are doing `shellsy' things, like waiting for command substitution or executing commands @@ -515,9 +595,12 @@ run_exit_trap () code = setjmp (top_level); if (code == 0) - parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); + { + reset_parser (); + parse_and_execute (trap_command, "exit trap", SEVAL_NONINT|SEVAL_NOHIST); + } else if (code == EXITPROG) - return (last_command_exit_value); + return (last_command_exit_value); else return (old_exit_value); } @@ -540,7 +623,7 @@ _run_trap_internal (sig, tag) char *tag; { char *trap_command, *old_trap; - int old_exit_value, old_line_number; + int old_exit_value, old_line_number, *token_state; /* Run the trap only if SIG is trapped and not ignored, and we are not currently executing in the trap handler. */ @@ -558,7 +641,12 @@ _run_trap_internal (sig, tag) /* Need to copy the value of line_number because parse_and_execute resets it to 1, and the trap command might want it. */ trap_line_number = line_number; + + token_state = save_token_state (); parse_and_execute (trap_command, tag, SEVAL_NONINT|SEVAL_NOHIST); + restore_token_state (token_state); + free (token_state); + last_command_exit_value = old_exit_value; running_trap = 0; @@ -587,6 +675,7 @@ run_interrupt_trap () _run_trap_internal (SIGINT, "interrupt trap"); } +#ifdef INCLUDE_UNUSED /* Free all the allocated strings in the list of traps and reset the trap values to the default. */ void @@ -602,6 +691,7 @@ free_trap_strings () } trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL; } +#endif /* Reset the handler for SIG to the original value. */ static void