2016-05-04 04:02:26 +08:00
|
|
|
// The library for various signal related issues.
|
2016-05-19 06:30:21 +08:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
|
|
|
|
2005-10-06 19:54:16 +08:00
|
|
|
#include <errno.h>
|
2016-05-04 04:02:26 +08:00
|
|
|
#include <signal.h>
|
|
|
|
#include <stdio.h>
|
2006-07-31 04:26:59 +08:00
|
|
|
#ifdef HAVE_SIGINFO_H
|
|
|
|
#include <siginfo.h>
|
|
|
|
#endif
|
2016-04-21 14:00:54 +08:00
|
|
|
#include <pthread.h>
|
2006-07-31 04:26:59 +08:00
|
|
|
|
2005-10-06 15:30:50 +08:00
|
|
|
#include "common.h"
|
|
|
|
#include "event.h"
|
2016-05-04 04:02:26 +08:00
|
|
|
#include "fallback.h" // IWYU pragma: keep
|
2005-10-06 15:30:50 +08:00
|
|
|
#include "proc.h"
|
2016-05-04 04:02:26 +08:00
|
|
|
#include "reader.h"
|
|
|
|
#include "wutil.h" // IWYU pragma: keep
|
2006-07-20 06:55:49 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
// This is a temporary var while we explore whether signal_block() and friends is needed.
|
2017-02-26 13:06:30 +08:00
|
|
|
bool ignore_signal_block = false;
|
2016-12-29 10:52:33 +08:00
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Struct describing an entry for the lookup table used to convert between signal names and signal
|
|
|
|
/// ids, etc.
|
|
|
|
struct lookup_entry {
|
|
|
|
/// Signal id.
|
2012-11-19 08:30:30 +08:00
|
|
|
int signal;
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Signal name.
|
2012-11-19 08:30:30 +08:00
|
|
|
const wchar_t *name;
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Signal description.
|
2012-11-19 08:30:30 +08:00
|
|
|
const wchar_t *desc;
|
2005-10-06 15:30:50 +08:00
|
|
|
};
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// The number of signal blocks in place. Increased by signal_block, decreased by signal_unblock.
|
|
|
|
static int block_count = 0;
|
2006-02-09 23:50:20 +08:00
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Lookup table used to convert between signal names and signal ids, etc.
|
|
|
|
static const struct lookup_entry lookup[] = {
|
2006-05-15 00:39:36 +08:00
|
|
|
#ifdef SIGHUP
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGHUP, L"SIGHUP", N_(L"Terminal hung up")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGINT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGINT, L"SIGINT", N_(L"Quit request from job control (^C)")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGQUIT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGQUIT, L"SIGQUIT", N_(L"Quit request from job control with core dump (^\\)")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGILL
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGILL, L"SIGILL", N_(L"Illegal instruction")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGTRAP
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGTRAP, L"SIGTRAP", N_(L"Trace or breakpoint trap")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGABRT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGABRT, L"SIGABRT", N_(L"Abort")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGBUS
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGBUS, L"SIGBUS", N_(L"Misaligned address error")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGFPE
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGFPE, L"SIGFPE", N_(L"Floating point exception")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGKILL
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGKILL, L"SIGKILL", N_(L"Forced quit")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGUSR1
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGUSR1, L"SIGUSR1", N_(L"User defined signal 1")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGUSR2
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGUSR2, L"SIGUSR2", N_(L"User defined signal 2")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGSEGV
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGSEGV, L"SIGSEGV", N_(L"Address boundary error")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGPIPE
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGPIPE, L"SIGPIPE", N_(L"Broken pipe")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGALRM
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGALRM, L"SIGALRM", N_(L"Timer expired")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGTERM
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGTERM, L"SIGTERM", N_(L"Polite quit request")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGCHLD
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGCHLD, L"SIGCHLD", N_(L"Child process status changed")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGCONT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGCONT, L"SIGCONT", N_(L"Continue previously stopped process")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGSTOP
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGSTOP, L"SIGSTOP", N_(L"Forced stop")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGTSTP
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGTSTP, L"SIGTSTP", N_(L"Stop request from job control (^Z)")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGTTIN
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGTTIN, L"SIGTTIN", N_(L"Stop from terminal input")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGTTOU
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGTTOU, L"SIGTTOU", N_(L"Stop from terminal output")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGURG
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGURG, L"SIGURG", N_(L"Urgent socket condition")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
2012-06-10 18:36:02 +08:00
|
|
|
#ifdef SIGXCPU
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGXCPU, L"SIGXCPU", N_(L"CPU time limit exceeded")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
2006-01-19 02:40:46 +08:00
|
|
|
#ifdef SIGXFSZ
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGXFSZ, L"SIGXFSZ", N_(L"File size limit exceeded")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
2006-05-15 00:39:36 +08:00
|
|
|
#ifdef SIGVTALRM
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGVTALRM, L"SIGVTALRM", N_(L"Virtual timer expired")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
2006-01-19 02:40:46 +08:00
|
|
|
#ifdef SIGPROF
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGPROF, L"SIGPROF", N_(L"Profiling timer expired")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGWINCH
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGWINCH, L"SIGWINCH", N_(L"Window size change")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGWIND
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGWIND, L"SIGWIND", N_(L"Window size change")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
2006-08-01 08:25:50 +08:00
|
|
|
#ifdef SIGIO
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGIO, L"SIGIO", N_(L"I/O on asynchronous file descriptor is possible")},
|
2006-05-15 00:39:36 +08:00
|
|
|
#endif
|
2005-10-06 15:30:50 +08:00
|
|
|
#ifdef SIGPWR
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGPWR, L"SIGPWR", N_(L"Power failure")},
|
2005-10-06 15:30:50 +08:00
|
|
|
#endif
|
2006-01-19 02:40:46 +08:00
|
|
|
#ifdef SIGSYS
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGSYS, L"SIGSYS", N_(L"Bad system call")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGINFO
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGINFO, L"SIGINFO", N_(L"Information request")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGSTKFLT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGSTKFLT, L"SISTKFLT", N_(L"Stack fault")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGEMT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGEMT, L"SIGEMT", N_(L"Emulator trap")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGIOT
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGIOT, L"SIGIOT", N_(L"Abort (Alias for SIGABRT)")},
|
2006-01-19 02:40:46 +08:00
|
|
|
#endif
|
|
|
|
#ifdef SIGUNUSED
|
2016-05-04 04:02:26 +08:00
|
|
|
{SIGUNUSED, L"SIGUNUSED", N_(L"Unused signal")},
|
2012-11-19 08:30:30 +08:00
|
|
|
#endif
|
2016-05-04 04:02:26 +08:00
|
|
|
{0, 0, 0}};
|
2005-10-06 15:30:50 +08:00
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Test if \c name is a string describing the signal named \c canonical.
|
|
|
|
static int match_signal_name(const wchar_t *canonical, const wchar_t *name) {
|
2016-10-02 08:21:40 +08:00
|
|
|
if (wcsncasecmp(name, L"sig", 3) == 0) name += 3;
|
2005-10-06 15:30:50 +08:00
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
return wcscasecmp(canonical + 3, name) == 0;
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
int wcs2sig(const wchar_t *str) {
|
2016-11-23 12:24:03 +08:00
|
|
|
for (int i = 0; lookup[i].desc; i++) {
|
2016-05-04 04:02:26 +08:00
|
|
|
if (match_signal_name(lookup[i].name, str)) {
|
2012-11-19 08:30:30 +08:00
|
|
|
return lookup[i].signal;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-23 12:24:03 +08:00
|
|
|
int res = fish_wcstoi(str);
|
|
|
|
if (errno || res < 0) return -1;
|
|
|
|
return res;
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
const wchar_t *sig2wcs(int sig) {
|
2016-10-02 08:21:40 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; lookup[i].desc; i++) {
|
2016-05-04 04:02:26 +08:00
|
|
|
if (lookup[i].signal == sig) {
|
2012-11-19 08:30:30 +08:00
|
|
|
return lookup[i].name;
|
|
|
|
}
|
|
|
|
}
|
2006-05-15 00:39:36 +08:00
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
return _(L"Unknown");
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
const wchar_t *signal_get_desc(int sig) {
|
2016-10-02 08:21:40 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; lookup[i].desc; i++) {
|
2016-05-04 04:02:26 +08:00
|
|
|
if (lookup[i].signal == sig) {
|
2012-11-19 08:30:30 +08:00
|
|
|
return _(lookup[i].desc);
|
|
|
|
}
|
|
|
|
}
|
2006-05-15 00:39:36 +08:00
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
return _(L"Unknown");
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Standard signal handler.
|
|
|
|
static void default_handler(int signal, siginfo_t *info, void *context) {
|
2016-10-10 05:38:26 +08:00
|
|
|
UNUSED(info);
|
|
|
|
UNUSED(context);
|
2016-05-04 04:02:26 +08:00
|
|
|
if (event_is_signal_observed(signal)) {
|
2012-11-19 08:30:30 +08:00
|
|
|
event_fire_signal(signal);
|
|
|
|
}
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-29 13:28:26 +08:00
|
|
|
#ifdef SIGWINCH
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Respond to a winch signal by checking the terminal size.
|
|
|
|
static void handle_winch(int sig, siginfo_t *info, void *context) {
|
2016-10-10 05:38:26 +08:00
|
|
|
UNUSED(info);
|
|
|
|
UNUSED(context);
|
2012-11-19 08:30:30 +08:00
|
|
|
common_handle_winch(sig);
|
|
|
|
default_handler(sig, 0, 0);
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
2016-05-29 13:28:26 +08:00
|
|
|
#endif
|
2005-10-06 15:30:50 +08:00
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Respond to a hup signal by exiting, unless it is caught by a shellscript function, in which case
|
|
|
|
/// we do nothing.
|
|
|
|
static void handle_hup(int sig, siginfo_t *info, void *context) {
|
2016-10-10 05:38:26 +08:00
|
|
|
UNUSED(info);
|
|
|
|
UNUSED(context);
|
2016-05-04 04:02:26 +08:00
|
|
|
if (event_is_signal_observed(SIGHUP)) {
|
2012-11-19 08:30:30 +08:00
|
|
|
default_handler(sig, 0, 0);
|
2016-05-04 04:02:26 +08:00
|
|
|
} else {
|
2012-11-19 08:30:30 +08:00
|
|
|
reader_exit(1, 1);
|
|
|
|
}
|
2006-05-14 18:16:23 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Handle sigterm. The only thing we do is restore the front process ID, then die.
|
|
|
|
static void handle_term(int sig, siginfo_t *info, void *context) {
|
2016-10-10 05:38:26 +08:00
|
|
|
UNUSED(sig);
|
|
|
|
UNUSED(info);
|
|
|
|
UNUSED(context);
|
2012-11-18 18:16:14 +08:00
|
|
|
restore_term_foreground_process_group();
|
|
|
|
signal(SIGTERM, SIG_DFL);
|
|
|
|
raise(SIGTERM);
|
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
/// Interactive mode ^C handler. Respond to int signal by setting interrupted-flag and stopping all
|
|
|
|
/// loops and conditionals.
|
|
|
|
static void handle_int(int sig, siginfo_t *info, void *context) {
|
2016-10-10 05:38:26 +08:00
|
|
|
reader_handle_sigint();
|
2012-11-19 08:30:30 +08:00
|
|
|
default_handler(sig, info, context);
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-10-02 08:21:40 +08:00
|
|
|
/// sigchld handler. Does notification and calls the handler in proc.c.
|
2016-05-04 04:02:26 +08:00
|
|
|
static void handle_chld(int sig, siginfo_t *info, void *context) {
|
2012-11-19 08:30:30 +08:00
|
|
|
job_handle_signal(sig, info, context);
|
|
|
|
default_handler(sig, info, context);
|
2005-10-06 19:54:16 +08:00
|
|
|
}
|
|
|
|
|
2017-01-22 06:07:54 +08:00
|
|
|
// We have a sigalarm handler that does nothing
|
|
|
|
// This is used in the signal torture test, to verify
|
|
|
|
// that we behave correctly when receiving lots of irrelevant signals
|
|
|
|
static void handle_sigalarm(int sig, siginfo_t *info, void *context) {
|
|
|
|
UNUSED(sig);
|
|
|
|
UNUSED(info);
|
|
|
|
UNUSED(context);
|
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
void signal_reset_handlers() {
|
2016-10-02 08:21:40 +08:00
|
|
|
int i;
|
|
|
|
|
2012-11-19 08:30:30 +08:00
|
|
|
struct sigaction act;
|
2016-05-04 04:02:26 +08:00
|
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
act.sa_flags = 0;
|
|
|
|
act.sa_handler = SIG_DFL;
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-10-02 08:21:40 +08:00
|
|
|
for (i = 0; lookup[i].desc; i++) {
|
2012-11-19 08:30:30 +08:00
|
|
|
sigaction(lookup[i].signal, &act, 0);
|
|
|
|
}
|
2005-10-06 19:54:16 +08:00
|
|
|
}
|
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
static void set_interactive_handlers() {
|
2012-11-19 08:30:30 +08:00
|
|
|
struct sigaction act;
|
2016-05-04 04:02:26 +08:00
|
|
|
sigemptyset(&act.sa_mask);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
// Interactive mode. Ignore interactive signals. We are a shell, we know what is best for
|
|
|
|
// the user.
|
|
|
|
act.sa_handler = SIG_IGN;
|
2012-11-19 08:30:30 +08:00
|
|
|
sigaction(SIGINT, &act, 0);
|
|
|
|
sigaction(SIGQUIT, &act, 0);
|
|
|
|
sigaction(SIGTSTP, &act, 0);
|
|
|
|
sigaction(SIGTTOU, &act, 0);
|
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
// We don't ignore SIGTTIN because we might send it to ourself.
|
|
|
|
act.sa_sigaction = &default_handler;
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGTTIN, &act, 0);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
act.sa_sigaction = &handle_int;
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGINT, &act, 0);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
// SIGTERM restores the terminal controlling process before dying.
|
|
|
|
act.sa_sigaction = &handle_term;
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGTERM, &act, 0);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
act.sa_sigaction = &handle_hup;
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGHUP, &act, 0);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2017-01-22 06:07:54 +08:00
|
|
|
// SIGALARM as part of our signal torture test
|
|
|
|
act.sa_sigaction = &handle_sigalarm;
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGALRM, &act, 0);
|
|
|
|
|
2007-01-21 23:01:14 +08:00
|
|
|
#ifdef SIGWINCH
|
2016-12-29 10:52:33 +08:00
|
|
|
act.sa_sigaction = &handle_winch;
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction(SIGWINCH, &act, 0);
|
2012-11-19 08:30:30 +08:00
|
|
|
#endif
|
2016-12-29 10:52:33 +08:00
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
static void set_non_interactive_handlers() {
|
|
|
|
struct sigaction act;
|
|
|
|
sigemptyset(&act.sa_mask);
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
// Non-interactive. Ignore interrupt, check exit status of processes to determine result
|
|
|
|
// instead.
|
|
|
|
act.sa_handler = SIG_IGN;
|
|
|
|
sigaction(SIGINT, &act, 0);
|
|
|
|
sigaction(SIGQUIT, &act, 0);
|
|
|
|
}
|
2012-11-19 08:30:30 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
/// Sets up appropriate signal handlers.
|
|
|
|
void signal_set_handlers() {
|
|
|
|
struct sigaction act;
|
|
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
|
|
|
|
// Ignore SIGPIPE. We'll detect failed writes and deal with them appropriately. We don't want
|
|
|
|
// this signal interrupting other syscalls or terminating us.
|
|
|
|
act.sa_handler = SIG_IGN;
|
|
|
|
sigaction(SIGPIPE, &act, 0);
|
|
|
|
|
|
|
|
// Whether or not we're interactive we want SIGCHLD to not interrupt restartable syscalls.
|
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
act.sa_sigaction = &handle_chld;
|
|
|
|
act.sa_flags = SA_SIGINFO | SA_RESTART;
|
|
|
|
if (sigaction(SIGCHLD, &act, 0)) {
|
|
|
|
wperror(L"sigaction");
|
|
|
|
FATAL_EXIT();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (shell_is_interactive()) {
|
|
|
|
set_interactive_handlers();
|
|
|
|
} else {
|
|
|
|
set_non_interactive_handlers();
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2005-10-06 15:30:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
void signal_handle(int sig, int do_handle) {
|
2012-11-19 08:30:30 +08:00
|
|
|
struct sigaction act;
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
// These should always be handled.
|
|
|
|
if ((sig == SIGINT) || (sig == SIGQUIT) || (sig == SIGTSTP) || (sig == SIGTTIN) ||
|
|
|
|
(sig == SIGTTOU) || (sig == SIGCHLD))
|
2012-11-19 08:30:30 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
sigemptyset(&act.sa_mask);
|
2016-05-04 04:02:26 +08:00
|
|
|
if (do_handle) {
|
2012-11-19 08:30:30 +08:00
|
|
|
act.sa_flags = SA_SIGINFO;
|
|
|
|
act.sa_sigaction = &default_handler;
|
2016-05-04 04:02:26 +08:00
|
|
|
} else {
|
2012-11-19 08:30:30 +08:00
|
|
|
act.sa_flags = 0;
|
|
|
|
act.sa_handler = SIG_DFL;
|
|
|
|
}
|
|
|
|
|
|
|
|
sigaction(sig, &act, 0);
|
2005-10-06 19:54:16 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
void get_signals_with_handlers(sigset_t *set) {
|
2012-08-15 15:57:56 +08:00
|
|
|
sigemptyset(set);
|
2016-05-04 04:02:26 +08:00
|
|
|
for (int i = 0; lookup[i].desc; i++) {
|
2012-08-15 15:57:56 +08:00
|
|
|
struct sigaction act = {};
|
2012-11-19 08:30:30 +08:00
|
|
|
sigaction(lookup[i].signal, NULL, &act);
|
2016-05-04 04:02:26 +08:00
|
|
|
if (act.sa_handler != SIG_DFL) sigaddset(set, lookup[i].signal);
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2012-08-15 15:57:56 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
void signal_block() {
|
2016-12-29 10:52:33 +08:00
|
|
|
if (ignore_signal_block) return;
|
|
|
|
|
2012-02-19 15:26:39 +08:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2012-11-19 08:30:30 +08:00
|
|
|
sigset_t chldset;
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
if (!block_count) {
|
2012-11-19 08:30:30 +08:00
|
|
|
sigfillset(&chldset);
|
2017-02-15 13:09:15 +08:00
|
|
|
DIE_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &chldset, NULL));
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
block_count++;
|
2016-12-29 10:52:33 +08:00
|
|
|
// debug( 0, L"signal block level increased to %d", block_count );
|
2005-10-14 19:40:33 +08:00
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
void signal_unblock() {
|
2016-12-29 10:52:33 +08:00
|
|
|
if (ignore_signal_block) return;
|
|
|
|
|
2012-02-19 15:26:39 +08:00
|
|
|
ASSERT_IS_MAIN_THREAD();
|
2012-11-19 08:30:30 +08:00
|
|
|
sigset_t chldset;
|
|
|
|
|
|
|
|
block_count--;
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
if (block_count < 0) {
|
2012-11-19 08:30:30 +08:00
|
|
|
debug(0, _(L"Signal block mismatch"));
|
|
|
|
bugreport();
|
|
|
|
FATAL_EXIT();
|
|
|
|
}
|
|
|
|
|
2016-05-04 04:02:26 +08:00
|
|
|
if (!block_count) {
|
2012-11-19 08:30:30 +08:00
|
|
|
sigfillset(&chldset);
|
2017-02-15 13:09:15 +08:00
|
|
|
DIE_ON_FAILURE(pthread_sigmask(SIG_UNBLOCK, &chldset, 0));
|
2012-11-19 08:30:30 +08:00
|
|
|
}
|
2016-12-29 10:52:33 +08:00
|
|
|
// debug( 0, L"signal block level decreased to %d", block_count );
|
2005-10-14 19:40:33 +08:00
|
|
|
}
|
2006-10-30 05:09:11 +08:00
|
|
|
|
2016-12-29 10:52:33 +08:00
|
|
|
bool signal_is_blocked() {
|
|
|
|
if (ignore_signal_block) return false;
|
|
|
|
return static_cast<bool>(block_count);
|
|
|
|
}
|