diff options
author | Jari Aalto <jari.aalto@cante.net> | 2005-12-07 14:08:12 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:57 +0000 |
commit | 95732b497d12c98613bb3c5db16b61f377501a59 (patch) | |
tree | 5e1cdf79eb0407e09dca4c0ec29e11442c7d1d15 /execute_cmd.c | |
parent | eb87367179effbe5f430236db8259006d71438b7 (diff) | |
download | android_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.c | 213 |
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); |