]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20130222 snapshot
authorChet Ramey <chet@caleb.ins.cwru.edu>
Mon, 4 Mar 2013 13:11:02 +0000 (08:11 -0500)
committerChet Ramey <chet@caleb.ins.cwru.edu>
Mon, 4 Mar 2013 13:11:02 +0000 (08:11 -0500)
22 files changed:
CHANGES-4.3
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
NEWS-4.3
bashline.c
braces.c
eval.c~ [new file with mode: 0644]
jobs.c
lib/readline/isearch.c
lib/readline/readline.c
lib/readline/search.c
nojobs.c
pcomplete.c
quit.h
quit.h~
redir.c
sig.c
sig.c~ [new file with mode: 0644]
sig.h
sig.h~ [new file with mode: 0644]
unwind_prot.c
unwind_prot.c~ [new file with mode: 0644]

index 33f721be4ad8a667c9c61114997ee5c8814380de..3ef8460565269e65aacb136f61e25fa3588a7ce0 100644 (file)
@@ -315,6 +315,22 @@ vvvv. Worked around a kernel problem that caused SIGCHLD to interrupt open(2)
 
 wwww. Fixed a problem that resulted in inconsistent expansion of $* and ${a[*]}.
 
+xxxx. Fixed a problem that caused `read -t' to crash when interrupted by
+      SIGINT.
+
+yyyy. Fixed a problem that caused pattern removal to fail randomly because the
+      pattern matcher read beyond the end of a string.
+
+zzzz. Fixed a bug that caused core dumps when shell functions tried to create
+      local shadow copies of special variables like GROUPS.
+
+aaaaa. Fixed a bug that caused SIGTERM to be occasionally lost by children of
+       interactive shells when it arrived before the child process reset the
+       handler from SIG_DFL.
+
+bbbbb. Fixed a bug that caused redirections like <&n- to leave file descriptor
+       n closed if executed with a builtin command.
+
 2.  Changes to Readline
 
 a.  Fixed a bug that did not allow the `dd', `cc', or `yy' vi editing mode
@@ -372,6 +388,9 @@ q.  Fixed a bug that caused binding a macro to a multi-character key sequence
 r.  Fixed several redisplay errors with multibyte characters and prompts
     containing invisible characters when using horizontal scrolling.
 
+s.  Fixed a bug that caused redisplay errors when trying to overwrite
+    existing characters using multibyte characters.
+
 3.  New Features in Bash
 
 a.  The `helptopic' completion action now maps to all the help topics, not just
@@ -472,6 +491,12 @@ dd. The `printf' %(...)T format specifier now uses the current time if no
 ee. There is a new variable, BASH_COMPAT, that controls the current shell
     compatibility level.
 
+ff. The `popd' builtin now treats additional arguments as errors.
+
+gg. The brace expansion code now treats a failed sequence expansion as a
+    simple string and will continue to expand brace terms in the remainder
+    of the word.
+
 4.  New Features in Readline
 
 a.  Readline is now more responsive to SIGHUP and other fatal signals when
index 47a0914c3b379ba1f14a0f96fda0afb3d23c1cf8..67d406f4e7e68386d9e03c56437934480e6594ad 100644 (file)
@@ -4528,7 +4528,7 @@ trap.c
 lib/glob/xmbsrtowcs.c
        - xdupmbstowcs2: fixed but where end of string was not handled
          correctly, causing loop to go past end of string in a bunch of cases.
-         Fixes bug reported by
+         Fixes bug reported by "Dashing" <dashing@hushmail.com>
 
 
                                   2/13
