summaryrefslogtreecommitdiff
path: root/execute_cmd.c
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2018-05-22 16:51:07 -0400
committerChet Ramey <chet.ramey@case.edu>2018-05-22 16:51:07 -0400
commit9a51695bed07d37086c352372ac69d0a30039a6b (patch)
tree4d0f57cba0dd1ec7a75aae56e18cfe9997d0b7a7 /execute_cmd.c
parent7de27456f6494f5f9c11ea1c19024d0024f31112 (diff)
downloadbash-5.0-alpha.tar.gz
bash-5.0-alpha releasebash-5.0-alpha
Diffstat (limited to 'execute_cmd.c')
-rw-r--r--execute_cmd.c444
1 files changed, 306 insertions, 138 deletions
diff --git a/execute_cmd.c b/execute_cmd.c
index 76a80766..3759376e 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -1,6 +1,6 @@
/* execute_cmd.c -- Execute a COMMAND structure. */
-/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2018 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -66,6 +66,7 @@ extern int errno;
#include "memalloc.h"
#include "shell.h"
#include <y.tab.h> /* use <...> so we pick it up from the build directory */
+#include "parser.h"
#include "flags.h"
#include "builtins.h"
#include "hashlib.h"
@@ -105,28 +106,13 @@ extern int errno;
# include <mbstr.h> /* mbschr */
#endif
-extern int dollar_dollar_pid;
-extern int posixly_correct;
-extern int expand_aliases;
-extern int autocd;
-extern int breaking, continuing, loop_level;
-extern int parse_and_execute_level, running_trap, sourcelevel;
-extern int command_string_index, line_number;
-extern int dot_found_in_search;
-extern int already_making_children;
-extern int tempenv_assign_error;
-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;
-extern char **subshell_argv, **subshell_envp;
-extern int subshell_argc;
+extern int command_string_index;
+extern char *the_printed_command;
extern time_t shell_start_time;
#if 0
extern char *glob_argv_flags;
#endif
-extern int job_control; /* XXX */
-
extern int close __P((int));
/* Static functions defined and used in this file. */
@@ -197,6 +183,7 @@ static char *getinterp __P((char *, int, int *));
static void initialize_subshell __P((void));
static int execute_in_subshell __P((COMMAND *, int, int, int, struct fd_bitmap *));
#if defined (COPROCESS_SUPPORT)
+static void coproc_setstatus __P((struct coproc *, int));
static int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *));
#endif
@@ -285,6 +272,8 @@ static int function_line_number;
report the correct line number. Kind of a hack. */
static int showing_function_line;
+static int connection_count;
+
/* $LINENO ($BASH_LINENO) for use by an ERR trap. Global so parse_and_execute
can save and restore it. */
int line_number_for_err_trap;
@@ -410,7 +399,7 @@ execute_command (command)
#if defined (PROCESS_SUBSTITUTION)
/* don't unlink fifos if we're in a shell function; wait until the function
returns. */
- if (variable_context == 0)
+ if (variable_context == 0 && executing_list == 0)
unlink_fifo_list ();
#endif /* PROCESS_SUBSTITUTION */
@@ -461,6 +450,16 @@ cleanup_redirects (list)
dispose_redirects (list);
}
+void
+undo_partial_redirects ()
+{
+ if (redirection_undo_list)
+ {
+ cleanup_redirects (redirection_undo_list);
+ redirection_undo_list = (REDIRECT *)NULL;
+ }
+}
+
#if 0
/* Function to unwind_protect the redirections for functions and builtins. */
static void
@@ -481,6 +480,16 @@ dispose_exec_redirects ()
}
}
+void
+dispose_partial_redirects ()
+{
+ if (redirection_undo_list)
+ {
+ dispose_redirects (redirection_undo_list);
+ redirection_undo_list = (REDIRECT *)NULL;
+ }
+}
+
#if defined (JOB_CONTROL)
/* A function to restore the signal mask to its proper value when the shell
is interrupted or errors occur while creating a pipeline. */
@@ -552,7 +561,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
int exec_result, user_subshell, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
char *tcmd;
- volatile int last_pid;
volatile int save_line_number;
#if defined (PROCESS_SUBSTITUTION)
volatile int ofifo, nfifo, osize, saved_fifo;
@@ -590,11 +598,21 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
#if defined (COPROCESS_SUPPORT)
if (command->type == cm_coproc)
- return (execute_coproc (command, pipe_in, pipe_out, fds_to_close));
+ return (last_command_exit_value = execute_coproc (command, pipe_in, pipe_out, fds_to_close));
#endif
user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0);
+#if defined (TIME_BEFORE_SUBSHELL)
+ if ((command->flags & CMD_TIME_PIPELINE) && user_subshell && asynchronous == 0)
+ {
+ command->flags |= CMD_FORCE_SUBSHELL;
+ exec_result = time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close);
+ currently_executing_command = (COMMAND *)NULL;
+ return (exec_result);
+ }
+#endif
+
if (command->type == cm_subshell ||
(command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) ||
(shell_control_structure (command->type) &&
@@ -602,12 +620,13 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
{
pid_t paren_pid;
int s;
+ char *p;
/* Fork a subshell, turn off the subshell bit, turn off job
control and call execute_command () on the command again. */
- line_number_for_err_trap = line_number; /* XXX - save value? */
+ line_number_for_err_trap = line_number = command->value.Subshell->line; /* XXX - save value? */
tcmd = make_command_string (command);
- paren_pid = make_child (savestring (tcmd), asynchronous);
+ paren_pid = make_child (p = savestring (tcmd), asynchronous);
if (user_subshell && signal_is_trapped (ERROR_TRAP) &&
signal_in_progress (DEBUG_TRAP) == 0 && running_trap == 0)
@@ -618,6 +637,9 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
if (paren_pid == 0)
{
+#if defined (JOB_CONTROL)
+ FREE (p); /* child doesn't use pointer */
+#endif
/* We want to run the exit trap for forced {} subshells, and we
want to note this before execute_in_subshell modifies the
COMMAND struct. Need to keep in mind that execute_in_subshell
@@ -722,6 +744,10 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
stdin_redir = stdin_redirects (command->redirects);
#if defined (PROCESS_SUBSTITUTION)
+# if !defined (HAVE_DEV_FD)
+ reap_procsubs ();
+# endif
+
if (variable_context != 0)
{
ofifo = num_fifos ();
@@ -738,38 +764,45 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
redirection.) */
if (do_redirections (command->redirects, RX_ACTIVE|RX_UNDOABLE) != 0)
{
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
+ undo_partial_redirects ();
dispose_exec_redirects ();
#if defined (PROCESS_SUBSTITUTION)
if (saved_fifo)
- {
+ {
free ((void *)ofifo_list);
- discard_unwind_frame ("internal_fifos");
- }
+ discard_unwind_frame ("internal_fifos");
+ }
#endif
return (last_command_exit_value = EXECUTION_FAILURE);
}
+#if 0
if (redirection_undo_list)
{
/* XXX - why copy here? */
my_undo_list = (REDIRECT *)copy_redirects (redirection_undo_list);
- dispose_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
+ dispose_partial_redirects ();
}
else
my_undo_list = (REDIRECT *)NULL;
+#else
+ my_undo_list = redirection_undo_list;
+ redirection_undo_list = (REDIRECT *)NULL;
+#endif
+#if 0
if (exec_redirection_undo_list)
{
/* XXX - why copy here? */
exec_undo_list = (REDIRECT *)copy_redirects (exec_redirection_undo_list);
- dispose_redirects (exec_redirection_undo_list);
- exec_redirection_undo_list = (REDIRECT *)NULL;
+ dispose_exec_redirects ();
}
else
exec_undo_list = (REDIRECT *)NULL;
+#else
+ exec_undo_list = exec_redirection_undo_list;
+ exec_redirection_undo_list = (REDIRECT *)NULL;
+#endif
if (my_undo_list || exec_undo_list)
begin_unwind_frame ("loop_redirections");
@@ -795,7 +828,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
#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;
if (ignore_return && command->value.Simple)
@@ -855,8 +887,13 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
}
/* 2009/02/13 -- pipeline failure is processed elsewhere. This handles
- only the failure of a simple command. */
- if (was_error_trap && ignore_return == 0 && invert == 0 && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS)
+ 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. */
+ 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 &&
+ exec_result != EXECUTION_SUCCESS)
{
last_command_exit_value = exec_result;
line_number = line_number_for_err_trap;
@@ -1047,10 +1084,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
}
if (my_undo_list)
- {
- do_redirections (my_undo_list, RX_ACTIVE);
- dispose_redirects (my_undo_list);
- }
+ cleanup_redirects (my_undo_list);
if (exec_undo_list)
dispose_redirects (exec_undo_list);
@@ -1090,6 +1124,8 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
# endif
set_pipestatus_from_exit (exec_result);
break;
+ default:
+ break;
}
#endif
@@ -1116,19 +1152,6 @@ extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeva
static const int precs[] = { 0, 100, 10, 1 };
-#if defined (HAVE_LOCALE_H) && defined (HAVE_LOCALECONV)
-static int
-decpoint ()
-{
- struct lconv *lv;
-
- lv = localeconv ();
- return (lv && lv->decimal_point && lv->decimal_point[0]) ? lv->decimal_point[0] : '.';
-}
-#else
-# define decpoint() '.'
-#endif
-
/* Expand one `%'-prefixed escape sequence from a time format string. */
static int
mkfmt (buf, prec, lng, sec, sec_fraction)
@@ -1173,7 +1196,7 @@ mkfmt (buf, prec, lng, sec, sec_fraction)
and 999. */
if (prec != 0)
{
- buf[ind++] = decpoint ();
+ buf[ind++] = locale_decpoint ();
for (aind = 1; aind <= prec; aind++)
{
buf[ind++] = (sec_fraction / precs[aind]) + '0';
@@ -1357,8 +1380,10 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close)
command->flags &= ~(CMD_TIME_PIPELINE|CMD_TIME_POSIX);
code = setjmp_nosigs (top_level);
if (code == NOT_JUMPED)
- rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
- command->flags = old_flags;
+ {
+ rv = execute_command_internal (command, asynchronous, pipe_in, pipe_out, fds_to_close);
+ command->flags = old_flags;
+ }
COPY_PROCENV (save_top_level, top_level);
rs = us = ss = 0;
@@ -1415,6 +1440,7 @@ time_command (command, asynchronous, pipe_in, pipe_out, fds_to_close)
else
time_format = BASH_TIMEFORMAT;
}
+
if (time_format && *time_format)
print_formatted_time (stderr, time_format, rs, rsf, us, usf, ss, ssf, cpu);
@@ -1435,9 +1461,8 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
int pipe_in, pipe_out;
struct fd_bitmap *fds_to_close;
{
- int user_subshell, return_code, function_value, should_redir_stdin, invert;
- int ois, user_coproc;
- int result;
+ volatile int user_subshell, user_coproc, invert;
+ int return_code, function_value, should_redir_stdin, ois, result;
volatile COMMAND *tcom;
USE_VAR(user_subshell);
@@ -1498,7 +1523,11 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
login_shell = interactive = 0;
if (user_subshell)
- subshell_environment = SUBSHELL_PAREN; /* XXX */
+ {
+ subshell_environment = SUBSHELL_PAREN; /* XXX */
+ if (asynchronous)
+ subshell_environment |= SUBSHELL_ASYNC;
+ }
else
{
subshell_environment = 0; /* XXX */
@@ -1534,11 +1563,9 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
set_sigint_handler ();
-#if defined (JOB_CONTROL)
/* Delete all traces that there were any jobs running. This is
only for subshells. */
without_job_control ();
-#endif /* JOB_CONTROL */
if (fds_to_close)
close_fd_bitmap (fds_to_close);
@@ -1572,6 +1599,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
if (should_redir_stdin && stdin_redir == 0)
async_redirect_stdin ();
+#if 0
+ /* bash-5.0 */
+ if (user_subshell && command->type == cm_subshell)
+ optimize_subshell_command (command->value.Subshell->command);
+#endif
+
/* Do redirections, then dispose of them before recursive call. */
if (command->redirects)
{
@@ -1880,6 +1913,17 @@ cpl_searchbyname (name)
return (struct cpelement *)NULL;
}
+static pid_t
+cpl_firstactive ()
+{
+ struct cpelement *cpe;
+
+ for (cpe = coproc_list.head ; cpe; cpe = cpe->next)
+ if ((cpe->coproc->c_flags & COPROC_DEAD) == 0)
+ return cpe->coproc->c_pid;
+ return (pid_t)NO_PID;
+}
+
#if 0
static void
cpl_prune ()
@@ -2123,6 +2167,21 @@ coproc_fdrestore (cp)
cp->c_wfd = cp->c_wsave;
}
+static void
+coproc_setstatus (cp, status)
+ struct coproc *cp;
+ int status;
+{
+ cp->c_lock = 4;
+ cp->c_status = status;
+ cp->c_flags |= COPROC_DEAD;
+ cp->c_flags &= ~COPROC_RUNNING;
+ /* Don't dispose the coproc or unset the COPROC_XXX variables because
+ this is executed in a signal handler context. Wait until coproc_reap
+ takes care of it. */
+ cp->c_lock = 0;
+}
+
void
coproc_pidchk (pid, status)
pid_t pid;
@@ -2133,24 +2192,26 @@ coproc_pidchk (pid, status)
#if MULTIPLE_COPROCS
struct cpelement *cpe;
- cpe = cpl_delete (pid);
+ /* We're not disposing the coproc because this is executed in a signal
+ handler context */
+ cpe = cpl_search (pid);
cp = cpe ? cpe->coproc : 0;
#else
cp = getcoprocbypid (pid);
#endif
if (cp)
- {
- cp->c_lock = 4;
- cp->c_status = status;
- cp->c_flags |= COPROC_DEAD;
- cp->c_flags &= ~COPROC_RUNNING;
- /* Don't dispose the coproc or unset the COPROC_XXX variables because
- this is executed in a signal handler context. Wait until coproc_reap
- takes care of it. */
- cp->c_lock = 0;
- }
+ coproc_setstatus (cp, status);
}
+pid_t
+coproc_active ()
+{
+#if MULTIPLE_COPROCS
+ return (cpl_firstactive ());
+#else
+ return ((sh_coproc.c_flags & COPROC_DEAD) ? NO_PID : sh_coproc.c_pid);
+#endif
+}
void
coproc_setvars (cp)
struct coproc *cp;
@@ -2212,7 +2273,7 @@ coproc_setvars (cp)
t = itos (cp->c_wfd);
ind = 1;
- bind_array_variable (cp->c_name, ind, t, 0);
+ v = bind_array_variable (cp->c_name, ind, t, 0);
free (t);
#else
sprintf (namevar, "%s_READ", cp->c_name);
@@ -2227,7 +2288,7 @@ coproc_setvars (cp)
sprintf (namevar, "%s_PID", cp->c_name);
t = itos (cp->c_pid);
- bind_variable (namevar, t, 0);
+ v = bind_variable (namevar, t, 0);
free (t);
free (namevar);
@@ -2270,17 +2331,33 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close)
int rpipe[2], wpipe[2], estat, invert;
pid_t coproc_pid;
Coproc *cp;
- char *tcmd;
+ char *tcmd, *p, *name;
sigset_t set, oset;
/* XXX -- can be removed after changes to handle multiple coprocs */
#if !MULTIPLE_COPROCS
- if (sh_coproc.c_pid != NO_PID)
+ if (sh_coproc.c_pid != NO_PID && (sh_coproc.c_rfd >= 0 || sh_coproc.c_wfd >= 0))
internal_warning (_("execute_coproc: coproc [%d:%s] still exists"), sh_coproc.c_pid, sh_coproc.c_name);
coproc_init (&sh_coproc);
#endif
invert = (command->flags & CMD_INVERT_RETURN) != 0;
+
+ /* XXX - expand coproc name without splitting -- bash-5.0 */
+ /* could make this dependent on a shopt option */
+ name = expand_string_unsplit_to_string (command->value.Coproc->name, 0);
+ /* Optional check -- bash-5.0. */
+ if (legal_identifier (name) == 0)
+ {
+ internal_error (_("`%s': not a valid identifier"), name);
+ return (invert ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+ }
+ else
+ {
+ free (command->value.Coproc->name);
+ command->value.Coproc->name = name;
+ }
+
command_string_index = 0;
tcmd = make_command_string (command);
@@ -2289,13 +2366,17 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close)
BLOCK_SIGNAL (SIGCHLD, set, oset);
- coproc_pid = make_child (savestring (tcmd), 1);
+ coproc_pid = make_child (p = savestring (tcmd), 1);
if (coproc_pid == 0)
{
close (rpipe[0]);
close (wpipe[1]);
+#if defined (JOB_CONTROL)
+ FREE (p);
+#endif
+
UNBLOCK_SIGNAL (oset);
estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close);
@@ -2308,11 +2389,13 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close)
close (rpipe[1]);
close (wpipe[0]);
- /* XXX - possibly run Coproc->name through word expansion? */
+ /* XXX - run Coproc->name through word expansion above -- bash-5.0 */
cp = coproc_alloc (command->value.Coproc->name, coproc_pid);
cp->c_rfd = rpipe[0];
cp->c_wfd = wpipe[1];
+ cp->c_flags |= COPROC_RUNNING;
+
SET_CLOSE_ON_EXEC (cp->c_rfd);
SET_CLOSE_ON_EXEC (cp->c_wfd);
@@ -2321,7 +2404,7 @@ execute_coproc (command, pipe_in, pipe_out, fds_to_close)
UNBLOCK_SIGNAL (oset);
#if 0
- itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command);
+ itrace ("execute_coproc (%s): [%d] %s", command->value.Coproc->name, coproc_pid, the_printed_command);
#endif
close_pipes (pipe_in, pipe_out);
@@ -2779,8 +2862,10 @@ execute_for_command (for_command)
sh_invalidid (list->word->word);
v = 0;
}
+ else if (readonly_p (v))
+ err_readonly (name_cell (v));
else
- v = bind_variable_value (v, list->word->word, 0);
+ v = bind_variable_value (v, list->word->word, ASS_NAMEREF);
}
else
v = bind_variable (identifier, list->word->word, 0);
@@ -2835,7 +2920,7 @@ execute_for_command (for_command)
{
SHELL_VAR *new_value;
- new_value = bind_variable (identifier, value_cell(old_value), 0);
+ new_value = bind_variable (identifier, value_cell (old_value), 0);
new_value->attributes = old_value->attributes;
dispose_variable (old_value);
}
@@ -2892,7 +2977,7 @@ eval_arith_for_expr (l, okp)
skip the command. */
#if defined (DEBUGGER)
if (debugging_mode == 0 || r == EXECUTION_SUCCESS)
- expresult = evalexp (new->word->word, okp);
+ expresult = evalexp (new->word->word, EXP_EXPANDED, okp);
else
{
expresult = 0;
@@ -2900,7 +2985,7 @@ eval_arith_for_expr (l, okp)
*okp = 1;
}
#else
- expresult = evalexp (new->word->word, okp);
+ expresult = evalexp (new->word->word, EXP_EXPANDED, okp);
#endif
dispose_words (new);
}
@@ -2933,11 +3018,12 @@ execute_arith_for_command (arith_for_command)
line_number before executing each expression -- for $LINENO
and the DEBUG trap. */
line_number = arith_lineno = arith_for_command->line;
- if (variable_context && interactive_shell)
+ if (variable_context && interactive_shell && sourcelevel == 0)
{
- line_number -= function_line_number;
- if (line_number < 0)
- line_number = 0;
+ /* line numbers in a function start at 1 */
+ line_number -= function_line_number - 1;
+ if (line_number <= 0)
+ line_number = 1;
}
/* Evaluate the initialization expression. */
@@ -3142,12 +3228,7 @@ select_query (list, list_len, prompt, print_menu)
WORD_LIST *l;
char *repl_string, *t;
-#if 0
- t = get_string_value ("LINES");
- LINES = (t && *t) ? atoi (t) : 24;
-#endif
- t = get_string_value ("COLUMNS");
- COLS = (t && *t) ? atoi (t) : 80;
+ COLS = default_columns ();
#if 0
t = get_string_value ("TABSIZE");
@@ -3350,7 +3431,7 @@ execute_case_command (case_command)
WORD_LIST *wlist, *es;
PATTERN_LIST *clauses;
char *word, *pattern;
- int retval, match, ignore_return, save_line_number;
+ int retval, match, ignore_return, save_line_number, qflags;
save_line_number = line_number;
line_number = case_command->line;
@@ -3402,7 +3483,18 @@ execute_case_command (case_command)
es = expand_word_leave_quoted (list->word, 0);
if (es && es->word && es->word->word && *(es->word->word))
- pattern = quote_string_for_globbing (es->word->word, QGLOB_CVTNULL);
+ {
+ /* Convert quoted null strings into empty strings. */
+ qflags = QGLOB_CVTNULL;
+
+ /* We left CTLESC in place quoting CTLESC and CTLNUL after the
+ call to expand_word_leave_quoted; tell quote_string_for_globbing
+ to remove those here. This works for both unquoted portions of
+ the word (which call quote_escapes) and quoted portions
+ (which call quote_string). */
+ qflags |= QGLOB_CTLESC;
+ pattern = quote_string_for_globbing (es->word->word, qflags);
+ }
else
{
pattern = (char *)xmalloc (1);
@@ -3581,13 +3673,14 @@ execute_arith_command (arith_command)
save_line_number = line_number;
this_command_name = "(("; /* )) */
- line_number = arith_command->line;
+ line_number_for_err_trap = line_number = arith_command->line;
/* If we're in a function, update the line number information. */
- if (variable_context && interactive_shell)
+ if (variable_context && interactive_shell && sourcelevel == 0)
{
- line_number -= function_line_number;
- if (line_number < 0)
- line_number = 0;
+ /* line numbers in a function start at 1 */
+ line_number -= function_line_number - 1;
+ if (line_number <= 0)
+ line_number = 1;
}
command_string_index = 0;
@@ -3623,7 +3716,7 @@ execute_arith_command (arith_command)
if (new)
{
exp = new->next ? string_list (new) : new->word->word;
- expresult = evalexp (exp, &expok);
+ expresult = evalexp (exp, EXP_EXPANDED, &expok);
line_number = save_line_number;
if (exp != new->word->word)
free (exp);
@@ -3779,17 +3872,17 @@ execute_cond_command (cond_command)
{
int retval, save_line_number;
- retval = EXECUTION_SUCCESS;
save_line_number = line_number;
this_command_name = "[[";
- line_number = cond_command->line;
+ line_number_for_err_trap = line_number = cond_command->line;
/* If we're in a function, update the line number information. */
- if (variable_context && interactive_shell)
+ if (variable_context && interactive_shell && sourcelevel == 0)
{
- line_number -= function_line_number;
- if (line_number < 0)
- line_number = 0;
+ /* line numbers in a function start at 1 */
+ line_number -= function_line_number - 1;
+ if (line_number <= 0)
+ line_number = 1;
}
command_string_index = 0;
print_cond_command (cond_command);
@@ -3849,7 +3942,11 @@ execute_null_command (redirects, pipe_in, pipe_out, async)
REDIRECT *rd;
for (forcefork = 0, rd = redirects; rd; rd = rd->next)
- forcefork += rd->rflags & REDIR_VARASSIGN;
+ {
+ forcefork += rd->rflags & REDIR_VARASSIGN;
+ /* Safety */
+ forcefork += (rd->redirector.dest == 0 || fd_is_bash_input (rd->redirector.dest)) && (INPUT_REDIRECT (rd->instruction) || TRANSLATE_REDIRECT (rd->instruction) || rd->instruction == r_close_this);
+ }
if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async)
{
@@ -3866,6 +3963,8 @@ execute_null_command (redirects, pipe_in, pipe_out, async)
coproc_closeall ();
#endif
+ interactive = 0; /* XXX */
+
subshell_environment = 0;
if (async)
subshell_environment |= SUBSHELL_ASYNC;
@@ -3962,9 +4061,10 @@ fix_assignment_words (words)
/* If we have an assignment builtin that does not create local variables,
make sure we create global variables even if we internally call
- `declare' */
+ `declare'. The CHKLOCAL flag means to set attributes or values on
+ an existing local variable */
if (b && ((b->flags & (ASSIGNMENT_BUILTIN|LOCALVAR_BUILTIN)) == ASSIGNMENT_BUILTIN))
- w->word->flags |= W_ASSNGLOBAL;
+ w->word->flags |= W_ASSNGLOBAL|W_CHKLOCAL;
}
#if defined (ARRAY_VARS)
/* Note that we saw an associative array option to a builtin that takes
@@ -4032,9 +4132,10 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
/* If we're in a function, update the line number information. */
if (variable_context && interactive_shell && sourcelevel == 0)
{
- line_number -= function_line_number;
- if (line_number < 0)
- line_number = 0;
+ /* line numbers in a function start at 1 */
+ line_number -= function_line_number - 1;
+ if (line_number <= 0)
+ line_number = 1;
}
/* Remember what this command line looks like at invocation. */
@@ -4067,7 +4168,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
last_command_subst_pid = NO_PID;
old_last_async_pid = last_asynchronous_pid;
- already_forked = dofork = 0;
+ already_forked = 0;
/* If we're in a pipeline or run in the background, set DOFORK so we
make the child early, before word expansion. This keeps assignment
@@ -4085,13 +4186,15 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (dofork)
{
+ char *p;
+
/* Do this now, because execute_disk_command will do it anyway in the
vast majority of cases. */
maybe_make_export_env ();
/* 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)
+ if (make_child (p = savestring (the_printed_command_except_trap), async) == 0)
{
already_forked = 1;
simple_command->flags |= CMD_NO_FORK;
@@ -4124,6 +4227,10 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (async)
subshell_level++; /* not for pipes yet */
+
+#if defined (JOB_CONTROL)
+ FREE (p); /* child doesn't use pointer */
+#endif
}
else
{
@@ -4133,12 +4240,14 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
result = last_command_exit_value;
close_pipes (pipe_in, pipe_out);
#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
+#if 0
/* Close /dev/fd file descriptors in the parent after forking the
last child in a (possibly one-element) pipeline. Defer this
until any running shell function completes. */
if (pipe_out == NO_PIPE && variable_context == 0) /* XXX */
unlink_fifo_list (); /* XXX */
#endif
+#endif
command_line = (char *)NULL; /* don't free this. */
bind_lastarg ((char *)NULL);
return (result);
@@ -4345,10 +4454,18 @@ run_builtin:
last_command_exit_value = EXECUTION_FAILURE;
jump_to_top_level (ERREXIT);
}
+ break;
+ case EX_DISKFALLBACK:
+ /* XXX - experimental */
+ executing_builtin = old_builtin;
+ executing_command_builtin = old_command_builtin;
+ builtin = 0;
+ /* XXX - redirections will have to be performed again */
+ goto execute_from_filesystem;
}
result = builtin_status (result);
if (builtin_is_special)
- special_builtin_failed = 1;
+ special_builtin_failed = 1; /* XXX - take command builtin into account? */
}
/* In POSIX mode, if there are assignment statements preceding
a special builtin, they persist after the builtin
@@ -4379,6 +4496,7 @@ run_builtin:
goto run_builtin;
}
+execute_from_filesystem:
if (command_line == 0)
command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : "");
@@ -4439,11 +4557,12 @@ execute_builtin (builtin, words, flags, subshell)
WORD_LIST *words;
int flags, subshell;
{
- int result, eval_unwind, ignexit_flag, old_e_flag;
- int isbltinenv;
+ int result, eval_unwind, ignexit_flag;
+ int isbltinenv, should_keep;
char *error_trap;
error_trap = 0;
+ should_keep = 0;
/* The eval builtin calls parse_and_execute, which does not know about
the setting of flags, and always calls the execution functions with
@@ -4479,7 +4598,18 @@ execute_builtin (builtin, words, flags, subshell)
problem only with the `unset', `source' and `eval' builtins.
`mapfile' is a special case because it uses evalstring (same as
eval or source) to run its callbacks. */
+ /* SHOULD_KEEP is for the pop_scope call below; it only matters when
+ posixly_correct is set, but we should propagate the temporary environment
+ to the enclosing environment only for special builtins. */
isbltinenv = (builtin == source_builtin || builtin == eval_builtin || builtin == unset_builtin || builtin == mapfile_builtin);
+ should_keep = isbltinenv && builtin != mapfile_builtin;
+#if defined (HISTORY) && defined (READLINE)
+ if (builtin == fc_builtin || builtin == read_builtin)
+ {
+ isbltinenv = 1;
+ should_keep = 0;
+ }
+#endif
if (isbltinenv)
{
@@ -4489,8 +4619,10 @@ execute_builtin (builtin, words, flags, subshell)
if (temporary_env)
{
push_scope (VC_BLTNENV, temporary_env);
+ if (flags & CMD_COMMAND_BUILTIN)
+ should_keep = 0;
if (subshell == 0)
- add_unwind_protect (pop_scope, (flags & CMD_COMMAND_BUILTIN) ? 0 : "1");
+ add_unwind_protect (pop_scope, should_keep ? "1" : 0);
temporary_env = (HASH_TABLE *)NULL;
}
}
@@ -4549,7 +4681,7 @@ execute_builtin (builtin, words, flags, subshell)
if (error_trap)
{
set_error_trap (error_trap);
- xfree (error_trap);
+ free (error_trap);
}
discard_unwind_frame ("eval_builtin");
}
@@ -4561,8 +4693,6 @@ static void
maybe_restore_getopt_state (gs)
sh_getopt_state_t *gs;
{
- SHELL_VAR *v;
-
/* If we have a local copy of OPTIND and it's at the right (current)
context, then we restore getopt's internal state. If not, we just
let it go. We know there is a local OPTIND if gs->gs_flags & 1.
@@ -4638,6 +4768,12 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
if (subshell == 0)
{
begin_unwind_frame ("function_calling");
+ /* If the shell is in posix mode, this will push the variables in
+ the temporary environment to the "current shell environment" (the
+ global scope), and dispose the temporary env before setting it to
+ NULL later. This behavior has disappeared from the latest edition
+ of the standard, so I will eventually remove it from variables.c:
+ push_var_context. */
push_context (var->name, subshell, temporary_env);
/* This has to be before the pop_context(), because the unwinding of
local variables may cause the restore of a local declaration of
@@ -4698,11 +4834,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
/* 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)
{
@@ -4741,6 +4873,11 @@ 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. */
+ /* Initialize BASH_ARGC and BASH_ARGV before we blow away the positional
+ parameters */
+ if (debugging_mode || shell_compatibility_level <= 44)
+ init_bash_argv ();
+
remember_args (words->next, 1);
/* Update BASH_ARGV and BASH_ARGC */
@@ -4911,6 +5048,8 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var,
without_job_control ();
set_sigchld_handler ();
+#else
+ without_job_control ();
#endif /* JOB_CONTROL */
set_sigint_handler ();
@@ -4947,6 +5086,15 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var,
fflush (stdout);
if (r == EX_USAGE)
r = EX_BADUSAGE;
+ /* XXX - experimental */
+ else if (r == EX_DISKFALLBACK)
+ {
+ char *command_line;
+
+ command_line = savestring (the_printed_command_except_trap ? the_printed_command_except_trap : "");
+ r = execute_disk_command (words, (REDIRECT *)0, command_line,
+ -1, -1, async, (struct fd_bitmap *)0, flags|CMD_NO_FORK);
+ }
sh_exit (r);
}
}
@@ -4995,8 +5143,7 @@ execute_builtin_or_function (words, builtin, var, redirects,
if (do_redirections (redirects, RX_ACTIVE|RX_UNDOABLE) != 0)
{
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
+ undo_partial_redirects ();
dispose_exec_redirects ();
#if defined (PROCESS_SUBSTITUTION)
free (ofifo_list);
@@ -5063,11 +5210,7 @@ execute_builtin_or_function (words, builtin, var, redirects,
discard_unwind_frame ("saved-redirects");
}
- if (redirection_undo_list)
- {
- cleanup_redirects (redirection_undo_list);
- redirection_undo_list = (REDIRECT *)NULL;
- }
+ undo_partial_redirects ();
#if defined (PROCESS_SUBSTITUTION)
/* Close any FIFOs created by this builtin or function. */
@@ -5139,7 +5282,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
struct fd_bitmap *fds_to_close;
int cmdflags;
{
- char *pathname, *command, **args;
+ char *pathname, *command, **args, *p;
int nofork, stdpath, result;
pid_t pid;
SHELL_VAR *hookf;
@@ -5149,6 +5292,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */
pathname = words->word->word;
+ p = 0;
result = EXECUTION_SUCCESS;
#if defined (RESTRICTED_SHELL)
command = (char *)NULL;
@@ -5168,9 +5312,15 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
#endif /* RESTRICTED_SHELL */
command = search_for_command (pathname, CMDSRCH_HASH|(stdpath ? CMDSRCH_STDPATH : 0));
+ QUIT;
if (command)
{
+ /* If we're optimizing out the fork (implicit `exec'), decrement the
+ shell level like `exec' would do. */
+ if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
+ adjust_shell_level (-1);
+
maybe_make_export_env ();
put_command_name_into_env (command);
}
@@ -5182,7 +5332,7 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
if (nofork && pipe_in == NO_PIPE && pipe_out == NO_PIPE)
pid = 0;
else
- pid = make_child (savestring (command_line), async);
+ pid = make_child (p = savestring (command_line), async);
if (pid == 0)
{
@@ -5194,6 +5344,10 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
CHECK_SIGTERM;
+#if defined (JOB_CONTROL)
+ FREE (p);
+#endif
+
/* restore_original_signals may have undone the work done
by make_child to ensure that SIGINT and SIGQUIT are ignored
in asynchronous children. */
@@ -5246,9 +5400,13 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */
}
+ /* We don't want to manage process groups for processes we start
+ from here, so we turn off job control and don't attempt to
+ manipulate the terminal's process group. */
+ without_job_control ();
+
#if defined (JOB_CONTROL)
- /* May need to reinitialize more of the job control state here. */
- kill_current_pipeline ();
+ set_sigchld_handler ();
#endif
wl = make_word_list (make_word (NOTFOUND_HOOK), words);
@@ -5271,9 +5429,11 @@ parent_return:
/* Make sure that the pipes are closed in the parent. */
close_pipes (pipe_in, pipe_out);
#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
+#if 0
if (variable_context == 0)
unlink_fifo_list ();
#endif
+#endif
FREE (command);
return (result);
}
@@ -5619,6 +5779,7 @@ execute_intern_function (name, funcdef)
FUNCTION_DEF *funcdef;
{
SHELL_VAR *var;
+ char *t;
if (check_identifier (name, posixly_correct) == 0)
{
@@ -5630,6 +5791,13 @@ execute_intern_function (name, funcdef)
return (EXECUTION_FAILURE);
}
+ if (strchr (name->word, CTLESC)) /* WHY? */
+ {
+ t = dequote_escapes (name->word);
+ free (name->word);
+ name->word = t;
+ }
+
/* Posix interpretation 383 */
if (posixly_correct && find_special_builtin (name->word))
{
@@ -5647,7 +5815,7 @@ execute_intern_function (name, funcdef)
}
#if defined (DEBUGGER)
- bind_function_def (name->word, funcdef);
+ bind_function_def (name->word, funcdef, 1);
#endif
bind_function (name->word, funcdef->command);