]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
posix mode changes for interp 1150; fix for varassign redirection; fix for nameref...
authorChet Ramey <chet.ramey@case.edu>
Tue, 11 Apr 2023 13:56:03 +0000 (09:56 -0400)
committerChet Ramey <chet.ramey@case.edu>
Tue, 11 Apr 2023 13:56:03 +0000 (09:56 -0400)
12 files changed:
CWRU/CWRU.chlog
doc/bashref.texi
doc/version.texi
execute_cmd.c
parse.y
redir.c
sig.c
sig.h
subst.c
subst.h
tests/nameref.right
tests/nameref4.sub

index 4c1b8201917af88997725dfa40e54047d9e4d224..02250cf463cc11285cb0767b561520b30ed51454 100644 (file)
@@ -5969,3 +5969,35 @@ lib/readline/vi_mode.c
        - _rl_domove_motion_cleanup: ditto for y/Y
        - rl_domove_motion_callback: if t/T/;/, fail (return non-zero without
          moving point), flag the motion command as having failed (MOVE_FAILED)
+
+                                   4/6
+                                   ---
+subst.c
+       - command_substitute: save the return status of the child process in
+         last_command_subst_status; don't assign to last_command_exit_value
+         in posix mode (posix interp 1150)
+
+execute_cmd.c
+       - execute_null_command: a simple command without a command word but
+         with command substitutions now returns last_command_subst_status.
+         It may or may not have already modified $? depending on posix mode
+
+redir.c
+       - redir_varvalue: legal_number validity check should be == 0, not < 0
+         From a report by Grisha Levit <grishalevit@gmail.com>
+
+                                  4/10
+                                  ----
+subst.c
+       - parameter_brace_expand_rhs: check for namerefs in the variable name
+         part of the ${name=word} expansion so we can go back and implement
+         the POSIX semantics of returning "the final value of parameter."
+         From a report by Grisha Levit <grishalevit@gmail.com>
+
+sig.c,sig.h
+       - sigpipe_handler: clean up, set $?, and throw to top level on receipt
+         of a SIGPIPE
+       - termsig_handler: if the variable builtin_catch_sigpipe is set (it's
+         not set anywhere yet), call sigpipe_handler instead of terminating
+         the shell. Still need to make sure a sighandler is installed for
+         SIGPIPE even if initialize_terminating_signals isn't called
index e34a6717c6bdf9715eb39f85adc01a75ea889c9e..e058c9b9b72320b0155cb6813e65ddccbbcb0997 100644 (file)
@@ -8561,6 +8561,13 @@ undergoes expansion.
 That means, for example, that a backslash preceding a double quote
 character will escape it and the backslash will be removed.
 
+@item
+Command substitutions don't set the @samp{?} special parameter. The exit
+status of a simple command without a command word is still the exit status
+of the last command substitution that occurred while evaluating the variable
+assignments and redirections in that command, but that does not happen until
+after all of the assignments and redirections.
+
 @end enumerate
 
 There is other @sc{posix} behavior that Bash does not implement by
index 6fc79710f17e1020ce163f144b38b08e1ee40efc..928b9836b6ce54aaeb7bd2af57be13a35dce8f32 100644 (file)
@@ -2,10 +2,10 @@
 Copyright (C) 1988-2023 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Tue Mar 21 11:05:49 EDT 2023
+@set LASTCHANGE Thu Apr  6 11:58:41 EDT 2023
 
 @set EDITION 5.2
 @set VERSION 5.2
 
-@set UPDATED 21 March 2023
-@set UPDATED-MONTH March 2023
+@set UPDATED 6 April 2023
+@set UPDATED-MONTH April 2023
index e7bdcdc9d915b4ba78aec0fe8dc2a3b8e18c9403..bfc76dea37f88f5df7f262fe171033e6b08aaaa7 100644 (file)
@@ -4123,7 +4123,7 @@ execute_null_command (REDIRECT *redirects, int pipe_in, int pipe_out, int async)
       if (r != 0)
        return (EXECUTION_FAILURE);
       else if (last_command_subst_pid != NO_PID)
-       return (last_command_exit_value);
+       return (last_command_subst_status);
       else
        return (EXECUTION_SUCCESS);
     }
diff --git a/parse.y b/parse.y
index a4c4c07c8640b65b1a0c1ca5868aad7f2f85f5ab..e70b340d48072a776b93ac1b659a7756d188149f 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -5891,7 +5891,7 @@ decode_prompt_string (char *string)
   WORD_LIST *list;
   char *result, *t, *orig_string;
   struct dstack save_dstack;
