From b4f53143b0e05fd3061cdf2e65e17a6a2904090b Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 24 Jul 2015 00:50:58 -0700 Subject: Migrate source files into src/ directory This change moves source files into a src/ directory, and puts object files into an obj/ directory. The Makefile and xcode project are updated accordingly. Fixes #1866 --- src/signal.cpp | 701 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 701 insertions(+) create mode 100644 src/signal.cpp (limited to 'src/signal.cpp') diff --git a/src/signal.cpp b/src/signal.cpp new file mode 100644 index 00000000..8e62f788 --- /dev/null +++ b/src/signal.cpp @@ -0,0 +1,701 @@ +/** \file signal.c + +The library for various signal related issues + +*/ + +#include "config.h" + + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SIGINFO_H +#include +#endif + +#include "common.h" +#include "fallback.h" +#include "util.h" + +#include "wutil.h" +#include "signal.h" +#include "event.h" +#include "reader.h" +#include "proc.h" + + +/** + Struct describing an entry for the lookup table used to convert + between signal names and signal ids, etc. +*/ +struct lookup_entry +{ + /** + Signal id + */ + int signal; + /** + Signal name + */ + const wchar_t *name; + /** + Signal description + */ + const wchar_t *desc; +}; + +/** + The number of signal blocks in place. Increased by signal_block, decreased by signal_unblock. +*/ +static int block_count=0; + + +/** + Lookup table used to convert between signal names and signal ids, + etc. +*/ +static const struct lookup_entry lookup[] = +{ +#ifdef SIGHUP + { + SIGHUP, + L"SIGHUP", + N_(L"Terminal hung up") + } + , +#endif +#ifdef SIGINT + { + SIGINT, + L"SIGINT", + N_(L"Quit request from job control (^C)") + } + , +#endif +#ifdef SIGQUIT + { + SIGQUIT, + L"SIGQUIT", + N_(L"Quit request from job control with core dump (^\\)") + } + , +#endif +#ifdef SIGILL + { + SIGILL, + L"SIGILL", + N_(L"Illegal instruction") + } + , +#endif +#ifdef SIGTRAP + { + SIGTRAP, + L"SIGTRAP", + N_(L"Trace or breakpoint trap") + } + , +#endif +#ifdef SIGABRT + { + SIGABRT, + L"SIGABRT", + N_(L"Abort") + } + , +#endif +#ifdef SIGBUS + { + SIGBUS, + L"SIGBUS", + N_(L"Misaligned address error") + } + , +#endif +#ifdef SIGFPE + { + SIGFPE, + L"SIGFPE", + N_(L"Floating point exception") + } + , +#endif +#ifdef SIGKILL + { + SIGKILL, + L"SIGKILL", + N_(L"Forced quit") + } + , +#endif +#ifdef SIGUSR1 + { + SIGUSR1, + L"SIGUSR1", + N_(L"User defined signal 1") + } + , +#endif +#ifdef SIGUSR2 + { + SIGUSR2, L"SIGUSR2", + N_(L"User defined signal 2") + } + , +#endif +#ifdef SIGSEGV + { + SIGSEGV, + L"SIGSEGV", + N_(L"Address boundary error") + } + , +#endif +#ifdef SIGPIPE + { + SIGPIPE, + L"SIGPIPE", + N_(L"Broken pipe") + } + , +#endif +#ifdef SIGALRM + { + SIGALRM, + L"SIGALRM", + N_(L"Timer expired") + } + , +#endif +#ifdef SIGTERM + { + SIGTERM, + L"SIGTERM", + N_(L"Polite quit request") + } + , +#endif +#ifdef SIGCHLD + { + SIGCHLD, + L"SIGCHLD", + N_(L"Child process status changed") + } + , +#endif +#ifdef SIGCONT + { + SIGCONT, + L"SIGCONT", + N_(L"Continue previously stopped process") + } + , +#endif +#ifdef SIGSTOP + { + SIGSTOP, + L"SIGSTOP", + N_(L"Forced stop") + } + , +#endif +#ifdef SIGTSTP + { + SIGTSTP, + L"SIGTSTP", + N_(L"Stop request from job control (^Z)") + } + , +#endif +#ifdef SIGTTIN + { + SIGTTIN, + L"SIGTTIN", + N_(L"Stop from terminal input") + } + , +#endif +#ifdef SIGTTOU + { + SIGTTOU, + L"SIGTTOU", + N_(L"Stop from terminal output") + } + , +#endif +#ifdef SIGURG + { + SIGURG, + L"SIGURG", + N_(L"Urgent socket condition") + } + , +#endif +#ifdef SIGXCPU + { + SIGXCPU, + L"SIGXCPU", + N_(L"CPU time limit exceeded") + } + , +#endif +#ifdef SIGXFSZ + { + SIGXFSZ, + L"SIGXFSZ", + N_(L"File size limit exceeded") + } + , +#endif +#ifdef SIGVTALRM + { + SIGVTALRM, + L"SIGVTALRM", + N_(L"Virtual timer expired") + } + , +#endif +#ifdef SIGPROF + { + SIGPROF, + L"SIGPROF", + N_(L"Profiling timer expired") + } + , +#endif +#ifdef SIGWINCH + { + SIGWINCH, + L"SIGWINCH", + N_(L"Window size change") + } + , +#endif +#ifdef SIGWIND + { + SIGWIND, + L"SIGWIND", + N_(L"Window size change") + } + , +#endif +#ifdef SIGIO + { + SIGIO, + L"SIGIO", + N_(L"I/O on asynchronous file descriptor is possible") + } + , +#endif +#ifdef SIGPWR + { + SIGPWR, + L"SIGPWR", + N_(L"Power failure") + } + , +#endif +#ifdef SIGSYS + { + SIGSYS, + L"SIGSYS", + N_(L"Bad system call") + } + , +#endif +#ifdef SIGINFO + { + SIGINFO, + L"SIGINFO", + N_(L"Information request") + } + , +#endif +#ifdef SIGSTKFLT + { + SIGSTKFLT, + L"SISTKFLT", + N_(L"Stack fault") + } + , +#endif +#ifdef SIGEMT + { + SIGEMT, + L"SIGEMT", + N_(L"Emulator trap") + } + , +#endif +#ifdef SIGIOT + { + SIGIOT, + L"SIGIOT", + N_(L"Abort (Alias for SIGABRT)") + } + , +#endif +#ifdef SIGUNUSED + { + SIGUNUSED, + L"SIGUNUSED", + N_(L"Unused signal") + } + , +#endif + { + 0, + 0, + 0 + } +} +; + + +/** + 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) +{ + if (wcsncasecmp(name, L"sig", 3)==0) + name +=3; + + return wcscasecmp(canonical+3,name) == 0; +} + + +int wcs2sig(const wchar_t *str) +{ + int i; + wchar_t *end=0; + + for (i=0; lookup[i].desc ; i++) + { + if (match_signal_name(lookup[i].name, str)) + { + return lookup[i].signal; + } + } + errno=0; + int res = fish_wcstoi(str, &end, 10); + if (!errno && res>=0 && !*end) + return res; + + return -1; +} + + +const wchar_t *sig2wcs(int sig) +{ + int i; + + for (i=0; lookup[i].desc ; i++) + { + if (lookup[i].signal == sig) + { + return lookup[i].name; + } + } + + return _(L"Unknown"); +} + +const wchar_t *signal_get_desc(int sig) +{ + int i; + + for (i=0; lookup[i].desc ; i++) + { + if (lookup[i].signal == sig) + { + return _(lookup[i].desc); + } + } + + return _(L"Unknown"); +} + +/** + Standard signal handler +*/ +static void default_handler(int signal, siginfo_t *info, void *context) +{ + if (event_is_signal_observed(signal)) + { + event_fire_signal(signal); + } +} + +/** + Respond to a winch signal by checking the terminal size +*/ +static void handle_winch(int sig, siginfo_t *info, void *context) +{ + common_handle_winch(sig); + default_handler(sig, 0, 0); +} + +/** + 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) +{ + if (event_is_signal_observed(SIGHUP)) + { + default_handler(sig, 0, 0); + } + else + { + reader_exit(1, 1); + } +} + +/** 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) +{ + restore_term_foreground_process_group(); + signal(SIGTERM, SIG_DFL); + raise(SIGTERM); +} + +/** + 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) +{ + reader_handle_int(sig); + default_handler(sig, info, context); +} + +/** + sigchld handler. Does notification and calls the handler in proc.c +*/ +static void handle_chld(int sig, siginfo_t *info, void *context) +{ + job_handle_signal(sig, info, context); + default_handler(sig, info, context); +} + +void signal_reset_handlers() +{ + int i; + + struct sigaction act; + sigemptyset(& act.sa_mask); + act.sa_flags=0; + act.sa_handler=SIG_DFL; + + for (i=0; lookup[i].desc ; i++) + { + sigaction(lookup[i].signal, &act, 0); + } +} + + +/** + Sets appropriate signal handlers. +*/ +void signal_set_handlers() +{ + struct sigaction act; + + if (get_is_interactive() == -1) + return; + + sigemptyset(& act.sa_mask); + act.sa_flags=SA_SIGINFO; + act.sa_sigaction = &default_handler; + + /* + First reset everything to a use default_handler, a function + whose sole action is to fire of an event + */ + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGTSTP, &act, 0); + sigaction(SIGTTIN, &act, 0); + sigaction(SIGTTOU, &act, 0); + sigaction(SIGCHLD, &act, 0); + + /* + Ignore sigpipe, it is generated if fishd dies, but we can + recover. + */ + sigaction(SIGPIPE, &act, 0); + + if (get_is_interactive()) + { + /* + Interactive mode. Ignore interactive signals. We are a + shell, we know whats best for the user. ;-) + */ + + act.sa_handler=SIG_IGN; + + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGTSTP, &act, 0); + sigaction(SIGTTIN, &act, 0); + sigaction(SIGTTOU, &act, 0); + + act.sa_sigaction = &handle_int; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGINT, &act, 0)) + { + wperror(L"sigaction"); + FATAL_EXIT(); + } + + act.sa_sigaction = &handle_chld; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGCHLD, &act, 0)) + { + wperror(L"sigaction"); + FATAL_EXIT(); + } + +#ifdef SIGWINCH + act.sa_flags = SA_SIGINFO; + act.sa_sigaction= &handle_winch; + if (sigaction(SIGWINCH, &act, 0)) + { + wperror(L"sigaction"); + FATAL_EXIT(); + } +#endif + + act.sa_flags = SA_SIGINFO; + act.sa_sigaction= &handle_hup; + if (sigaction(SIGHUP, &act, 0)) + { + wperror(L"sigaction"); + FATAL_EXIT(); + } + + // SIGTERM restores the terminal controlling process before dying + act.sa_flags = SA_SIGINFO; + act.sa_sigaction= &handle_term; + if (sigaction(SIGTERM, &act, 0)) + { + wperror(L"sigaction"); + FATAL_EXIT(); + } + + } + else + { + /* + 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); + + act.sa_handler=SIG_DFL; + + act.sa_sigaction = &handle_chld; + act.sa_flags = SA_SIGINFO; + if (sigaction(SIGCHLD, &act, 0)) + { + wperror(L"sigaction"); + exit_without_destructors(1); + } + } + +} + +void signal_handle(int sig, int do_handle) +{ + struct sigaction act; + + /* + These should always be handled + */ + if ((sig == SIGINT) || + (sig == SIGQUIT) || + (sig == SIGTSTP) || + (sig == SIGTTIN) || + (sig == SIGTTOU) || + (sig == SIGCHLD)) + return; + + sigemptyset(&act.sa_mask); + if (do_handle) + { + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = &default_handler; + } + else + { + act.sa_flags = 0; + act.sa_handler = SIG_DFL; + } + + sigaction(sig, &act, 0); +} + +void get_signals_with_handlers(sigset_t *set) +{ + sigemptyset(set); + for (int i=0; lookup[i].desc ; i++) + { + struct sigaction act = {}; + sigaction(lookup[i].signal, NULL, &act); + if (act.sa_handler != SIG_DFL) + sigaddset(set, lookup[i].signal); + } +} + +void signal_block() +{ + ASSERT_IS_MAIN_THREAD(); + sigset_t chldset; + + if (!block_count) + { + sigfillset(&chldset); + VOMIT_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &chldset, NULL)); + } + + block_count++; +// debug( 0, L"signal block level increased to %d", block_count ); +} + +void signal_unblock() +{ + ASSERT_IS_MAIN_THREAD(); + sigset_t chldset; + + block_count--; + + if (block_count < 0) + { + debug(0, _(L"Signal block mismatch")); + bugreport(); + FATAL_EXIT(); + } + + if (!block_count) + { + sigfillset(&chldset); + VOMIT_ON_FAILURE(pthread_sigmask(SIG_UNBLOCK, &chldset, 0)); + } +// debug( 0, L"signal block level decreased to %d", block_count ); +} + +bool signal_is_blocked() +{ + return !!block_count; +} + -- cgit v1.2.3