NeoMutt  2025-09-05-55-g97fc89
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
signal.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <signal.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36#include "signal2.h"
37
38int endwin(void);
39
41static sigset_t Sigset;
43static sigset_t SigsetSys;
44
46static struct sigaction SysOldInt;
48static struct sigaction SysOldQuit;
49
52static bool SignalsBlocked;
53
57
64
67
68volatile sig_atomic_t SigInt;
69volatile sig_atomic_t SigWinch;
70
75static void exit_print_uint(unsigned int n)
76{
77 char digit;
78
79 if (n > 9)
80 exit_print_uint(n / 10);
81
82 digit = '0' + (n % 10);
83
84 if (write(STDOUT_FILENO, &digit, 1) == -1)
85 {
86 // do nothing
87 }
88}
89
94static void exit_print_int(int n)
95{
96 if (n < 0)
97 {
98 if (write(STDOUT_FILENO, "-", 1) == -1)
99 {
100 // do nothing
101 }
102
103 n = -n;
104 }
106}
107
112static void exit_print_string(const char *str)
113{
114 if (!str)
115 return;
116
117 if (write(STDOUT_FILENO, str, strlen(str)) == -1)
118 {
119 // do nothing
120 }
121}
122
131{
132}
133
139{
140 exit_print_string("Caught signal ");
141 exit_print_int(sig);
143#ifdef HAVE_DECL_SYS_SIGLIST
144 exit_print_string(sys_siglist[sig]);
145#elif (defined(__sun__) && defined(__svr4__))
146 exit_print_string(_sys_siglist[sig]);
147#elif (defined(__alpha) && defined(__osf__))
148 exit_print_string(__sys_siglist[sig]);
149#endif
150 exit_print_string("... Exiting\n");
151 exit(0);
152}
153
164{
165 if (sig_fn)
166 SigHandler = sig_fn;
167
168 if (exit_fn)
169 ExitHandler = exit_fn;
170
171 if (segv_fn)
172 SegvHandler = segv_fn;
173
174 struct sigaction act = { 0 };
175 struct sigaction old_act = { 0 };
176
177 sigemptyset(&act.sa_mask);
178 act.sa_flags = 0;
179 act.sa_handler = SIG_IGN;
180 sigaction(SIGPIPE, &act, NULL);
181
182 act.sa_handler = SegvHandler;
183 sigaction(SIGSEGV, &act, &old_act);
184 OldSegvHandler = old_act.sa_handler;
185
186 act.sa_handler = ExitHandler;
187 sigaction(SIGTERM, &act, NULL);
188 sigaction(SIGHUP, &act, NULL);
189 sigaction(SIGQUIT, &act, NULL);
190
191 /* we want to avoid race conditions */
192 sigaddset(&act.sa_mask, SIGTSTP);
193
194 act.sa_handler = SigHandler;
195
196 /* we want SIGALRM to abort the current syscall, so we do this before
197 * setting the SA_RESTART flag below. currently this is only used to
198 * timeout on a connect() call in a reasonable amount of time. */
199 sigaction(SIGALRM, &act, NULL);
200
201/* we also don't want to mess with interrupted system calls */
202#ifdef SA_RESTART
203 act.sa_flags = SA_RESTART;
204#endif
205
206 sigaction(SIGCONT, &act, NULL);
207 sigaction(SIGTSTP, &act, NULL);
208 sigaction(SIGINT, &act, NULL);
209 sigaction(SIGWINCH, &act, NULL);
210
211 /* POSIX doesn't allow us to ignore SIGCHLD,
212 * so we just install a dummy handler for it */
213 act.sa_handler = mutt_sig_empty_handler;
214 /* don't need to block any other signals here */
215 sigemptyset(&act.sa_mask);
216 /* we don't want to mess with stopped children */
217 act.sa_flags |= SA_NOCLDSTOP;
218 sigaction(SIGCHLD, &act, NULL);
219}
220
228{
229 if (SignalsBlocked)
230 return;
231
232 sigemptyset(&Sigset);
233 sigaddset(&Sigset, SIGTERM);
234 sigaddset(&Sigset, SIGHUP);
235 sigaddset(&Sigset, SIGTSTP);
236 sigaddset(&Sigset, SIGINT);
237 sigaddset(&Sigset, SIGWINCH);
238 sigprocmask(SIG_BLOCK, &Sigset, 0);
239 SignalsBlocked = true;
240}
241
246{
247 if (!SignalsBlocked)
248 return;
249
250 sigprocmask(SIG_UNBLOCK, &Sigset, 0);
251 SignalsBlocked = false;
252}
253
261{
263 return;
264
265 struct sigaction sa = { 0 };
266
267 /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */
268 sa.sa_handler = SIG_IGN;
269 sa.sa_flags = 0;
270 sigemptyset(&sa.sa_mask);
271 sigaction(SIGINT, &sa, &SysOldInt);
272 sigaction(SIGQUIT, &sa, &SysOldQuit);
273
274 sigemptyset(&SigsetSys);
275 sigaddset(&SigsetSys, SIGCHLD);
276 sigprocmask(SIG_BLOCK, &SigsetSys, 0);
277 SysSignalsBlocked = true;
278}
279
284void mutt_sig_unblock_system(bool restore)
285{
287 return;
288
289 sigprocmask(SIG_UNBLOCK, &SigsetSys, NULL);
290 if (restore)
291 {
292 sigaction(SIGQUIT, &SysOldQuit, NULL);
293 sigaction(SIGINT, &SysOldInt, NULL);
294 }
295 else
296 {
297 struct sigaction sa = { 0 };
298
299 sa.sa_handler = SIG_DFL;
300 sigemptyset(&sa.sa_mask);
301 sa.sa_flags = 0;
302 sigaction(SIGQUIT, &sa, NULL);
303 sigaction(SIGINT, &sa, NULL);
304 }
305
306 SysSignalsBlocked = false;
307}
308
316{
317 struct sigaction sa = { 0 };
318
319 sa.sa_handler = SigHandler;
320#ifdef SA_RESTART
321 if (!allow)
322 sa.sa_flags |= SA_RESTART;
323#endif
324 sigaction(SIGINT, &sa, NULL);
325}
326
337{
338 struct sigaction sa = { 0 };
339
340 sa.sa_handler = SIG_DFL;
341 sa.sa_flags = 0;
342 sigemptyset(&sa.sa_mask);
343
344 /* These signals are set to SIG_IGN and must be reset */
345 sigaction(SIGPIPE, &sa, NULL);
346
347 /* These technically don't need to be reset, but the code has been
348 * doing so for a long time. */
349 sigaction(SIGTERM, &sa, NULL);
350 sigaction(SIGTSTP, &sa, NULL);
351 sigaction(SIGCONT, &sa, NULL);
352}
353
361void assertion_dump(const char *file, int line, const char *func, const char *cond)
362{
363 endwin();
365 printf("%s:%d:%s() -- assertion failed (%s)\n", file, line, func, cond);
366}
void show_backtrace(void)
Log the program's call stack.
Definition backtrace.c:40
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:163
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:361
static bool SysSignalsBlocked
true when system signals are blocked, e.g.
Definition signal.c:56
static sig_handler_t ExitHandler
Function to handle SIGTERM (15), SIGHUP (1), SIGQUIT (3) signals.
Definition signal.c:61
volatile sig_atomic_t SigWinch
true after SIGWINCH is received
Definition signal.c:69
static sig_handler_t SigHandler
Function to handle other signals, e.g. SIGINT (2)
Definition signal.c:59
static struct sigaction SysOldQuit
Backup of SIGQUIT handler, when mutt_sig_block_system() is called.
Definition signal.c:48
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition signal.c:130
static sigset_t Sigset
A set of signals used by mutt_sig_block(), mutt_sig_unblock()
Definition signal.c:41
void mutt_sig_reset_child_signals(void)
Reset ignored signals back to the default.
Definition signal.c:336
static void exit_print_uint(unsigned int n)
AS-safe version of printf("%u", n)
Definition signal.c:75
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition signal.c:68
sig_handler_t OldSegvHandler
Keep the old SEGV handler, it could have been set by ASAN.
Definition signal.c:66
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition signal.c:260
int endwin(void)
void mutt_sig_block(void)
Block signals during critical operations.
Definition signal.c:227
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition signal.c:245
static bool SignalsBlocked
true when signals are blocked, e.g.
Definition signal.c:52
static void exit_print_int(int n)
AS-safe version of printf("%d", n)
Definition signal.c:94
static sig_handler_t SegvHandler
Function to handle SIGSEGV (11) signals.
Definition signal.c:63
static sigset_t SigsetSys
A set of signals used by mutt_sig_block_system(), mutt_sig_unblock_system()
Definition signal.c:43
void mutt_sig_unblock_system(bool restore)
Restore previously blocked signals.
Definition signal.c:284
static struct sigaction SysOldInt
Backup of SIGINT handler, when mutt_sig_block_system() is called.
Definition signal.c:46
static void exit_print_string(const char *str)
AS-safe version of printf("%s", str)
Definition signal.c:112
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition signal.c:315
void mutt_sig_exit_handler(int sig)
Notify the user and shutdown gracefully.
Definition signal.c:138