From 3710ed629f6b52a3f9247ecf7b02080aec9451f8 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Tue, 14 Jul 2020 17:04:20 -0400 Subject: [PATCH] commit bash-20200710 snapshot --- CWRU/CWRU.chlog | 21 +++++++- MANIFEST | 1 + builtins/command.def | 4 ++ doc/bashref.texi | 2 +- execute_cmd.c | 123 +++++++++++++++++++++++++++++++++++++------ tests/RUN-ONE-TEST | 2 +- tests/builtins.right | 38 ++++++++++++- tests/builtins.tests | 3 ++ tests/builtins7.sub | 38 +++++++++++++ 9 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 tests/builtins7.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index e0049883..c89fb94e 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -8429,10 +8429,10 @@ lib/readline/kill.c fix for bug reported by Phi Debian lib/readline/vi_mode.c - - _rl_vi_change_char: make sure _rl_vi_last_replacement gets filled in + - rl_vi_change_char: make sure _rl_vi_last_replacement gets filled in in the case where MB_CUR_MAX == 1. Rest of fix for bug reported by Phi Debian - - rl_vi_change_char: same fix for _rl_vi_last_replacement + - _rl_vi_callback_change_char: same fix for _rl_vi_last_replacement 5/29 ---- @@ -8702,3 +8702,20 @@ lib/readline/signals.c - _rl_handle_signal: block SIGTTOU while handling a SIGTTOU, since we no longer run this in a signal handling context where SIGTTOIU would be blocked + + 7/14 + ---- +execute_cmd.c + - execute_simple_command: use new variable `cmdflags' instead of using + simple_command->flags directly; initialize from simple_command->flags + - check_command_builtin: take a simple command list of words starting + with `command' and including a command_word argument, and peel off + the `command' and any instances of `-p' and `--' and return the + updated list + - execute_simple_command: if the first word of the simple command is + `command', call check_command_builtin to peel off any `command' and + `-p' and `--' and go on to execute the rest of the words as a simple + command. If we're in posix mode, we've got the special builtins + handled before this runs. Fixes complaint about `command' in the + background running an extra bash process from Dmitry Alexandrov + diff --git a/MANIFEST b/MANIFEST index 2bc9fa4b..9b601cc4 100644 --- a/MANIFEST +++ b/MANIFEST @@ -945,6 +945,7 @@ tests/builtins3.sub f tests/builtins4.sub f tests/builtins5.sub f tests/builtins6.sub f +tests/builtins7.sub f tests/source1.sub f tests/source2.sub f tests/source3.sub f diff --git a/builtins/command.def b/builtins/command.def index cea55b8e..acd46cc1 100644 --- a/builtins/command.def +++ b/builtins/command.def @@ -124,6 +124,10 @@ command_builtin (list) #define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0)) +#ifdef DEBUG + itrace("command_builtin: running execute_command for `%s'", list->word->word); +#endif + /* We don't want this to be reparsed (consider command echo 'foo &'), so just make a simple_command structure and call execute_command with it. */ command = make_bare_simple_command (); diff --git a/doc/bashref.texi b/doc/bashref.texi index 8c18536b..e80044f9 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -3787,7 +3787,7 @@ shift [@var{n}] Shift the positional parameters to the left by @var{n}. The positional parameters from @var{n}+1 @dots{} @code{$#} are renamed to @code{$1} @dots{} @code{$#}-@var{n}. -Parameters represented by the numbers @code{$#} to @code{$#}-@var{n}+1 +Parameters represented by the numbers @code{$#} down to @code{$#}-@var{n}+1 are unset. @var{n} must be a non-negative number less than or equal to @code{$#}. If @var{n} is zero or greater than @code{$#}, the positional parameters diff --git a/execute_cmd.c b/execute_cmd.c index 62d21171..831516d2 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -896,6 +896,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, only the failure of a simple command. We don't want to run the error trap if the command run by the `command' builtin fails; we want to defer that until the command builtin itself returns failure. */ + /* 2020/07/14 -- this changes with how the command builtin is handled */ if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && (command->value.Simple->flags & CMD_COMMAND_BUILTIN) == 0 && @@ -4161,6 +4162,52 @@ fix_assignment_words (words) } } +#ifndef ISOPTION +# define ISOPTION(s, c) (s[0] == '-' && s[1] == c && s[2] == 0) +#endif + +#define RETURN_NOT_COMMAND() \ + do { if (typep) *typep = 0; return words; } while (0) + +/* Make sure we have `command [-p] command_name [args]', and handle skipping + over the usual `--' that ends the options. Returns the updated WORDS with + the command and options stripped and sets *TYPEP to a non-zero value. If + any other options are supplied, or there is not a command_name, we punt + and return a zero value in *TYPEP without updating WORDS. */ +static WORD_LIST * +check_command_builtin (words, typep) + WORD_LIST *words; + int *typep; +{ + int type; + WORD_LIST *w; + + w = words->next; + type = 1; + + if (w && ISOPTION (w->word->word, 'p')) /* command -p */ + { +#if defined (RESTRICTED_SHELL) + if (restricted) + RETURN_NOT_COMMAND(); +#endif + w = w->next; + type = 2; + } + + if (w && ISOPTION (w->word->word, '-')) /* command [-p] -- */ + w = w->next; + else if (w && w->word->word[0] == '-') /* any other option */ + RETURN_NOT_COMMAND(); + + if (w == 0 || w->word->word == 0) /* must have a command_name */ + RETURN_NOT_COMMAND(); + + if (typep) + *typep = type; + return w; +} + /* Return 1 if the file found by searching $PATH for PATHNAME, defaulting to PATHNAME, is a directory. Used by the autocd code below. */ static int @@ -4188,7 +4235,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) WORD_LIST *words, *lastword; char *command_line, *lastarg, *temp; int first_word_quoted, result, builtin_is_special, already_forked, dofork; - int fork_flags; + int fork_flags, cmdflags; pid_t old_last_async_pid; sh_builtin_func_t *builtin; SHELL_VAR *func; @@ -4233,6 +4280,8 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) return (EXECUTION_SUCCESS); #endif + cmdflags = simple_command->flags; + first_word_quoted = simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0; @@ -4269,7 +4318,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) if (make_child (p = savestring (the_printed_command_except_trap), fork_flags) == 0) { already_forked = 1; - simple_command->flags |= CMD_NO_FORK; + cmdflags |= CMD_NO_FORK; subshell_environment = SUBSHELL_FORK; /* XXX */ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE) @@ -4318,15 +4367,15 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) /* If we are re-running this as the result of executing the `command' builtin, do not expand the command words a second time. */ - if ((simple_command->flags & CMD_INHIBIT_EXPANSION) == 0) + if ((cmdflags & CMD_INHIBIT_EXPANSION) == 0) { current_fds_to_close = fds_to_close; fix_assignment_words (simple_command->words); /* Pass the ignore return flag down to command substitutions */ - if (simple_command->flags & CMD_IGNORE_RETURN) /* XXX */ + if (cmdflags & CMD_IGNORE_RETURN) /* XXX */ comsub_ignore_return++; words = expand_words (simple_command->words); - if (simple_command->flags & CMD_IGNORE_RETURN) + if (cmdflags & CMD_IGNORE_RETURN) comsub_ignore_return--; current_fds_to_close = (struct fd_bitmap *)NULL; } @@ -4356,12 +4405,16 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) begin_unwind_frame ("simple-command"); - if (echo_command_at_execute && (simple_command->flags & CMD_COMMAND_BUILTIN) == 0) + if (echo_command_at_execute && (cmdflags & CMD_COMMAND_BUILTIN) == 0) xtrace_print_word_list (words, 1); builtin = (sh_builtin_func_t *)NULL; func = (SHELL_VAR *)NULL; - if ((simple_command->flags & CMD_NO_FUNCTIONS) == 0) + + /* This test is still here in case we want to change the command builtin + handler code below to recursively call execute_simple_command (after + modifying the simple_command struct). */ + if ((cmdflags & CMD_NO_FUNCTIONS) == 0) { /* Posix.2 says special builtins are found before functions. We don't set builtin_is_special anywhere other than here, because @@ -4393,6 +4446,41 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) } tempenv_assign_error = 0; /* don't care about this any more */ + old_command_builtin = -1; + if (builtin == 0 && func == 0) + { + WORD_LIST *disposer, *l; + int cmdtype; + + builtin = find_shell_builtin (words->word->word); + while (builtin == command_builtin) + { + disposer = words; + cmdtype = 0; + words = check_command_builtin (words, &cmdtype); + if (cmdtype > 0) /* command -p [--] words */ + { + for (l = disposer; l->next != words; l = l->next) + ; + l->next = 0; + dispose_words (disposer); + cmdflags |= CMD_COMMAND_BUILTIN | CMD_NO_FUNCTIONS; + if (cmdtype == 2) + cmdflags |= CMD_STDPATH; + builtin = find_shell_builtin (words->word->word); + } + else + break; + } + if (cmdflags & CMD_COMMAND_BUILTIN) + { + old_command_builtin = executing_command_builtin; + unwind_protect_int (executing_command_builtin); + executing_command_builtin |= 1; + } + builtin = 0; + } + add_unwind_protect (dispose_words, words); QUIT; @@ -4469,9 +4557,12 @@ run_builtin: if (builtin) { old_builtin = executing_builtin; - old_command_builtin = executing_command_builtin; unwind_protect_int (executing_builtin); /* modified in execute_builtin */ - unwind_protect_int (executing_command_builtin); /* ditto */ + if (old_command_builtin == -1) /* sentinel, can be set above */ + { + old_command_builtin = executing_command_builtin; + unwind_protect_int (executing_command_builtin); /* ditto and set above */ + } } if (already_forked) { @@ -4484,7 +4575,7 @@ run_builtin: if (async) { - if ((simple_command->flags & CMD_STDIN_REDIR) && + if ((cmdflags & CMD_STDIN_REDIR) && pipe_in == NO_PIPE && (stdin_redirects (simple_command->redirects) == 0)) async_redirect_stdin (); @@ -4496,14 +4587,14 @@ run_builtin: execute_subshell_builtin_or_function (words, simple_command->redirects, builtin, func, pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); + cmdflags); subshell_level--; } else { result = execute_builtin_or_function (words, builtin, func, simple_command->redirects, fds_to_close, - simple_command->flags); + cmdflags); if (builtin) { if (result > EX_SHERRBASE) @@ -4569,12 +4660,12 @@ execute_from_filesystem: /* The old code did not test already_forked and only did this if subshell_environment&SUBSHELL_COMSUB != 0 (comsubs and procsubs). Other uses of the no-fork optimization left FIFOs in $TMPDIR */ - if (already_forked == 0 && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0) - simple_command->flags &= ~CMD_NO_FORK; + if (already_forked == 0 && (cmdflags & CMD_NO_FORK) && fifos_pending() > 0) + cmdflags &= ~CMD_NO_FORK; #endif result = execute_disk_command (words, simple_command->redirects, command_line, pipe_in, pipe_out, async, fds_to_close, - simple_command->flags); + cmdflags); return_result: bind_lastarg (lastarg); @@ -4637,7 +4728,7 @@ execute_builtin (builtin, words, flags, subshell) the ERR trap, then restore them when the command completes. This is also a problem (as below) for the command and source/. builtins. */ if (subshell == 0 && (flags & CMD_IGNORE_RETURN) && - (builtin == eval_builtin || builtin == command_builtin || builtin == source_builtin)) + (builtin == eval_builtin || (flags & CMD_COMMAND_BUILTIN) || builtin == source_builtin)) { begin_unwind_frame ("eval_builtin"); unwind_protect_int (exit_immediately_on_error); diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 0b063810..c8bef8dd 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/builtins.right b/tests/builtins.right index 9aa182cd..832472f6 100644 --- a/tests/builtins.right +++ b/tests/builtins.right @@ -235,4 +235,40 @@ f2 () funcs unset: one-two two-two -./builtins.tests: line 279: exit: status: numeric argument required +bash: line 1: notthere: No such file or directory +one +bash: line 1: notthere: No such file or directory +two +bash: line 1: .: notthere: file not found +one +bash: line 1: .: notthere: file not found +0 +0 +0 +0 +argv[1] = +0 +argv[1] = +0 +three +0 +four +0 +./builtins7.sub: line 19: : command not found +127 +0 +./builtins7.sub: line 27: notthere: No such file or directory +after 1 +./builtins7.sub: line 28: notthere: No such file or directory +after 2 +type is a shell builtin ++ command -v type +type ++ command command -v type +type ++ command -p command -v type +type ++ command -p -- command -v type +type ++ set +x +./builtins.tests: line 282: exit: status: numeric argument required diff --git a/tests/builtins.tests b/tests/builtins.tests index 4e314416..00ebc0fd 100644 --- a/tests/builtins.tests +++ b/tests/builtins.tests @@ -275,6 +275,9 @@ ${THIS_SH} ./builtins5.sub # test behavior of unset builtin with -f and -v options ${THIS_SH} ./builtins6.sub +# test behavior of command builtin after changing it to a pseudo-keyword +${THIS_SH} ./builtins7.sub + # this must be last -- it is a fatal error exit status diff --git a/tests/builtins7.sub b/tests/builtins7.sub new file mode 100644 index 00000000..67e5e610 --- /dev/null +++ b/tests/builtins7.sub @@ -0,0 +1,38 @@ +: ${THIS_SH:=./bash} + +${THIS_SH} -c 'command . notthere ; echo one' bash +${THIS_SH} -c '. notthere ; echo two' bash + +${THIS_SH} -o posix -c 'command . notthere ; echo one' bash +${THIS_SH} -o posix -c '. notthere ; echo two' bash + +command ; echo $? +command -- ; echo $? +command -p ; echo $? +command -p -- ; echo $? + +command recho one; echo $? +command -- recho two; echo $? +command -p echo three; echo $? +command -p -- echo four ; echo $? + +command '' +echo $? + +command -p +echo $? + +${THIS_SH} -c 'set -e ; command false ; echo after' bash + +command command command -p . notthere ; echo after 1 +command -p command command . notthere ; echo after 2 + +command -p command -V type + +set -x +command -v type +command command -v type +command -p command -v type +command -p -- command -v type +set +x +