-  int last_exit_value, last_comsub_pid;
+  int last_exit_value, last_comsub_pid, last_comsub_status;
 #if defined (PROMPT_STRING_DECODE)
   size_t result_size;
   size_t result_index;
@@ -6297,12 +6297,14 @@ not_escape:
     {
       last_exit_value = last_command_exit_value;
       last_comsub_pid = last_command_subst_pid;
+      last_comsub_status = last_command_subst_status;
       list = expand_prompt_string (result, Q_DOUBLE_QUOTES, 0);
       free (result);
       result = string_list (list);
       dispose_words (list);
       last_command_exit_value = last_exit_value;
       last_command_subst_pid = last_comsub_pid;
+      last_command_subst_status = last_comsub_status;
     }
   else
     {
diff --git a/redir.c b/redir.c
index 804d9b8274e0b4ccdba6c744e5f1ec9d3cc3054b..267a9fc8bf11e5ca47a8ccde4b0b8b402ce91f68 100644 (file)
--- a/redir.c
+++ b/redir.c
@@ -1459,7 +1459,7 @@ redir_varvalue (REDIRECT *redir)
   if (val == 0 || *val == 0)
     return -1;
 
-  if (legal_number (val, &vmax) < 0)
+  if (legal_number (val, &vmax) == 0)
     return -1;
 
   i = vmax;    /* integer truncation */
diff --git a/sig.c b/sig.c
index b6ccaa19cbd29f35d4aef769b89335ee431f2b36..fc0ae878f45978bd1212e8b274b507745c2d88ed 100644 (file)
--- a/sig.c
+++ b/sig.c
@@ -74,6 +74,8 @@ volatile sig_atomic_t sigterm_received = 0;
 /* Set to the value of any terminating signal received. */
 volatile sig_atomic_t terminating_signal = 0;
 
+volatile int builtin_catch_sigpipe = 0;
+
 /* The environment at the top-level R-E loop.  We use this in
    the case of error return. */
 procenv_t top_level;
@@ -591,6 +593,9 @@ termsig_handler (int sig)
   handling_termsig = terminating_signal;       /* for termsig_sighandler */
   terminating_signal = 0;      /* keep macro from re-testing true. */
 
+  if (builtin_catch_sigpipe)
+    sigpipe_handler (sig);
+
   /* I don't believe this condition ever tests true. */
   if (sig == SIGINT && signal_is_trapped (SIGINT))
     run_interrupt_trap (0);
@@ -714,6 +719,7 @@ sigint_sighandler (int sig)
       set_exit_status (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
@@ -762,6 +768,15 @@ sigterm_sighandler (int sig)
   SIGRETURN (0);
 }
 
+void
+sigpipe_handler (int sig)
+{
+  handling_termsig = 0;
+  builtin_catch_sigpipe = 0;
+  last_command_exit_value = 128 + sig;
+  throw_to_top_level ();
+}  
+
 /* Signal functions used by the rest of the code. */
 #if !defined (HAVE_POSIX_SIGNALS)
 
diff --git a/sig.h b/sig.h
index 720e7969a23cf4e63cd805892d3e90e466306370..8d197be6d3590b81ef5467c276376aadb7077233 100644 (file)
--- a/sig.h
+++ b/sig.h
@@ -108,6 +108,8 @@ extern volatile sig_atomic_t sigterm_received;
 extern int interrupt_immediately;      /* no longer used */
 extern int terminate_immediately;
 
+extern volatile int builtin_catch_sigpipe;     /* not used yet */
+
 /* Functions from sig.c. */
 extern sighandler termsig_sighandler (int);
 extern void termsig_handler (int);
@@ -126,6 +128,8 @@ extern void unset_sigwinch_handler (void);
 
 extern sighandler sigterm_sighandler (int);
 
+extern void sigpipe_handler (int);
+
 /* Functions defined in trap.c. */
 extern SigHandler *set_sigint_handler (void);
 extern SigHandler *trap_to_sighandler (int);
diff --git a/subst.c b/subst.c
index 555d18db8eafaba83d8aa4243128f4fc9034343d..bdb5ba88e2ff2fb746f2047f982740d27a5d2b4b 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -149,6 +149,7 @@ typedef WORD_LIST *EXPFUNC (const char *, int);
 /* Process ID of the last command executed within command substitution. */
 pid_t last_command_subst_pid = NO_PID;
 pid_t current_command_subst_pid = NO_PID;
+int last_command_subst_status = 0;
 
 /* Variables used to keep track of the characters in IFS. */
 SHELL_VAR *ifs_var;
@@ -6723,13 +6724,16 @@ command_substitute (char *string, int quoted, int flags)
          istring = optimize_cat_file (cmd->value.Simple->redirects, quoted, flags, &tflag);
          if (istring == &expand_param_error)
            {
-             last_command_exit_value = EXECUTION_FAILURE;
+             last_command_subst_status = EXECUTION_FAILURE;
              istring = 0;
            }
          else
-           last_command_exit_value = EXECUTION_SUCCESS;        /* compat */
+           last_command_subst_status = EXECUTION_SUCCESS;      /* compat */
          last_command_subst_pid = dollar_dollar_pid;
 
+         if (posixly_correct == 0)     /* POSIX interp 1150 */
+           last_command_exit_value = last_command_subst_status;        /* XXX */
+
          dispose_command (cmd);          
          ret = alloc_word_desc ();
          ret->word = istring;
@@ -6974,10 +6978,13 @@ command_substitute (char *string, int quoted, int flags)
       UNBLOCK_SIGNAL (oset);
 
       current_command_subst_pid = pid;
-      last_command_exit_value = wait_for (pid, JWAIT_NOTERM);
+      last_command_subst_status = wait_for (pid, JWAIT_NOTERM);
       last_command_subst_pid = pid;
       last_made_pid = old_pid;
 
+      if (posixly_correct == 0)                /* POSIX interp 1150 */
+       last_command_exit_value = last_command_subst_status;    /* XXX */
+
 #if defined (JOB_CONTROL)
       /* If last_command_exit_value > 128, then the substituted command
         was terminated by a signal.  If that signal was SIGINT, then send
@@ -7626,7 +7633,24 @@ parameter_brace_expand_rhs (char *name, char *value,
          return &expand_wdesc_error;
        }
     }
-    
+  /* We check for this here instead of letting bind_variable do it so we can
+     satisfy the POSIX semantics of returning the final value assigned to the
+     variable, even after assignment transformations (uppercase, lowercase, etc.).
+     We need the final name to get the right value back. */
+  else if ((v = find_variable_last_nameref (name, 0)) && nameref_p (v))
+    {
+      temp = nameref_cell (v);
+      /* shouldn't happen at this point, but... */
+      if (temp == 0 || *temp == 0)
+       {
+         report_error (_("%s: bad substitution"), name);
+         free (t1);
+         dispose_word (w);
+         return &expand_wdesc_error;
+       }
+      vname = savestring (temp);
+    }
+
   arrayref = 0;
 #if defined (ARRAY_VARS)
   if (valid_array_reference (vname, 0))
diff --git a/subst.h b/subst.h
index c8c0adde046c1203c50bb1c7440a4c4947720fa8..a42d8c84c23091de2ab7d0c595c6f9dcc4c6b1cc 100644 (file)
--- a/subst.h
+++ b/subst.h
@@ -350,6 +350,7 @@ extern int expanding_redir;
 extern int inherit_errexit;
 
 extern pid_t last_command_subst_pid;
+extern int last_command_subst_status;
 
 /* Evaluates to 1 if C is a character in $IFS. */
 #define isifs(c)       (ifs_cmap[(unsigned char)(c)] != 0)
index a28c8845c97da4aa9e43426cfa0b9b56f2a18ab3..419bbe1408697385777c4c23aea2c58df1dd656e 100644 (file)
@@ -92,6 +92,10 @@ expect <one>
 one
 expect <four>
 four
+expect <X>
+X
+expect <X>
+X
 errors = 0
 1
 2
index 6367d565644a18a803f4b7be3893990152672345..970a85e9803bff3f423e5f243437734409392c5d 100644 (file)
@@ -228,6 +228,20 @@ echo "expect <four>"
 echo $qux
 ckval qux ${bar[3]}
 
+bar=()
+declare -n ref='bar[1]'
+
+echo "expect <X>"
+echo ${ref=X}
+ckval ref ${bar[1]}
+
+unset -n ref
+declare -n ref
+
+echo "expect <X>"
+echo ${ref=X}
+ckval ref ${ref}
+
 # Need to add code and tests for `for' loop nameref variables
 
 echo errors = $errors