- shell_execve: rearrange code so that we check for a bad interpreter
before printing a generic ENOENT error message. Report from
Kirill Elagin <kirelagin@gmail.com>
+
+ 10/12
+ -----
+lib/readline/callback.c
+ - CALLBACK_READ_RETURN: add an inlined call to RL_CHECK_SIGNALS so we
+ can handle any signals that arrived before we restored the calling
+ application's signal handlers. From a gdb dicussion with
+ Simon Marchi <simon.marchi@polymtl.ca>
+
+ 10/12
+ -----
+variables.c
+ - pop_var_context: flag an internal error for shell_variables not
+ pointing to a function context only if we haven't already flushed
+ all the local contexts and reset variable_context. This can happen
+ if errexit is enabled and we're going to be exiting the shell, but
+ we're running unwind-protects on our way out. Report from
+ Xavier Delaruelle <xavier.delaruelle@gmail.com>
+
+ 10/13
+ -----
+sig.c
+ - kill_shell: broke the code that resets the signal disposition to the
+ default and sends a terminating signal to the shell into a separate
+ function
+ - termsig_handler: set handling_termsig to terminating_signal and make
+ it file-scope so other functions know we're handling a terminating
+ signal and are about to exit, and which signal it is (latter not used
+ yet)
+ - termsig_sighandler: if we get a fatal signal while we're handling a
+ fatal signal, kill ourselves with the second fatal signal immediately.
+ Fixes issue reported by Andreas Schwab <schwab@suse.de>
+
+execute_cmd.c
+ - execute_case_command: call CHECK_TERMSIG after the call to strmatch,
+ since gmatch will return FNM_NOMATCH if there's a pending terminating
+ signal and we don't want incorrect results
+
+subst.c
+ - pat_subst: make sure REP is non-NULL before calling savestring on it.
+ Report from Justin Wood (Callek) <callek@gmail.com>
+
+ 10/14
+ -----
+builtins/{shopt.def,common.h}
+ - expand_aliases: split into a variable that holds the current state
+ of alias expansion (expand_aliases) and a variable that reflects the
+ global option value (expalias_flag), make sure expand_aliases is set
+ appropriately by shopt
+
+shell.c,execute_cmd.c,general.c
+ - expand_aliases: make sure expand_aliases and expalias_flag always
+ agree
+
+parser.h
+ - PST_STRING: new parser flag, set when parsing a string to a command
+ or word list
+
+parse.y
+ - reset_parser: if we're parsing a command substitution or a string,
+ and need to restore expand_aliases, make sure it's set to the value
+ of expalias_flag.
+ Fixes SIGINT during interactive command substitution parsing bug
+ reported by feng xiangjun <fengxj325@gmail.com>
+ - parse_string_to_word_list,parse_string_to_command: make sure to set
+ PST_STRING in parser_flags since we're resetting expand_aliases
extern int extglob_flag;
#endif
+extern int expaliases_flag;
+
/* variables from source.def */
extern int source_searches_cwd;
extern int source_uses_path;
char *ostring;
volatile sigset_t ps_sigmask;
+ /* unwind-protects common to this and parse_and_execute */
parse_prologue (string, flags, PS_TAG);
#if defined (HAVE_POSIX_SIGNALS)
static int shopt_set_extglob PARAMS((char *, int));
#endif
+int expaliases_flag = 0;
+static int shopt_set_expaliases PARAMS((char *, int));
+
static int shopt_set_debug_mode PARAMS((char *, int));
static int shopt_login_shell;
#endif
{ "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
{ "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
- { "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
+ { "expand_aliases", &expaliases_flag, shopt_set_expaliases },
#if defined (DEBUGGER)
{ "extdebug", &debugging_mode, shopt_set_debug_mode },
#endif
check_window_size = CHECKWINSIZE_DEFAULT;
allow_null_glob_expansion = glob_dot_filenames = 0;
no_exit_on_failed_exec = 0;
- expand_aliases = 0;
+ expand_aliases = expaliases_flag = 0;
extended_quote = 1;
fail_glob_expansion = 0;
glob_asciirange = GLOBASCII_DEFAULT;
return (0);
}
+static int
+shopt_set_expaliases (option_name, mode)
+ char *option_name;
+ int mode;
+{
+ expand_aliases = expaliases_flag;
+ return 0;
+}
+
#if defined (EXTENDED_GLOB)
static int
shopt_set_extglob (option_name, mode)
shopt_enable_hostname_completion (option_name, mode)
char *option_name;
int mode;
-
-
{
return (enable_hostname_completion (mode));
}
expansion with `shopt -s expand_alias' to continue to expand
aliases. */
if (ois != interactive_shell)
- expand_aliases = 0;
+ expand_aliases = expaliases_flag = 0;
}
/* Subshells are neither login nor interactive. */
free (pattern);
dispose_words (es);
+ CHECK_TERMSIG;
if (match)
{
{
&interactive_comments,
&source_uses_path,
- &expand_aliases,
+ &expaliases_flag,
&inherit_errexit,
&print_shift_error,
0
/* Things that should be turned on when posix mode is enabled. */
if (on != 0)
{
- interactive_comments = source_uses_path = expand_aliases = 1;
+ interactive_comments = source_uses_path = 1;
+ expand_aliases = expaliases_flag = 1;
inherit_errexit = 1;
source_searches_cwd = 0;
print_shift_error = 1;
else if (saved_posix_vars) /* on == 0, restore saved settings */
{
set_posix_options (saved_posix_vars);
+ expand_aliases = expaliases_flag;
free (saved_posix_vars);
saved_posix_vars = 0;
}
else /* on == 0, restore a default set of settings */
{
source_searches_cwd = 1;
- expand_aliases = interactive_shell;
+ expand_aliases = expaliases_flag = interactive_shell; /* XXX */
print_shift_error = 0;
}
}
#define CALLBACK_READ_RETURN() \
do { \
if (rl_persistent_signal_handlers == 0) \
- rl_clear_signals (); \
+ { \
+ rl_clear_signals (); \
+ if (_rl_caught_signal) _rl_signal_handler (_rl_caught_signal); \
+ } \
return; \
} while (0)
#else
if (parser_state & (PST_EXTPAT|PST_CMDSUBST))
extended_glob = extglob_flag;
#endif
+ if (parser_state & (PST_CMDSUBST|PST_STRING))
+ expand_aliases = expaliases_flag;
parser_state = 0;
here_doc_first_line = 0;
if (flags & SX_COMPLETE)
parser_state |= PST_NOERROR;
+ parser_state |= PST_STRING;
expand_aliases = 0;
cmd = 0;
/* State flags we don't want to persist into compound assignments. */
parser_state &= ~PST_NOEXPAND; /* parse_comsub sentinel */
/* State flags we want to set for this run through the tokenizer. */
- parser_state |= PST_COMPASSIGN|PST_REPARSE;
+ parser_state |= PST_COMPASSIGN|PST_REPARSE|PST_STRING;
}
while ((tok = read_token (READ)) != yacc_EOF)
#define PST_ENDALIAS 0x200000 /* just finished expanding and consuming an alias */
#define PST_NOEXPAND 0x400000 /* don't expand anything in read_token_word; for command substitution */
#define PST_NOERROR 0x800000 /* don't print error messages in yyerror */
+#define PST_STRING 0x1000000 /* parsing a string to a command or word list */
/* Definition of the delimiter stack. Needed by parse.y and bashhist.c. */
struct dstack {
static void
init_interactive ()
{
- expand_aliases = interactive_shell = startup_state = 1;
- interactive = 1;
+ expand_aliases = expaliases_flag = 1;
+ interactive_shell = startup_state = interactive = 1;
#if defined (HISTORY)
if (enable_history_list == -1)
enable_history_list = 1; /* set default */
bash_history_reinit (0);
#endif /* HISTORY */
interactive_shell = startup_state = interactive = 0;
- expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */
+ expand_aliases = expaliases_flag = posixly_correct; /* XXX - was 0 not posixly_correct */
no_line_editing = 1;
#if defined (JOB_CONTROL)
/* Even if the shell is not interactive, enable job control if the -i or
enable_history_list = 1;
#endif
init_noninteractive ();
- expand_aliases = interactive_shell = startup_state = 1;
+ expand_aliases = expaliases_flag = interactive_shell = startup_state = 1;
#if defined (HISTORY)
remember_on_history = enable_history_list; /* XXX */
#endif
debugging = do_version = line_number = last_command_exit_value = 0;
forced_interactive = interactive_shell = 0;
subshell_environment = running_in_background = 0;
- expand_aliases = 0;
+ expand_aliases = expaliases_flag = 0;
bash_argv_initialized = 0;
/* XXX - should we set jobs_m_flag to 0 here? */
#endif
static void initialize_shell_signals PARAMS((void));
+static void kill_shell PARAMS((int));
void
initialize_signals (reinit)
#endif
}
+static int handling_termsig = 0;
+
sighandler
termsig_sighandler (sig)
int sig;
sig == terminating_signal)
terminate_immediately = 1;
+ /* If we are currently handling a terminating signal, we have a couple of
+ choices here. We can ignore this second terminating signal and let the
+ shell exit from the first one, or we can exit immediately by killing
+ the shell with this signal. This code implements the latter; to implement
+ the former, replace the kill_shell(sig) with return. */
+ if (handling_termsig)
+ kill_shell (sig); /* just short-circuit now */
+
terminating_signal = sig;
if (terminate_immediately)
termsig_handler (sig)
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
block multiple occurrences of the terminating signals while running. */
if (handling_termsig)
return;
- handling_termsig = 1;
+
+ handling_termsig = terminating_signal; /* for termsig_sighandler */
terminating_signal = 0; /* keep macro from re-testing true. */
/* I don't believe this condition ever tests true. */
run_exit_trap (); /* XXX - run exit trap possibly in signal context? */
+ kill_shell (sig);
+}
+
+static void
+kill_shell (sig)
+ int sig;
+{
+ int i, core;
+ sigset_t mask;
+
/* 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). What we do is to restore the
if (dollar_dollar_pid != 1)
exit (128+sig); /* just in case the kill fails? */
- /* We get here only under extraordinary circumstances. */
+ /* We get here only under extraordinarily rare circumstances. */
/* 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
if (value)
{
t = (value->next) ? string_list (value) : value->word->word;
- ret = quote_string_for_repl (t, quoted);
+ ret = t ? quote_string_for_repl (t, quoted) : t;
if (t != value->word->word)
free (t);
dispose_words (value);
return (ret);
}
else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0))
- return ((mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2) : savestring (rep));
+ return (mflags & MATCH_EXPREP) ? strcreplace (rep, '&', "", 2)
+ : (rep ? savestring (rep) : savestring (""));
ret = (char *)xmalloc (rsize = 64);
ret[0] = '\0';
# in the right place
builtin cd "$MYDIR"
+# seg fault in bash-5.2
+foo=
+foo=${foo/#*([.])}
+unset foo
+
${THIS_SH} ./extglob1.sub
${THIS_SH} ./extglob1a.sub
${THIS_SH} ./extglob3.sub
vcxt = shell_variables;
if (vc_isfuncenv (vcxt) == 0)
{
- internal_error (_("pop_var_context: head of shell_variables not a function context"));
+ /* If we haven't flushed all of the local contexts already, flag an error */
+ if (shell_variables != global_variables || variable_context > 0)
+ internal_error (_("pop_var_context: head of shell_variables not a function context"));
return;
}