extern int errno;
#endif
+#define NEED_FPURGE_DECL
+
#include "bashansi.h"
#include "bashintl.h"
extern int expand_aliases;
extern int autocd;
extern int breaking, continuing, loop_level;
-extern int parse_and_execute_level, running_trap;
+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;
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
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;
#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
{
int user_subshell, return_code, function_value, should_redir_stdin, invert;
int ois, user_coproc;
+ int result;
COMMAND *tcom;
USE_VAR(user_subshell);
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);
int pipe_in, pipe_out;
struct fd_bitmap *fds_to_close;
{
- int rpipe[2], wpipe[2];
+ int rpipe[2], wpipe[2], estat;
pid_t coproc_pid;
Coproc *cp;
char *tcmd;
close (rpipe[0]);
close (wpipe[1]);
- exit (execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close));
+ estat = execute_in_subshell (command, 1, wpipe[0], rpipe[1], fds_to_close);
+
+ fflush (stdout);
+ fflush (stderr);
+
+ exit (estat);
}
close (rpipe[1]);
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)
}
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)
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;
+ 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;
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;
/* 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);
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. */
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. */
{
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. This is also a problem (as
- below) for the command and source/. builtins. */
+ 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;
}
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");
}
#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);
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 */
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. */
#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);
}
#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);
/* 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);
}
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 */