@@ -4615,3 +4615,38 @@ lib/readline/display.c
        - use new variable `bytes_to_insert' instead of overloading temp in
          some code blocks (nls - nfd, bytes that comprise the characters
          different in the new line from the old)
+
+                                  2/18
+                                  ----
+redir.c
+       - do_redirection_internal: add undoable redirection for the implicit
+         close performed by the <&n- and >&n- redirections.  Fixes bug
+         reported by Stephane Chazelas <stephane.chazelas@gmail.com>
+
+                                  2/19
+                                  ----
+sig.c
+       - termsig_handler: an interactive shell killed by SIGHUP and keeping
+         command history will try to save the shell history before exiting.
+         This is an attempt to preserve the save-history-when-the-terminal-
+         window-is-closed behavior
+
+                                  2/21
+                                  ----
+braces.c
+       - brace_expand: if a sequence expansion fails (e.g. because the
+         integers overflow), treat that expansion as a simple string, including
+         the braces, and try to process any remainder of the string.  The
+         remainder may include brace expansions.  Derived from SuSE bug
+         804551 example (https://bugzilla.novell.com/show_bug.cgi?id=804551)
+
+                                  2/23
+                                  ----
+{quit,sig}.h,sig.c
+       - sigterm_received declaration now in sig.h; type is sig_atomic_t
+       - sigwinch_received type now sig_atomic_t
+       - sig.h includes bashtypes.h and <signal.h> if SIG_DFL not defined
+         (same logic as trap.h) to pick up sig_atomic_t
+
+unwind_prot.c
+       - include sig.h before quit.h (reverse order)
index ad8ff0d1f12562e8e452c1518193ee8d7849e32c..53f67c34bdcc967a4dd78e8f32d76194881e6490 100644 (file)
@@ -4528,7 +4528,7 @@ trap.c
 lib/glob/xmbsrtowcs.c
        - xdupmbstowcs2: fixed but where end of string was not handled
          correctly, causing loop to go past end of string in a bunch of cases.
-         Fixes bug reported by
+         Fixes bug reported by "Dashing" <dashing@hushmail.com>
 
 
                                   2/13
@@ -4603,3 +4603,47 @@ execute_cmd.c
 lib/readline/display.c
        - open_some_spaces: new function, subset of insert_some_chars that just
          opens up a specified number of spaces to be overwritten
+       - insert_some_spaces: now just calls to open_some_spaces followed by
+         _rl_output_some_chars
+       - update_line: use col_temp instead of recalculating it using
+         _rl_col_width in the case where we use more columns with fewer bytes
+       - update_line: use open_some_spaces and then output the right number
+         of chars instead of trying to print new characters then overwrite
+         existing characters in two separate calls.  This includes removing
+         some dodgy code and making things simpler.  Fix from Egmont
+         Koblinger <egmont@gmail.com>
+       - use new variable `bytes_to_insert' instead of overloading temp in
+         some code blocks (nls - nfd, bytes that comprise the characters
+         different in the new line from the old)
+
+                                  2/18
+                                  ----
+redir.c
+       - do_redirection_internal: add undoable redirection for the implicit
+         close performed by the <&n- and >&n- redirections.  Fixes bug
+         reported by Stephane Chazelas <stephane.chazelas@gmail.com>
+
+                                  2/19
+                                  ----
+sig.c
+       - termsig_handler: an interactive shell killed by SIGHUP and keeping
+         command history will try to save the shell history before exiting.
+         This is an attempt to preserve the save-history-when-the-terminal-
+         window-is-closed behavior
+
+                                  2/21
+                                  ----
+braces.c
+       - brace_expand: if a sequence expansion fails (e.g. because the
+         integers overflow), treat that expansion as a simple string, including
+         the braces, and try to process any remainder of the string.  The
+         remainder may include brace expansions.  Derived from SuSE bug
+         804551 example (https://bugzilla.novell.com/show_bug.cgi?id=804551)
+
+                                  2/23
+                                  ----
+{quit,sig}.h,sig.c
+       - sigterm_received declaration now in sig.h; type is sig_atomic_t
+       - sigwinch_received type now sig_atomic_t
+       - sig.h includes bashtypes.h and <signal.h> if SIG_DFL not defined
+         (same logic as trap.h) to pick up sig_atomic_t
index a02033aef232398b193562c0e10a018d5e76178c..94e30931235d15bc51492829b798980fd80d4b39 100644 (file)
--- a/NEWS-4.3
+++ b/NEWS-4.3
@@ -102,6 +102,12 @@ dd. The `printf' %(...)T format specifier now uses the current time if no
 ee. There is a new variable, BASH_COMPAT, that controls the current shell
     compatibility level.
 
+ff. The `popd' builtin now treats additional arguments as errors.
+
+gg. The brace expansion code now treats a failed sequence expansion as a
+    simple string and will continue to expand brace terms in the remainder
+    of the word.
+
 2.  New Features in Readline
 
 a.  Readline is now more responsive to SIGHUP and other fatal signals when
index 3a72f04247ba7ea1c87761259385eff387dc7820..eafe3d92bd4c1255d233a99a7b65514560048b91 100644 (file)
@@ -4140,10 +4140,6 @@ bash_dequote_text (text)
 static int
 bash_event_hook ()
 {
-#if defined (DEBUG)
-itrace("bash_event_hook");
-#endif
-
   /* If we're going to longjmp to top_level, make sure we clean up readline */
   if (interrupt_state && signal_is_trapped (SIGINT) == 0)
     rl_cleanup_after_signal ();
index 155b5a08441213174c9c97e35a49de7a3216a070..3c373e11c21cafe65cb6b1ce9d7a0a0bd1efeeaa 100644 (file)
--- a/braces.c
+++ b/braces.c
@@ -228,6 +228,19 @@ brace_expand (text)
       tack = expand_seqterm (amble, alen);
       if (tack)
        goto add_tack;
+      else if (text[i + 1])
+       {
+         /* If the sequence expansion fails (e.g., because the integers
+            overflow), but there is more in the string, try and process
+            the rest of the string, which may contain additional brace
+            expansions.  Treat the unexpanded sequence term as a simple
+            string (including the braces). */
+         tack = strvec_create (2);
+         tack[0] = savestring (text+start-1);
+         tack[0][i-start+2] = '\0';
+         tack[1] = (char *)0;
+         goto add_tack;
+       }
       else
        {
          free (amble);
diff --git a/eval.c~ b/eval.c~
new file mode 100644 (file)
index 0000000..2f96a06
--- /dev/null
+++ b/eval.c~
@@ -0,0 +1,292 @@
+/* eval.c -- reading and evaluating commands. */
+
+/* Copyright (C) 1996-2011 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   Bash is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include <stdio.h>
+
+#include "bashintl.h"
+
+
+#include "shell.h"
+#include "flags.h"
+#include "trap.h"
+
+#include "builtins/common.h"
+
+#include "input.h"
+#include "execute_cmd.h"
+
+#if defined (HISTORY)
+#  include "bashhist.h"
+#endif
+
+extern int EOF_reached;
+extern int indirection_level;
+extern int posixly_correct;
+extern int subshell_environment, running_under_emacs;
+extern int last_command_exit_value, stdin_redir;
+extern int need_here_doc;
+extern int current_command_number, current_command_line_count, line_number;
+extern int expand_aliases;
+
+#if defined (HAVE_POSIX_SIGNALS)
+extern sigset_t top_level_mask;
+#endif
+
+static void send_pwd_to_eterm __P((void));
+static sighandler alrm_catcher __P((int));
+
+/* Read and execute commands until EOF is reached.  This assumes that
+   the input source has already been initialized. */
+int
+reader_loop ()
+{
+  int our_indirection_level;
+  COMMAND * volatile current_command;
+
+  USE_VAR(current_command);
+
+  current_command = (COMMAND *)NULL;
+
+  our_indirection_level = ++indirection_level;
+
+  while (EOF_Reached == 0)
+    {
+      int code;
+
+      code = setjmp_nosigs (top_level);
+
+#if defined (PROCESS_SUBSTITUTION)
+      unlink_fifo_list ();
+#endif /* PROCESS_SUBSTITUTION */
+
+      /* XXX - why do we set this every time through the loop? */
+      if (interactive_shell && signal_is_ignored (SIGINT) == 0)
+       set_signal_handler (SIGINT, sigint_sighandler);
+
+      if (code != NOT_JUMPED)
+       {
+         indirection_level = our_indirection_level;
+
+         switch (code)
+           {
+             /* Some kind of throw to top_level has occured. */
+           case FORCE_EOF:
+           case ERREXIT:
+           case EXITPROG:
+             current_command = (COMMAND *)NULL;
+             if (exit_immediately_on_error)
+               variable_context = 0;   /* not in a function */
+             EOF_Reached = EOF;
+             goto exec_done;
+
+           case DISCARD:
+             /* Make sure the exit status is reset to a non-zero value, but
+                leave existing non-zero values (e.g., > 128 on signal)
+                alone. */
+             if (last_command_exit_value == 0)
+               last_command_exit_value = EXECUTION_FAILURE;
+             if (subshell_environment)
+               {
+                 current_command = (COMMAND *)NULL;
+                 EOF_Reached = EOF;
+                 goto exec_done;
+               }
+             /* Obstack free command elements, etc. */
+             if (current_command)
+               {
+                 dispose_command (current_command);
+                 current_command = (COMMAND *)NULL;
+               }
+#if defined (HAVE_POSIX_SIGNALS)
+             sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
+#endif
+             break;
+
+           default:
+             command_error ("reader_loop", CMDERR_BADJUMP, code, 0);
+           }
+       }
+
+      executing = 0;
+      if (temporary_env)
+       dispose_used_env_vars ();
+
+#if (defined (ultrix) && defined (mips)) || defined (C_ALLOCA)
+      /* Attempt to reclaim memory allocated with alloca (). */
+      (void) alloca (0);
+#endif
+
+      if (read_command () == 0)
+       {
+         if (interactive_shell == 0 && read_but_dont_execute)
+           {
+             last_command_exit_value = EXECUTION_SUCCESS;
+             dispose_command (global_command);
+             global_command = (COMMAND *)NULL;
+           }
+         else if (current_command = global_command)
+           {
+             global_command = (COMMAND *)NULL;
+             current_command_number++;
+
+             executing = 1;
+             stdin_redir = 0;
+             execute_command (current_command);
+
+           exec_done:
+             QUIT;
+
+             if (current_command)
+               {
+                 dispose_command (current_command);
+                 current_command = (COMMAND *)NULL;
+               }
+           }
+       }
+      else
+       {
+         /* Parse error, maybe discard rest of stream if not interactive. */
+         if (interactive == 0)
+           EOF_Reached = EOF;
+       }
+      if (just_one_command)
+       EOF_Reached = EOF;
+    }
+  indirection_level--;
+  return (last_command_exit_value);
+}
+
+static sighandler
+alrm_catcher(i)
+     int i;
+{
+  printf (_("\007timed out waiting for input: auto-logout\n"));
+  fflush (stdout);
+  bash_logout ();      /* run ~/.bash_logout if this is a login shell */
+  jump_to_top_level (EXITPROG);
+  SIGRETURN (0);
+}
+
+/* Send an escape sequence to emacs term mode to tell it the
+   current working directory. */
+static void
+send_pwd_to_eterm ()
+{
+  char *pwd, *f;
+
+  f = 0;
+  pwd = get_string_value ("PWD");
+  if (pwd == 0)
+    f = pwd = get_working_directory ("eterm");
+  fprintf (stderr, "\032/%s\n", pwd);
+  free (f);
+}
+
+/* Call the YACC-generated parser and return the status of the parse.
+   Input is read from the current input stream (bash_input).  yyparse
+   leaves the parsed command in the global variable GLOBAL_COMMAND.
+   This is where PROMPT_COMMAND is executed. */
+int
+parse_command ()
+{
+  int r;
+  char *command_to_execute;
+
+  need_here_doc = 0;
+  run_pending_traps ();
+
+  /* Allow the execution of a random command just before the printing
+     of each primary prompt.  If the shell variable PROMPT_COMMAND
+     is set then the value of it is the command to execute. */
+  if (interactive && bash_input.type != st_string)
+    {
+      command_to_execute = get_string_value ("PROMPT_COMMAND");
+      if (command_to_execute)
+       execute_variable_command (command_to_execute, "PROMPT_COMMAND");
+
+      if (running_under_emacs == 2)
+       send_pwd_to_eterm ();   /* Yuck */
+    }
+
+  current_command_line_count = 0;
+  r = yyparse ();
+
+  if (need_here_doc)
+    gather_here_documents ();
+
+  return (r);
+}
+
+/* Read and parse a command, returning the status of the parse.  The command
+   is left in the globval variable GLOBAL_COMMAND for use by reader_loop.
+   This is where the shell timeout code is executed. */
+int
+read_command ()
+{
+  SHELL_VAR *tmout_var;
+  int tmout_len, result;
+  SigHandler *old_alrm;
+
+  set_current_prompt_level (1);
+  global_command = (COMMAND *)NULL;
+
+  /* Only do timeouts if interactive. */
+  tmout_var = (SHELL_VAR *)NULL;
+  tmout_len = 0;
+  old_alrm = (SigHandler *)NULL;
+
+  if (interactive)
+    {
+      tmout_var = find_variable ("TMOUT");
+
+      if (tmout_var && var_isset (tmout_var))
+       {
+         tmout_len = atoi (value_cell (tmout_var));
+         if (tmout_len > 0)
+           {
+             old_alrm = set_signal_handler (SIGALRM, alrm_catcher);
+             alarm (tmout_len);
+           }
+       }
+    }
+
+  QUIT;
+
+  current_command_line_count = 0;
+  result = parse_command ();
+
+  if (interactive && tmout_var && (tmout_len > 0))
+    {
+      alarm(0);
+      set_signal_handler (SIGALRM, old_alrm);
+    }
+
+  return (result);
+}
diff --git a/jobs.c b/jobs.c
index 1338661cb82794636482a7548150e2af1132d46d..257cb6c8f393cb785ad17d1b768446af313c363f 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -1717,6 +1717,8 @@ make_child (command, async_p)
   sigset_t set, oset;
   pid_t pid;
 
+  /* XXX - block SIGTERM here and unblock in child after fork resets the
+     set of pending signals? */
   sigemptyset (&set);
   sigaddset (&set, SIGCHLD);
   sigaddset (&set, SIGINT);
@@ -1747,11 +1749,16 @@ make_child (command, async_p)
       waitchld (-1, 0);
 
       sys_error ("fork: retry");
+      RESET_SIGTERM;
+
       if (sleep (forksleep) != 0)
        break;
       forksleep <<= 1;
     }
 
+  if (pid != 0)
+    RESET_SIGTERM;
+
   if (pid < 0)
     {
       sys_error ("fork");
@@ -1767,9 +1774,6 @@ make_child (command, async_p)
       throw_to_top_level ();   /* Reset signals, etc. */
     }
 
-  if (pid != 0)
-    RESET_SIGTERM;
-
   if (pid == 0)
     {
       /* In the child.  Give this child the right process group, set the
index fcc01d9b71c1bb15277c2fb3ef527538d90dc799..dfd8ff8c9d9f13bba7a10ad9aa42d8771620c8d0 100644 (file)
@@ -318,6 +318,7 @@ _rl_search_getchar (cxt)
     c = cxt->lastc = _rl_read_mbstring (cxt->lastc, cxt->mb, MB_LEN_MAX);
 #endif
 
+  RL_CHECK_SIGNALS ();
   return c;
 }
 
index 1946ff146fa6c605ca84bfa99f2c420bcbff0d7e..947dfdbe20b44304fcb8152bfb373f8e86ec26d2 100644 (file)
@@ -559,7 +559,8 @@ readline_internal_charloop ()
 
       /* look at input.c:rl_getc() for the circumstances under which this will
         be returned; punt immediately on read error without converting it to
-        a newline. */
+        a newline; assume that rl_read_key has already called the signal
+        handler. */
       if (c == READERR)
        {
 #if defined (READLINE_CALLBACKS)
index 453074656d80a944139f5ee72cb44c7f279f00f8..aff6654ef6a2c3076d3bc70e1d4be6453153966a 100644 (file)
@@ -468,6 +468,7 @@ rl_history_search_internal (count, dir)
      copy into the line buffer. */
   while (count)
     {
+      RL_CHECK_SIGNALS ();
       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
       if (ret == -1)
        break;
index 3046cd9120b1d3de66ceb68f98300e6cd9bd6c58..16126be57cd099055eb19c20c3138539e77a2cdf 100644 (file)
--- a/nojobs.c
+++ b/nojobs.c
@@ -501,11 +501,17 @@ make_child (command, async_p)
     sync_buffered_stream (default_buffered_input);
 #endif /* BUFFERED_INPUT */
 
+  /* XXX - block SIGTERM here and unblock in child after fork resets the
+     set of pending signals? */
+  RESET_SIGTERM;
+
   /* Create the child, handle severe errors.  Retry on EAGAIN. */
   forksleep = 1;
   while ((pid = fork ()) < 0 && errno == EAGAIN && forksleep < FORKSLEEP_MAX)
     {
       sys_error ("fork: retry");
+      RESET_SIGTERM;
+
 #if defined (HAVE_WAITPID)
       /* Posix systems with a non-blocking waitpid () system call available
         get another chance after zombies are reaped. */
@@ -519,6 +525,9 @@ make_child (command, async_p)
       forksleep <<= 1;
     }
 
+  if (pid != 0)
+    RESET_SIGTERM;
+
   if (pid < 0)
     {
       sys_error ("fork");
index 38faab1ae2856663eaa9548c730417c97f69ec81..6b4e03323912c55fbc3b98df0a8b01049f403774 100644 (file)
@@ -729,7 +729,7 @@ pcomp_filename_completion_function (text, state)
     {
       FREE (dfn);
       /* remove backslashes quoting special characters in filenames. */
-      /* There are roughtly three paths we can follow to get here:
+      /* There are roughly three paths we can follow to get here:
                1.  complete -f
                2.  compgen -f "$word" from a completion function
                3.  compgen -f "$word" from the command line
diff --git a/quit.h b/quit.h
index adfb3ebbf9e98ba53912a62558be1b336ac24e6e..87d9b8c264bf28a303b13eab1bfe3b61c9bee920 100644 (file)
--- a/quit.h
+++ b/quit.h
@@ -25,8 +25,6 @@
 extern volatile int interrupt_state;
 extern volatile int terminating_signal;
 
-extern sig_atomic_t sigterm_received;
-
 /* Macro to call a great deal.  SIGINT just sets the interrupt_state variable.
    When it is safe, put QUIT in the code, and the "interrupt" will take
    place.  The same scheme is used for terminating signals (e.g., SIGHUP)
diff --git a/quit.h~ b/quit.h~
index c72d310b29a93ee47e6b147d647c7d4fdee25626..adfb3ebbf9e98ba53912a62558be1b336ac24e6e 100644 (file)
--- a/quit.h~
+++ b/quit.h~
@@ -1,6 +1,6 @@
 /* quit.h -- How to handle SIGINT gracefully. */
 
-/* Copyright (C) 1993-2012 Free Software Foundation, Inc.
+/* Copyright (C) 1993-2013 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
diff --git a/redir.c b/redir.c
index aa3d16df6879a7ee712e6212d4a34c8a211b145f..9e5ca0f08bcb257cef8621aefcb5c195fb6cf22c 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -1044,6 +1044,16 @@ do_redirection_internal (redirect, flags)
                r = add_undo_close_redirect (redirector);
              REDIRECTION_ERROR (r, errno, -1);
            }
+         if ((flags & RX_UNDOABLE) && (ri == r_move_input || ri == r_move_output))
+           {
+             /* r_move_input and r_move_output add an additional close()
+                that needs to be undone */
+             if (fcntl (redirector, F_GETFD, 0) != -1)
+               {
+                 r = add_undo_redirect (redir_fd, r_close_this, -1);
+                 REDIRECTION_ERROR (r, errno, -1);
+               }
+           }
 #if defined (BUFFERED_INPUT)
          check_bash_input (redirector);
 #endif
diff --git a/sig.c b/sig.c
index 893446aac2af79d4e731d5480d32b1db16cd2728..fc6e41e2dfc78b86cd571aee82d033f718fd1c14 100644 (file)
--- a/sig.c
+++ b/sig.c
@@ -71,13 +71,14 @@ extern void initialize_siglist ();
 volatile int interrupt_state = 0;
 
 /* Non-zero after SIGWINCH */
-volatile int sigwinch_received = 0;
+sig_atomic_t sigwinch_received = 0;
+
+/* Non-zero after SIGTERM */
+sig_atomic_t sigterm_received = 0;
 
 /* Set to the value of any terminating signal received. */
 volatile int terminating_signal = 0;
 
-sig_atomic_t sigterm_received = 0;
-
 /* The environment at the top-level R-E loop.  We use this in
    the case of error return. */
 procenv_t top_level;
@@ -420,7 +421,8 @@ throw_to_top_level ()
 #endif /* JOB_CONTROL */
 
 #if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
-  /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
+  /* This needs to stay because jobs.c:make_child() uses it without resetting
+     the signal mask. */
   sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
 #endif
 
@@ -553,12 +555,14 @@ termsig_handler (sig)
   if (sig == SIGINT && signal_is_trapped (SIGINT))
     run_interrupt_trap ();
 
-#if 0
 #if defined (HISTORY)
-  if (interactive_shell && (sig != SIGABRT && sig != SIGINT && sig != SIGHUP && sig != SIGTERM))
+  /* If we don't do something like this, the history will not be saved when
+     an interactive shell is running in a terminal window that gets closed
+     with the `close' button.  We can't test for RL_STATE_READCMD because
+     readline no longer handles SIGTERM synchronously.  */
+  if (interactive_shell && interactive && sig == SIGHUP && remember_on_history)
     maybe_save_shell_history ();
 #endif /* HISTORY */
-#endif
 
 #if defined (JOB_CONTROL)
   if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
diff --git a/sig.c~ b/sig.c~
new file mode 100644 (file)
index 0000000..539a1ff
--- /dev/null
+++ b/sig.c~
@@ -0,0 +1,722 @@
+/* sig.c - interface for shell signal handlers and signal initialization. */
+
+/* Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   Bash is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "bashintl.h"
+
+#include "shell.h"
+#if defined (JOB_CONTROL)
+#include "jobs.h"
+#endif /* JOB_CONTROL */
+#include "siglist.h"
+#include "sig.h"
+#include "trap.h"
+
+#include "builtins/common.h"
+
+#if defined (READLINE)
+#  include "bashline.h"
+#  include <readline/readline.h>
+#endif
+
+#if defined (HISTORY)
+#  include "bashhist.h"
+#endif
+
+extern int last_command_exit_value;
+extern int last_command_exit_signal;
+extern int return_catch_flag;
+extern int loop_level, continuing, breaking, funcnest;
+extern int executing_list;
+extern int comsub_ignore_return;
+extern int parse_and_execute_level, shell_initialized;
+#if defined (HISTORY)
+extern int history_lines_this_session;
+#endif
+extern int no_line_editing;
+
+extern void initialize_siglist ();
+
+/* Non-zero after SIGINT. */
+volatile int interrupt_state = 0;
+
+/* Non-zero after SIGWINCH */
+volatile int sigwinch_received = 0;
+
+/* Set to the value of any terminating signal received. */
+volatile int terminating_signal = 0;
+
+sig_atomic_t sigterm_received = 0;
+
+/* The environment at the top-level R-E loop.  We use this in
+   the case of error return. */
+procenv_t top_level;
+
+#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
+/* The signal masks that this shell runs with. */
+sigset_t top_level_mask;
+#endif /* JOB_CONTROL */
+
+/* When non-zero, we throw_to_top_level (). */
+int interrupt_immediately = 0;
+
+/* When non-zero, we call the terminating signal handler immediately. */
+int terminate_immediately = 0;
+
+#if defined (SIGWINCH)
+static SigHandler *old_winch = (SigHandler *)SIG_DFL;
+#endif
+
+static void initialize_shell_signals __P((void));
+
+void
+initialize_signals (reinit)
+     int reinit;
+{
+  initialize_shell_signals ();
+  initialize_job_signals ();
+#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
+  if (reinit == 0)
+    initialize_siglist ();
+#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
+}
+
+/* A structure describing a signal that terminates the shell if not
+   caught.  The orig_handler member is present so children can reset
+   these signals back to their original handlers. */
+struct termsig {
+     int signum;
+     SigHandler *orig_handler;
+     int orig_flags;
+};
+
+#define NULL_HANDLER (SigHandler *)SIG_DFL
+
+/* The list of signals that would terminate the shell if not caught.
+   We catch them, but just so that we can write the history file,
+   and so forth. */
+static struct termsig terminating_signals[] = {
+#ifdef SIGHUP
+{  SIGHUP, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGINT
+{  SIGINT, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGILL
+{  SIGILL, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGTRAP
+{  SIGTRAP, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGIOT
+{  SIGIOT, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGDANGER
+{  SIGDANGER, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGEMT
+{  SIGEMT, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGFPE
+{  SIGFPE, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGBUS
+{  SIGBUS, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGSEGV
+{  SIGSEGV, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGSYS
+{  SIGSYS, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGPIPE
+{  SIGPIPE, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGALRM
+{  SIGALRM, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGTERM
+{  SIGTERM, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGXCPU
+{  SIGXCPU, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGXFSZ
+{  SIGXFSZ, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGVTALRM
+{  SIGVTALRM, NULL_HANDLER, 0 },
+#endif
+
+#if 0
+#ifdef SIGPROF
+{  SIGPROF, NULL_HANDLER, 0 },
+#endif
+#endif
+
+#ifdef SIGLOST
+{  SIGLOST, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGUSR1
+{  SIGUSR1, NULL_HANDLER, 0 },
+#endif
+
+#ifdef SIGUSR2
+{  SIGUSR2, NULL_HANDLER, 0 },
+#endif
+};
+
+#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
+
+#define XSIG(x) (terminating_signals[x].signum)
+#define XHANDLER(x) (terminating_signals[x].orig_handler)
+#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
+
+static int termsigs_initialized = 0;
+
+/* Initialize signals that will terminate the shell to do some
+   unwind protection.  For non-interactive shells, we only call
+   this when a trap is defined for EXIT (0) or when trap is run
+   to display signal dispositions. */
+void
+initialize_terminating_signals ()
+{
+  register int i;
+#if defined (HAVE_POSIX_SIGNALS)
+  struct sigaction act, oact;
+#endif
+
+  if (termsigs_initialized)
+    return;
+
+  /* The following code is to avoid an expensive call to
+     set_signal_handler () for each terminating_signals.  Fortunately,
+     this is possible in Posix.  Unfortunately, we have to call signal ()
+     on non-Posix systems for each signal in terminating_signals. */
+#if defined (HAVE_POSIX_SIGNALS)
+  act.sa_handler = termsig_sighandler;
+  act.sa_flags = 0;
+  sigemptyset (&act.sa_mask);
+  sigemptyset (&oact.sa_mask);
+  for (i = 0; i < TERMSIGS_LENGTH; i++)
+    sigaddset (&act.sa_mask, XSIG (i));
+  for (i = 0; i < TERMSIGS_LENGTH; i++)
+    {
+      /* If we've already trapped it, don't do anything. */
+      if (signal_is_trapped (XSIG (i)))
+       continue;
+
+      sigaction (XSIG (i), &act, &oact);
+      XHANDLER(i) = oact.sa_handler;
+      XSAFLAGS(i) = oact.sa_flags;
+      /* Don't do anything with signals that are ignored at shell entry
+        if the shell is not interactive. */
+      /* XXX - should we do this for interactive shells, too? */
+      if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
+       {
+         sigaction (XSIG (i), &oact, &act);
+         set_signal_ignored (XSIG (i));
+       }
+#if defined (SIGPROF) && !defined (_MINIX)
+      if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
+       sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
+#endif /* SIGPROF && !_MINIX */
+    }
+
+#else /* !HAVE_POSIX_SIGNALS */
+
+  for (i = 0; i < TERMSIGS_LENGTH; i++)
+    {
+      /* If we've already trapped it, don't do anything. */
+      if (signal_is_trapped (XSIG (i)))
+       continue;
+
+      XHANDLER(i) = signal (XSIG (i), termsig_sighandler);
+      XSAFLAGS(i) = 0;
+      /* Don't do anything with signals that are ignored at shell entry
+        if the shell is not interactive. */
+      /* XXX - should we do this for interactive shells, too? */
+      if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
+       {
+         signal (XSIG (i), SIG_IGN);
+         set_signal_ignored (XSIG (i));
+       }
+#ifdef SIGPROF
+      if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
+       signal (XSIG (i), XHANDLER (i));
+#endif
+    }
+
+#endif /* !HAVE_POSIX_SIGNALS */
+
+  termsigs_initialized = 1;
+}
+
+static void
+initialize_shell_signals ()
+{
+  if (interactive)
+    initialize_terminating_signals ();
+
+#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
+  /* All shells use the signal mask they inherit, and pass it along
+     to child processes.  Children will never block SIGCHLD, though. */
+  sigemptyset (&top_level_mask);
+  sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
+#  if defined (SIGCHLD)
+  sigdelset (&top_level_mask, SIGCHLD);
+#  endif
+#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
+
+  /* And, some signals that are specifically ignored by the shell. */
+  set_signal_handler (SIGQUIT, SIG_IGN);
+
+  if (interactive)
+    {
+      set_signal_handler (SIGINT, sigint_sighandler);
+      get_original_signal (SIGTERM);
+      if (signal_is_hard_ignored (SIGTERM) == 0)
+       set_signal_handler (SIGTERM, sigterm_sighandler);
+      set_sigwinch_handler ();
+    }
+}
+
+void
+reset_terminating_signals ()
+{
+  register int i;
+#if defined (HAVE_POSIX_SIGNALS)
+  struct sigaction act;
+#endif
+
+  if (termsigs_initialized == 0)
+    return;
+
+#if defined (HAVE_POSIX_SIGNALS)
+  act.sa_flags = 0;
+  sigemptyset (&act.sa_mask);
+  for (i = 0; i < TERMSIGS_LENGTH; i++)
+    {
+      /* Skip a signal if it's trapped or handled specially, because the
+        trap code will restore the correct value. */
+      if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
+       continue;
+
+      act.sa_handler = XHANDLER (i);
+      act.sa_flags = XSAFLAGS (i);
+      sigaction (XSIG (i), &act, (struct sigaction *) NULL);
+    }
+#else /* !HAVE_POSIX_SIGNALS */
+  for (i = 0; i < TERMSIGS_LENGTH; i++)
+    {
+      if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
+       continue;
+
+      signal (XSIG (i), XHANDLER (i));
+    }
+#endif /* !HAVE_POSIX_SIGNALS */
+
+  termsigs_initialized = 0;
+}
+#undef XSIG
+#undef XHANDLER
+
+/* Run some of the cleanups that should be performed when we run
+   jump_to_top_level from a builtin command context.  XXX - might want to
+   also call reset_parser here. */
+void
+top_level_cleanup ()
+{
+  /* Clean up string parser environment. */
+  while (parse_and_execute_level)
+    parse_and_execute_cleanup ();
+
+#if defined (PROCESS_SUBSTITUTION)
+  unlink_fifo_list ();
+#endif /* PROCESS_SUBSTITUTION */
+
+  run_unwind_protects ();
+  loop_level = continuing = breaking = funcnest = 0;
+  executing_list = comsub_ignore_return = return_catch_flag = 0;
+}
+
+/* What to do when we've been interrupted, and it is safe to handle it. */
+void
+throw_to_top_level ()
+{
+  int print_newline = 0;
+
+  if (interrupt_state)
+    {
+      if (last_command_exit_value < 128)
+       last_command_exit_value = 128 + SIGINT;
+      print_newline = 1;
+      DELINTERRUPT;
+    }
+
+  if (interrupt_state)
+    return;
+
+  last_command_exit_signal = (last_command_exit_value > 128) ?
+                               (last_command_exit_value - 128) : 0;
+  last_command_exit_value |= 128;
+
+  /* Run any traps set on SIGINT. */
+  run_interrupt_trap ();
+
+  /* Clean up string parser environment. */
+  while (parse_and_execute_level)
+    parse_and_execute_cleanup ();
+
+#if defined (JOB_CONTROL)
+  give_terminal_to (shell_pgrp, 0);
+#endif /* JOB_CONTROL */
+
+#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
+  /* This needs to stay because jobs.c:make_child() uses it without resetting
+     the signal mask. */
+  sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
+#endif
+
+  reset_parser ();
+
+#if defined (READLINE)
+  if (interactive)
+    bashline_reset ();
+#endif /* READLINE */
+
+#if defined (PROCESS_SUBSTITUTION)
+  unlink_fifo_list ();
+#endif /* PROCESS_SUBSTITUTION */
+
+  run_unwind_protects ();
+  loop_level = continuing = breaking = funcnest = 0;
+  executing_list = comsub_ignore_return = return_catch_flag = 0;
+
+  if (interactive && print_newline)
+    {
+      fflush (stdout);
+      fprintf (stderr, "\n");
+      fflush (stderr);
+    }
+
+  /* An interrupted `wait' command in a script does not exit the script. */
+  if (interactive || (interactive_shell && !shell_initialized) ||
+      (print_newline && signal_is_trapped (SIGINT)))
+    jump_to_top_level (DISCARD);
+  else
+    jump_to_top_level (EXITPROG);
+}
+
+/* This is just here to isolate the longjmp calls. */
+void
+jump_to_top_level (value)
+     int value;
+{
+  longjmp (top_level, value);
+}
+
+sighandler
+termsig_sighandler (sig)
+     int sig;
+{
+  /* If we get called twice with the same signal before handling it,
+     terminate right away. */
+  if (
+#ifdef SIGHUP
+    sig != SIGHUP &&
+#endif
+#ifdef SIGINT
+    sig != SIGINT &&
+#endif
+#ifdef SIGDANGER
+    sig != SIGDANGER &&
+#endif
+#ifdef SIGPIPE
+    sig != SIGPIPE &&
+#endif
+#ifdef SIGALRM
+    sig != SIGALRM &&
+#endif
+#ifdef SIGTERM
+    sig != SIGTERM &&
+#endif
+#ifdef SIGXCPU
+    sig != SIGXCPU &&
+#endif
+#ifdef SIGXFSZ
+    sig != SIGXFSZ &&
+#endif
+#ifdef SIGVTALRM
+    sig != SIGVTALRM &&
+#endif
+#ifdef SIGLOST
+    sig != SIGLOST &&
+#endif
+#ifdef SIGUSR1
+    sig != SIGUSR1 &&
+#endif
+#ifdef SIGUSR2
+   sig != SIGUSR2 &&
+#endif
+   sig == terminating_signal)
+    terminate_immediately = 1;
+
+  terminating_signal = sig;
+
+  /* XXX - should this also trigger when interrupt_immediately is set? */
+  if (terminate_immediately)
+    {
+#if defined (HISTORY)
+      /* XXX - will inhibit history file being written */
+#  if defined (READLINE)
+      if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0))
+#  endif
+        history_lines_this_session = 0;
+#endif
+      terminate_immediately = 0;
+      termsig_handler (sig);
+    }
+
+#if defined (READLINE)
+  /* 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 (interactive_shell && interactive && no_line_editing == 0)
+    bashline_set_event_hook ();
+#endif
+
+  SIGRETURN (0);
+}
+
+void
+termsig_handler (sig)
+     int sig;
+{
+  static int handling_termsig = 0;
+
+  /* Simple semaphore to keep this function from being executed multiple
+     times.  Since we no longer are running as a signal handler, we don't
+     block multiple occurrences of the terminating signals while running. */
+  if (handling_termsig)
+    return;
+  handling_termsig = 1;
+  terminating_signal = 0;      /* keep macro from re-testing true. */
+
+  /* I don't believe this condition ever tests true. */
+  if (sig == SIGINT && signal_is_trapped (SIGINT))
+    run_interrupt_trap ();
+
+#if defined (HISTORY)
+  /* If we don't do something like this, the history will not be saved when
+     an interactive shell is running in a terminal window that gets closed
+     with the `close' button.  We can't test for RL_STATE_READCMD because
+     readline no longer handles SIGTERM synchronously.  */
+  if (interactive_shell && interactive && sig == SIGHUP && remember_on_history)
+    maybe_save_shell_history ();
+#endif /* HISTORY */
+
+#if defined (JOB_CONTROL)
+  if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
+    hangup_all_jobs ();
+  end_job_control ();
+#endif /* JOB_CONTROL */
+
+#if defined (PROCESS_SUBSTITUTION)
+  unlink_fifo_list ();
+#endif /* PROCESS_SUBSTITUTION */
+
+  /* Reset execution context */
+  loop_level = continuing = breaking = funcnest = 0;
+  executing_list = comsub_ignore_return = return_catch_flag = 0;
+
+  run_exit_trap ();
+  set_signal_handler (sig, SIG_DFL);
+  kill (getpid (), sig);
+}
+
+/* What we really do when SIGINT occurs. */
+sighandler
+sigint_sighandler (sig)
+     int sig;
+{
+#if defined (MUST_REINSTALL_SIGHANDLERS)
+  signal (sig, sigint_sighandler);
+#endif
+
+  /* interrupt_state needs to be set for the stack of interrupts to work
+     right.  Should it be set unconditionally? */
+  if (interrupt_state == 0)
+    ADDINTERRUPT;
+
+  if (interrupt_immediately)
+    {
+      interrupt_immediately = 0;
+      last_command_exit_value = 128 + sig;
+      throw_to_top_level ();
+    }
+#if defined (READLINE)
+  /* 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. */
+  else if (RL_ISSTATE (RL_STATE_SIGHANDLER))
+    bashline_set_event_hook ();
+#endif
+
+  SIGRETURN (0);
+}
+
+#if defined (SIGWINCH)
+sighandler
+sigwinch_sighandler (sig)
+     int sig;
+{
+#if defined (MUST_REINSTALL_SIGHANDLERS)
+  set_signal_handler (SIGWINCH, sigwinch_sighandler);
+#endif /* MUST_REINSTALL_SIGHANDLERS */
+  sigwinch_received = 1;
+  SIGRETURN (0);
+}
+#endif /* SIGWINCH */
+
+void
+set_sigwinch_handler ()
+{
+#if defined (SIGWINCH)
+ old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
+#endif
+}
+
+void
+unset_sigwinch_handler ()
+{
+#if defined (SIGWINCH)
+  set_signal_handler (SIGWINCH, old_winch);
+#endif
+}
+
+sighandler
+sigterm_sighandler (sig)
+     int sig;
+{
+  sigterm_received = 1;                /* XXX - counter? */
+  SIGRETURN (0);
+}
+
+/* Signal functions used by the rest of the code. */
+#if !defined (HAVE_POSIX_SIGNALS)
+
+/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
+sigprocmask (operation, newset, oldset)
+     int operation, *newset, *oldset;
+{
+  int old, new;
+
+  if (newset)
+    new = *newset;
+  else
+    new = 0;
+
+  switch (operation)
+    {
+    case SIG_BLOCK:
+      old = sigblock (new);
+      break;
+
+    case SIG_SETMASK:
+      old = sigsetmask (new);
+      break;
+
+    default:
+      internal_error (_("sigprocmask: %d: invalid operation"), operation);
+    }
+
+  if (oldset)
+    *oldset = old;
+}
+
+#else
+
+#if !defined (SA_INTERRUPT)
+#  define SA_INTERRUPT 0
+#endif
+
+#if !defined (SA_RESTART)
+#  define SA_RESTART 0
+#endif
+
+SigHandler *
+set_signal_handler (sig, handler)
+     int sig;
+     SigHandler *handler;
+{
+  struct sigaction act, oact;
+
+  act.sa_handler = handler;
+  act.sa_flags = 0;
+
+  /* XXX - bash-4.2 */
+  /* We don't want a child death to interrupt interruptible system calls, even
+     if we take the time to reap children */
+#if defined (SIGCHLD)
+  if (sig == SIGCHLD)
+    act.sa_flags |= SA_RESTART;                /* XXX */
+#endif
+  /* If we're installing a SIGTERM handler for interactive shells, we want
+     it to be as close to SIG_IGN as possible. */
+  if (sig == SIGTERM && handler == sigterm_sighandler)
+    act.sa_flags |= SA_RESTART;                /* XXX */
+
+  sigemptyset (&act.sa_mask);
+  sigemptyset (&oact.sa_mask);
+  sigaction (sig, &act, &oact);
+  return (oact.sa_handler);
+}
+#endif /* HAVE_POSIX_SIGNALS */
diff --git a/sig.h b/sig.h
index 392072f29dde8a5b1f17d07072277d036f7efb0e..eba65ec7fa3162d50e233e70aee73078d051544f 100644 (file)
--- a/sig.h
+++ b/sig.h
 
 #include "stdc.h"
 
+#if !defined (SIG_DFL)
+#  include <signal.h>          /* for sig_atomic_t */
+#endif
+
 #if !defined (SIGABRT) && defined (SIGIOT)
 #  define SIGABRT SIGIOT
 #endif
@@ -104,7 +108,8 @@ do { \
 #endif /* !HAVE_POSIX_SIGNALS */
 
 /* Extern variables */
-extern volatile int sigwinch_received;
+extern sig_atomic_t sigwinch_received;
+extern sig_atomic_t sigterm_received;
 
 extern int interrupt_immediately;
 extern int terminate_immediately;
diff --git a/sig.h~ b/sig.h~
new file mode 100644 (file)
index 0000000..fa28c72
--- /dev/null
+++ b/sig.h~
@@ -0,0 +1,139 @@
+/* sig.h -- header file for signal handler definitions. */
+
+/* Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   Bash is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Make sure that this is included *after* config.h! */
+
+#if !defined (_SIG_H_)
+#  define _SIG_H_
+
+#include "stdc.h"
+
+#if !defined (SIG_DFL)
+#  include <signal.h>
+#endif
+
+#if !defined (SIGABRT) && defined (SIGIOT)
+#  define SIGABRT SIGIOT
+#endif
+
+#define sighandler RETSIGTYPE
+typedef RETSIGTYPE SigHandler __P((int));
+
+#if defined (VOID_SIGHANDLER)
+#  define SIGRETURN(n) return
+#else
+#  define SIGRETURN(n) return(n)
+#endif /* !VOID_SIGHANDLER */
+
+/* Here is a definition for set_signal_handler () which simply expands to
+   a call to signal () for non-Posix systems.  The code for set_signal_handler
+   in the Posix case resides in general.c. */
+#if !defined (HAVE_POSIX_SIGNALS)
+#  define set_signal_handler(sig, handler) (SigHandler *)signal (sig, handler)
+#else
+extern SigHandler *set_signal_handler __P((int, SigHandler *));        /* in sig.c */
+#endif /* _POSIX_VERSION */
+
+#if !defined (SIGCHLD) && defined (SIGCLD)
+#  define SIGCHLD SIGCLD
+#endif
+
+#if !defined (HAVE_POSIX_SIGNALS) && !defined (sigmask)
+#  define sigmask(x) (1 << ((x)-1))
+#endif /* !HAVE_POSIX_SIGNALS && !sigmask */
+
+#if !defined (HAVE_POSIX_SIGNALS)
+#  if !defined (SIG_BLOCK)
+#    define SIG_BLOCK 2
+#    define SIG_SETMASK 3
+#  endif /* SIG_BLOCK */
+
+/* sigset_t defined in config.h */
+
+/* Make sure there is nothing inside the signal set. */
+#  define sigemptyset(set) (*(set) = 0)
+
+/* Initialize the signal set to hold all signals. */
+#  define sigfillset(set) (*set) = sigmask (NSIG) - 1
+
+/* Add SIG to the contents of SET. */
+#  define sigaddset(set, sig) *(set) |= sigmask (sig)
+
+/* Delete SIG from signal set SET. */
+#  define sigdelset(set, sig) *(set) &= ~sigmask (sig)
+
+/* Is SIG a member of the signal set SET? */
+#  define sigismember(set, sig) ((*(set) & sigmask (sig)) != 0)
+
+/* Suspend the process until the reception of one of the signals
+   not present in SET. */
+#  define sigsuspend(set) sigpause (*(set))
+#endif /* !HAVE_POSIX_SIGNALS */
+
+/* These definitions are used both in POSIX and non-POSIX implementations. */
+
+#define BLOCK_SIGNAL(sig, nvar, ovar) \
+do { \
+  sigemptyset (&nvar); \
+  sigaddset (&nvar, sig); \
+  sigemptyset (&ovar); \
+  sigprocmask (SIG_BLOCK, &nvar, &ovar); \
+} while (0)
+
+#define UNBLOCK_SIGNAL(ovar) sigprocmask (SIG_SETMASK, &ovar, (sigset_t *) NULL)
+
+#if defined (HAVE_POSIX_SIGNALS)
+#  define BLOCK_CHILD(nvar, ovar) BLOCK_SIGNAL (SIGCHLD, nvar, ovar)
+#  define UNBLOCK_CHILD(ovar) UNBLOCK_SIGNAL(ovar)
+#else /* !HAVE_POSIX_SIGNALS */
+#  define BLOCK_CHILD(nvar, ovar) ovar = sigblock (sigmask (SIGCHLD))
+#  define UNBLOCK_CHILD(ovar) sigsetmask (ovar)
+#endif /* !HAVE_POSIX_SIGNALS */
+
+/* Extern variables */
+extern sig_atomic_t sigwinch_received;
+extern sig_atomic_t sigterm_received;
+
+extern int interrupt_immediately;
+extern int terminate_immediately;
+
+/* Functions from sig.c. */
+extern sighandler termsig_sighandler __P((int));
+extern void termsig_handler __P((int));
+extern sighandler sigint_sighandler __P((int));
+extern void initialize_signals __P((int));
+extern void initialize_terminating_signals __P((void));
+extern void reset_terminating_signals __P((void));
+extern void top_level_cleanup __P((void));
+extern void throw_to_top_level __P((void));
+extern void jump_to_top_level __P((int)) __attribute__((__noreturn__));
+
+extern sighandler sigwinch_sighandler __P((int));
+extern void set_sigwinch_handler __P((void));
+extern void unset_sigwinch_handler __P((void));
+
+extern sighandler sigterm_sighandler __P((int));
+
+/* Functions defined in trap.c. */
+extern SigHandler *set_sigint_handler __P((void));
+extern SigHandler *trap_to_sighandler __P((int));
+extern sighandler trap_handler __P((int));
+
+#endif /* _SIG_H_ */
index a477c03a9b6a6044dd76edad0f1b4effe6fc48cd..85a10b578c58fb1d9fefd9a00379fd2943d44b4a 100644 (file)
@@ -46,8 +46,8 @@
 #include "command.h"
 #include "general.h"
 #include "unwind_prot.h"
-#include "quit.h"
 #include "sig.h"
+#include "quit.h"
 #include "error.h"     /* for internal_warning */
 
 /* Structure describing a saved variable and the value to restore it to.  */
diff --git a/unwind_prot.c~ b/unwind_prot.c~
new file mode 100644 (file)
index 0000000..a477c03
--- /dev/null
@@ -0,0 +1,357 @@
+/* unwind_prot.c - a simple unwind-protect system for internal variables */
+
+/* I can't stand it anymore!  Please can't we just write the
+   whole Unix system in lisp or something? */
+
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   Bash is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* **************************************************************** */
+/*                                                                 */
+/*                   Unwind Protection Scheme for Bash             */
+/*                                                                 */
+/* **************************************************************** */
+#include "config.h"
+
+#include "bashtypes.h"
+#include "bashansi.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#if STDC_HEADERS
+#  include <stddef.h>
+#endif
+
+#ifndef offsetof
+#  define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#include "command.h"
+#include "general.h"
+#include "unwind_prot.h"
+#include "quit.h"
+#include "sig.h"
+#include "error.h"     /* for internal_warning */
+
+/* Structure describing a saved variable and the value to restore it to.  */
+typedef struct {
+  char *variable;
+  int size;
+  char desired_setting[1]; /* actual size is `size' */
+} SAVED_VAR;
+
+/* If HEAD.CLEANUP is null, then ARG.V contains a tag to throw back to.
+   If HEAD.CLEANUP is restore_variable, then SV.V contains the saved
+   variable.  Otherwise, call HEAD.CLEANUP (ARG.V) to clean up.  */
+typedef union uwp {
+  struct uwp_head {
+    union uwp *next;
+    Function *cleanup;
+  } head;
+  struct {
+    struct uwp_head uwp_head;
+    char *v;
+  } arg;
+  struct {
+    struct uwp_head uwp_head;
+    SAVED_VAR v;
+  } sv;
+} UNWIND_ELT;
+
+
+static void without_interrupts __P((VFunction *, char *, char *));
+static void unwind_frame_discard_internal __P((char *, char *));
+static void unwind_frame_run_internal __P((char *, char *));
+static void add_unwind_protect_internal __P((Function *, char *));
+static void remove_unwind_protect_internal __P((char *, char *));
+static void run_unwind_protects_internal __P((char *, char *));
+static void clear_unwind_protects_internal __P((char *, char *));
+static inline void restore_variable __P((SAVED_VAR *));
+static void unwind_protect_mem_internal __P((char *, char *));
+
+static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
+
+#define uwpalloc(elt)  (elt) = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT))
+#define uwpfree(elt)   free(elt)
+
+/* Run a function without interrupts.  This relies on the fact that the
+   FUNCTION cannot change the value of interrupt_immediately.  (I.e., does
+   not call QUIT (). */
+static void
+without_interrupts (function, arg1, arg2)
+     VFunction *function;
+     char *arg1, *arg2;
+{
+  int old_interrupt_immediately;
+
+  old_interrupt_immediately = interrupt_immediately;
+  interrupt_immediately = 0;
+
+  (*function)(arg1, arg2);
+
+  interrupt_immediately = old_interrupt_immediately;
+}
+
+/* Start the beginning of a region. */
+void
+begin_unwind_frame (tag)
+     char *tag;
+{
+  add_unwind_protect ((Function *)NULL, tag);
+}
+
+/* Discard the unwind protects back to TAG. */
+void
+discard_unwind_frame (tag)
+     char *tag;
+{
+  if (unwind_protect_list)
+    without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
+}
+
+/* Run the unwind protects back to TAG. */
+void
+run_unwind_frame (tag)
+     char *tag;
+{
+  if (unwind_protect_list)
+    without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
+}
+
+/* Add the function CLEANUP with ARG to the list of unwindable things. */
+void
+add_unwind_protect (cleanup, arg)
+     Function *cleanup;
+     char *arg;
+{
+  without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
+}
+
+/* Remove the top unwind protect from the list. */
+void
+remove_unwind_protect ()
+{
+  if (unwind_protect_list)
+    without_interrupts
+      (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Run the list of cleanup functions in unwind_protect_list. */
+void
+run_unwind_protects ()
+{
+  if (unwind_protect_list)
+    without_interrupts
+      (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
+}
+
+/* Erase the unwind-protect list.  If flags is 1, free the elements. */
+void
+clear_unwind_protect_list (flags)
+     int flags;
+{
+  char *flag;
+
+  if (unwind_protect_list)
+    {
+      flag = flags ? "" : (char *)NULL;
+      without_interrupts
+        (clear_unwind_protects_internal, flag, (char *)NULL);
+    }
+}
+
+int
+have_unwind_protects ()
+{
+  return (unwind_protect_list != 0);
+}
+
+/* **************************************************************** */
+/*                                                                 */
+/*                     The Actual Functions                        */
+/*                                                                 */
+/* **************************************************************** */
+
+static void
+add_unwind_protect_internal (cleanup, arg)
+     Function *cleanup;
+     char *arg;
+{
+  UNWIND_ELT *elt;
+
+  uwpalloc (elt);
+  elt->head.next = unwind_protect_list;
+  elt->head.cleanup = cleanup;
+  elt->arg.v = arg;
+  unwind_protect_list = elt;
+}
+
+static void
+remove_unwind_protect_internal (ignore1, ignore2)
+     char *ignore1, *ignore2;
+{
+  UNWIND_ELT *elt;
+
+  elt = unwind_protect_list;
+  if (elt)
+    {
+      unwind_protect_list = unwind_protect_list->head.next;
+      uwpfree (elt);
+    }
+}
+
+static void
+run_unwind_protects_internal (ignore1, ignore2)
+     char *ignore1, *ignore2;
+{
+  unwind_frame_run_internal ((char *) NULL, (char *) NULL);
+}
+
+static void
+clear_unwind_protects_internal (flag, ignore)
+     char *flag, *ignore;
+{
+  if (flag)
+    {
+      while (unwind_protect_list)
+       remove_unwind_protect_internal ((char *)NULL, (char *)NULL);
+    }
+  unwind_protect_list = (UNWIND_ELT *)NULL;
+}
+
+static void
+unwind_frame_discard_internal (tag, ignore)
+     char *tag, *ignore;
+{
+  UNWIND_ELT *elt;
+  int found;
+
+  found = 0;
+  while (elt = unwind_protect_list)
+    {
+      unwind_protect_list = unwind_protect_list->head.next;
+      if (elt->head.cleanup == 0 && (STREQ (elt->arg.v, tag)))
+       {
+         uwpfree (elt);
+         found = 1;
+         break;
+       }
+      else
+       uwpfree (elt);
+    }
+
+  if (found == 0)
+    internal_warning ("unwind_frame_discard: %s: frame not found", tag);
+}
+
+/* Restore the value of a variable, based on the contents of SV.
+   sv->desired_setting is a block of memory SIZE bytes long holding the
+   value itself.  This block of memory is copied back into the variable. */
+static inline void
+restore_variable (sv)
+     SAVED_VAR *sv;
+{
+  FASTCOPY (sv->desired_setting, sv->variable, sv->size);
+}
+
+static void
+unwind_frame_run_internal (tag, ignore)
+     char *tag, *ignore;
+{
+  UNWIND_ELT *elt;
+  int found;
+
+  found = 0;
+  while (elt = unwind_protect_list)
+    {
+      unwind_protect_list = elt->head.next;
+
+      /* If tag, then compare. */
+      if (elt->head.cleanup == 0)
+       {
+         if (tag && STREQ (elt->arg.v, tag))
+           {
+             uwpfree (elt);
+             found = 1;
+             break;
+           }
+       }
+      else
+       {
+         if (elt->head.cleanup == (Function *) restore_variable)
+           restore_variable (&elt->sv.v);
+         else
+           (*(elt->head.cleanup)) (elt->arg.v);
+       }
+
+      uwpfree (elt);
+    }
+  if (tag && found == 0)
+    internal_warning ("unwind_frame_run: %s: frame not found", tag);
+}
+
+static void
+unwind_protect_mem_internal (var, psize)
+     char *var;
+     char *psize;
+{
+  int size, allocated;
+  UNWIND_ELT *elt;
+
+  size = *(int *) psize;
+  allocated = size + offsetof (UNWIND_ELT, sv.v.desired_setting[0]);
+  elt = (UNWIND_ELT *)xmalloc (allocated);
+  elt->head.next = unwind_protect_list;
+  elt->head.cleanup = (Function *) restore_variable;
+  elt->sv.v.variable = var;
+  elt->sv.v.size = size;
+  FASTCOPY (var, elt->sv.v.desired_setting, size);
+  unwind_protect_list = elt;
+}
+
+/* Save the value of a variable so it will be restored when unwind-protects
+   are run.  VAR is a pointer to the variable.  SIZE is the size in
+   bytes of VAR.  */
+void
+unwind_protect_mem (var, size)
+     char *var;
+     int size;
+{
+  without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
+}
+
+#if defined (DEBUG)
+#include <stdio.h>
+
+void
+print_unwind_protect_tags ()
+{
+  UNWIND_ELT *elt;
+
+  elt = unwind_protect_list;
+  while (elt)
+    {
+      unwind_protect_list = unwind_protect_list->head.next;
+      if (elt->head.cleanup == 0)
+        fprintf(stderr, "tag: %s\n", elt->arg.v);
+      elt = unwind_protect_list;
+    }
+}
+#endif