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