diff options
Diffstat (limited to 'execute_cmd.c')
-rw-r--r-- | execute_cmd.c | 1020 |
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); |