summaryrefslogtreecommitdiff
path: root/execute_cmd.c
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2020-09-09 15:25:32 -0400
committerChet Ramey <chet.ramey@case.edu>2020-09-09 15:25:32 -0400
commit3eb0018e75b74bb886df7fba4b1712529ce7258f (patch)
tree13b53713ef8f483a82295324e314da48b59c9346 /execute_cmd.c
parent712f80b0a49c3a0227d0b52bff5e0b763747697e (diff)
downloadbash-5.1-beta.tar.gz
bash-5.1 beta releasebash-5.1-beta
Diffstat (limited to 'execute_cmd.c')
-rw-r--r--execute_cmd.c130
1 files changed, 114 insertions, 16 deletions
diff --git a/execute_cmd.c b/execute_cmd.c
index 0ba17f6c..7cb75f88 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,43 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
}
tempenv_assign_error = 0; /* don't care about this any more */
+ /* This is where we handle the command builtin as a pseudo-reserved word
+ prefix. This allows us to optimize away forks if we can. */
+ 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 +4559,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 +4577,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 +4589,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 +4662,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 +4730,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);
@@ -4831,6 +4924,11 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
if (tc && (flags & CMD_IGNORE_RETURN))
tc->flags |= CMD_IGNORE_RETURN;
+ /* A limited attempt at optimization: shell functions at the end of command
+ substitutions that are already marked NO_FORK. */
+ if (tc && (flags & CMD_NO_FORK) && (subshell_environment & SUBSHELL_COMSUB))
+ optimize_shell_function (tc);
+
gs = sh_getopt_save_istate ();
if (subshell == 0)
{