]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20101015 snapshot
authorChet Ramey <chet.ramey@case.edu>
Tue, 13 Dec 2011 03:08:08 +0000 (22:08 -0500)
committerChet Ramey <chet.ramey@case.edu>
Tue, 13 Dec 2011 03:08:08 +0000 (22:08 -0500)
33 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
builtins/cd.def
builtins/cd.def~
builtins/evalstring.c~
builtins/exec.def
builtins/exec.def~
builtins/trap.def
builtins/trap.def~
doc/bash.1
doc/bash.1~
doc/bashref.texi
doc/bashref.texi~
doc/version.texi
doc/version.texi~
execute_cmd.c
execute_cmd.c~
include/chartypes.h
lib/sh/strtrans.c
parse.y
parse.y~
shell.c~
subst.c
subst.c~
tests/RUN-ONE-TEST
tests/exec.right
tests/execscript
tests/execscript~ [new file with mode: 0644]
tests/posixexp.right
unwind_prot.c
unwind_prot.c~ [new file with mode: 0644]
variables.c
variables.c~

index dbbd5bb884bf09326744eb08a8aaecaabb586ccd..95e30415f8c725809c88e1beb6e4947b9ff0cd9d 100644 (file)
@@ -10446,3 +10446,73 @@ builtins/{source.def,evalfile.c}
          how `command' can cancel effects of special builtin exit properties
          in the case of `dot file not found'
 
+                                  10/13
+                                  -----
+lib/sh/strtrans.c
+       - pass \c through unchanged if not escaping for `echo -e' and they are
+         the final two characters in the string
+
+                                  10/15
+                                  -----
+subst.c
+       - extract_dollar_brace_string: fix problem with single quotes
+         in unquoted ${...} for Posix compliance
+
+                                  10/16
+                                  -----
+builtins/exec.def
+       - catch return value from shell_execve; don't print duplicate error
+         message if return value is EX_NOTFOUND.  Make sure exit status
+         from exec is 127 if command is not found
+
+execute_cmd.c
+       - fix typo (`saved_redirects' should be `saved redirects') in
+         execute_function_or_builtin `command exec' case.  Typo caused
+         too much of the unwind-protect stack to be discarded
+       - in same execute_function_or_builtin case, don't discard the
+         `saved redirects' frame unconditionally; only discard it if
+         saved_redirects is non-null in the `command exec' case.  Fixes
+         sh -c 'command exec; exit 1' hanging bug uncovered by FreeBSD
+         sh test cases
+
+                                  10/18
+                                  -----
+subst.c
+       - when in posix mode, shell should not exit if a variable assignment
+         error (e.g., assigning to readonly variable) occurs preceding a
+         command that is not a special builtin.  Fixes bug uncovered by
+         FreeBSD sh test cases
+       - when in posix mode, the ${!?} and ${!#} expansions are not indirect
+         expansions, but posix word expansions involving the `!' variable
+
+parse.y
+       - fix parse_comsub so that it does not skip backslash-newline when
+         parsing a comment
+
+                                  10/19
+                                  -----
+subst.c
+       - fix parameter_brace_expand so that an attempt to use the % or #
+         expansions on an unset variable with -u set will cause a non-
+         interactive shell to abort.  Posix change
+       - fix parameter_brace_expand so that an attempt to use pattern
+         substitution or case modification expansions on an unset variable
+         with -u set will cause and unbound variable error and make a
+         non-interactive shell abort
+       - change parameter_brace_expand_length to return INTMAX_MIN if a
+         positional parameter is unset and -u is set
+       - if parameter_brace_expand_length returns INTMAX_MIN when -u is set,
+         treat it as an unbound variable error and make a non-interactive
+         shell abort.  Posix change
+       - change parameter_brace_expand_length to return INTMAX_MIN if an
+         implicit reference to array[0] is made ${#array} and array[0] is
+         not set when -u is set
+
+                                  10/20
+                                  -----
+builtins/cd.def
+       - Posix 2008 says that if no matching directories are found in $CDPATH,
+         use the directory name passed as an operand and go on.  Posix change
+
+doc/bashref.texi
+       - change Posix mode section with latest additions and removals
index e6490f70da4cf3f76bff963759188718339c40d6..45991fbec725da58fcac080e8879d481350f98e9 100644 (file)
@@ -10438,3 +10438,78 @@ execute_cmd.c
        - set executing_command_builtin in execute_builtin if the builtin is
          command_builtin.  Unwind-protected in execute_function_or_builtin
          (like executing_builtin variable).  Available for rest of shell
+
+builtins/{source.def,evalfile.c}
+       - make sure that non-interactive posix mode shells exit if the file
+         argument to `.' is not found only if they are not being executed
+         by the command builtin (executing_command_builtin == 0).  This is
+         how `command' can cancel effects of special builtin exit properties
+         in the case of `dot file not found'
+
+                                  10/13
+                                  -----
+lib/sh/strtrans.c
+       - pass \c through unchanged if not escaping for `echo -e' and they are
+         the final two characters in the string
+
+                                  10/15
+                                  -----
+subst.c
+       - extract_dollar_brace_string: fix problem with single quotes
+         in unquoted ${...} for Posix compliance
+
+                                  10/16
+                                  -----
+builtins/exec.def
+       - catch return value from shell_execve; don't print duplicate error
+         message if return value is EX_NOTFOUND.  Make sure exit status
+         from exec is 127 if command is not found
+
+execute_cmd.c
+       - fix typo (`saved_redirects' should be `saved redirects') in
+         execute_function_or_builtin `command exec' case.  Typo caused
+         too much of the unwind-protect stack to be discarded
+       - in same execute_function_or_builtin case, don't discard the
+         `saved redirects' frame unconditionally; only discard it if
+         saved_redirects is non-null in the `command exec' case.  Fixes
+         sh -c 'command exec; exit 1' hanging bug uncovered by FreeBSD
+         sh test cases
+
+                                  10/18
+                                  -----
+subst.c
+       - when in posix mode, shell should not exit if a variable assignment
+         error (e.g., assigning to readonly variable) occurs preceding a
+         command that is not a special builtin.  Fixes bug uncovered by
+         FreeBSD sh test cases
+       - when in posix mode, the ${!?} and ${!#} expansions are not indirect
+         expansions, but posix word expansions involving the `!' variable
+
+parse.y
+       - fix parse_comsub so that it does not skip backslash-newline when
+         parsing a comment
+
+                                  10/19
+                                  -----
+subst.c
+       - fix parameter_brace_expand so that an attempt to use the % or #
+         expansions on an unset variable with -u set will cause a non-
+         interactive shell to abort.  Posix change
+       - fix parameter_brace_expand so that an attempt to use pattern
+         substitution or case modification expansions on an unset variable
+         with -u set will cause and unbound variable error and make a
+         non-interactive shell abort
+       - change parameter_brace_expand_length to return INTMAX_MIN if a
+         positional parameter is unset and -u is set
+       - if parameter_brace_expand_length returns INTMAX_MIN when -u is set,
+         treat it as an unbound variable error and make a non-interactive
+         shell abort.  Posix change
+       - change parameter_brace_expand_length to return INTMAX_MIN if an
+         implicit reference to array[0] is made ${#array} and array[0] is
+         not set when -u is set
+
+                                  10/20
+                                  -----
+builtins/cd.def
+       - Posix 2008 says that if no matching directories are found in $CDPATH,
+         use the directory name passed as an operand and go on.  Posix change
index 5526c4dfbfd76d49b4f63b69953cf0617e12c4f5..148c59db26933a802b953a5f8377e5e35d985bae 100644 (file)
@@ -283,6 +283,7 @@ cd_builtin (list)
            free (temp);
        }
 
+#if 0  /* changed for bash-4.2 Posix cd description steps 5-6 */
       /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
         try the current directory, so we just punt now with an error
         message if POSIXLY_CORRECT is non-zero.  The check for cdpath[0]
@@ -293,6 +294,7 @@ cd_builtin (list)
          builtin_error ("%s: %s", dirname, strerror (ENOENT));
          return (EXECUTION_FAILURE);
        }
+#endif
     }
   else
     dirname = list->word->word;
