to the flags passed to quote_string_for_globbing. Same issue as the
one with `case' fixed on 4/7, report from Martijn Dekker
<martijn@inlv.org>
+
+ 4/30
+ ----
+redir.c
+ - do_redirection_internal: r_close_this: if the file descriptor is
+ already closed before the shell is asked to close it, make sure to
+ add an undo list redirect to make sure it stays closed. Report from
+ Martijn Dekker <martijn@inlv.org>
+
+ 5/2
+ ---
+variables.c
+ - push_posix_temp_var: new function, takes the SHELL_VAR * passed as
+ an argument and uses the name and value to create a global variable
+ - merge_temporary_env: if posixly_correct is set, call
+ push_posix_temp_var to create global variables, otherwise call
+ push_temp_var to preserve the old behavior. Right now, it's only
+ called when in posix mode, but that might change. This undoes the
+ change from 4/27 when in posix mode
+
+ 5/3
+ ---
+sig.c
+ - struct that holds the terminating signal information has a new
+ field: whether that signal is expected to cause a core dump
+ - termsig_handler: if the call to kill(2) doesn't kill the process,
+ we have a problem. If our pid is not 1, we just exit with status
+ 128+sig (fake the sig exit status). If the pid is 1, we assume
+ we're in a Linux pid namespace and aren't allowed to send a signal
+ to ourselves. If we need to generate a core dump, we try to get
+ the kernel to SIGSEGV us by dereferencing location 0. If not, we
+ just exit with 128+sig. From a report and patch from Andrei Vagin
+ <avagin@virtuozzo.com>
+
+ 5/4
+ ---
+bashline.c
+ - bash_execute_unix_command: make sure that parse_and_execute is called
+ with newly-allocated memory to avoid prematurely freeing the
+ command. Report and fix from Koichi Murase <myoga.murase@gmail.com>
array_needs_making = 1;
save_parser_state (&ps);
- r = parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
+ r = parse_and_execute (savestring (cmd), "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE);
restore_parser_state (&ps);
v = find_variable ("READLINE_LINE");
Exit Status:
Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is
-not a shell builtin..
+not a shell builtin.
$END
#include <config.h>
of consecutive @code{EOF} characters that can be read as the
first character on an input line
before the shell will exit. If the variable exists but does not
-have a numeric value (or has no value) then the default is 10.
+have a numeric value, or has no value, then the default is 10.
If the variable does not exist, then @code{EOF} signifies the end of
input to the shell. This is only in effect for interactive shells.
r = 0;
/* XXX - only if REDIR_VARASSIGN not set? */
- if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1))
+ if (flags & RX_UNDOABLE)
{
- r = add_undo_redirect (redirector, ri, -1);
+ if (fcntl (redirector, F_GETFD, 0) != -1)
+ r = add_undo_redirect (redirector, ri, -1);
+ else
+ r = add_undo_close_redirect (redirector);
REDIRECTION_ERROR (r, errno, redirector);
}
/* sig.c - interface for shell signal handlers and signal initialization. */
-/* Copyright (C) 1994-2015 Free Software Foundation, Inc.
+/* Copyright (C) 1994-2018 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
int signum;
SigHandler *orig_handler;
int orig_flags;
+ int core_dump;
};
#define NULL_HANDLER (SigHandler *)SIG_DFL
#endif
#ifdef SIGILL
-{ SIGILL, NULL_HANDLER, 0 },
+{ SIGILL, NULL_HANDLER, 0, 1},
#endif
#ifdef SIGTRAP
-{ SIGTRAP, NULL_HANDLER, 0 },
+{ SIGTRAP, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGIOT
-{ SIGIOT, NULL_HANDLER, 0 },
+{ SIGIOT, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGDANGER
#endif
#ifdef SIGFPE
-{ SIGFPE, NULL_HANDLER, 0 },
+{ SIGFPE, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGBUS
-{ SIGBUS, NULL_HANDLER, 0 },
+{ SIGBUS, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGSEGV
-{ SIGSEGV, NULL_HANDLER, 0 },
+{ SIGSEGV, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGSYS
-{ SIGSYS, NULL_HANDLER, 0 },
+{ SIGSYS, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGPIPE
{ SIGTERM, NULL_HANDLER, 0 },
#endif
+/* These don't generate core dumps on anything but Linux, but we're doing
+ this just for Linux anyway. */
#ifdef SIGXCPU
-{ SIGXCPU, NULL_HANDLER, 0 },
+{ SIGXCPU, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGXFSZ
-{ SIGXFSZ, NULL_HANDLER, 0 },
+{ SIGXFSZ, NULL_HANDLER, 0, 1 },
#endif
#ifdef SIGVTALRM
#define XSIG(x) (terminating_signals[x].signum)
#define XHANDLER(x) (terminating_signals[x].orig_handler)
#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
+#define XCOREDUMP(x) (terminating_signals[x].core_dump)
static int termsigs_initialized = 0;
termsigs_initialized = 0;
}
-#undef XSIG
#undef XHANDLER
/* Run some of the cleanups that should be performed when we run
int sig;
{
static int handling_termsig = 0;
+ int i, core;
+ sigset_t mask;
/* Simple semaphore to keep this function from being executed multiple
times. Since we no longer are running as a signal handler, we don't
executing_list = comsub_ignore_return = return_catch_flag = wait_intr_flag = 0;
run_exit_trap (); /* XXX - run exit trap possibly in signal context? */
+
+ /* We don't change the set of blocked signals. If a user starts the shell
+ with a terminating signal blocked, we won't get here (and if by some
+ magic chance we do, we'll exit below). */
set_signal_handler (sig, SIG_DFL);
+
kill (getpid (), sig);
- exit (1); /* just in case the kill fails? */
+ if (dollar_dollar_pid != 1)
+ exit (128+sig); /* just in case the kill fails? */
+
+ /* We are PID 1, and the kill above failed to kill the process. We assume
+ this means that we are running as an init process in a pid namespace
+ on Linux. In this case, we can't send ourselves a fatal signal, so we
+ determine whether or not we should have generated a core dump with the
+ kill call and attempt to trick the kernel into generating one if
+ necessary. */
+ sigprocmask (SIG_SETMASK, (sigset_t *)NULL, &mask);
+ for (i = core = 0; i < TERMSIGS_LENGTH; i++)
+ {
+ set_signal_handler (XSIG (i), SIG_DFL);
+ sigdelset (&mask, XSIG (i));
+ if (sig == XSIG (i))
+ core = XCOREDUMP (i);
+ }
+ sigprocmask (SIG_SETMASK, &mask, (sigset_t *)NULL);
+
+ if (core)
+ *((volatile unsigned long *) NULL) = 0xdead0000 + sig; /* SIGSEGV */
+
+ exit (128+sig);
}
+#undef XSIG
/* What we really do when SIGINT occurs. */
sighandler
-BUILD_DIR=/usr/local/build/bash/bash-current
+BUILD_DIR=/usr/local/build/chet/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
test2
test3
test4
- 8
+8
test5
test6
test7
l8r
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
intern
- 1
- 0
- 0
- 0
- 0
+1
+0
+0
+0
+0
extern
- 1
- 0
- 0
- 0
- 0
+1
+0
+0
+0
+0
123
# process substitution constructs that have caused problems in the past
+. ./test-glue-functions
eval cat <(echo test1)
eval "echo foo;cat" <(echo test2)
FN=$TMPDIR/bashtest-procsub-$$
cat >"$FN" <<EOF
-echo "test 12" | wc -c
+echo "test 12" | wc -c | _cut_leading_spaces
cat "\$1"
EOF
unset -f f1 f2
-moo() { ls -l "$1" >/dev/null; ls -l "$1" >/dev/null; }; moo >(true)
-moo() { ls -al "$1" >/dev/null; (true); ls -al "$1" >/dev/null; }; moo >(true)
-
-unset -f moo
+# set up conditions for test
+ulimit -n 256
bug()
{
}
echo intern
-count_lines <(date)
+count_lines <(date) | _cut_leading_spaces
unset -f count_lines
echo extern
wc -l < \$1
EOF
-${THIS_SH} -c "source $FN <(date)"
+${THIS_SH} -c "source $FN <(date)" | _cut_leading_spaces
rm -f $FN
+moo() { ls -l "$1" >/dev/null; ls -l "$1" >/dev/null; }; moo >(true)
+moo() { ls -al "$1" >/dev/null; (true); ls -al "$1" >/dev/null; }; moo >(true)
+
+unset -f moo
+
${THIS_SH} ./procsub1.sub
sed -e 's/[[:space:]]\{1,\}/ /g' -e 's/[[:space:]]*$//'
}
-
+# avoid whitespace differences in wc implementations
+_cut_leading_spaces()
+{
+ sed -e 's/^[[:space:]]*//g'
+}
declare -A foo=([one]="one" [zero]="zero" )
declare -a bar=([0]="zero" [1]="one")
./varenv11.sub: line 29: a: readonly variable
+foo=abc
a=z
a=b
a=z
static SHELL_VAR *find_variable_last_nameref_context __P((SHELL_VAR *, VAR_CONTEXT *, VAR_CONTEXT **));
static SHELL_VAR *bind_tempenv_variable __P((const char *, char *));
+static void push_posix_temp_var __P((PTR_T));
static void push_temp_var __P((PTR_T));
static void propagate_temp_var __P((PTR_T));
static void dispose_temporary_env __P((sh_free_func_t *));
char **tempvar_list;
int tvlist_ind;
+/* Take a variable from an assignment statement preceding a posix special
+ builtin (including `return') and create a global variable from it. This
+ is called from merge_temporary_env, which is only called when in posix
+ mode. */
+static void
+push_posix_temp_var (data)
+ PTR_T data;
+{
+ SHELL_VAR *var, *v;
+ HASH_TABLE *binding_table;
+
+ var = (SHELL_VAR *)data;
+
+ binding_table = global_variables->table;
+ if (binding_table == 0)
+ binding_table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS);
+
+ v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP);
+
+ /* global variables are no longer temporary and don't need propagating. */
+ var->attributes &= ~(att_tempvar|att_propagate);
+ if (v)
+ v->attributes |= var->attributes;
+
+ if (find_special_var (var->name) >= 0)
+ tempvar_list[tvlist_ind++] = savestring (var->name);
+
+ dispose_variable (var);
+}
+
/* Push the variable described by (SHELL_VAR *)DATA down to the next
- variable context from the temporary environment. */
+ variable context from the temporary environment. This can be called
+ from one context:
+ 1. propagate_temp_var: which is called to propagate variables in
+ assignments like `var=value declare -x var' to the surrounding
+ scope.
+
+ In this case, the variable should have the att_propagate flag set and
+ we can create variables in the current scope.
+*/
static void
push_temp_var (data)
PTR_T data;
v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP);
/* XXX - should we set the context here? It shouldn't matter because of how
- assign_in_env works, but might want to check. */
+ assign_in_env works, but we do it anyway. */
if (v)
v->context = shell_variables->scope;
dispose_variable (var);
}
+/* Take a variable described by DATA and push it to the surrounding scope if
+ the PROPAGATE attribute is set. That gets set by push_temp_var if we are
+ taking a variable like `var=value declare -x var' and propagating it to
+ the enclosing scope. */
static void
propagate_temp_var (data)
PTR_T data;
}
/* Take all of the shell variables in the temporary environment HASH_TABLE
- and make shell variables from them at the current variable context. */
+ and make shell variables from them at the current variable context.
+ Right now, this is only called in Posix mode to implement the historical
+ accident of creating global variables from assignment statements preceding
+ special builtins, but we check in case this acquires another caller later. */
void
merge_temporary_env ()
{
if (temporary_env)
- dispose_temporary_env (push_temp_var);
+ dispose_temporary_env (posixly_correct ? push_posix_temp_var : push_temp_var);
}
void
return (shell_variables = vc);
}
+/* This can be called from one of two code paths:
+ 1. pop_scope, which implements the posix rules for propagating variable
+ assignments preceding special builtins to the surrounding scope.
+ 2. pop_var_context, which is called from pop_context and implements the
+ posix rules for propagating variable assignments preceding function
+ calls to the surrounding scope.
+
+ It takes variables out of a temporary environment hash table. We take the
+ variable in data
+*/
static void
push_func_var (data)
PTR_T data;
propagated, bind it in the previous scope before disposing it. */
/* XXX - This isn't exactly right, because all tempenv variables have the
export attribute set. */
-#if 0
- if (exported_p (var) || (var->attributes & att_propagate))
-#else
if (tempvar_p (var) && exported_p (var) && (var->attributes & att_propagate))
-#endif
{
var->attributes &= ~att_tempvar; /* XXX */
v = bind_variable_internal (var->name, value_cell (var), shell_variables->table, 0, 0);
dispose_variable (var);
}
+/* This is called to propagate variables in the temporary environment of a
+ special builtin (if IS_SPECIAL != 0) or exported variables that are the
+ result of a builtin like `source' or `command' that can operate on the
+ variables in its temporary environment. In the first case, we call
+ push_func_var, which does the right thing (for now) */
void
pop_scope (is_special)
int is_special;
{
VAR_CONTEXT *vcxt, *ret;
+ int is_bltinenv;
vcxt = shell_variables;
if (vc_istempscope (vcxt) == 0)
internal_error (_("pop_scope: head of shell_variables not a temporary environment scope"));
return;
}
+ is_bltinenv = vc_isbltnenv (vcxt); /* XXX - for later */
ret = vcxt->down;
if (ret)
#define regen_p(var) ((((var)->attributes) & (att_regenerate)))
#define tempvar_p(var) ((((var)->attributes) & (att_tempvar)))
+#define propagate_p(var) ((((var)->attributes) & (att_propagate)))
/* Variable names: lvalues */
#define name_cell(var) ((var)->name)