From: Chet Ramey Date: Tue, 13 Dec 2011 03:08:08 +0000 (-0500) Subject: commit bash-20101015 snapshot X-Git-Tag: bash-4.3-alpha~157 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=048b249ea3221fe186bef2ada4887587e7973c58;p=thirdparty%2Fbash.git commit bash-20101015 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index dbbd5bb88..95e30415f 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index e6490f70d..45991fbec 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -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 diff --git a/builtins/cd.def b/builtins/cd.def index 5526c4dfb..148c59db2 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -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; diff --git a/builtins/cd.def~ b/builtins/cd.def~ index 48cfcfa54..1fb067f05 100644 --- a/builtins/cd.def~ +++ b/builtins/cd.def~ @@ -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 diff --git a/builtins/evalstring.c~ b/builtins/evalstring.c~ index 82c0d96aa..ca95ce858 100644 --- a/builtins/evalstring.c~ +++ b/builtins/evalstring.c~ @@ -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 */ diff --git a/builtins/exec.def b/builtins/exec.def index abbeda9ed..5d1e625b9 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -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 */ diff --git a/builtins/exec.def~ b/builtins/exec.def~ index f29e5a336..bd0da7a8a 100644 --- a/builtins/exec.def~ +++ b/builtins/exec.def~ @@ -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 */ diff --git a/builtins/trap.def b/builtins/trap.def index 9523cfc3c..2119f5b3c 100644 --- a/builtins/trap.def +++ b/builtins/trap.def @@ -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. diff --git a/builtins/trap.def~ b/builtins/trap.def~ index 4de3990de..f76f2ef0f 100644 --- a/builtins/trap.def~ +++ b/builtins/trap.def~ @@ -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. diff --git a/doc/bash.1 b/doc/bash.1 index ad7985925..9a01d6e61 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -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 diff --git a/doc/bash.1~ b/doc/bash.1~ index 70709cd31..ad7985925 100644 --- a/doc/bash.1~ +++ b/doc/bash.1~ @@ -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. diff --git a/doc/bashref.texi b/doc/bashref.texi index 2f457515b..a299899b5 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -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 diff --git a/doc/bashref.texi~ b/doc/bashref.texi~ index 1a94dc039..2f457515b 100644 --- a/doc/bashref.texi~ +++ b/doc/bashref.texi~ @@ -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. diff --git a/doc/version.texi b/doc/version.texi index a68f5e796..cc4b015c8 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -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 diff --git a/doc/version.texi~ b/doc/version.texi~ index 061b86ac9..a68f5e796 100644 --- a/doc/version.texi~ +++ b/doc/version.texi~ @@ -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 diff --git a/execute_cmd.c b/execute_cmd.c index 2f76d1107..1795c5472 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -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) diff --git a/execute_cmd.c~ b/execute_cmd.c~ index c28335f75..83eddd0c8 100644 --- a/execute_cmd.c~ +++ b/execute_cmd.c~ @@ -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) diff --git a/include/chartypes.h b/include/chartypes.h index 05607691c..77bcad976 100644 --- a/include/chartypes.h +++ b/include/chartypes.h @@ -107,7 +107,7 @@ #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 */ diff --git a/lib/sh/strtrans.c b/lib/sh/strtrans.c index c742ef874..13d928d43 100644 --- a/lib/sh/strtrans.c +++ b/lib/sh/strtrans.c @@ -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 08f5f7fdd..449f0c67d 100644 --- 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) { diff --git a/parse.y~ b/parse.y~ index 5dccdb3ca..fe03328b4 100644 --- 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 diff --git a/shell.c~ b/shell.c~ index 4f2faa773..f55a582e0 100644 --- 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 80d096c8f..ea607b40c 100644 --- 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); diff --git a/subst.c~ b/subst.c~ index b4601e794..1da1b6fc4 100644 --- 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); diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 3efcf32d6..72ec06a2c 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -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 diff --git a/tests/exec.right b/tests/exec.right index 86a099c20..aae910da0 100644 --- a/tests/exec.right +++ b/tests/exec.right @@ -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 diff --git a/tests/execscript b/tests/execscript index 3629c57a9..a20f051ee 100644 --- a/tests/execscript +++ b/tests/execscript @@ -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 index 000000000..0d2389b57 --- /dev/null +++ b/tests/execscript~ @@ -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' >&- + +# 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}' diff --git a/tests/posixexp.right b/tests/posixexp.right index e1898319b..aa1bbf4ef 100644 --- a/tests/posixexp.right +++ b/tests/posixexp.right @@ -35,7 +35,7 @@ argv[1] = <.> <.> <.> <.> argv[1] = <'bar> argv[1] = -argv[1] = +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 diff --git a/unwind_prot.c b/unwind_prot.c index 9e150a662..0a160b4c5 100644 --- a/unwind_prot.c +++ b/unwind_prot.c @@ -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 index 000000000..a4b269352 --- /dev/null +++ b/unwind_prot.c~ @@ -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 . +*/ + +/* **************************************************************** */ +/* */ +/* Unwind Protection Scheme for Bash */ +/* */ +/* **************************************************************** */ +#include "config.h" + +#include "bashtypes.h" +#include "bashansi.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if STDC_HEADERS +# include +#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 diff --git a/variables.c b/variables.c index 78fd9da2c..7552c4781 100644 --- a/variables.c +++ b/variables.c @@ -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; } diff --git a/variables.c~ b/variables.c~ index 47a6bb288..78fd9da2c 100644 --- a/variables.c~ +++ b/variables.c~ @@ -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) {