index 48cfcfa54cfc35ed811a80dc1e91edea3d00e4e0..1fb067f05f5b8cff24b0eba8c61672874a094a85 100644 (file)
@@ -67,6 +67,8 @@ int cdspelling = 0;
 
 int cdable_vars;
 
+static int eflag;      /* file scope so bindpwd() can see it */
+
 $BUILTIN cd
 $FUNCTION cd_builtin
 $SHORT_DOC cd [-L|[-P [-e]]] [dir]
@@ -141,6 +143,8 @@ bindpwd (no_symlinks)
     }
 
   setpwd (dirname);
+  if (dirname == 0 && eflag)
+    r = EXECUTION_FAILURE;
 
   if (dirname && dirname != the_current_working_directory)
     free (dirname);
@@ -176,7 +180,7 @@ cd_builtin (list)
      WORD_LIST *list;
 {
   char *dirname, *cdpath, *path, *temp;
-  int path_index, no_symlinks, opt, lflag, eflag;
+  int path_index, no_symlinks, opt, lflag;
 
 #if defined (RESTRICTED_SHELL)
   if (restricted)
@@ -211,6 +215,8 @@ cd_builtin (list)
 
   lflag = (cdable_vars ? LCD_DOVARS : 0) |
          ((interactive && cdspelling) ? LCD_DOSPELL : 0);
+  if (eflag && no_symlinks == 0)
+    eflag = 0;
 
   if (list == 0)
     {
@@ -284,8 +290,15 @@ cd_builtin (list)
         specifying the current directory. */
       if (posixly_correct && cdpath[0])
        {
+#if 0
          builtin_error ("%s: %s", dirname, strerror (ENOENT));
          return (EXECUTION_FAILURE);
+#else  /* changed for bash-4.2 Posix cd description steps 5-6 */
+         if (no_symlinks)
+           dirname = list->word->word;
+         else
+           dirname = 
+#endif
        }
     }
   else
index 82c0d96aa30c342459eff86dcc0214cb30c8b952..ca95ce8584bf5f9ba61a2df0e562092dbb25742b 100644 (file)
@@ -1,6 +1,6 @@
 /* evalstring.c - evaluate a string as one or more shell commands. 
 
-/* Copyright (C) 1996-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1996-2010 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -263,6 +263,7 @@ parse_and_execute (string, from_file, flags)
 
              bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
              begin_unwind_frame ("pe_dispose");
+itrace("begin_unwind_frame: pe_dispose");
              add_unwind_protect (dispose_fd_bitmap, bitmap);
              add_unwind_protect (dispose_command, command);    /* XXX */
 
index abbeda9eded97c87f32ca1749df577b6bc35785d..5d1e625b92c2e48b94a93a6ab1a72ca59e7c37b8 100644 (file)
@@ -212,7 +212,7 @@ exec_builtin (list)
     end_job_control ();
 #endif /* JOB_CONTROL */
 
-  shell_execve (command, args, env);
+  exit_value = shell_execve (command, args, env);
 
   /* We have to set this to NULL because shell_execve has called realloc()
      to stuff more items at the front of the array, which may have caused
@@ -221,7 +221,9 @@ exec_builtin (list)
   if (cleanenv == 0)
     adjust_shell_level (1);
 
-  if (executable_file (command) == 0)
+  if (exit_value == EX_NOTFOUND)       /* no duplicate error message */
+    goto failed_exec;
+  else if (executable_file (command) == 0)
     {
       builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
       exit_value = EX_NOEXEC;  /* As per Posix.2, 3.14.6 */
index f29e5a3361726e0d0d70bba750373ec022b5411c..bd0da7a8a280d5ce353416dc26482c27f4eb2524 100644 (file)
@@ -150,7 +150,11 @@ exec_builtin (list)
     {
       if (file_isdir (args[0]))
        {
+#if defined (EISDIR)
+         builtin_error (_("%s: cannot execute: %s"), args[0], strerror (EISDIR));
+#else
          builtin_error (_("%s: cannot execute: %s"), args[0], strerror (errno));
+#endif
          exit_value = EX_NOEXEC;
        }
       else
@@ -208,7 +212,7 @@ exec_builtin (list)
     end_job_control ();
 #endif /* JOB_CONTROL */
 
-  shell_execve (command, args, env);
+  exit_value = shell_execve (command, args, env);
 
   /* We have to set this to NULL because shell_execve has called realloc()
      to stuff more items at the front of the array, which may have caused
@@ -217,7 +221,9 @@ exec_builtin (list)
   if (cleanenv == 0)
     adjust_shell_level (1);
 
-  if (executable_file (command) == 0)
+  if (exit_value == EX_NOTFOUND)
+    goto failed_exec;
+  else if (executable_file (command) == 0)
     {
       builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
       exit_value = EX_NOEXEC;  /* As per Posix.2, 3.14.6 */
index 9523cfc3ceb1e17c02ed866ee80a90d9f001b296..2119f5b3cb818273ffb053d3c0f9e42b506c19f1 100644 (file)
@@ -35,7 +35,11 @@ value.  If ARG is the null string each SIGNAL_SPEC is ignored by the
 shell and by the commands it invokes.
 
 If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell.  If
-a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.
+a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.  If
+a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
+script run by the . or source builtins finishes executing.  A SIGNAL_SPEC
+of ERR means to execute ARG each time a command's failure would cause the
+shell to exit when the -e option is enabled.
 
 If no arguments are supplied, trap prints the list of commands associated
 with each signal.
index 4de3990de447062e53d7f2ac3457decc331f7fea..f76f2ef0fca40cb136e335c38fd36dff31af1c30 100644 (file)
@@ -1,7 +1,7 @@
 This file is trap.def, from which is created trap.c.
 It implements the builtin "trap" in Bash.
 
-Copyright (C) 1987-2009 Free Software Foundation, Inc.
+Copyright (C) 1987-2010 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -35,7 +35,9 @@ value.  If ARG is the null string each SIGNAL_SPEC is ignored by the
 shell and by the commands it invokes.
 
 If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell.  If
-a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.
+a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.  If
+a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
+script run by the . or source builtins finishes executing.
 
 If no arguments are supplied, trap prints the list of commands associated
 with each signal.
index ad79859255d36d09f73d91689b9f00f66316172a..9a01d6e613392888473d4154b7b8f7bca34c5946 100644 (file)
@@ -9366,8 +9366,8 @@ is
 .BR RETURN ,
 the command
 .I arg
-is executed each time a shell function or a script executed with the
-\fB.\fP or \fBsource\fP builtins finishes executing.
+is executed each time a shell function or a script executed with
+the \fB.\fP or \fBsource\fP builtins finishes executing.
 .if t .sp 0.5
 .if n .sp 1
 If a
index 70709cd31bd326fd4f95e9664deebb3b3af8e272..ad79859255d36d09f73d91689b9f00f66316172a 100644 (file)
@@ -5,12 +5,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.cwru.edu
 .\"
-.\"    Last Change: Sat Aug 28 18:55:45 EDT 2010
+.\"    Last Change: Mon Sep  6 22:07:38 EDT 2010
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2010 August 28" "GNU Bash-4.2"
+.TH BASH 1 "2010 September 6" "GNU Bash-4.2"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
index 2f457515b2d91844bfe508b82615c43fc5593e13..a299899b5133e16aeddbd955d0f5af820e0f0f78 100644 (file)
@@ -6694,14 +6694,6 @@ the @sc{posix} standard, and include things like passing incorrect options,
 redirection errors, variable assignment errors for assignments preceding
 the command name, and so on.
 
-@item
-If @env{CDPATH} is set, the @code{cd} builtin will not implicitly
-append the current directory to it.  This means that @code{cd} will
-fail if no valid directory name can be constructed from
-any of the entries in @env{$CDPATH}, even if the a directory with
-the same name as the name given as an argument to @code{cd} exists
-in the current directory.
-
 @item
 A non-interactive shell exits with an error status if a variable
 assignment error occurs when no command name follows the assignment
@@ -6709,6 +6701,11 @@ statements.
 A variable assignment error occurs, for example, when trying to assign
 a value to a readonly variable.
 
+@item
+A non-interactive shell exists with an error status if a variable
+assignment error occurs in an assignment statement preceding a special
+builtin, but not with any other simple command.
+
 @item
 A non-interactive shell exits with an error status if the iteration
 variable in a @code{for} statement or the selection variable in a
@@ -6774,10 +6771,6 @@ constructed from @code{$PWD} and the directory name supplied as an argument
 does not refer to an existing directory, @code{cd} will fail instead of
 falling back to @var{physical} mode.
 
-@item
-When the @code{pwd} builtin is supplied the @option{-P} option, it resets
-@code{$PWD} to a pathname containing no symlinks.
-
 @item
 The @code{pwd} builtin verifies that the value it prints is the same as the
 current directory, even if it is not asked to check the file system with the
index 1a94dc0391910e5914a0bb60b7c1680da4edebcc..2f457515b2d91844bfe508b82615c43fc5593e13 100644 (file)
@@ -1135,7 +1135,7 @@ command (@pxref{Redirections}).
 The file descriptors can be utilized as arguments to shell commands
 and redirections using standard word expansions.
 
-The process id of the shell spawned to execute the coprocess is
+The process ID of the shell spawned to execute the coprocess is
 available as the value of the variable @var{NAME}_PID.
 The @code{wait}
 builtin command may be used to wait for the coprocess to terminate.
@@ -1382,7 +1382,7 @@ In the context where an assignment statement is assigning a value
 to a shell variable or array index (@pxref{Arrays}), the @samp{+=}
 operator can be used to   
 append to or add to the variable's previous value.
-When @samp{+=} is applied to a variable for which the integer attribute
+When @samp{+=} is applied to a variable for which the @var{integer} attribute
 has been set, @var{value} is evaluated as an arithmetic expression and
 added to the variable's current value, which is also evaluated.
 When @samp{+=} is applied to an array variable using compound assignment
@@ -1717,7 +1717,7 @@ Bash uses the value of the variable formed from the rest of
 expanded and that value is used in the rest of the substitution, rather
 than the value of @var{parameter} itself.
 This is known as @code{indirect expansion}.
-The exceptions to this are the expansions of $@{!@var{prefix*}@}
+The exceptions to this are the expansions of $@{!@var{prefix}@*}
 and $@{!@var{name}[@@]@}
 described below.
 The exclamation point must immediately follow the left brace in order to
@@ -3061,7 +3061,7 @@ invocation if a new set of parameters is to be used.
 When the end of options is encountered, @code{getopts} exits with a
 return value greater than zero.
 @env{OPTIND} is set to the index of the first non-option argument,
-and @code{name} is set to @samp{?}.
+and @var{name} is set to @samp{?}.
 
 @code{getopts}
 normally parses the positional parameters, but if more arguments are
@@ -4141,8 +4141,8 @@ parameters, or to display the names and values of shell variables.
 @item set
 @btindex set
 @example
-set [--abefhkmnptuvxBCEHPT] [-o @var{option}] [@var{argument} @dots{}]
-set [+abefhkmnptuvxBCEHPT] [+o @var{option}] [@var{argument} @dots{}]
+set [--abefhkmnptuvxBCEHPT] [-o @var{option-name}] [@var{argument} @dots{}]
+set [+abefhkmnptuvxBCEHPT] [+o @var{option-name}] [@var{argument} @dots{}]
 @end example
 
 If no options or arguments are supplied, @code{set} displays the names
@@ -4503,18 +4503,19 @@ easy re-editing of multi-line commands.
 @item compat31
 If set, Bash
 changes its behavior to that of version 3.1 with respect to quoted
-arguments to the conditional command's =~ operator.
+arguments to the conditional command's @samp{=~} operator.
 
 @item compat32
 If set, Bash
 changes its behavior to that of version 3.2 with respect to locale-specific
-string comparison when using the conditional command's < and > operators.
+string comparison when using the conditional command's @samp{<} and @samp{>}
+operators.
 
 @item compat40
 If set, Bash
 changes its behavior to that of version 4.0 with respect to locale-specific
-string comparison when using the conditional command's < and > operators
-and the effect of interrupting a command list.
+string comparison when using the conditional command's @samp{<} and @samp{>}
+operators and the effect of interrupting a command list.
 
 @item compat41
 If set, Bash, when in posix mode, treats a single quote in a double-quoted
@@ -4850,13 +4851,13 @@ starts up, each shell option in the list will be enabled before
 reading any startup files.  This variable is readonly.
 
 @item BASHPID
-Expands to the process id of the current Bash process.
+Expands to the process ID of the current Bash process.
 This differs from @code{$$} under certain circumstances, such as subshells
 that do not require Bash to be re-initialized.
 
 @item BASH_ALIASES
 An associative array variable whose members correspond to the internal
-list of aliases as maintained by the @code{alias} builtin
+list of aliases as maintained by the @code{alias} builtin.
 (@pxref{Bourne Shell Builtins}).
 Elements added to this array appear in the alias list; unsetting array
 elements cause aliases to be removed from the alias list.
@@ -5728,7 +5729,7 @@ No other startup files are read.
 @subsubheading Invoked by remote shell daemon
 
 Bash attempts to determine when it is being run with its standard input
-connected to a network connection, as if by the remote shell
+connected to a network connection, as when executed by the remote shell
 daemon, usually @code{rshd}, or the secure shell daemon @code{sshd}.
 If Bash determines it is being run in
 this fashion, it reads and executes commands from @file{~/.bashrc}, if that
@@ -6132,7 +6133,7 @@ The value of a variable is evaluated as an arithmetic expression
 when it is referenced, or when a variable which has been given the  
 @var{integer} attribute using @samp{declare -i} is assigned a value.
 A null value evaluates to 0.
-A shell variable need not have its integer attribute turned on
+A shell variable need not have its @var{integer} attribute turned on
 to be used in an expression.
 
 Constants with a leading 0 are interpreted as octal numbers.
index a68f5e7969e44008244a5aaf5e7f3cac2b593a8a..cc4b015c82a456a78b9e6cc5e725d2477faeeee3 100644 (file)
@@ -2,9 +2,9 @@
 Copyright (C) 1988-2010 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Mon Sep  6 22:08:10 EDT 2010
+@set LASTCHANGE Wed Oct 20 21:37:22 EDT 2010
 
 @set EDITION 4.2
 @set VERSION 4.2
-@set UPDATED 6 September 2010
-@set UPDATED-MONTH September 2010
+@set UPDATED 20 October 2010
+@set UPDATED-MONTH October 2010
index 061b86ac9751245933e2b8d9ae4562c1d9c1ca51..a68f5e7969e44008244a5aaf5e7f3cac2b593a8a 100644 (file)
@@ -2,9 +2,9 @@
 Copyright (C) 1988-2010 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Sat Aug 28 18:56:04 EDT 2010
+@set LASTCHANGE Mon Sep  6 22:08:10 EDT 2010
 
 @set EDITION 4.2
 @set VERSION 4.2
-@set UPDATED 28 August 2010
-@set UPDATED-MONTH August 2010
+@set UPDATED 6 September 2010
+@set UPDATED-MONTH September 2010
index 2f76d1107f083a69ee421f4437deef7fe89b07c0..1795c5472d18527d8011b86854632bc7ddaa02ee 100644 (file)
@@ -4523,11 +4523,18 @@ execute_builtin_or_function (words, builtin, var, redirects,
      and preserve the redirections. */
   if (builtin == command_builtin && this_shell_builtin == exec_builtin)
     {
+      int discard;
+
+      discard = 0;
       if (saved_undo_list)
-       dispose_redirects (saved_undo_list);
+       {
+         dispose_redirects (saved_undo_list);
+         discard = 1;
+       }
       redirection_undo_list = exec_redirection_undo_list;
       saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;      
-      discard_unwind_frame ("saved_redirects");
+      if (discard)
+       discard_unwind_frame ("saved redirects");
     }
 
   if (saved_undo_list)
index c28335f75736465ca60880d62c718c98929433aa..83eddd0c8a9cbcbe8439ffdb19127f2aa15879f0 100644 (file)
@@ -4081,7 +4081,7 @@ execute_builtin (builtin, words, flags, subshell)
     }
 
   executing_builtin++;
-  executing_command_builtin = builtin == command_builtin;
+  executing_command_builtin |= builtin == command_builtin;
   result = ((*builtin) (words->next));
 
   /* This shouldn't happen, but in case `return' comes back instead of
@@ -4523,11 +4523,18 @@ execute_builtin_or_function (words, builtin, var, redirects,
      and preserve the redirections. */
   if (builtin == command_builtin && this_shell_builtin == exec_builtin)
     {
+      int discard;
+
+      discard = 0;
       if (saved_undo_list)
-       dispose_redirects (saved_undo_list);
+       {
+         dispose_redirects (saved_undo_list);
+         discard = 1;
+       }
       redirection_undo_list = exec_redirection_undo_list;
       saved_undo_list = exec_redirection_undo_list = (REDIRECT *)NULL;      
-      discard_unwind_frame ("saved_redirects");
+      if (discard)
+       discard_unwind_frame ("saved redirects");
     }
 
   if (saved_undo_list)
@@ -4929,6 +4936,7 @@ shell_execve (command, args, env)
   CHECK_TERMSIG;
   SETOSTYPE (1);
 
+itrace("shell_execve: command = %s", command);
   /* If we get to this point, then start checking out the file.
      Maybe it is something we can hack ourselves. */
   if (i != ENOEXEC)
index 05607691c8e7c2b6a8ad2c901a74e5564019869c..77bcad97677be0eeb0a18f2077812156b88ad090 100644 (file)
 #endif
 #ifndef UNCTRL
    /* control char to letter -- ASCII */
-#  define UNCTRL(x)    (TOUPPER((x) | 0x40))
+#  define UNCTRL(x)    (TOUPPER(x) ^ 0x40)
 #endif
 
 #endif /* _SH_CHARTYPES_H */
index c742ef874c0b51d73ab800612f78f89cfa22f5c7..13d928d43688373bae420ab0194fa7b0cccb6918 100644 (file)
@@ -171,6 +171,8 @@ ansicstr (string, len, flags, sawc, rlen)
                    *rlen = r - ret;
                  return ret;
                }
+             else if ((flags & 1) == 0 && *s == 0)
+               ;               /* pass \c through */
              else if ((flags & 1) == 0 && (c = *s))
                {
                  s++;
diff --git a/parse.y b/parse.y
index 08f5f7fddd85a929b064223a342f9c3a6d549c10..449f0c67d49255d5246a52a5605287dbcd219997 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -1647,6 +1647,9 @@ typedef struct stream_saver {
 /* The globally known line number. */
 int line_number = 0;
 
+/* The line number offset set by assigning to LINENO.  Not currently used. */
+int line_number_base = 0;
+
 #if defined (COND_COMMAND)
 static int cond_lineno;
 static int cond_token;
@@ -3162,7 +3165,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
   start_lineno = line_number;
   while (count)
     {
-      ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+      ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0);
 
       if (ch == EOF)
        {
@@ -3431,7 +3434,7 @@ parse_comsub (qc, open, close, lenp, flags)
   while (count)
     {
 comsub_readchar:
-      ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+      ch = shell_getc (qc != '\'' && (tflags & (LEX_INCOMMENT|LEX_PASSNEXT)) == 0);
 
       if (ch == EOF)
        {
index 5dccdb3ca7b18d791c53d6756e084cdf588db54b..fe03328b4d4c2497100cfcdedbfa1812e391ee7c 100644 (file)
--- a/parse.y~
+++ b/parse.y~
@@ -1647,6 +1647,9 @@ typedef struct stream_saver {
 /* The globally known line number. */
 int line_number = 0;
 
+/* The line number offset set by assigning to LINENO.  Not currently used. */
+int line_number_base = 0;
+
 #if defined (COND_COMMAND)
 static int cond_lineno;
 static int cond_token;
@@ -3162,7 +3165,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
   start_lineno = line_number;
   while (count)
     {
-      ch = shell_getc (qc != '\'' && (tflags & LEX_PASSNEXT) == 0);
+      ch = shell_getc (qc != '\'' && (tflags & (LEX_PASSNEXT)) == 0);
 
       if (ch == EOF)
        {
@@ -4953,7 +4956,6 @@ prompt_again ()
 {
   char *temp_prompt;
 
-itrace("prompt_again()");
   if (interactive == 0 || expanding_alias ())  /* XXX */
     return;
 
@@ -4988,7 +4990,6 @@ itrace("prompt_again()");
       FREE (current_decoded_prompt);
       current_decoded_prompt = temp_prompt;
     }
-itrace("prompt_again: current_prompt_string = %s", current_prompt_string);
 }
 
 int
index 4f2faa773e55fc0334e725a9cdaa67914ad6e752..f55a582e0bf028d5de4f8845f4873e3a01bd0085 100644 (file)
--- a/shell.c~
+++ b/shell.c~
@@ -526,21 +526,20 @@ main (argc, argv, env)
   else
     init_noninteractive ();
 
-#define CLOSE_FDS_AT_LOGIN
-#if defined (CLOSE_FDS_AT_LOGIN)
   /*
    * Some systems have the bad habit of starting login shells with lots of open
    * file descriptors.  For instance, most systems that have picked up the
    * pre-4.0 Sun YP code leave a file descriptor open each time you call one
    * of the getpw* functions, and it's set to be open across execs.  That
-   * means one for login, one for xterm, one for shelltool, etc.
+   * means one for login, one for xterm, one for shelltool, etc.  There are
+   * also systems that open persistent FDs to other agents or files as part
+   * of process startup; these need to be set to be close-on-exec.
    */
   if (login_shell && interactive_shell)
     {
       for (i = 3; i < 20; i++)
-       close (i);
+       SET_CLOSE_ON_EXEC (i);
     }
-#endif /* CLOSE_FDS_AT_LOGIN */
 
   /* If we're in a strict Posix.2 mode, turn on interactive comments,
      alias expansion in non-interactive shells, and other Posix.2 things. */
@@ -1293,12 +1292,13 @@ run_one_command (command)
   int code;
 
   code = setjmp (top_level);
-
+itrace("run_one_command: setjmp: code = %d", code);
   if (code != NOT_JUMPED)
     {
 #if defined (PROCESS_SUBSTITUTION)
       unlink_fifo_list ();
 #endif /* PROCESS_SUBSTITUTION */
+itrace("run_one_command: code = %d", code);
       switch (code)
        {
          /* Some kind of throw to top_level has occured. */
diff --git a/subst.c b/subst.c
index 80d096c8fc01e85218a104f4da185c0799fe3030..ea607b40c3850806505a7af0caf4a99382d3e3d0 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -108,7 +108,7 @@ extern int errno;
 /* Evaluates to 1 if C is one of the shell's special parameters for which an
    indirect variable reference may be made. */
 #define VALID_INDIR_PARAM(c) \
-  ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*')
+  ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
 
 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
    in ${parameter[:]OPword}. */
@@ -1461,7 +1461,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
       if (c == '\'')
        {
 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
-         if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE)
+         if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
            ADVANCE_CHAR (string, slen, i);
          else
            {
@@ -5907,7 +5907,7 @@ parameter_brace_expand_length (name)
          break;
        case '!':
          if (last_asynchronous_pid == NO_PID)
-           t = (char *)NULL;
+           t = (char *)NULL;   /* XXX - error if set -u set? */
          else
            t = itos (last_asynchronous_pid);
          break;
@@ -5929,6 +5929,8 @@ parameter_brace_expand_length (name)
       if (legal_number (name + 1, &arg_index))         /* ${#1} */
        {
          t = get_dollar_var_value (arg_index);
+         if (t == 0 && unbound_vars_is_error)
+           return INTMAX_MIN;
          number = MB_STRLEN (t);
          FREE (t);
        }
@@ -5939,6 +5941,8 @@ parameter_brace_expand_length (name)
            t = assoc_reference (assoc_cell (var), "0");
          else
            t = array_reference (array_cell (var), 0);
+         if (t == 0 && unbound_vars_is_error)
+           return INTMAX_MIN;
          number = MB_STRLEN (t);
        }
 #endif
@@ -6940,15 +6944,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
   /* If the name really consists of a special variable, then make sure
      that we have the entire name.  We don't allow indirect references
      to special variables except `#', `?', `@' and `*'. */
-  if ((sindex == t_index &&
-       (string[t_index] == '-' ||
-        string[t_index] == '?' ||
-        string[t_index] == '#')) ||
-      (sindex == t_index - 1 && string[sindex] == '!' &&
-       (string[t_index] == '#' ||
-        string[t_index] == '?' ||
-        string[t_index] == '@' ||
-        string[t_index] == '*')))
+  if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
+      (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
     {
       t_index++;
       free (name);
@@ -7043,6 +7040,13 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
        }
 
       number = parameter_brace_expand_length (name);
+      if (number == INTMAX_MIN && unbound_vars_is_error)
+       {
+         last_command_exit_value = EXECUTION_FAILURE;
+         err_unboundvar (name+1);
+         free (name);
+         return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+       }
       free (name);
 
       *indexp = sindex;
@@ -7178,6 +7182,21 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
 
   *indexp = sindex;
 
+  /* All the cases where an expansion can possibly generate an unbound
+     variable error. */
+  if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
+    {
+      if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
+       {
+         last_command_exit_value = EXECUTION_FAILURE;
+         err_unboundvar (name);
+         FREE (value);
+         FREE (temp);
+         free (name);
+         return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+       }
+    }
+    
   /* If this is a substring spec, process it and add the result. */
   if (want_substring)
     {
@@ -7251,15 +7270,6 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
       return &expand_wdesc_error;
 
     case RBRACE:
-      if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
-       {
-         last_command_exit_value = EXECUTION_FAILURE;
-         err_unboundvar (name);
-         FREE (value);
-         FREE (temp);
-         free (name);
-         return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
-       }
       break;
 
     case '#':  /* ${param#[#]pattern} */
@@ -9324,6 +9334,7 @@ expand_word_list_internal (list, eflags)
   if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
     {
       sh_wassign_func_t *assign_func;
+      int is_special_builtin;
 
       /* If the remainder of the words expand to nothing, Posix.2 requires
         that the variable and environment assignments affect the shell's
@@ -9331,6 +9342,10 @@ expand_word_list_internal (list, eflags)
       assign_func = new_list ? assign_in_env : do_word_assignment;
       tempenv_assign_error = 0;
 
+      /* Posix says that special builtins exit if a variable assignment error
+        occurs in an assignment preceding it. */
+      is_special_builtin = (posixly_correct && new_list && find_special_builtin (new_list->word->word));
+      
       for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
        {
          this_command_name = (char *)NULL;
@@ -9344,7 +9359,7 @@ expand_word_list_internal (list, eflags)
              if (assign_func == do_word_assignment)
                {
                  last_command_exit_value = EXECUTION_FAILURE;
-                 if (interactive_shell == 0 && posixly_correct)
+                 if (interactive_shell == 0 && posixly_correct && is_special_builtin)
                    exp_jump_to_top_level (FORCE_EOF);
                  else
                    exp_jump_to_top_level (DISCARD);
index b4601e794304a68815abd132e2ac7d1e4a4c29ee..1da1b6fc4e4ff53a0ff7352b8c8ae5505c2d4514 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -108,7 +108,7 @@ extern int errno;
 /* Evaluates to 1 if C is one of the shell's special parameters for which an
    indirect variable reference may be made. */
 #define VALID_INDIR_PARAM(c) \
-  ((c) == '#' || (c) == '?' || (c) == '@' || (c) == '*')
+  ((posixly_correct == 0 && (c) == '#') || (posixly_correct == 0 && (c) == '?') || (c) == '@' || (c) == '*')
 
 /* Evaluates to 1 if C is one of the OP characters that follows the parameter
    in ${parameter[:]OPword}. */
@@ -1461,7 +1461,7 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
       if (c == '\'')
        {
 /*itrace("extract_dollar_brace_string: c == single quote flags = %d quoted = %d dolbrace_state = %d", flags, quoted, dolbrace_state);*/
-         if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE)
+         if (posixly_correct && shell_compatibility_level > 41 && dolbrace_state != DOLBRACE_QUOTE && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
            ADVANCE_CHAR (string, slen, i);
          else
            {
@@ -5929,6 +5929,8 @@ parameter_brace_expand_length (name)
       if (legal_number (name + 1, &arg_index))         /* ${#1} */
        {
          t = get_dollar_var_value (arg_index);
+         if (t == 0 && unbound_vars_is_error)
+           return INTMAX_MIN;
          number = MB_STRLEN (t);
          FREE (t);
        }
@@ -5939,6 +5941,8 @@ parameter_brace_expand_length (name)
            t = assoc_reference (assoc_cell (var), "0");
          else
            t = array_reference (array_cell (var), 0);
+         if (t == 0 && unbound_vars_is_error)
+           return INTMAX_MIN;
          number = MB_STRLEN (t);
        }
 #endif
@@ -6940,15 +6944,8 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
   /* If the name really consists of a special variable, then make sure
      that we have the entire name.  We don't allow indirect references
      to special variables except `#', `?', `@' and `*'. */
-  if ((sindex == t_index &&
-       (string[t_index] == '-' ||
-        string[t_index] == '?' ||
-        string[t_index] == '#')) ||
-      (sindex == t_index - 1 && string[sindex] == '!' &&
-       (string[t_index] == '#' ||
-        string[t_index] == '?' ||
-        string[t_index] == '@' ||
-        string[t_index] == '*')))
+  if ((sindex == t_index && VALID_SPECIAL_LENGTH_PARAM (string[t_index])) ||
+      (sindex == t_index - 1 && string[sindex] == '!' && VALID_INDIR_PARAM (string[t_index])))
     {
       t_index++;
       free (name);
@@ -7043,6 +7040,13 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
        }
 
       number = parameter_brace_expand_length (name);
+      if (number == INTMAX_MIN && unbound_vars_is_error)
+       {
+         last_command_exit_value = EXECUTION_FAILURE;
+         err_unboundvar (name+1);
+         free (name);
+         return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+       }
       free (name);
 
       *indexp = sindex;
@@ -7178,6 +7182,21 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
 
   *indexp = sindex;
 
+  /* All the cases where an expansion can possibly generate an unbound
+     variable error. */
+  if (want_substring || want_patsub || want_casemod || c == '#' || c == '%' || c == RBRACE)
+    {
+      if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
+       {
+         last_command_exit_value = EXECUTION_FAILURE;
+         err_unboundvar (name);
+         FREE (value);
+         FREE (temp);
+         free (name);
+         return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
+       }
+    }
+    
   /* If this is a substring spec, process it and add the result. */
   if (want_substring)
     {
@@ -7251,15 +7270,6 @@ parameter_brace_expand (string, indexp, quoted, pflags, quoted_dollar_atp, conta
       return &expand_wdesc_error;
 
     case RBRACE:
-      if (var_is_set == 0 && unbound_vars_is_error && ((name[0] != '@' && name[0] != '*') || name[1]))
-       {
-         last_command_exit_value = EXECUTION_FAILURE;
-         err_unboundvar (name);
-         FREE (value);
-         FREE (temp);
-         free (name);
-         return (interactive_shell ? &expand_wdesc_error : &expand_wdesc_fatal);
-       }
       break;
 
     case '#':  /* ${param#[#]pattern} */
@@ -7449,7 +7459,6 @@ param_expand (string, sindex, quoted, expanded_something,
     /* $? -- return value of the last synchronous command. */
     case '?':
       temp = itos (last_command_exit_value);
-itrace("last_command_exit_value = %d", last_command_exit_value);
       break;
 
     /* $- -- flags supplied to the shell on invocation or by `set'. */
@@ -9325,6 +9334,7 @@ expand_word_list_internal (list, eflags)
   if ((eflags & WEXP_VARASSIGN) && subst_assign_varlist)
     {
       sh_wassign_func_t *assign_func;
+      int is_special_builtin;
 
       /* If the remainder of the words expand to nothing, Posix.2 requires
         that the variable and environment assignments affect the shell's
@@ -9332,6 +9342,10 @@ expand_word_list_internal (list, eflags)
       assign_func = new_list ? assign_in_env : do_word_assignment;
       tempenv_assign_error = 0;
 
+      /* Posix says that special builtins exit if a variable assignment error
+        occurs in an assignment preceding it. */
+      is_special_builtin = (posixly_correct && new_list && find_special_builtin (new_list->word->word));
+      
       for (temp_list = subst_assign_varlist; temp_list; temp_list = temp_list->next)
        {
          this_command_name = (char *)NULL;
@@ -9345,7 +9359,7 @@ expand_word_list_internal (list, eflags)
              if (assign_func == do_word_assignment)
                {
                  last_command_exit_value = EXECUTION_FAILURE;
-                 if (interactive_shell == 0 && posixly_correct)
+                 if (interactive_shell == 0 && posixly_correct && is_special_builtin)
                    exp_jump_to_top_level (FORCE_EOF);
                  else
                    exp_jump_to_top_level (DISCARD);
index 3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04..72ec06a2c1fd8dde92acea5e8ac773e35f1d061b 100755 (executable)
@@ -1,4 +1,4 @@
-BUILD_DIR=/usr/local/build/chet/bash/bash-current
+BUILD_DIR=/usr/local/build/bash/bash-current
 THIS_SH=$BUILD_DIR/bash
 PATH=$PATH:$BUILD_DIR
 
index 86a099c20bc6625029ebae896378175e97dde389..aae910da026fc206c67804e07938c21185a254ff 100644 (file)
@@ -10,7 +10,7 @@ after exec1.sub without args: 0
 127
 /bin/sh: /bin/sh: cannot execute binary file
 126
-./execscript: line 39: /: is a directory
+./execscript: line 39: /: Is a directory
 126
 /: /: is a directory
 126
@@ -20,8 +20,7 @@ after exec1.sub without args: 0
 0
 this is bashenv
 ./exec3.sub: line 3: /tmp/bash-notthere: No such file or directory
-./exec3.sub: line 3: exec: /tmp/bash-notthere: cannot execute: No such file or directory
-126
+127
 ./execscript: line 70: notthere: No such file or directory
 127
 ./execscript: line 73: notthere: No such file or directory
index 3629c57a90899b2ee10cbe8ae03b2fab9a06dade..a20f051ee84ac12ec893bf9cd059159161488d22 100644 (file)
@@ -112,3 +112,6 @@ ${THIS_SH} -i ./exec8.sub
 true | `echo true` &
 
 echo after
+
+# Problem with bash at least back to version 3.0
+${THIS_SH} -c 'VAR=0; VAR=1 command exec; exit ${VAR}'
diff --git a/tests/execscript~ b/tests/execscript~
new file mode 100644 (file)
index 0000000..0d2389b
--- /dev/null
@@ -0,0 +1,116 @@
+export LC_ALL=C
+export LANG=C
+
+if [ $UID -eq 0 ]; then
+        echo "execscript: the test suite should not be run as root" >&2
+fi
+
+set -- one two three
+echo before exec1.sub: "$@"
+echo calling exec1.sub
+./exec1.sub aa bb cc dd ee
+echo after exec1.sub with args: $?
+./exec1.sub
+echo after exec1.sub without args: $?
+
+# set up a fixed path so we know notthere will not be found
+PATH=/usr/bin:/bin:/usr/local/bin:
+export PATH
+
+notthere
+echo $?
+
+# this is iffy, since the error messages may vary from system to system
+# and /tmp might not exist
+ln -s ${THIS_SH} /tmp/bash 2>/dev/null
+if [ -f /tmp/bash ]; then
+       /tmp/bash notthere
+else
+       ${THIS_SH} notthere
+fi
+echo $?
+rm -f /tmp/bash
+
+# /bin/sh should be there on all systems
+${THIS_SH} /bin/sh
+echo $?
+
+# try executing a directory
+/
+echo $?
+
+${THIS_SH} /
+echo $?
+
+# try sourcing a directory
+. /
+echo $?
+
+# try sourcing a binary file -- post-2.04 versions don't do the binary file
+# check, and will probably fail with `command not found', or status 127
+# bash-4.1 and later check for 256 NUL characters and fail as binary files
+# if there are more than that, it's probably binary
+. ${THIS_SH} 2>/dev/null
+echo $?
+
+# post-bash-2.05 versions allow sourcing non-regular files
+. /dev/null
+echo $?
+
+# kill two birds with one test -- test out the BASH_ENV code
+echo echo this is bashenv > /tmp/bashenv
+export BASH_ENV=/tmp/bashenv
+${THIS_SH} ./exec3.sub
+rm -f /tmp/bashenv
+unset BASH_ENV
+
+# we're resetting the $PATH to empty, so this should be last
+PATH=
+
+notthere
+echo $?
+
+command notthere
+echo $?
+
+command -p notthere
+echo $?
+
+# but -p should guarantee that we find all the standard utilities, even
+# with an empty or unset $PATH
+command -p sh -c 'echo this is $0'
+unset PATH
+command -p sh -c 'echo this is $0'
+
+# a bug in bash before bash-2.01 caused PATH to be set to the empty string
+# when command -p was run with PATH unset
+echo ${PATH-unset}
+
+echo "echo ok" | ${THIS_SH} -t
+
+${THIS_SH} ./exec2.sub
+echo $?
+
+${THIS_SH} ./exec4.sub
+
+# try exec'ing a command that cannot be found in $PATH
+${THIS_SH} ./exec5.sub
+
+# this was a bug in bash versions before bash-2.04
+${THIS_SH} -c 'cat </dev/null | cat >/dev/null' >&-
+
+# checks for proper return values in subshell commands with inverted return
+# values
+
+${THIS_SH} ./exec6.sub
+
+# checks for properly deciding what constitutes an executable file
+${THIS_SH} ./exec7.sub
+
+${THIS_SH} -i ./exec8.sub
+
+true | `echo true` &
+
+echo after
+
+${THIS_SH} -c 'VAR=0; VAR=1 command exec; exit ${VAR}'
index e1898319be54428efb3e69a46b2c7da7d1bf7567..aa1bbf4efd5db7c6aab1891141368630aa72fada 100644 (file)
@@ -35,7 +35,7 @@ argv[1] = <x'>
 <x> <.> <w> <.> <x> <.> <w> <.> 
 argv[1] = <'bar>
 argv[1] = <foo 'bar baz>
-argv[1] = <z}>
+argv[1] = <}z>
 argv[1] = <''z}>
 ./posixexp.tests: line 68: unexpected EOF while looking for matching `}'
 ./posixexp.tests: line 69: syntax error: unexpected end of file
index 9e150a662aaa815b3651dcf6ee95785731d0589c..0a160b4c5d5be8a48f11e5d8a80e9592897c2a4c 100644 (file)
@@ -240,18 +240,24 @@ 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.
@@ -269,17 +275,20 @@ 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)
+      if (elt->head.cleanup == 0)
        {
          if (tag && STREQ (elt->arg.v, tag))
            {
              uwpfree (elt);
+             found = 1;
              break;
            }
        }
@@ -293,6 +302,8 @@ unwind_frame_run_internal (tag, ignore)
 
       uwpfree (elt);
     }
+  if (tag && found == 0)
+    internal_warning ("unwind_frame_run: %s: frame not found", tag);
 }
 
 static void
@@ -324,3 +335,20 @@ unwind_protect_mem (var, size)
 {
   without_interrupts (unwind_protect_mem_internal, var, (char *) &size);
 }
+
+#if defined (DEBUG)
+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
diff --git a/unwind_prot.c~ b/unwind_prot.c~
new file mode 100644 (file)
index 0000000..a4b2693
--- /dev/null
@@ -0,0 +1,354 @@
+/* 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"
+
+/* 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 (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)
+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
index 78fd9da2c65847e8f4464bea73a9038b6958d8a0..7552c47812e2f25adff4f007f5025c6eab76bd6b 100644 (file)
@@ -83,7 +83,7 @@ extern char **environ;
 
 /* Variables used here and defined in other files. */
 extern int posixly_correct;
-extern int line_number;
+extern int line_number, line_number_base;
 extern int subshell_environment, indirection_level, subshell_level;
 extern int build_version, patch_level;
 extern int expanding_redir;
@@ -1336,7 +1336,7 @@ assign_lineno (var, value, unused, key)
 
   if (value == 0 || *value == '\0' || legal_number (value, &new_value) == 0)
     new_value = 0;
-  line_number = new_value;
+  line_number = line_number_base = new_value;
   return var;
 }
 
index 47a6bb288784392d256abf53225adf9d28b002ed..78fd9da2c65847e8f4464bea73a9038b6958d8a0 100644 (file)
@@ -387,11 +387,14 @@ initialize_shell_variables (env, privmode)
 #endif
        {
          temp_var = bind_variable (name, string, 0);
-         if (legal_identifier (name))
-           VSETATTR (temp_var, (att_exported | att_imported));
-         else
-           VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
-         array_needs_making = 1;
+         if (temp_var)
+           {
+             if (legal_identifier (name))
+               VSETATTR (temp_var, (att_exported | att_imported));
+             else
+               VSETATTR (temp_var, (att_exported | att_imported | att_invisible));
+             array_needs_making = 1;
+           }
        }
 
       name[char_index] = '=';
@@ -2389,7 +2392,7 @@ bind_int_variable (lhs, rhs)
 #endif
     v = bind_variable (lhs, rhs, 0);
 
-  if (isint)
+  if (v && isint)
     VSETATTR (v, att_integer);
 
   return (v);
@@ -2838,7 +2841,7 @@ delete_all_variables (hashed_vars)
       if (!entry) \
        { \
          entry = bind_variable (name, "", 0); \
-         if (!no_invisible_vars) entry->attributes |= att_invisible; \
+         if (!no_invisible_vars && entry) entry->attributes |= att_invisible; \
        } \
     } \
   while (0)
@@ -4733,7 +4736,6 @@ sv_xtracefd (name)
   int fd;
   FILE *fp;
 
-itrace("sv_xtracefd: %s", name);
   v = find_variable (name);
   if (v == 0)
     {