/* sig.c - interface for shell signal handlers and signal initialization. */
-/* Copyright (C) 1994-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1994-2013 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
#include "trap.h"
#include "builtins/common.h"
+#include "builtins/builtext.h"
#if defined (READLINE)
# include "bashline.h"
+# include <readline/readline.h>
#endif
#if defined (HISTORY)
extern int last_command_exit_value;
extern int last_command_exit_signal;
extern int return_catch_flag;
-extern int loop_level, continuing, breaking;
+extern int loop_level, continuing, breaking, funcnest;
extern int executing_list;
extern int comsub_ignore_return;
extern int parse_and_execute_level, shell_initialized;
+#if defined (HISTORY)
+extern int history_lines_this_session;
+#endif
+extern int no_line_editing;
+extern int wait_signal_received;
+extern sh_builtin_func_t *this_shell_builtin;
+
+extern void initialize_siglist ();
/* Non-zero after SIGINT. */
-volatile int interrupt_state = 0;
+volatile sig_atomic_t interrupt_state = 0;
/* Non-zero after SIGWINCH */
-volatile int sigwinch_received = 0;
+volatile sig_atomic_t sigwinch_received = 0;
+
+/* Non-zero after SIGTERM */
+volatile sig_atomic_t sigterm_received = 0;
/* Set to the value of any terminating signal received. */
-volatile int terminating_signal = 0;
+volatile sig_atomic_t terminating_signal = 0;
/* The environment at the top-level R-E loop. We use this in
the case of error return. */
/* Initialize signals that will terminate the shell to do some
unwind protection. For non-interactive shells, we only call
- this when a trap is defined for EXIT (0). */
+ this when a trap is defined for EXIT (0) or when trap is run
+ to display signal dispositions. */
void
initialize_terminating_signals ()
{
XSAFLAGS(i) = oact.sa_flags;
/* Don't do anything with signals that are ignored at shell entry
if the shell is not interactive. */
- if (!interactive_shell && XHANDLER (i) == SIG_IGN)
+ /* XXX - should we do this for interactive shells, too? */
+ if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
{
sigaction (XSIG (i), &oact, &act);
- set_signal_ignored (XSIG (i));
+ set_signal_hard_ignored (XSIG (i));
}
#if defined (SIGPROF) && !defined (_MINIX)
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
XSAFLAGS(i) = 0;
/* Don't do anything with signals that are ignored at shell entry
if the shell is not interactive. */
- if (!interactive_shell && XHANDLER (i) == SIG_IGN)
+ /* XXX - should we do this for interactive shells, too? */
+ if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
{
signal (XSIG (i), SIG_IGN);
- set_signal_ignored (XSIG (i));
+ set_signal_hard_ignored (XSIG (i));
}
#ifdef SIGPROF
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
if (interactive)
{
set_signal_handler (SIGINT, sigint_sighandler);
- set_signal_handler (SIGTERM, SIG_IGN);
+ get_original_signal (SIGTERM);
+ if (signal_is_hard_ignored (SIGTERM) == 0)
+ set_signal_handler (SIGTERM, sigterm_sighandler);
set_sigwinch_handler ();
}
}
signal (XSIG (i), XHANDLER (i));
}
#endif /* !HAVE_POSIX_SIGNALS */
+
+ termsigs_initialized = 0;
}
#undef XSIG
#undef XHANDLER
#endif /* PROCESS_SUBSTITUTION */
run_unwind_protects ();
- loop_level = continuing = breaking = 0;
+ loop_level = continuing = breaking = funcnest = 0;
executing_list = comsub_ignore_return = return_catch_flag = 0;
}
if (interrupt_state)
{
+ if (last_command_exit_value < 128)
+ last_command_exit_value = 128 + SIGINT;
print_newline = 1;
DELINTERRUPT;
}
#endif /* JOB_CONTROL */
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
- /* This should not be necessary on systems using sigsetjmp/siglongjmp. */
+ /* This needs to stay because jobs.c:make_child() uses it without resetting
+ the signal mask. */
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
#endif
#endif /* PROCESS_SUBSTITUTION */
run_unwind_protects ();
- loop_level = continuing = breaking = 0;
+ loop_level = continuing = breaking = funcnest = 0;
executing_list = comsub_ignore_return = return_catch_flag = 0;
if (interactive && print_newline)
termsig_sighandler (sig)
int sig;
{
+ /* If we get called twice with the same signal before handling it,
+ terminate right away. */
+ if (
+#ifdef SIGHUP
+ sig != SIGHUP &&
+#endif
+#ifdef SIGINT
+ sig != SIGINT &&
+#endif
+#ifdef SIGDANGER
+ sig != SIGDANGER &&
+#endif
+#ifdef SIGPIPE
+ sig != SIGPIPE &&
+#endif
+#ifdef SIGALRM
+ sig != SIGALRM &&
+#endif
+#ifdef SIGTERM
+ sig != SIGTERM &&
+#endif
+#ifdef SIGXCPU
+ sig != SIGXCPU &&
+#endif
+#ifdef SIGXFSZ
+ sig != SIGXFSZ &&
+#endif
+#ifdef SIGVTALRM
+ sig != SIGVTALRM &&
+#endif
+#ifdef SIGLOST
+ sig != SIGLOST &&
+#endif
+#ifdef SIGUSR1
+ sig != SIGUSR1 &&
+#endif
+#ifdef SIGUSR2
+ sig != SIGUSR2 &&
+#endif
+ sig == terminating_signal)
+ terminate_immediately = 1;
+
terminating_signal = sig;
/* XXX - should this also trigger when interrupt_immediately is set? */
if (terminate_immediately)
{
+#if defined (HISTORY)
+ /* XXX - will inhibit history file being written */
+# if defined (READLINE)
+ if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0))
+# endif
+ history_lines_this_session = 0;
+#endif
terminate_immediately = 0;
termsig_handler (sig);
}
+#if defined (READLINE)
+ /* Set the event hook so readline will call it after the signal handlers
+ finish executing, so if this interrupted character input we can get
+ quick response. */
+ if (interactive_shell && interactive && no_line_editing == 0)
+ bashline_set_event_hook ();
+#endif
+
SIGRETURN (0);
}
run_interrupt_trap ();
#if defined (HISTORY)
- if (interactive_shell && sig != SIGABRT)
+ /* If we don't do something like this, the history will not be saved when
+ an interactive shell is running in a terminal window that gets closed
+ with the `close' button. We can't test for RL_STATE_READCMD because
+ readline no longer handles SIGTERM synchronously. */
+ if (interactive_shell && interactive && (sig == SIGHUP || sig == SIGTERM) && remember_on_history)
maybe_save_shell_history ();
#endif /* HISTORY */
#if defined (JOB_CONTROL)
- if (interactive && sig == SIGHUP)
+ if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
hangup_all_jobs ();
end_job_control ();
#endif /* JOB_CONTROL */
#endif /* PROCESS_SUBSTITUTION */
/* Reset execution context */
- loop_level = continuing = breaking = 0;
+ loop_level = continuing = breaking = funcnest = 0;
executing_list = comsub_ignore_return = return_catch_flag = 0;
- run_exit_trap ();
+ run_exit_trap (); /* XXX - run exit trap possibly in signal context? */
set_signal_handler (sig, SIG_DFL);
kill (getpid (), sig);
}
if (interrupt_state == 0)
ADDINTERRUPT;
+ /* We will get here in interactive shells with job control active; allow
+ an interactive wait to be interrupted. */
+ if (this_shell_builtin && this_shell_builtin == wait_builtin)
+ {
+ last_command_exit_value = 128 + sig;
+ wait_signal_received = sig;
+ SIGRETURN (0);
+ }
+
if (interrupt_immediately)
{
interrupt_immediately = 0;
+ last_command_exit_value = 128 + sig;
throw_to_top_level ();
}
+#if defined (READLINE)
+ /* Set the event hook so readline will call it after the signal handlers
+ finish executing, so if this interrupted character input we can get
+ quick response. */
+ else if (RL_ISSTATE (RL_STATE_SIGHANDLER))
+ bashline_set_event_hook ();
+#endif
SIGRETURN (0);
}
#endif
}
+sighandler
+sigterm_sighandler (sig)
+ int sig;
+{
+ sigterm_received = 1; /* XXX - counter? */
+ SIGRETURN (0);
+}
+
/* Signal functions used by the rest of the code. */
#if !defined (HAVE_POSIX_SIGNALS)
-#if defined (JOB_CONTROL)
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
sigprocmask (operation, newset, oldset)
int operation, *newset, *oldset;
break;
case SIG_SETMASK:
- sigsetmask (new);
+ old = sigsetmask (new);
break;
default:
if (oldset)
*oldset = old;
}
-#endif /* JOB_CONTROL */
#else
act.sa_handler = handler;
act.sa_flags = 0;
-#if 0
- if (sig == SIGALRM)
- act.sa_flags |= SA_INTERRUPT; /* XXX */
- else
+
+ /* XXX - bash-4.2 */
+ /* We don't want a child death to interrupt interruptible system calls, even
+ if we take the time to reap children */
+#if defined (SIGCHLD)
+ if (sig == SIGCHLD)
act.sa_flags |= SA_RESTART; /* XXX */
#endif
+ /* If we're installing a SIGTERM handler for interactive shells, we want
+ it to be as close to SIG_IGN as possible. */
+ if (sig == SIGTERM && handler == sigterm_sighandler)
+ act.sa_flags |= SA_RESTART; /* XXX */
+
sigemptyset (&act.sa_mask);
sigemptyset (&oact.sa_mask);
- sigaction (sig, &act, &oact);
- return (oact.sa_handler);
+ if (sigaction (sig, &act, &oact) == 0)
+ return (oact.sa_handler);
+ else
+ return (SIG_DFL);
}
#endif /* HAVE_POSIX_SIGNALS */