summaryrefslogtreecommitdiff
path: root/execute_cmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'execute_cmd.c')
-rw-r--r--execute_cmd.c1020
1 files changed, 934 insertions, 86 deletions
diff --git a/execute_cmd.c b/execute_cmd.c
index 662889a..e65a03f 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -1,22 +1,23 @@
/* execute_cmd.c -- Execute a COMMAND structure. */
-/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
- Bash is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ Bash is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
- Bash is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
+ Bash is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with Bash; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
+
#include "config.h"
#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
@@ -56,6 +57,8 @@
extern int errno;
#endif
+#define NEED_FPURGE_DECL
+
#include "bashansi.h"
#include "bashintl.h"
@@ -96,9 +99,10 @@ extern int errno;
#endif
extern int posixly_correct;
-extern int breaking, continuing, loop_level;
extern int expand_aliases;
-extern int parse_and_execute_level, running_trap;
+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;
@@ -180,6 +184,9 @@ static void execute_disk_command __P((WORD_LIST *, REDIRECT *, char *,
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 int execute_coproc __P((COMMAND *, int, int, struct fd_bitmap *));
+#endif
static int execute_pipeline __P((COMMAND *, int, int, int, struct fd_bitmap *));
@@ -187,9 +194,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;
-
/* Set to 1 if fd 0 was the subject of redirection to a subshell. Global
so that reader_loop can set it to zero before executing a command. */
int stdin_redir;
@@ -203,19 +207,6 @@ char *this_command_name;
a debugger to know where exactly the program is currently executing. */
char *the_printed_command_except_trap;
-static COMMAND *currently_executing_command;
-
-struct stat SB; /* used for debugging */
-
-static int special_builtin_failed;
-
-/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line
- number containing the function name. Used by executing_line_number to
- report the correct line number. Kind of a hack. */
-static int showing_function_line;
-
-static int line_number_for_err_trap;
-
/* For catching RETURN in a function. */
int return_catch_flag;
int return_catch_value;
@@ -237,6 +228,18 @@ REDIRECT *redirection_undo_list = (REDIRECT *)NULL;
that must be undone even when exec discards redirection_undo_list. */
REDIRECT *exec_redirection_undo_list = (REDIRECT *)NULL;
+/* When greater than zero, value is the `level' of builtins we are
+ currently executing (e.g. `eval echo a' would have it set to 2). */
+int executing_builtin = 0;
+
+/* Non-zero if we are executing a command list (a;b;c, etc.) */
+int executing_list = 0;
+
+/* Non-zero if failing commands in a command substitution should not exit the
+ shell even if -e is set. Used to pass the CMD_IGNORE_RETURN flag down to
+ commands run in command substitutions by parse_and_execute. */
+int comsub_ignore_return = 0;
+
/* Non-zero if we have just forked and are currently running in a subshell
environment. */
int subshell_environment;
@@ -250,6 +253,26 @@ SHELL_VAR *this_shell_function;
/* If non-zero, matches in case and [[ ... ]] are case-insensitive */
int match_ignore_case = 0;
+struct stat SB; /* used for debugging */
+
+static int special_builtin_failed;
+
+static COMMAND *currently_executing_command;
+
+/* The line number that the currently executing function starts on. */
+static int function_line_number;
+
+/* XXX - set to 1 if we're running the DEBUG trap and we want to show the line
+ number containing the function name. Used by executing_line_number to
+ report the correct line number. Kind of a hack. */
+static int showing_function_line;
+
+static int line_number_for_err_trap;
+
+/* A sort of function nesting level counter */
+static int funcnest = 0;
+int funcnest_max = 0; /* XXX - for bash-4.2 */
+
struct fd_bitmap *current_fds_to_close = (struct fd_bitmap *)NULL;
#define FD_BITMAP_DEFAULT_SIZE 32
@@ -496,13 +519,20 @@ 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_error_trap;
+ int exec_result, user_subshell, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
volatile int last_pid;
volatile int save_line_number;
+#if 0
if (command == 0 || breaking || continuing || read_but_dont_execute)
return (EXECUTION_SUCCESS);
+#else
+ if (breaking || continuing)
+ return (last_command_exit_value);
+ if (command == 0 || read_but_dont_execute)
+ return (EXECUTION_SUCCESS);
+#endif
QUIT;
run_pending_traps ();
@@ -528,6 +558,13 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
if (command->type == cm_subshell && (command->flags & CMD_NO_FORK))
return (execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close));
+#if defined (COPROCESS_SUPPORT)
+ if (command->type == cm_coproc)
+ return (execute_coproc (command, pipe_in, pipe_out, fds_to_close));
+#endif
+
+ user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0);
+
if (command->type == cm_subshell ||
(command->flags & (CMD_WANT_SUBSHELL|CMD_FORCE_SUBSHELL)) ||
(shell_control_structure (command->type) &&
@@ -537,6 +574,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* 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;
paren_pid = make_child (savestring (make_command_string (command)),
asynchronous);
if (paren_pid == 0)
@@ -561,6 +599,10 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
if (asynchronous == 0)
{
+ was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
+ invert = (command->flags & CMD_INVERT_RETURN) != 0;
+ ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
+
last_command_exit_value = wait_for (paren_pid);
/* If we have to, invert the return value. */
@@ -571,6 +613,22 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
else
exec_result = last_command_exit_value;
+ if (user_subshell && was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ save_line_number = line_number;
+ line_number = line_number_for_err_trap;
+ run_error_trap ();
+ line_number = save_line_number;
+ }
+
+ if (user_subshell && ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ run_pending_traps ();
+ jump_to_top_level (ERREXIT);
+ }
+
return (last_command_exit_value = exec_result);
}
else
@@ -614,7 +672,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
cleanup_redirects (redirection_undo_list);
redirection_undo_list = (REDIRECT *)NULL;
dispose_exec_redirects ();
- return (EXECUTION_FAILURE);
+ return (last_command_exit_value = EXECUTION_FAILURE);
}
if (redirection_undo_list)
@@ -712,15 +770,19 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
}
}
- if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
+ /* 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)
{
last_command_exit_value = exec_result;
+ line_number = line_number_for_err_trap;
run_error_trap ();
+ line_number = save_line_number;
}
if (ignore_return == 0 && invert == 0 &&
((posixly_correct && interactive == 0 && special_builtin_failed) ||
- (exit_immediately_on_error && (exec_result != EXECUTION_SUCCESS))))
+ (exit_immediately_on_error && pipe_in == NO_PIPE && pipe_out == NO_PIPE && exec_result != EXECUTION_SUCCESS)))
{
last_command_exit_value = exec_result;
run_pending_traps ();
@@ -826,19 +888,58 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
#if defined (DPAREN_ARITHMETIC)
case cm_arith:
+ was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
if (ignore_return)
command->value.Arith->flags |= CMD_IGNORE_RETURN;
+ line_number_for_err_trap = save_line_number = line_number;
exec_result = execute_arith_command (command->value.Arith);
+ line_number = save_line_number;
+
+ if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ save_line_number = line_number;
+ line_number = line_number_for_err_trap;
+ run_error_trap ();
+ line_number = save_line_number;
+ }
+
+ if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ run_pending_traps ();
+ jump_to_top_level (ERREXIT);
+ }
+
break;
#endif
#if defined (COND_COMMAND)
case cm_cond:
+ was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
if (ignore_return)
command->value.Cond->flags |= CMD_IGNORE_RETURN;
- save_line_number = line_number;
+
+ line_number_for_err_trap = save_line_number = line_number;
exec_result = execute_cond_command (command->value.Cond);
line_number = save_line_number;
+
+ if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ save_line_number = line_number;
+ line_number = line_number_for_err_trap;
+ run_error_trap ();
+ line_number = save_line_number;
+ }
+
+ if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ run_pending_traps ();
+ jump_to_top_level (ERREXIT);
+ }
+
break;
#endif
@@ -907,7 +1008,7 @@ extern int timeval_to_cpu __P((struct timeval *, struct timeval *, struct timeva
#define POSIX_TIMEFORMAT "real %2R\nuser %2U\nsys %2S"
#define BASH_TIMEFORMAT "\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS"
-static int precs[] = { 0, 100, 10, 1 };
+static const int precs[] = { 0, 100, 10, 1 };
/* Expand one `%'-prefixed escape sequence from a time format string. */
static int
@@ -1023,8 +1124,11 @@ print_formatted_time (fp, format, rs, rsf, us, usf, ss, ssf, cpu)
else if (s[1] == 'P')
{
s++;
+#if 0
+ /* clamp CPU usage at 100% */
if (cpu > 10000)
cpu = 10000;
+#endif
sum = cpu / 100;
sum_frac = (cpu % 100) * 10;
len = mkfmt (ts, 2, 0, sum, sum_frac);
@@ -1187,10 +1291,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
struct fd_bitmap *fds_to_close;
{
int user_subshell, return_code, function_value, should_redir_stdin, invert;
- int ois;
+ int ois, user_coproc;
+ int result;
COMMAND *tcom;
USE_VAR(user_subshell);
+ USE_VAR(user_coproc);
USE_VAR(invert);
USE_VAR(tcom);
USE_VAR(asynchronous);
@@ -1202,6 +1308,7 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
invert = (command->flags & CMD_INVERT_RETURN) != 0;
user_subshell = command->type == cm_subshell || ((command->flags & CMD_WANT_SUBSHELL) != 0);
+ user_coproc = command->type == cm_coproc;
command->flags &= ~(CMD_FORCE_SUBSHELL | CMD_WANT_SUBSHELL | CMD_INVERT_RETURN);
@@ -1254,6 +1361,8 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
subshell_environment |= SUBSHELL_ASYNC;
if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
subshell_environment |= SUBSHELL_PIPE;
+ if (user_coproc)
+ subshell_environment |= SUBSHELL_COPROC;
}
reset_terminating_signals (); /* in sig.c */
@@ -1287,6 +1396,10 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
do_piping (pipe_in, pipe_out);
+#if defined (COPROCESS_SUPPORT)
+ coproc_closeall ();
+#endif
+
/* If this is a user subshell, set a flag if stdin was redirected.
This is used later to decide whether to redirect fd 0 to
/dev/null for async commands in the subshell. This adds more
@@ -1313,7 +1426,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
command->redirects = (REDIRECT *)NULL;
}
- tcom = (command->type == cm_subshell) ? command->value.Subshell->command : command;
+ if (command->type == cm_subshell)
+ tcom = command->value.Subshell->command;
+ else if (user_coproc)
+ tcom = command->value.Coproc->command;
+ else
+ tcom = command;
if (command->flags & CMD_TIME_PIPELINE)
tcom->flags |= CMD_TIME_PIPELINE;
@@ -1329,7 +1447,7 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
This means things like ( sleep 10 ) will only cause one fork.
If we're timing the command or inverting its return value, however,
we cannot do this optimization. */
- if (user_subshell && (tcom->type == cm_simple || tcom->type == cm_subshell) &&
+ if ((user_subshell || user_coproc) && (tcom->type == cm_simple || tcom->type == cm_subshell) &&
((tcom->flags & CMD_TIME_PIPELINE) == 0) &&
((tcom->flags & CMD_INVERT_RETURN) == 0))
{
@@ -1341,13 +1459,21 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
invert = (tcom->flags & CMD_INVERT_RETURN) != 0;
tcom->flags &= ~CMD_INVERT_RETURN;
+ result = setjmp (top_level);
+
/* If we're inside a function while executing this subshell, we
need to handle a possible `return'. */
function_value = 0;
if (return_catch_flag)
function_value = setjmp (return_catch);
- if (function_value)
+ /* If we're going to exit the shell, we don't want to invert the return
+ status. */
+ if (result == EXITPROG)
+ invert = 0, return_code = last_command_exit_value;
+ else if (result)
+ return_code = EXECUTION_FAILURE;
+ else if (function_value)
return_code = return_catch_value;
else
return_code = execute_command_internal (tcom, asynchronous, NO_PIPE, NO_PIPE, fds_to_close);
@@ -1370,6 +1496,556 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close)
/* NOTREACHED */
}
+#if defined (COPROCESS_SUPPORT)
+#define COPROC_MAX 16
+
+typedef struct cpelement
+ {
+ struct cpelement *next;
+ struct coproc *coproc;
+ }
+cpelement_t;
+
+typedef struct cplist
+ {
+ struct cpelement *head;
+ struct cpelement *tail;
+ int ncoproc;
+ }
+cplist_t;
+
+static struct cpelement *cpe_alloc __P((struct coproc *));
+static void cpe_dispose __P((struct cpelement *));
+static struct cpelement *cpl_add __P((struct coproc *));
+static struct cpelement *cpl_delete __P((pid_t));
+static void cpl_reap __P((void));
+static void cpl_flush __P((void));
+static struct cpelement *cpl_search __P((pid_t));
+static struct cpelement *cpl_searchbyname __P((char *));
+static void cpl_prune __P((void));
+
+Coproc sh_coproc = { 0, NO_PID, -1, -1, 0, 0 };
+
+cplist_t coproc_list = {0, 0, 0};
+
+/* Functions to manage the list of coprocs */
+
+static struct cpelement *
+cpe_alloc (cp)
+ Coproc *cp;
+{
+ struct cpelement *cpe;
+
+ cpe = (struct cpelement *)xmalloc (sizeof (struct cpelement));
+ cpe->coproc = cp;
+ cpe->next = (struct cpelement *)0;
+ return cpe;
+}
+
+static void
+cpe_dispose (cpe)
+ struct cpelement *cpe;
+{
+ free (cpe);
+}
+
+static struct cpelement *
+cpl_add (cp)
+ Coproc *cp;
+{
+ struct cpelement *cpe;
+
+ cpe = cpe_alloc (cp);
+
+ if (coproc_list.head == 0)
+ {
+ coproc_list.head = coproc_list.tail = cpe;
+ coproc_list.ncoproc = 0; /* just to make sure */
+ }
+ else
+ {
+ coproc_list.tail->next = cpe;
+ coproc_list.tail = cpe;
+ }
+ coproc_list.ncoproc++;
+
+ return cpe;
+}
+
+static struct cpelement *
+cpl_delete (pid)
+ pid_t pid;
+{
+ struct cpelement *prev, *p;
+
+ for (prev = p = coproc_list.head; p; prev = p, p = p->next)
+ if (p->coproc->c_pid == pid)
+ {
+ prev->next = p->next; /* remove from list */
+ break;
+ }
+
+ if (p == 0)
+ return 0; /* not found */
+
+#if defined (DEBUG)
+ itrace("cpl_delete: deleting %d", pid);
+#endif
+
+ /* Housekeeping in the border cases. */
+ if (p == coproc_list.head)
+ coproc_list.head = coproc_list.head->next;
+ else if (p == coproc_list.tail)
+ coproc_list.tail = prev;
+
+ coproc_list.ncoproc--;
+ if (coproc_list.ncoproc == 0)
+ coproc_list.head = coproc_list.tail = 0;
+ else if (coproc_list.ncoproc == 1)
+ coproc_list.tail = coproc_list.head; /* just to make sure */
+
+ return (p);
+}
+
+static void
+cpl_reap ()
+{
+ struct cpelement *prev, *p;
+
+ for (prev = p = coproc_list.head; p; prev = p, p = p->next)
+ if (p->coproc->c_flags & COPROC_DEAD)
+ {
+ prev->next = p->next; /* remove from list */
+
+ /* Housekeeping in the border cases. */
+ if (p == coproc_list.head)
+ coproc_list.head = coproc_list.head->next;
+ else if (p == coproc_list.tail)
+ coproc_list.tail = prev;
+
+ coproc_list.ncoproc--;
+ if (coproc_list.ncoproc == 0)
+ coproc_list.head = coproc_list.tail = 0;
+ else if (coproc_list.ncoproc == 1)
+ coproc_list.tail = coproc_list.head; /* just to make sure */
+
+#if defined (DEBUG)
+ itrace("cpl_reap: deleting %d", p->coproc->c_pid);
+#endif
+
+ coproc_dispose (p->coproc);
+ cpe_dispose (p);
+ }
+}
+
+/* Clear out the list of saved statuses */
+static void
+cpl_flush ()
+{
+ struct cpelement *cpe, *p;
+
+ for (cpe = coproc_list.head; cpe; )
+ {
+ p = cpe;
+ cpe = cpe->next;
+
+ coproc_dispose (p->coproc);
+ cpe_dispose (p);
+ }
+
+ coproc_list.head = coproc_list.tail = 0;
+ coproc_list.ncoproc = 0;
+}
+
+/* Search for PID in the list of coprocs; return the cpelement struct if
+ found. If not found, return NULL. */
+static struct cpelement *
+cpl_search (pid)
+ pid_t pid;
+{
+ struct cpelement *cp;
+
+ for (cp = coproc_list.head ; cp; cp = cp->next)
+ if (cp->coproc->c_pid == pid)
+ return cp;
+ return (struct cpelement *)NULL;
+}
+
+/* Search for the coproc named NAME in the list of coprocs; return the
+ cpelement struct if found. If not found, return NULL. */
+static struct cpelement *
+cpl_searchbyname (name)
+ char *name;
+{
+ struct cpelement *cp;
+
+ for (cp = coproc_list.head ; cp; cp = cp->next)
+ if (STREQ (cp->coproc->c_name, name))
+ return cp;
+ return (struct cpelement *)NULL;
+}
+
+#if 0
+static void
+cpl_prune ()
+{
+ struct cpelement *cp;
+
+ while (coproc_list.head && coproc_list.ncoproc > COPROC_MAX)
+ {
+ cp = coproc_list.head;
+ coproc_list.head = coproc_list.head->next;
+ coproc_dispose (cp->coproc);
+ cpe_dispose (cp);
+ coproc_list.ncoproc--;
+ }
+}
+#endif
+
+/* These currently use a single global "shell coproc" but are written in a
+ way to not preclude additional coprocs later (using the list management
+ package above). */
+
+struct coproc *
+getcoprocbypid (pid)
+ pid_t pid;
+{
+ return (pid == sh_coproc.c_pid ? &sh_coproc : 0);
+}
+
+struct coproc *
+getcoprocbyname (name)
+ const char *name;
+{
+ return ((sh_coproc.c_name && STREQ (sh_coproc.c_name, name)) ? &sh_coproc : 0);
+}
+
+void
+coproc_init (cp)
+ struct coproc *cp;
+{
+ cp->c_name = 0;
+ cp->c_pid = NO_PID;
+ cp->c_rfd = cp->c_wfd = -1;
+ cp->c_rsave = cp->c_wsave = -1;
+ cp->c_flags = cp->c_status = 0;
+}
+
+struct coproc *
+coproc_alloc (name, pid)
+ char *name;
+ pid_t pid;
+{
+ struct coproc *cp;
+
+ cp = &sh_coproc; /* XXX */
+ coproc_init (cp);
+
+ cp->c_name = savestring (name);
+ cp->c_pid = pid;
+
+ return (cp);
+}
+
+void
+coproc_dispose (cp)
+ struct coproc *cp;
+{
+ if (cp == 0)
+ return;
+
+ coproc_unsetvars (cp);
+ FREE (cp->c_name);
+ coproc_close (cp);
+ coproc_init (cp);
+}
+
+/* Placeholder for now. */
+void
+coproc_flush ()
+{
+ coproc_dispose (&sh_coproc);
+}
+
+void
+coproc_close (cp)
+ struct coproc *cp;
+{
+ if (cp->c_rfd >= 0)
+ {
+ close (cp->c_rfd);
+ cp->c_rfd = -1;
+ }
+ if (cp->c_wfd >= 0)
+ {
+ close (cp->c_wfd);
+ cp->c_wfd = -1;
+ }
+ cp->c_rsave = cp->c_wsave = -1;
+}
+
+void
+coproc_closeall ()
+{
+ coproc_close (&sh_coproc);
+}
+
+void
+coproc_reap ()
+{
+ struct coproc *cp;
+
+ cp = &sh_coproc;
+ if (cp && (cp->c_flags & COPROC_DEAD))
+ coproc_dispose (cp);
+}
+
+void
+coproc_rclose (cp, fd)
+ struct coproc *cp;
+ int fd;
+{
+ if (cp->c_rfd >= 0 && cp->c_rfd == fd)
+ {
+ close (cp->c_rfd);
+ cp->c_rfd = -1;
+ }
+}
+
+void
+coproc_wclose (cp, fd)
+ struct coproc *cp;
+ int fd;
+{
+ if (cp->c_wfd >= 0 && cp->c_wfd == fd)
+ {
+ close (cp->c_wfd);
+ cp->c_wfd = -1;
+ }
+}
+
+void
+coproc_checkfd (cp, fd)
+ struct coproc *cp;
+ int fd;
+{
+ int update;
+
+ update = 0;
+ if (cp->c_rfd >= 0 && cp->c_rfd == fd)
+ update = cp->c_rfd = -1;
+ if (cp->c_wfd >= 0 && cp->c_wfd == fd)
+ update = cp->c_wfd = -1;
+ if (update)
+ coproc_setvars (cp);
+}
+
+void
+coproc_fdchk (fd)
+ int fd;
+{
+ coproc_checkfd (&sh_coproc, fd);
+}
+
+void
+coproc_fdclose (cp, fd)
+ struct coproc *cp;
+ int fd;
+{
+ coproc_rclose (cp, fd);
+ coproc_wclose (cp, fd);
+ coproc_setvars (cp);
+}
+
+void
+coproc_fdsave (cp)
+ struct coproc *cp;
+{
+ cp->c_rsave = cp->c_rfd;
+ cp->c_wsave = cp->c_wfd;
+}
+
+void
+coproc_fdrestore (cp)
+ struct coproc *cp;
+{
+ cp->c_rfd = cp->c_rsave;
+ cp->c_wfd = cp->c_wsave;
+}
+
+void
+coproc_pidchk (pid, status)
+ pid_t pid;
+{
+ struct coproc *cp;
+
+ cp = getcoprocbypid (pid);
+#if 0
+ if (cp)
+ itrace("coproc_pidchk: pid %d has died", pid);
+#endif
+ if (cp)
+ {
+ cp->c_status = status;
+ cp->c_flags |= COPROC_DEAD;
+ cp->c_flags &= ~COPROC_RUNNING;
+#if 0
+ coproc_dispose (cp);
+#endif
+ }
+}
+
+void
+coproc_setvars (cp)
+ struct coproc *cp;
+{
+ SHELL_VAR *v;
+ char *namevar, *t;
+ int l;
+#if defined (ARRAY_VARS)
+ arrayind_t ind;
+#endif
+
+ if (cp->c_name == 0)
+ return;
+
+ l = strlen (cp->c_name);
+ namevar = xmalloc (l + 16);
+
+#if defined (ARRAY_VARS)
+ v = find_variable (cp->c_name);
+ if (v == 0)
+ v = make_new_array_variable (cp->c_name);
+ if (array_p (v) == 0)
+ v = convert_var_to_array (v);
+
+ t = itos (cp->c_rfd);
+ ind = 0;
+ v = bind_array_variable (cp->c_name, ind, t, 0);
+ free (t);
+
+ t = itos (cp->c_wfd);
+ ind = 1;
+ bind_array_variable (cp->c_name, ind, t, 0);
+ free (t);
+#else
+ sprintf (namevar, "%s_READ", cp->c_name);
+ t = itos (cp->c_rfd);
+ bind_variable (namevar, t, 0);
+ free (t);
+ sprintf (namevar, "%s_WRITE", cp->c_name);
+ t = itos (cp->c_wfd);
+ bind_variable (namevar, t, 0);
+ free (t);
+#endif
+
+ sprintf (namevar, "%s_PID", cp->c_name);
+ t = itos (cp->c_pid);
+ bind_variable (namevar, t, 0);
+ free (t);
+
+ free (namevar);
+}
+
+void
+coproc_unsetvars (cp)
+ struct coproc *cp;
+{
+ int l;
+ char *namevar;
+
+ if (cp->c_name == 0)
+ return;
+
+ l = strlen (cp->c_name);
+ namevar = xmalloc (l + 16);
+
+ sprintf (namevar, "%s_PID", cp->c_name);
+ unbind_variable (namevar);
+
+#if defined (ARRAY_VARS)
+ unbind_variable (cp->c_name);
+#else
+ sprintf (namevar, "%s_READ", cp->c_name);
+ unbind_variable (namevar);
+ sprintf (namevar, "%s_WRITE", cp->c_name);
+ unbind_variable (namevar);
+#endif
+
+ free (namevar);
+}
+
+static int
+execute_coproc (command, pipe_in, pipe_out, fds_to_close)
+ COMMAND *command;
+ int pipe_in, pipe_out;
+ struct fd_bitmap *fds_to_close;
+{
+ int rpipe[2], wpipe[2], estat;
+ pid_t coproc_pid;
+ Coproc *cp;
+ char *tcmd;
+
+ /* XXX -- will require changes to handle multiple coprocs */
+ if (sh_coproc.c_pid != NO_PID)
+ {
+#if 0
+ internal_error ("execute_coproc: coproc [%d:%s] already exists", sh_coproc.c_pid, sh_coproc.c_name);
+ return (last_command_exit_value = EXECUTION_FAILURE);
+#else
+ internal_warning ("execute_coproc: coproc [%d:%s] still exists", sh_coproc.c_pid, sh_coproc.c_name);
+#endif
+ }
+ coproc_init (&sh_coproc);
+
+ command_string_index = 0;
+ tcmd = make_command_string (command);
+
+ sh_openpipe ((int *)&rpipe); /* 0 = parent read, 1 = child write */
+ sh_openpipe ((int *)&wpipe); /* 0 = child read, 1 = parent write */
+
+ coproc_pid = make_child (savestring (tcmd), 1);
+ if (coproc_pid == 0)
+ {
+ close (rpipe[0]);
+ close (wpipe[1]);
+
+ estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close);
+
+ fflush (stdout);
+ fflush (stderr);
+
+ exit (estat);
+ }
+
+ close (rpipe[1]);
+ close (wpipe[0]);
+
+ cp = coproc_alloc (command->value.Coproc->name, coproc_pid);
+ cp->c_rfd = rpipe[0];
+ cp->c_wfd = wpipe[1];
+
+ SET_CLOSE_ON_EXEC (cp->c_rfd);
+ SET_CLOSE_ON_EXEC (cp->c_wfd);
+
+ coproc_setvars (cp);
+
+#if 0
+ itrace ("execute_coproc: [%d] %s", coproc_pid, the_printed_command);
+#endif
+
+ close_pipes (pipe_in, pipe_out);
+#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
+ unlink_fifo_list ();
+#endif
+ stop_pipeline (1, (COMMAND *)NULL);
+ DESCRIBE_PID (coproc_pid);
+ run_pending_traps ();
+
+ return (EXECUTION_SUCCESS);
+}
+#endif
+
static int
execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
COMMAND *command;
@@ -1396,7 +2072,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
/* Make a pipeline between the two commands. */
if (pipe (fildes) < 0)
{
- sys_error ("pipe error");
+ sys_error (_("pipe error"));
#if defined (JOB_CONTROL)
terminate_current_pipeline ();
kill_current_pipeline ();
@@ -1480,6 +2156,7 @@ execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close)
UNBLOCK_CHILD (oset);
#endif
+ QUIT;
return (exec_result);
}
@@ -1491,7 +2168,8 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
{
REDIRECT *rp;
COMMAND *tc, *second;
- int ignore_return, exec_result;
+ int ignore_return, exec_result, was_error_trap, invert;
+ volatile int save_line_number;
ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
@@ -1521,6 +2199,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
tc->flags |= CMD_STDIN_REDIR;
exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close);
+ QUIT;
if (tc->flags & CMD_STDIN_REDIR)
tc->flags &= ~CMD_STDIN_REDIR;
@@ -1545,16 +2224,40 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
if (command->value.Connection->second)
command->value.Connection->second->flags |= CMD_IGNORE_RETURN;
}
+ executing_list++;
QUIT;
execute_command (command->value.Connection->first);
QUIT;
exec_result = execute_command_internal (command->value.Connection->second,
asynchronous, pipe_in, pipe_out,
fds_to_close);
+ executing_list--;
break;
case '|':
+ was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
+ invert = (command->flags & CMD_INVERT_RETURN) != 0;
+ ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
+
+ line_number_for_err_trap = line_number;
exec_result = execute_pipeline (command, asynchronous, pipe_in, pipe_out, fds_to_close);
+
+ if (was_error_trap && ignore_return == 0 && invert == 0 && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ save_line_number = line_number;
+ line_number = line_number_for_err_trap;
+ run_error_trap ();
+ line_number = save_line_number;
+ }
+
+ if (ignore_return == 0 && invert == 0 && exit_immediately_on_error && exec_result != EXECUTION_SUCCESS)
+ {
+ last_command_exit_value = exec_result;
+ run_pending_traps ();
+ jump_to_top_level (ERREXIT);
+ }
+
break;
case AND_AND:
@@ -1576,6 +2279,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
and the connector is OR_OR, then execute the second command,
otherwise return. */
+ executing_list++;
if (command->value.Connection->first)
command->value.Connection->first->flags |= CMD_IGNORE_RETURN;
@@ -1591,6 +2295,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
exec_result = execute_command (command->value.Connection->second);
}
+ executing_list--;
break;
default:
@@ -1629,7 +2334,7 @@ execute_for_command (for_command)
{
if (posixly_correct && interactive_shell == 0)
{
- last_command_exit_value = EX_USAGE;
+ last_command_exit_value = EX_BADUSAGE;
jump_to_top_level (ERREXIT);
}
return (EXECUTION_FAILURE);
@@ -2287,10 +2992,17 @@ execute_case_command (case_command)
if (match)
{
- if (clauses->action && ignore_return)
- clauses->action->flags |= CMD_IGNORE_RETURN;
- retval = execute_command (clauses->action);
- EXIT_CASE ();
+ do
+ {
+ if (clauses->action && ignore_return)
+ clauses->action->flags |= CMD_IGNORE_RETURN;
+ retval = execute_command (clauses->action);
+ }
+ while ((clauses->flags & CASEPAT_FALLTHROUGH) && (clauses = clauses->next));
+ if (clauses == 0 || (clauses->flags & CASEPAT_TESTNEXT) == 0)
+ EXIT_CASE ();
+ else
+ break;
}
QUIT;
@@ -2496,17 +3208,25 @@ execute_arith_command (arith_command)
#if defined (COND_COMMAND)
-static char *nullstr = "";
+static char * const nullstr = "";
static int
execute_cond_node (cond)
COND_COM *cond;
{
- int result, invert, patmatch, rmatch, mflags;
+ int result, invert, patmatch, rmatch, mflags, ignore;
char *arg1, *arg2;
invert = (cond->flags & CMD_INVERT_RETURN);
-
+ ignore = (cond->flags & CMD_IGNORE_RETURN);
+ if (ignore)
+ {
+ if (cond->left)
+ cond->left->flags |= CMD_IGNORE_RETURN;
+ if (cond->right)
+ cond->right->flags |= CMD_IGNORE_RETURN;
+ }
+
if (cond->type == COND_EXPR)
result = execute_cond_node (cond->left);
else if (cond->type == COND_OR)
@@ -2523,7 +3243,11 @@ execute_cond_node (cond)
}
else if (cond->type == COND_UNARY)
{
+ if (ignore)
+ comsub_ignore_return++;
arg1 = cond_expand_word (cond->left->op, 0);
+ if (ignore)
+ comsub_ignore_return--;
if (arg1 == 0)
arg1 = nullstr;
if (echo_command_at_execute)
@@ -2543,10 +3267,19 @@ execute_cond_node (cond)
cond->op->word[2] == '\0');
#endif
+ if (ignore)
+ comsub_ignore_return++;
arg1 = cond_expand_word (cond->left->op, 0);
+ if (ignore)
+ comsub_ignore_return--;
if (arg1 == 0)
arg1 = nullstr;
- arg2 = cond_expand_word (cond->right->op, patmatch||rmatch);
+ if (ignore)
+ comsub_ignore_return++;
+ arg2 = cond_expand_word (cond->right->op,
+ (rmatch && shell_compatibility_level > 31) ? 2 : (patmatch ? 1 : 0));
+ if (ignore)
+ comsub_ignore_return--;
if (arg2 == 0)
arg2 = nullstr;
@@ -2569,7 +3302,7 @@ execute_cond_node (cond)
int oe;
oe = extended_glob;
extended_glob = 1;
- result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP)
+ result = binary_test (cond->op->word, arg1, arg2, TEST_PATMATCH|TEST_ARITHEXP|TEST_LOCALE)
? EXECUTION_SUCCESS
: EXECUTION_FAILURE;
extended_glob = oe;
@@ -2606,7 +3339,6 @@ execute_cond_command (cond_command)
/* If we're in a function, update the line number information. */
if (variable_context && interactive_shell)
line_number -= function_line_number;
-
command_string_index = 0;
print_cond_command (cond_command);
@@ -2660,8 +3392,13 @@ execute_null_command (redirects, pipe_in, pipe_out, async)
int pipe_in, pipe_out, async;
{
int r;
+ int forcefork;
+ REDIRECT *rd;
- if (pipe_in != NO_PIPE || pipe_out != NO_PIPE || async)
+ for (forcefork = 0, rd = redirects; rd; rd = rd->next)
+ forcefork += rd->rflags & REDIR_VARASSIGN;
+
+ if (forcefork || pipe_in != NO_PIPE || pipe_out != NO_PIPE || async)
{
/* We have a null command, but we really want a subshell to take
care of it. Just fork, do piping and redirections, and exit. */
@@ -2672,6 +3409,11 @@ execute_null_command (redirects, pipe_in, pipe_out, async)
do_piping (pipe_in, pipe_out);
+#if defined (COPROCESS_SUPPORT)
+ coproc_closeall ();
+#endif
+
+ subshell_environment = 0;
if (async)
subshell_environment |= SUBSHELL_ASYNC;
if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
@@ -2721,11 +3463,13 @@ fix_assignment_words (words)
{
WORD_LIST *w;
struct builtin *b;
+ int assoc;
if (words == 0)
return;
b = 0;
+ assoc = 0;
for (w = words; w; w = w->next)
if (w->word->flags & W_ASSIGNMENT)
@@ -2739,7 +3483,39 @@ fix_assignment_words (words)
words->word->flags |= W_ASSNBLTIN;
}
w->word->flags |= (W_NOSPLIT|W_NOGLOB|W_TILDEEXP|W_ASSIGNARG);
+#if defined (ARRAY_VARS)
+ if (assoc)
+ w->word->flags |= W_ASSIGNASSOC;
+#endif
}
+#if defined (ARRAY_VARS)
+ /* Note that we saw an associative array option to a builtin that takes
+ assignment statements. This is a bit of a kludge. */
+ else if (w->word->word[0] == '-' && strchr (w->word->word, 'A'))
+ {
+ if (b == 0)
+ {
+ 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;
+ }
+ if (words->word->flags & W_ASSNBLTIN)
+ assoc = 1;
+ }
+#endif
+}
+
+/* Return 1 if the file found by searching $PATH for PATHNAME, defaulting
+ to PATHNAME, is a directory. Used by the autocd code below. */
+static int
+is_dirname (pathname)
+ char *pathname;
+{
+ char *temp;
+ temp = search_for_command (pathname);
+ return (temp ? file_isdir (temp) : file_isdir (pathname));
}
/* The meaty part of all the executions. We have to start hacking the
@@ -2763,7 +3539,7 @@ 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 && interactive_shell)
+ if (variable_context && interactive_shell && sourcelevel == 0)
line_number -= function_line_number;
/* Remember what this command line looks like at invocation. */
@@ -2791,7 +3567,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
#endif
first_word_quoted =
- simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0;
+ simple_command->words ? (simple_command->words->word->flags & W_QUOTED) : 0;
last_command_subst_pid = NO_PID;
old_last_async_pid = last_asynchronous_pid;
@@ -2839,6 +3615,9 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
do_piping (pipe_in, pipe_out);
pipe_in = pipe_out = NO_PIPE;
+#if defined (COPROCESS_SUPPORT)
+ coproc_closeall ();
+#endif
last_asynchronous_pid = old_last_async_pid;
}
@@ -2860,7 +3639,12 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
{
current_fds_to_close = fds_to_close;
fix_assignment_words (simple_command->words);
+ /* Pass the ignore return flag down to command substitutions */
+ if (simple_command->flags & CMD_IGNORE_RETURN) /* XXX */
+ comsub_ignore_return++;
words = expand_words (simple_command->words);
+ if (simple_command->flags & CMD_IGNORE_RETURN)
+ comsub_ignore_return--;
current_fds_to_close = (struct fd_bitmap *)NULL;
}
else
@@ -2974,6 +3758,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
}
#endif /* JOB_CONTROL */
+run_builtin:
/* Remember the name of this command globally. */
this_command_name = words->word->word;
@@ -2992,6 +3777,8 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (builtin || func)
{
+ if (builtin)
+ unwind_protect_int (executing_builtin); /* modified in execute_builtin */
if (already_forked)
{
/* reset_terminating_signals (); */ /* XXX */
@@ -3047,9 +3834,21 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
}
}
+ if (autocd && interactive && words->word && is_dirname (words->word->word))
+ {
+ words = make_word_list (make_word ("cd"), words);
+ xtrace_print_word_list (words, 0);
+ goto run_builtin;
+ }
+
if (command_line == 0)
command_line = savestring (the_printed_command_except_trap);
+#if defined (PROCESS_SUBSTITUTION)
+ if ((subshell_environment & SUBSHELL_COMSUB) && (simple_command->flags & CMD_NO_FORK) && fifos_pending() > 0)
+ simple_command->flags &= ~CMD_NO_FORK;
+#endif
+
execute_disk_command (words, simple_command->redirects, command_line,
pipe_in, pipe_out, async, fds_to_close,
simple_command->flags);
@@ -3097,18 +3896,35 @@ execute_builtin (builtin, words, flags, subshell)
{
int old_e_flag, result, eval_unwind;
int isbltinenv;
+ char *error_trap;
+#if 0
+ /* XXX -- added 12/11 */
+ terminate_immediately++;
+#endif
+
+ error_trap = 0;
old_e_flag = exit_immediately_on_error;
/* The eval builtin calls parse_and_execute, which does not know about
the setting of flags, and always calls the execution functions with
flags that will exit the shell on an error if -e is set. If the
eval builtin is being called, and we're supposed to ignore the exit
- value of the command, we turn the -e flag off ourselves, then
- restore it when the command completes. */
- if (subshell == 0 && builtin == eval_builtin && (flags & CMD_IGNORE_RETURN))
+ value of the command, we turn the -e flag off ourselves and disable
+ the ERR trap, then restore them when the command completes. This is
+ also a problem (as below) for the command and source/. builtins. */
+ if (subshell == 0 && (flags & CMD_IGNORE_RETURN) &&
+ (builtin == eval_builtin || builtin == command_builtin || builtin == source_builtin))
{
begin_unwind_frame ("eval_builtin");
unwind_protect_int (exit_immediately_on_error);
+ error_trap = TRAP_STRING (ERROR_TRAP);
+ if (error_trap)
+ {
+ error_trap = savestring (error_trap);
+ add_unwind_protect (xfree, error_trap);
+ add_unwind_protect (set_error_trap, error_trap);
+ restore_default_signal (ERROR_TRAP);
+ }
exit_immediately_on_error = 0;
eval_unwind = 1;
}
@@ -3145,6 +3961,7 @@ execute_builtin (builtin, words, flags, subshell)
add_unwind_protect (merge_temporary_env, (char *)NULL);
}
+ executing_builtin++;
result = ((*builtin) (words->next));
/* This shouldn't happen, but in case `return' comes back instead of
@@ -3158,9 +3975,19 @@ execute_builtin (builtin, words, flags, subshell)
if (eval_unwind)
{
exit_immediately_on_error += old_e_flag;
+ if (error_trap)
+ {
+ set_error_trap (error_trap);
+ xfree (error_trap);
+ }
discard_unwind_frame ("eval_builtin");
}
+#if 0
+ /* XXX -- added 12/11 */
+ terminate_immediately--;
+#endif
+
return (result);
}
@@ -3181,10 +4008,17 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
#endif
FUNCTION_DEF *shell_fn;
char *sfile, *t;
- static int funcnest = 0;
USE_VAR(fc);
+#if 0 /* for bash-4.2 */
+ if (funcnest_max > 0 && funcnest >= funcnest_max)
+ {
+ internal_error ("%s: maximum function nesting level exceeded (%d)", var->name, funcnest);
+ jump_to_top_level (DISCARD);
+ }
+#endif
+
#if defined (ARRAY_VARS)
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
@@ -3206,6 +4040,7 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
add_unwind_protect (dispose_command, (char *)tc);
unwind_protect_pointer (this_shell_function);
unwind_protect_int (loop_level);
+ unwind_protect_int (funcnest);
}
else
push_context (var->name, subshell, temporary_env); /* don't unwind-protect for subshells */
@@ -3347,7 +4182,6 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
if (subshell == 0)
run_unwind_frame ("function_calling");
- funcnest--;
#if defined (ARRAY_VARS)
/* These two variables cannot be unset, and cannot be affected by the
function. */
@@ -3362,8 +4196,13 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
#endif
if (variable_context == 0 || this_shell_function == 0)
- make_funcname_visible (0);
-
+ {
+ make_funcname_visible (0);
+#if defined (PROCESS_SUBSTITUTION)
+ unlink_fifo_list ();
+#endif
+ }
+
return (result);
}
@@ -3470,13 +4309,18 @@ execute_subshell_builtin_or_function (words, redirects, builtin, var,
else
{
r = execute_builtin (builtin, words, flags, 1);
+ fflush (stdout);
if (r == EX_USAGE)
r = EX_BADUSAGE;
exit (r);
}
}
else
- exit (execute_function (var, words, flags, fds_to_close, async, 1));
+ {
+ r = execute_function (var, words, flags, fds_to_close, async, 1);
+ fflush (stdout);
+ exit (r);
+ }
}
/* Execute a builtin or function in the current shell context. If BUILTIN
@@ -3536,6 +4380,8 @@ execute_builtin_or_function (words, builtin, var, redirects,
result = execute_function (var, words, flags, fds_to_close, 0, 0);
/* We do this before undoing the effects of any redirections. */
+ fflush (stdout);
+ fpurge (stdout);
if (ferror (stdout))
clearerr (stdout);
@@ -3605,6 +4451,12 @@ setup_async_signals ()
this gnarly hair, for no good reason.
NOTE: callers expect this to fork or exit(). */
+
+/* Name of a shell function to call when a command name is not found. */
+#ifndef NOTFOUND_HOOK
+# define NOTFOUND_HOOK "command_not_found_handle"
+#endif
+
static void
execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
async, fds_to_close, cmdflags)
@@ -3618,13 +4470,15 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
char *pathname, *command, **args;
int nofork;
pid_t pid;
+ SHELL_VAR *hookf;
+ WORD_LIST *wl;
nofork = (cmdflags & CMD_NO_FORK); /* Don't fork, just exec, if no pipes */
pathname = words->word->word;
#if defined (RESTRICTED_SHELL)
command = (char *)NULL;
- if (restricted && xstrchr (pathname, '/'))
+ if (restricted && mbschr (pathname, '/'))
{
internal_error (_("%s: restricted: cannot specify `/' in command names"),
pathname);
@@ -3714,26 +4568,15 @@ execute_disk_command (words, redirects, command_line, pipe_in, pipe_out,
if (command == 0)
{
- SHELL_VAR *f, *v;
- WORD_LIST *cmdlist;
- WORD_DESC *w;
- int fval;
- if( (posixly_correct || interactive_shell == 0) ||
- (f = find_function ("command_not_found_handle")) == 0)
+ hookf = find_function (NOTFOUND_HOOK);
+ if (hookf == 0)
{
internal_error (_("%s: command not found"), pathname);
- exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */
+ exit (EX_NOTFOUND); /* Posix.2 says the exit status is 127 */
}
- w = make_word("command_not_found_handle");
- cmdlist = make_word_list(w, (WORD_LIST*)NULL);
-
- w = make_word(pathname);
- cmdlist->next = make_word_list(w, (WORD_LIST*)NULL);
-
- fval = execute_shell_function (f, cmdlist);
- if (fval == EX_NOTFOUND)
- internal_error (_("%s: command not found"), pathname);
- exit(fval);
+
+ wl = make_word_list (make_word (NOTFOUND_HOOK), words);
+ exit (execute_shell_function (hookf, wl));
}
/* Execve expects the command name to be in args[0]. So we
@@ -3748,7 +4591,8 @@ 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)
- unlink_fifo_list ();
+ if (variable_context == 0)
+ unlink_fifo_list ();
#endif
FREE (command);
}
@@ -3893,9 +4737,13 @@ initialize_subshell ()
shell_variables = shell_variables->down;
clear_unwind_protect_list (0);
+ /* XXX -- are there other things we should be resetting here? */
+ parse_and_execute_level = 0; /* nothing left to restore it */
/* We're no longer inside a shell function. */
- variable_context = return_catch_flag = 0;
+ variable_context = return_catch_flag = funcnest = 0;
+
+ executing_list = 0; /* XXX */
/* If we're not interactive, close the file descriptor from which we're
reading the current shell script. */
@@ -3930,7 +4778,6 @@ shell_execve (command, args, env)
char *command;
char **args, **env;
{
- struct stat finfo;
int larray, i, fd;
char sample[80];
int sample_len;
@@ -3938,13 +4785,14 @@ shell_execve (command, args, env)
SETOSTYPE (0); /* Some systems use for USG/POSIX semantics */
execve (command, args, env);
i = errno; /* error from execve() */
+ CHECK_TERMSIG;
SETOSTYPE (1);
/* If we get to this point, then start checking out the file.
Maybe it is something we can hack ourselves. */
if (i != ENOEXEC)
{
- if ((stat (command, &finfo) == 0) && (S_ISDIR (finfo.st_mode)))
+ if (file_isdir (command))
internal_error (_("%s: is a directory"), command);
else if (executable_file (command) == 0)
{
@@ -4078,7 +4926,7 @@ execute_intern_function (name, function)
{
if (posixly_correct && interactive_shell == 0)
{
- last_command_exit_value = EX_USAGE;
+ last_command_exit_value = EX_BADUSAGE;
jump_to_top_level (ERREXIT);
}
return (EXECUTION_FAILURE);