Imported from ../bash-2.05b.tar.gz.

This commit is contained in:
Jari Aalto 2002-07-17 14:10:11 +00:00
commit 7117c2d221
362 changed files with 34387 additions and 15063 deletions

View file

@ -1,6 +1,6 @@
/* execute_command.c -- Execute a COMMAND structure. */
/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@ -101,7 +101,6 @@ extern int parse_and_execute_level, running_trap, trap_line_number;
extern int command_string_index, line_number;
extern int dot_found_in_search;
extern int already_making_children;
extern char **temporary_env, **function_env, **builtin_env;
extern char *the_printed_command, *shell_name;
extern pid_t last_command_subst_pid;
extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
@ -133,7 +132,7 @@ static int execute_for_command __P((FOR_COM *));
static int print_index_and_element __P((int, int, WORD_LIST *));
static void indent __P((int, int));
static void print_select_list __P((WORD_LIST *, int, int, int));
static char *select_query __P((WORD_LIST *, int, char *));
static char *select_query __P((WORD_LIST *, int, char *, int));
static int execute_select_command __P((SELECT_COM *));
#endif
#if defined (DPAREN_ARITHMETIC)
@ -151,7 +150,7 @@ static void print_formatted_time __P((FILE *, char *,
static int time_command __P((COMMAND *, int, int, int, struct fd_bitmap *));
#endif
#if defined (ARITH_FOR_COMMAND)
static long eval_arith_for_expr __P((WORD_LIST *, int *));
static intmax_t eval_arith_for_expr __P((WORD_LIST *, int *));
static int execute_arith_for_command __P((ARITH_FOR_COM *));
#endif
static int execute_case_command __P((CASE_COM *));
@ -186,8 +185,6 @@ static int execute_connection __P((COMMAND *, int, int, int, struct fd_bitmap *)
static int execute_intern_function __P((WORD_DESC *, COMMAND *));
/* The line number that the currently executing function starts on. */
static int function_line_number;
@ -249,7 +246,7 @@ new_fd_bitmap (size)
if (size)
{
ret->bitmap = (char *)xmalloc (size);
bzero (ret->bitmap, size);
memset (ret->bitmap, '\0', size);
}
else
ret->bitmap = (char *)NULL;
@ -285,9 +282,19 @@ close_fd_bitmap (fdbp)
int
executing_line_number ()
{
if (executing && variable_context == 0 && currently_executing_command &&
currently_executing_command->type == cm_simple)
return currently_executing_command->value.Simple->line;
if (executing && (variable_context == 0 || interactive_shell == 0) && currently_executing_command)
{
if (currently_executing_command->type == cm_simple)
return currently_executing_command->value.Simple->line;
else if (currently_executing_command->type == cm_cond)
return currently_executing_command->value.Cond->line;
else if (currently_executing_command->type == cm_arith)
return currently_executing_command->value.Arith->line;
else if (currently_executing_command->type == cm_arith_for)
return currently_executing_command->value.ArithFor->line;
else
return line_number;
}
else if (running_trap)
return trap_line_number;
else
@ -459,7 +466,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
int pipe_in, pipe_out;
struct fd_bitmap *fds_to_close;
{
int exec_result, invert, ignore_return, was_debug_trap, was_error_trap;
int exec_result, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
volatile pid_t last_pid;
@ -613,7 +620,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
call to execute_simple_command if a longjmp occurs as the
result of a `return' builtin. This is true for sure with gcc. */
last_pid = last_made_pid;
was_debug_trap = signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0;
was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
if (ignore_return && command->value.Simple)
@ -668,12 +674,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
}
}
if (was_debug_trap)
{
last_command_exit_value = exec_result;
run_debug_trap ();
}
if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
{
last_command_exit_value = exec_result;
@ -910,16 +910,16 @@ mkfmt (buf, prec, lng, sec, sec_fraction)
/* Interpret the format string FORMAT, interpolating the following escape
sequences:
%[prec][l][RUS]
%[prec][l][RUS]
where the optional `prec' is a precision, meaning the number of
characters after the decimal point, the optional `l' means to format
using minutes and seconds (MMmNN[.FF]s), like the `times' builtin',
and the last character is one of
R number of seconds of `real' time
U number of seconds of `user' time
S number of seconds of `system' time
R number of seconds of `real' time
U number of seconds of `user' time
S number of seconds of `system' time
An occurrence of `%%' in the format string is translated to a `%'. The
result is printed to FP, a pointer to a FILE. The other variables are
@ -1392,9 +1392,6 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
int asynchronous, pipe_in, pipe_out;
struct fd_bitmap *fds_to_close;
{
#if 0
REDIRECT *tr, *tl;
#endif
REDIRECT *rp;
COMMAND *tc, *second;
int ignore_return, exec_result;
@ -1424,37 +1421,12 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
#else
if (!stdin_redir)
#endif /* JOB_CONTROL */
{
#if 0
rd.filename = make_bare_word ("/dev/null");
tr = make_redirection (0, r_inputa_direction, rd);
tr->next = tc->redirects;
tc->redirects = tr;
#endif
tc->flags |= CMD_STDIN_REDIR;
}
tc->flags |= CMD_STDIN_REDIR;
exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close);
if (tc->flags & CMD_STDIN_REDIR)
{
#if 0
/* Remove the redirection we added above. It matters,
especially for loops, which call execute_command ()
multiple times with the same command. */
tr = tc->redirects;
do
{
tl = tc->redirects;
tc->redirects = tc->redirects->next;
}
while (tc->redirects && tc->redirects != rp);
tl->next = (REDIRECT *)NULL;
dispose_redirects (tr);
#endif
tc->flags &= ~CMD_STDIN_REDIR;
}
tc->flags &= ~CMD_STDIN_REDIR;
second = command->value.Connection->second;
if (second)
@ -1628,7 +1600,7 @@ execute_for_command (for_command)
if (lexical_scoping)
{
if (!old_value)
makunbound (identifier, shell_variables);
unbind_variable (identifier);
else
{
SHELL_VAR *new_value;
@ -1661,19 +1633,22 @@ execute_for_command (for_command)
eval \(\( step \)\)
done
*/
static long
static intmax_t
eval_arith_for_expr (l, okp)
WORD_LIST *l;
int *okp;
{
WORD_LIST *new;
long expresult;
intmax_t expresult;
new = expand_words_no_vars (l);
if (new)
{
if (echo_command_at_execute)
xtrace_print_arith_cmd (new);
this_command_name = "(("; /* )) for expression error messages */
if (signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0)
run_debug_trap ();
expresult = evalexp (new->word->word, okp);
dispose_words (new);
}
@ -1690,8 +1665,8 @@ static int
execute_arith_for_command (arith_for_command)
ARITH_FOR_COM *arith_for_command;
{
long expresult;
int expok, body_status;
intmax_t expresult;
int expok, body_status, arith_lineno, save_lineno;
body_status = EXECUTION_SUCCESS;
loop_level++;
@ -1701,8 +1676,12 @@ execute_arith_for_command (arith_for_command)
this_command_name = "(("; /* )) for expression error messages */
if (variable_context)
line_number = arith_for_command->line - function_line_number;
/* save the starting line number of the command so we can reset
line_number before executing each expression -- for $LINENO
and the DEBUG trap. */
arith_lineno = arith_for_command->line;
if (variable_context && interactive_shell)
line_number = arith_lineno -= function_line_number;
/* Evaluate the initialization expression. */
expresult = eval_arith_for_expr (arith_for_command->init, &expok);
@ -1712,7 +1691,11 @@ execute_arith_for_command (arith_for_command)
while (1)
{
/* Evaluate the test expression. */
save_lineno = line_number;
line_number = arith_lineno;
expresult = eval_arith_for_expr (arith_for_command->test, &expok);
line_number = save_lineno;
if (expok == 0)
{
body_status = EXECUTION_FAILURE;
@ -1742,7 +1725,11 @@ execute_arith_for_command (arith_for_command)
}
/* Evaluate the step expression. */
save_lineno = line_number;
line_number = arith_lineno;
expresult = eval_arith_for_expr (arith_for_command->step, &expok);
line_number = save_lineno;
if (expok == 0)
{
body_status = EXECUTION_FAILURE;
@ -1859,13 +1846,14 @@ print_select_list (list, list_len, max_elem_len, indices_len)
is read, return a null string. If a blank line is entered, or an invalid
number is entered, the loop is executed again. */
static char *
select_query (list, list_len, prompt)
select_query (list, list_len, prompt, print_menu)
WORD_LIST *list;
int list_len;
char *prompt;
int print_menu;
{
int max_elem_len, indices_len, len;
long reply;
intmax_t reply;
WORD_LIST *l;
char *repl_string, *t;
@ -1895,7 +1883,8 @@ select_query (list, list_len, prompt)
while (1)
{
print_select_list (list, list_len, max_elem_len, indices_len);
if (print_menu)
print_select_list (list, list_len, max_elem_len, indices_len);
fprintf (stderr, "%s", prompt);
fflush (stderr);
QUIT;
@ -1907,7 +1896,10 @@ select_query (list, list_len, prompt)
}
repl_string = get_string_value ("REPLY");
if (*repl_string == 0)
continue;
{
print_menu = 1;
continue;
}
if (legal_number (repl_string, &reply) == 0)
return "";
if (reply < 1 || reply > list_len)
@ -1930,8 +1922,8 @@ execute_select_command (select_command)
WORD_LIST *releaser, *list;
SHELL_VAR *v;
char *identifier, *ps3_prompt, *selection;
int retval, list_len;
int retval, list_len, show_menu;
if (check_identifier (select_command->name, 1) == 0)
return (EXECUTION_FAILURE);
@ -1956,6 +1948,7 @@ execute_select_command (select_command)
select_command->action->flags |= CMD_IGNORE_RETURN;
retval = EXECUTION_SUCCESS;
show_menu = 1;
while (1)
{
@ -1964,10 +1957,15 @@ execute_select_command (select_command)
ps3_prompt = "#? ";
QUIT;
selection = select_query (list, list_len, ps3_prompt);
selection = select_query (list, list_len, ps3_prompt, show_menu);
QUIT;
if (selection == 0)
break;
{
/* select_query returns EXECUTION_FAILURE if the read builtin
fails, so we want to return failure in this case. */
retval = EXECUTION_FAILURE;
break;
}
v = bind_variable (identifier, selection);
if (readonly_p (v) || noassign_p (v))
@ -2001,6 +1999,13 @@ execute_select_command (select_command)
if (continuing)
break;
}
#if defined (KSH_COMPATIBLE_SELECT)
show_menu = 0;
selection = get_string_value ("REPLY");
if (selection && *selection == '\0')
show_menu = 1;
#endif
}
loop_level--;
@ -2027,7 +2032,7 @@ execute_case_command (case_command)
/* Posix.2 specifies that the WORD is tilde expanded. */
if (member ('~', case_command->word->word))
{
word = bash_tilde_expand (case_command->word->word);
word = bash_tilde_expand (case_command->word->word, 0);
free (case_command->word->word);
case_command->word->word = word;
}
@ -2053,7 +2058,7 @@ execute_case_command (case_command)
list. */
if (member ('~', list->word->word))
{
pattern = bash_tilde_expand (list->word->word);
pattern = bash_tilde_expand (list->word->word, 0);
free (list->word->word);
list->word->word = pattern;
}
@ -2217,16 +2222,22 @@ execute_arith_command (arith_command)
ARITH_COM *arith_command;
{
int expok;
long expresult;
intmax_t expresult;
WORD_LIST *new;
expresult = 0;
this_command_name = "(("; /* )) */
/* If we're in a function, update the line number information. */
if (variable_context)
if (variable_context && interactive_shell)
line_number = arith_command->line - function_line_number;
/* Run the debug trap before each arithmetic command, but do it after we
update the line number information and before we expand the various
words in the expression. */
if (signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0)
run_debug_trap ();
new = expand_words (arith_command->exp);
/* If we're tracing, make a new word list with `((' at the front and `))'
@ -2329,9 +2340,14 @@ execute_cond_command (cond_command)
this_command_name = "[[";
/* If we're in a function, update the line number information. */
if (variable_context)
if (variable_context && interactive_shell)
line_number = cond_command->line - function_line_number;
/* Run the debug trap before each conditional command, but do it after we
update the line number information. */
if (signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0)
run_debug_trap ();
#if 0
debug_print_cond_command (cond_command);
#endif
@ -2418,13 +2434,19 @@ fix_assignment_words (words)
if (words == 0)
return;
b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
b = 0;
for (w = words; w; w = w->next)
if (w->word->flags & W_ASSIGNMENT)
w->word->flags |= (W_NOSPLIT|W_NOGLOB);
{
if (b == 0)
{
b = builtin_address_internal (words->word->word, 0);
if (b == 0 || (b->flags & ASSIGNMENT_BUILTIN) == 0)
return;
}
w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP);
}
}
/* The meaty part of all the executions. We have to start hacking the
@ -2448,9 +2470,14 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
command_line = (char *)0;
/* If we're in a function, update the line number information. */
if (variable_context)
if (variable_context && interactive_shell)
line_number = simple_command->line - function_line_number;
/* Run the debug trap before each simple command, but do it after we
update the line number information. */
if (signal_is_trapped (DEBUG_TRAP) && signal_is_ignored (DEBUG_TRAP) == 0)
run_debug_trap ();
/* Remember what this command line looks like at invocation. */
command_string_index = 0;
print_simple_command (simple_command);
@ -2607,48 +2634,25 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
pipe_out == NO_PIPE &&
(temp = get_string_value ("auto_resume")))
{
char *word;
register int i;
int wl, cl, exact_p, substring_p, match, started_status;
register PROCESS *p;
int job, jflags, started_status;
word = words->word->word;
exact_p = STREQ (temp, "exact");
substring_p = STREQ (temp, "substring");
wl = strlen (word);
for (i = job_slots - 1; i > -1; i--)
jflags = JM_STOPPED|JM_FIRSTMATCH;
if (STREQ (temp, "exact"))
jflags |= JM_EXACT;
else if (STREQ (temp, "substring"))
jflags |= JM_SUBSTRING;
else
jflags |= JM_PREFIX;
job = get_job_by_name (words->word->word, jflags);
if (job != NO_JOB)
{
if (jobs[i] == 0 || (JOBSTATE (i) != JSTOPPED))
continue;
run_unwind_frame ("simple-command");
this_command_name = "fg";
last_shell_builtin = this_shell_builtin;
this_shell_builtin = builtin_address ("fg");
p = jobs[i]->pipe;
do
{
if (exact_p)
{
cl = strlen (p->command);
match = STREQN (p->command, word, cl);
}
else if (substring_p)
match = strindex (p->command, word) != (char *)0;
else
match = STREQN (p->command, word, wl);
if (match == 0)
{
p = p->next;
continue;
}
run_unwind_frame ("simple-command");
this_command_name = "fg";
last_shell_builtin = this_shell_builtin;
this_shell_builtin = builtin_address ("fg");
started_status = start_job (i, 1);
return ((started_status < 0) ? EXECUTION_FAILURE : started_status);
}
while (p != jobs[i]->pipe);
started_status = start_job (job, 1);
return ((started_status < 0) ? EXECUTION_FAILURE : started_status);
}
}
#endif /* JOB_CONTROL */
@ -2771,6 +2775,7 @@ execute_builtin (builtin, words, flags, subshell)
int flags, subshell;
{
int old_e_flag, result, eval_unwind;
int isbltinenv;
old_e_flag = exit_immediately_on_error;
/* The eval builtin calls parse_and_execute, which does not know about
@ -2792,19 +2797,19 @@ 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. */
if (builtin == source_builtin || builtin == eval_builtin)
isbltinenv = (builtin == source_builtin || builtin == eval_builtin);
if (isbltinenv)
{
if (subshell == 0)
begin_unwind_frame ("builtin_env");
if (temporary_env)
{
builtin_env = copy_array (temporary_env);
push_scope (VC_BLTNENV, temporary_env);
if (subshell == 0)
add_unwind_protect (dispose_builtin_env, (char *)NULL);
dispose_used_env_vars ();
add_unwind_protect (pop_scope, "1");
temporary_env = (HASH_TABLE *)NULL;
}
/* Otherwise we inherit builtin_env from our caller. */
}
/* `return' does a longjmp() back to a saved environment in execute_function.
@ -2824,16 +2829,8 @@ execute_builtin (builtin, words, flags, subshell)
if (posixly_correct && subshell == 0 && builtin == return_builtin && temporary_env)
discard_unwind_frame ("return_temp_env");
if (subshell == 0 && (builtin == source_builtin || builtin == eval_builtin))
{
/* In POSIX mode, if any variable assignments precede the `.' or
`eval' builtin, they persist after the builtin completes, since `.'
and `eval' are special builtins. */
if (posixly_correct && builtin_env)
merge_builtin_env ();
run_unwind_frame ("builtin_env");
}
if (subshell == 0 && isbltinenv)
run_unwind_frame ("builtin_env");
if (eval_unwind)
{
@ -2865,7 +2862,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
if (subshell == 0)
{
begin_unwind_frame ("function_calling");
push_context ();
push_context (var->name, subshell, temporary_env);
add_unwind_protect (pop_context, (char *)NULL);
unwind_protect_int (line_number);
unwind_protect_int (return_catch_flag);
@ -2874,6 +2871,10 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
unwind_protect_pointer (this_shell_function);
unwind_protect_int (loop_level);
}
else
push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */
temporary_env = (HASH_TABLE *)NULL;
this_shell_function = var;
make_funcname_visible (1);
@ -2885,7 +2886,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
important here! unwind-protect commands are run in reverse order
of registration. If this causes problems, take out the xfree
unwind-protect calls and live with the small memory leak. */
if (debug_trap)
if (debug_trap && (trace_p (var) == 0))
{
if (subshell == 0)
{
@ -2909,27 +2910,12 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
/* The temporary environment for a function is supposed to apply to
all commands executed within the function body. */
if (temporary_env)
{
function_env = copy_array (temporary_env);
/* In POSIX mode, variable assignments preceding function names are
supposed to persist in the environment after the function returns,
as if a special builtin command had been executed. */
if (subshell == 0)
{
if (posixly_correct)
add_unwind_protect (merge_function_env, (char *)NULL);
else
add_unwind_protect (dispose_function_env, (char *)NULL);
}
dispose_used_env_vars ();
}
/* Otherwise, we inherit function_env from our caller. */
remember_args (words->next, 1);
/* Number of the line on which the function body starts. */
line_number = function_line_number = tc->line;
if (interactive_shell)
line_number = function_line_number = tc->line;
if (subshell)
{
@ -2940,8 +2926,6 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
if (fc && (flags & CMD_IGNORE_RETURN))
fc->flags |= CMD_IGNORE_RETURN;
variable_context++;
}
else
fc = tc;
@ -3202,7 +3186,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
pathname = words->word->word;
#if defined (RESTRICTED_SHELL)
if (restricted && strchr (pathname, '/'))
if (restricted && xstrchr (pathname, '/'))
{
internal_error ("%s: restricted: cannot specify `/' in command names",
pathname);
@ -3293,7 +3277,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
/* Execve expects the command name to be in args[0]. So we
leave it there, in the same format that the user used to
type it in. */
args = word_list_to_argv (words, 0, 0, (int *)NULL);
args = strvec_from_word_list (words, 0, 0, (int *)NULL);
exit (shell_execve (command, args, export_env));
}
else
@ -3387,9 +3371,8 @@ execute_shell_script (sample, sample_len, command, args, env)
size_increment = 2;
}
larry = array_len (args) + size_increment;
args = (char **)xrealloc ((char *)args, (1 + larry) * sizeof (char *));
larry = strvec_len (args) + size_increment;
args = strvec_resize (args, larry + 1);
for (i = larry - 1; i; i--)
args[i] = args[i - size_increment];
@ -3440,8 +3423,10 @@ initialize_subshell ()
/* Zero out builtin_env, since this could be a shell script run from a
sourced file with a temporary environment supplied to the `source/.'
builtin. Such variables are not supposed to be exported (empirical
testing with sh and ksh). */
builtin_env = 0;
testing with sh and ksh). Just throw it away; don't worry about a
memory leak. */
if (vc_isbltnenv (shell_variables))
shell_variables = shell_variables->down;
clear_unwind_protect_list (0);
@ -3497,8 +3482,15 @@ shell_execve (command, args, env)
{
if ((stat (command, &finfo) == 0) && (S_ISDIR (finfo.st_mode)))
internal_error ("%s: is a directory", command);
else if (executable_file (command) == 0)
{
errno = i;
file_error (command);
}
else
{
/* The file has the execute bits set, but the kernel refuses to
run it for some reason. See why. */
#if defined (HAVE_HASH_BANG_EXEC)
READ_SAMPLE_BUF (command, sample, sample_len);
if (sample_len > 2 && sample[0] == '#' && sample[1] == '!')
@ -3557,8 +3549,8 @@ shell_execve (command, args, env)
set_sigint_handler ();
/* Insert the name of this shell into the argument list. */
larray = array_len (args) + 1;
args = (char **)xrealloc ((char *)args, (1 + larray) * sizeof (char *));
larray = strvec_len (args) + 1;
args = strvec_resize (args, larray + 1);
for (i = larray - 1; i; i--)
args[i] = args[i - 1];
@ -3634,7 +3626,7 @@ close_all_files ()
fd_table_size = getdtablesize ();
if (fd_table_size > 256) /* clamp to a reasonable value */
fd_table_size = 256;
fd_table_size = 256;
for (i = 3; i < fd_table_size; i++)
close (i);