aboutsummaryrefslogtreecommitdiffstats
path: root/execute_cmd.c
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2005-12-07 14:08:12 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:57 +0000
commit95732b497d12c98613bb3c5db16b61f377501a59 (patch)
tree5e1cdf79eb0407e09dca4c0ec29e11442c7d1d15 /execute_cmd.c
parenteb87367179effbe5f430236db8259006d71438b7 (diff)
downloadandroid_external_bash-95732b497d12c98613bb3c5db16b61f377501a59.tar.gz
android_external_bash-95732b497d12c98613bb3c5db16b61f377501a59.tar.bz2
android_external_bash-95732b497d12c98613bb3c5db16b61f377501a59.zip
Imported from ../bash-3.1.tar.gz.
Diffstat (limited to 'execute_cmd.c')
-rw-r--r--execute_cmd.c213
1 files changed, 126 insertions, 87 deletions
diff --git a/execute_cmd.c b/execute_cmd.c
index 44426fd..ce90d25 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -1,6 +1,6 @@
/* execute_command.c -- Execute a COMMAND structure. */
-/* Copyright (C) 1987-2003 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -160,7 +160,7 @@ static int execute_while_command __P((WHILE_COM *));
static int execute_until_command __P((WHILE_COM *));
static int execute_while_or_until __P((WHILE_COM *, int));
static int execute_if_command __P((IF_COM *));
-static int execute_null_command __P((REDIRECT *, int, int, int, pid_t));
+static int execute_null_command __P((REDIRECT *, int, int, int));
static void fix_assignment_words __P((WORD_LIST *));
static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *));
static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int));
@@ -245,6 +245,9 @@ int subshell_level = 0;
/* Currently-executing shell function. */
SHELL_VAR *this_shell_function;
+/* If non-zero, matches in case and [[ ... ]] are case-insensitive */
+int match_ignore_case = 0;
+
struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL;
#define FD_BITMAP_DEFAULT_SIZE 32
@@ -366,7 +369,6 @@ shell_control_structure (type)
{
switch (type)
{
- case cm_for:
#if defined (ARITH_FOR_COMMAND)
case cm_arith_for:
#endif
@@ -383,7 +385,9 @@ shell_control_structure (type)
case cm_while:
case cm_until:
case cm_if:
+ case cm_for:
case cm_group:
+ case cm_function_def:
return (1);
default:
@@ -491,7 +495,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
{
int exec_result, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
- volatile pid_t last_pid;
+ volatile int last_pid;
volatile int save_line_number;
if (command == 0 || breaking || continuing || read_but_dont_execute)
@@ -648,6 +652,9 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* We can't rely on variables retaining their values across a
call to execute_simple_command if a longjmp occurs as the
result of a `return' builtin. This is true for sure with gcc. */
+#if defined (RECYCLES_PIDS)
+ last_made_pid = NO_PID;
+#endif
last_pid = last_made_pid;
was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
@@ -678,7 +685,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* XXX - this is something to watch out for if there are problems
when the shell is compiled without job control. */
if (already_making_children && pipe_out == NO_PIPE &&
- last_pid != last_made_pid)
+ last_made_pid != last_pid)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
@@ -698,14 +705,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
subshells forked to execute builtin commands (e.g., in
pipelines) to be waited for twice. */
exec_result = wait_for (last_made_pid);
-#if defined (RECYCLES_PIDS)
- /* LynxOS, for one, recycles pids very quickly -- so quickly
- that a new process may have the same pid as the last one
- created. This has been reported to fix the problem on that
- OS, and a similar problem on Cygwin. */
- if (exec_result == 0)
- last_made_pid = NO_PID;
-#endif
}
}
@@ -1274,6 +1273,11 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
tcom = (command->type == cm_subshell) ? command->value.Subshell->command : command;
+ if (command->flags & CMD_TIME_PIPELINE)
+ tcom->flags |= CMD_TIME_PIPELINE;
+ if (command->flags & CMD_TIME_POSIX)
+ tcom->flags |= CMD_TIME_POSIX;
+
/* Make sure the subshell inherits any CMD_IGNORE_RETURN flag. */
if ((command->flags & CMD_IGNORE_RETURN) && tcom != command)
tcom->flags |= CMD_IGNORE_RETURN;
@@ -1355,6 +1359,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
#if defined (JOB_CONTROL)
terminate_current_pipeline ();
kill_current_pipeline ();
+ UNBLOCK_CHILD (oset);
#endif /* JOB_CONTROL */
last_command_exit_value = EXECUTION_FAILURE;
/* The unwind-protects installed below will take care
@@ -1622,8 +1627,9 @@ execute_for_command (for_command)
if (echo_command_at_execute)
xtrace_print_for_command_head (for_command);
- /* Save this command unless it's a trap command. */
- if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))
+ /* Save this command unless it's a trap command and we're not running
+ a debug trap. */
+ if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
{
FREE (the_printed_command_except_trap);
the_printed_command_except_trap = savestring (the_printed_command);
@@ -1638,7 +1644,7 @@ execute_for_command (for_command)
#endif
this_command_name = (char *)NULL;
- v = bind_variable (identifier, list->word->word);
+ v = bind_variable (identifier, list->word->word, 0);
if (readonly_p (v) || noassign_p (v))
{
line_number = save_line_number;
@@ -1685,7 +1691,7 @@ execute_for_command (for_command)
{
SHELL_VAR *new_value;
- new_value = bind_variable (identifier, value_cell(old_value));
+ new_value = bind_variable (identifier, value_cell(old_value), 0);
new_value->attributes = old_value->attributes;
dispose_variable (old_value);
}
@@ -1731,8 +1737,11 @@ eval_arith_for_expr (l, okp)
command_string_index = 0;
print_arith_command (new);
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
+ if (signal_in_progress (DEBUG_TRAP) == 0)
+ {
+ FREE (the_printed_command_except_trap);
+ the_printed_command_except_trap = savestring (the_printed_command);
+ }
r = run_debug_trap ();
/* In debugging mode, if the DEBUG trap returns a non-zero status, we
@@ -2039,8 +2048,11 @@ execute_select_command (select_command)
if (echo_command_at_execute)
xtrace_print_select_command_head (select_command);
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
+ if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
+ {
+ FREE (the_printed_command_except_trap);
+ the_printed_command_except_trap = savestring (the_printed_command);
+ }
retval = run_debug_trap ();
#if defined (DEBUGGER)
@@ -2092,7 +2104,7 @@ execute_select_command (select_command)
break;
}
- v = bind_variable (identifier, selection);
+ v = bind_variable (identifier, selection, 0);
if (readonly_p (v) || noassign_p (v))
{
if (readonly_p (v) && interactive_shell == 0 && posixly_correct)
@@ -2168,7 +2180,7 @@ execute_case_command (case_command)
if (echo_command_at_execute)
xtrace_print_case_command_head (case_command);
- if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))
+ if (signal_in_progress (DEBUG_TRAP == 0) && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
{
FREE (the_printed_command_except_trap);
the_printed_command_except_trap = savestring (the_printed_command);
@@ -2185,14 +2197,6 @@ execute_case_command (case_command)
}
#endif
- /* Posix.2 specifies that the WORD is tilde expanded. */
- if (member ('~', case_command->word->word))
- {
- word = bash_tilde_expand (case_command->word->word, 0);
- free (case_command->word->word);
- case_command->word->word = word;
- }
-
wlist = expand_word_unsplit (case_command->word, 0);
word = wlist ? string_list (wlist) : savestring ("");
dispose_words (wlist);
@@ -2210,15 +2214,6 @@ execute_case_command (case_command)
QUIT;
for (list = clauses->patterns; list; list = list->next)
{
- /* Posix.2 specifies to tilde expand each member of the pattern
- list. */
- if (member ('~', list->word->word))
- {
- pattern = bash_tilde_expand (list->word->word, 0);
- free (list->word->word);
- list->word->word = pattern;
- }
-
es = expand_word_leave_quoted (list->word, 0);
if (es && es->word && es->word->word && *(es->word->word))
@@ -2232,7 +2227,7 @@ execute_case_command (case_command)
/* Since the pattern does not undergo quote removal (as per
Posix.2, section 3.9.4.3), the strmatch () call must be able
to recognize backslashes as escape characters. */
- match = strmatch (pattern, word, FNMATCH_EXTFLAG) != FNM_NOMATCH;
+ match = strmatch (pattern, word, FNMATCH_EXTFLAG|FNMATCH_IGNCASE) != FNM_NOMATCH;
free (pattern);
dispose_words (es);
@@ -2395,8 +2390,12 @@ execute_arith_command (arith_command)
command_string_index = 0;
print_arith_command (arith_command->exp);
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
+
+ if (signal_in_progress (DEBUG_TRAP) == 0)
+ {
+ FREE (the_printed_command_except_trap);
+ the_printed_command_except_trap = savestring (the_printed_command);
+ }
/* Run the debug trap before each arithmetic command, but do it after we
update the line number information and before we expand the various
@@ -2508,9 +2507,15 @@ execute_cond_node (cond)
}
else
#endif /* COND_REGEXP */
- result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP)
- ? EXECUTION_SUCCESS
- : EXECUTION_FAILURE;
+ {
+ int oe;
+ oe = extended_glob;
+ extended_glob = 1;
+ result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP)
+ ? EXECUTION_SUCCESS
+ : EXECUTION_FAILURE;
+ extended_glob = oe;
+ }
if (arg1 != nullstr)
free (arg1);
if (arg2 != nullstr)
@@ -2546,8 +2551,12 @@ execute_cond_command (cond_command)
command_string_index = 0;
print_cond_command (cond_command);
- FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
+
+ if (signal_in_progress (DEBUG_TRAP) == 0)
+ {
+ FREE (the_printed_command_except_trap);
+ the_printed_command_except_trap = savestring (the_printed_command);
+ }
/* Run the debug trap before each conditional command, but do it after we
update the line number information. */
@@ -2580,7 +2589,7 @@ bind_lastarg (arg)
if (arg == 0)
arg = "";
- var = bind_variable ("_", arg);
+ var = bind_variable ("_", arg, 0);
VUNSETATTR (var, att_exported);
}
@@ -2588,10 +2597,9 @@ bind_lastarg (arg)
to be run asynchronously. This handles all the side effects that are
supposed to take place. */
static int
-execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subst_pid)
+execute_null_command (redirects, pipe_in, pipe_out, async)
REDIRECT *redirects;
int pipe_in, pipe_out, async;
- pid_t old_last_command_subst_pid;
{
int r;
@@ -2637,7 +2645,7 @@ execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subs
if (r != 0)
return (EXECUTION_FAILURE);
- else if (old_last_command_subst_pid != last_command_subst_pid)
+ else if (last_command_subst_pid != NO_PID)
return (last_command_exit_value);
else
return (EXECUTION_SUCCESS);
@@ -2666,8 +2674,10 @@ fix_assignment_words (words)
b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
+ else if (b && (b->flags & ASSIGNMENT_BUILTIN))
+ words->word->flags |= W_ASSNBLTIN;
}
- w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP);
+ w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
}
}
@@ -2683,7 +2693,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;
- pid_t old_last_command_subst_pid, old_last_async_pid;
+ pid_t old_last_async_pid;
sh_builtin_func_t *builtin;
SHELL_VAR *func;
@@ -2699,10 +2709,10 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
command_string_index = 0;
print_simple_command (simple_command);
- if (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0))
+ if (signal_in_progress (DEBUG_TRAP) == 0 && (this_command_name == 0 || (STREQ (this_command_name, "trap") == 0)))
{
FREE (the_printed_command_except_trap);
- the_printed_command_except_trap = savestring (the_printed_command);
+ the_printed_command_except_trap = the_printed_command ? savestring (the_printed_command) : (char *)0;
}
/* Run the debug trap before each simple command, but do it after we
@@ -2718,7 +2728,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
first_word_quoted =
simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0;
- old_last_command_subst_pid = last_command_subst_pid;
+ last_command_subst_pid = NO_PID;
old_last_async_pid = last_asynchronous_pid;
already_forked = dofork = 0;
@@ -2739,27 +2749,22 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (dofork)
{
-#if 0
- /* XXX memory leak if expand_words() error causes a jump_to_top_level */
- command_line = savestring (the_printed_command);
-#endif
-
/* Do this now, because execute_disk_command will do it anyway in the
vast majority of cases. */
maybe_make_export_env ();
-#if 0
- if (make_child (command_line, async) == 0)
-#else
- if (make_child (savestring (the_printed_command), async) == 0)
-#endif
+ /* Don't let a DEBUG trap overwrite the command string to be saved with
+ the process/job associated with this child. */
+ if (make_child (savestring (the_printed_command_except_trap), async) == 0)
{
already_forked = 1;
simple_command->flags |= CMD_NO_FORK;
- subshell_environment = (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
- ? (SUBSHELL_PIPE|SUBSHELL_FORK)
- : (SUBSHELL_ASYNC|SUBSHELL_FORK);
+ subshell_environment = SUBSHELL_FORK;
+ if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
+ subshell_environment |= SUBSHELL_PIPE;
+ if (async)
+ subshell_environment |= SUBSHELL_ASYNC;
/* We need to do this before piping to handle some really
pathological cases where one of the pipe file descriptors
@@ -2804,8 +2809,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
this_command_name = 0;
result = execute_null_command (simple_command->redirects,
pipe_in, pipe_out,
- already_forked ? 0 : async,
- old_last_command_subst_pid);
+ already_forked ? 0 : async);
if (already_forked)
exit (result);
else
@@ -3048,8 +3052,10 @@ execute_builtin (builtin, words, flags, subshell)
/* The temporary environment for a builtin is supposed to apply to
all commands executed by that builtin. Currently, this is a
- problem only with the `source' and `eval' builtins. */
- isbltinenv = (builtin == source_builtin || builtin == eval_builtin);
+ problem only with the `unset', `source' and `eval' builtins. */
+
+ isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin);
+
if (isbltinenv)
{
if (subshell == 0)
@@ -3059,7 +3065,7 @@ execute_builtin (builtin, words, flags, subshell)
{
push_scope (VC_BLTNENV, temporary_env);
if (subshell == 0)
- add_unwind_protect (pop_scope, "1");
+ add_unwind_protect (pop_scope, (flags & CMD_COMMAND_BUILTIN) ? 0 : "1");
temporary_env = (HASH_TABLE *)NULL;
}
}
@@ -3105,7 +3111,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
COMMAND *tc, *fc, *save_current;
char *debug_trap, *error_trap, *return_trap;
#if defined (ARRAY_VARS)
- SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
+ SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v;
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
#endif
FUNCTION_DEF *shell_fn;
@@ -3178,7 +3184,13 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
restore_default_signal (ERROR_TRAP);
}
+ /* Shell functions inherit the RETURN trap if function tracing is on
+ globally or on individually for this function. */
+#if 0
if (return_trap && ((trace_p (var) == 0) && function_trace_mode == 0))
+#else
+ if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0)))
+#endif
{
if (subshell == 0)
{
@@ -3214,24 +3226,24 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
/* Number of the line on which the function body starts. */
line_number = function_line_number = tc->line;
- if (subshell)
- {
#if defined (JOB_CONTROL)
- stop_pipeline (async, (COMMAND *)NULL);
+ if (subshell)
+ stop_pipeline (async, (COMMAND *)NULL);
#endif
- fc = (tc->type == cm_group) ? tc->value.Group->command : tc;
- if (fc && (flags & CMD_IGNORE_RETURN))
- fc->flags |= CMD_IGNORE_RETURN;
- }
- else
- fc = tc;
+ fc = tc;
return_catch_flag++;
return_val = setjmp (return_catch);
if (return_val)
- result = return_catch_value;
+ {
+ result = return_catch_value;
+ /* Run the RETURN trap in the function's context. */
+ save_current = currently_executing_command;
+ run_return_trap ();
+ currently_executing_command = save_current;
+ }
else
{
/* Run the debug trap here so we can trap at the start of a function's
@@ -3255,6 +3267,10 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
}
#else
result = execute_command_internal (fc, 0, NO_PIPE, NO_PIPE, fds_to_close);
+
+ save_current = currently_executing_command;
+ run_return_trap ();
+ currently_executing_command = save_current;
#endif
showing_function_line = 0;
}
@@ -3268,9 +3284,16 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
funcnest--;
#if defined (ARRAY_VARS)
+ /* These two variables cannot be unset, and cannot be affected by the
+ function. */
array_pop (bash_source_a);
- array_pop (funcname_a);
array_pop (bash_lineno_a);
+
+ /* FUNCNAME can be unset, and so can potentially be changed by the
+ function. */
+ GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a);
+ if (nfv == funcname_v)
+ array_pop (funcname_a);
#endif
if (variable_context == 0 || this_shell_function == 0)
@@ -3759,6 +3782,7 @@ initialize_subshell ()
/* Forget about the way job control was working. We are in a subshell. */
without_job_control ();
set_sigchld_handler ();
+ init_job_stats ();
#endif /* JOB_CONTROL */
/* Reset the values of the shell flags and options. */
@@ -3833,6 +3857,12 @@ shell_execve (command, args, env)
errno = i;
file_error (command);
}
+ /* errors not involving the path argument to execve. */
+ else if (i == E2BIG || i == ENOMEM)
+ {
+ errno = i;
+ file_error (command);
+ }
else
{
/* The file has the execute bits set, but the kernel refuses to
@@ -3842,9 +3872,18 @@ shell_execve (command, args, env)
if (sample_len > 2 && sample[0] == '#' && sample[1] == '!')
{
char *interp;
+ int ilen;
interp = getinterp (sample, sample_len, (int *)NULL);
+ ilen = strlen (interp);
errno = i;
+ if (interp[ilen - 1] == '\r')
+ {
+ interp = xrealloc (interp, ilen + 2);
+ interp[ilen - 1] = '^';
+ interp[ilen] = 'M';
+ interp[ilen + 1] = '\0';
+ }
sys_error (_("%s: %s: bad interpreter"), command, interp ? interp : "");
FREE (interp);
return (EX_NOEXEC);