NeoMutt  2024-04-25-100-gcb3684
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
signal.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <signal.h>
31#include <stdbool.h>
32#include <stddef.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37#include "signal2.h"
38
39int endwin(void);
40
42static sigset_t Sigset;
44static sigset_t SigsetSys;
45
47static struct sigaction SysOldInt;
49static struct sigaction SysOldQuit;
50
53static bool SignalsBlocked;
54
58
65
66volatile sig_atomic_t SigInt;
67volatile sig_atomic_t SigWinch;
68
73static void exit_print_uint(unsigned int n)
74{
75 char digit;
76
77 if (n > 9)
78 exit_print_uint(n / 10);
79
80 digit = '0' + (n % 10);
81 write(STDOUT_FILENO, &digit, 1);
82}
83
88static void exit_print_int(int n)
89{
90 if (n < 0)
91 {
92 write(STDOUT_FILENO, "-", 1);
93 n = -n;
94 }
96}
97
102static void exit_print_string(const char *str)
103{
104 if (!str)
105 return;
106
107 write(STDOUT_FILENO, str, strlen(str));
108}
109
118{
119}
120
126{
127 exit_print_string("Caught signal ");
128 exit_print_int(sig);
130#ifdef HAVE_DECL_SYS_SIGLIST
131 exit_print_string(sys_siglist[sig]);
132#elif (defined(__sun__) && defined(__svr4__))
133 exit_print_string(_sys_siglist[sig]);
134#elif (defined(__alpha) && defined(__osf__))
135 exit_print_string(__sys_siglist[sig]);
136#endif
137 exit_print_string("... Exiting\n");
138 exit(0);
139}
140
151{
152 if (sig_fn)
153 SigHandler = sig_fn;
154
155 if (exit_fn)
156 ExitHandler = exit_fn;
157
158 if (segv_fn)
159 SegvHandler = segv_fn;
160
161 struct sigaction act = { 0 };
162
163 sigemptyset(&act.sa_mask);
164 act.sa_flags = 0;
165 act.sa_handler = SIG_IGN;
166 sigaction(SIGPIPE, &act, NULL);
167
168 act.sa_handler = SegvHandler;
169 sigaction(SIGSEGV, &act, NULL);
170
171 act.sa_handler = ExitHandler;
172 sigaction(SIGTERM, &act, NULL);
173 sigaction(SIGHUP, &act, NULL);
174 sigaction(SIGQUIT, &act, NULL);
175
176 /* we want to avoid race conditions */
177 sigaddset(&act.sa_mask, SIGTSTP);
178
179 act.sa_handler = SigHandler;
180
181 /* we want SIGALRM to abort the current syscall, so we do this before
182 * setting the SA_RESTART flag below. currently this is only used to
183 * timeout on a connect() call in a reasonable amount of time. */
184 sigaction(SIGALRM, &act, NULL);
185
186/* we also don't want to mess with interrupted system calls */
187#ifdef SA_RESTART
188 act.sa_flags = SA_RESTART;
189#endif
190
191 sigaction(SIGCONT, &act, NULL);
192 sigaction(SIGTSTP, &act, NULL);
193 sigaction(SIGINT, &act, NULL);
194 sigaction(SIGWINCH, &act, NULL);
195
196 /* POSIX doesn't allow us to ignore SIGCHLD,
197 * so we just install a dummy handler for it */
198 act.sa_handler = mutt_sig_empty_handler;
199 /* don't need to block any other signals here */
200 sigemptyset(&act.sa_mask);
201 /* we don't want to mess with stopped children */
202 act.sa_flags |= SA_NOCLDSTOP;
203 sigaction(SIGCHLD, &act, NULL);
204}
205
213{
214 if (SignalsBlocked)
215 return;
216
217 sigemptyset(&Sigset);
218 sigaddset(&Sigset, SIGTERM);
219 sigaddset(&Sigset, SIGHUP);
220 sigaddset(&Sigset, SIGTSTP);
221 sigaddset(&Sigset, SIGINT);
222 sigaddset(&Sigset, SIGWINCH);
223 sigprocmask(SIG_BLOCK, &Sigset, 0);
224 SignalsBlocked = true;
225}
226
231{
232 if (!SignalsBlocked)
233 return;
234
235 sigprocmask(SIG_UNBLOCK, &Sigset, 0);
236 SignalsBlocked = false;
237}
238
246{
248 return;
249
250 struct sigaction sa = { 0 };
251
252 /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */
253 sa.sa_handler = SIG_IGN;
254 sa.sa_flags = 0;
255 sigemptyset(&sa.sa_mask);
256 sigaction(SIGINT, &sa, &SysOldInt);
257 sigaction(SIGQUIT, &sa, &SysOldQuit);
258
259 sigemptyset(&SigsetSys);
260 sigaddset(&SigsetSys, SIGCHLD);
261 sigprocmask(SIG_BLOCK, &SigsetSys, 0);
262 SysSignalsBlocked = true;
263}
264
269void mutt_sig_unblock_system(bool restore)
270{
272 return;
273
274 sigprocmask(SIG_UNBLOCK, &SigsetSys, NULL);
275 if (restore)
276 {
277 sigaction(SIGQUIT, &SysOldQuit, NULL);
278 sigaction(SIGINT, &SysOldInt, NULL);
279 }
280 else
281 {
282 struct sigaction sa = { 0 };
283
284 sa.sa_handler = SIG_DFL;
285 sigemptyset(&sa.sa_mask);
286 sa.sa_flags = 0;
287 sigaction(SIGQUIT, &sa, NULL);
288 sigaction(SIGINT, &sa, NULL);
289 }
290
291 SysSignalsBlocked = false;
292}
293
301{
302 struct sigaction sa = { 0 };
303
304 sa.sa_handler = SigHandler;
305#ifdef SA_RESTART
306 if (!allow)
307 sa.sa_flags |= SA_RESTART;
308#endif
309 sigaction(SIGINT, &sa, NULL);
310}
311
322{
323 struct sigaction sa = { 0 };
324
325 sa.sa_handler = SIG_DFL;
326 sa.sa_flags = 0;
327 sigemptyset(&sa.sa_mask);
328
329 /* These signals are set to SIG_IGN and must be reset */
330 sigaction(SIGPIPE, &sa, NULL);
331
332 /* These technically don't need to be reset, but the code has been
333 * doing so for a long time. */
334 sigaction(SIGTERM, &sa, NULL);
335 sigaction(SIGTSTP, &sa, NULL);
336 sigaction(SIGCONT, &sa, NULL);
337}
338
346void assertion_dump(const char *file, int line, const char *func, const char *cond)
347{
348 endwin();
350 printf("%s:%d:%s() -- assertion failed (%s)\n", file, line, func, cond);
351}
void show_backtrace(void)
Log the program's call stack.
Definition: backtrace.c:39
int digit(const char *s)
Signal handling.
void(* sig_handler_t)(int sig)
Definition: signal2.h:46
void mutt_sig_init(sig_handler_t sig_fn, sig_handler_t exit_fn, sig_handler_t segv_fn)
Initialise the signal handling.
Definition: signal.c:150
void assertion_dump(const char *file, int line, const char *func, const char *cond)
Dump some debugging info before we stop the program.
Definition: signal.c:346
static bool SysSignalsBlocked
true when system signals are blocked, e.g.
Definition: signal.c:57
static sig_handler_t ExitHandler
Function to handle SIGTERM (15), SIGHUP (1), SIGQUIT (3) signals.
Definition: signal.c:62
volatile sig_atomic_t SigWinch
true after SIGWINCH is received
Definition: signal.c:67
static sig_handler_t SigHandler
Function to handle other signals, e.g. SIGINT (2)
Definition: signal.c:60
static struct sigaction SysOldQuit
Backup of SIGQUIT handler, when mutt_sig_block_system() is called.
Definition: signal.c:49
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition: signal.c:117
static sigset_t Sigset
A set of signals used by mutt_sig_block(), mutt_sig_unblock()
Definition: signal.c:42
void mutt_sig_reset_child_signals(void)
Reset ignored signals back to the default.
Definition: signal.c:321
static void exit_print_uint(unsigned int n)
AS-safe version of printf("%u", n)
Definition: signal.c:73
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:66
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition: signal.c:245
int endwin(void)
void mutt_sig_block(void)
Block signals during critical operations.
Definition: signal.c:212
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition: signal.c:230
static bool SignalsBlocked
true when signals are blocked, e.g.
Definition: signal.c:53
static void exit_print_int(int n)
AS-safe version of printf("%d", n)
Definition: signal.c:88
static sig_handler_t SegvHandler
Function to handle SIGSEGV (11) signals.
Definition: signal.c:64
static sigset_t SigsetSys
A set of signals used by mutt_sig_block_system(), mutt_sig_unblock_system()
Definition: signal.c:44
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition: signal.c:269
static struct sigaction SysOldInt
Backup of SIGINT handler, when mutt_sig_block_system() is called.
Definition: signal.c:47
static void exit_print_string(const char *str)
AS-safe version of printf("%s", str)
Definition: signal.c:102
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:300
void mutt_sig_exit_handler(int sig)
Notify the user and shutdown gracefully.
Definition: signal.c:125