1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
/**
* @file
* Signal handling
*
* @authors
* Copyright (C) 2017-2023 Richard Russon <rich@flatcap.org>
*
* @copyright
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @page neo_mutt_signal Signal handling
*
* Signal handling
*/
#include "config.h"
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "attach/lib.h"
#include "protos.h"
#if defined(USE_DEBUG_GRAPHVIZ) || defined(USE_DEBUG_BACKTRACE)
#include "debug/lib.h"
#endif
/// Ncurses function isendwin() has been called
static int IsEndwin = 0;
/**
* curses_signal_handler - Catch signals and relay the info to the main program - Implements ::sig_handler_t - @ingroup sig_handler_api
* @param sig Signal number, e.g. SIGINT
*/
static void curses_signal_handler(int sig)
{
int save_errno = errno;
enum MuttCursorState old_cursor = MUTT_CURSOR_VISIBLE;
switch (sig)
{
case SIGTSTP: /* user requested a suspend */
{
const bool c_suspend = cs_subset_bool(NeoMutt->sub, "suspend");
if (!c_suspend)
break;
IsEndwin = isendwin();
old_cursor = mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE);
if (!IsEndwin)
endwin();
kill(0, SIGSTOP);
}
FALLTHROUGH;
case SIGCONT:
if (!IsEndwin)
refresh();
mutt_curses_set_cursor(old_cursor);
/* We don't receive SIGWINCH when suspended; however, no harm is done by
* just assuming we received one, and triggering the 'resize' anyway. */
SigWinch = true;
break;
case SIGWINCH:
SigWinch = true;
break;
case SIGINT:
SigInt = true;
break;
}
errno = save_errno;
}
/**
* curses_exit_handler - Notify the user and shutdown gracefully - Implements ::sig_handler_t - @ingroup sig_handler_api
* @param sig Signal number, e.g. SIGTERM
*/
static void curses_exit_handler(int sig)
{
mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE);
endwin(); /* just to be safe */
mutt_temp_attachments_cleanup();
mutt_sig_exit_handler(sig); /* DOES NOT RETURN */
}
/**
* curses_segv_handler - Catch a segfault and print a backtrace - Implements ::sig_handler_t - @ingroup sig_handler_api
* @param sig Signal number, e.g. SIGSEGV
*/
static void curses_segv_handler(int sig)
{
mutt_curses_set_cursor(MUTT_CURSOR_VISIBLE);
endwin(); /* just to be safe */
#ifdef USE_DEBUG_BACKTRACE
show_backtrace();
#endif
#ifdef USE_DEBUG_GRAPHVIZ
dump_graphviz("segfault", NULL);
#endif
// Chain the old SEGV handler, it could have been set by ASAN
if (OldSegvHandler)
OldSegvHandler(sig);
struct sigaction act = { 0 };
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = SIG_DFL;
sigaction(sig, &act, NULL);
// Re-raise the signal to give outside handlers a chance to deal with it
raise(sig);
}
/**
* mutt_signal_init - Initialise the signal handling
*/
void mutt_signal_init(void)
{
mutt_sig_init(curses_signal_handler, curses_exit_handler, curses_segv_handler);
}
|