NeoMutt  2025-01-09-117-gace867
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
68
69volatile sig_atomic_t SigInt;
70volatile sig_atomic_t SigWinch;
71
76static void exit_print_uint(unsigned int n)
77{
78 char digit;
79
80 if (n > 9)
81 exit_print_uint(n / 10);
82
83 digit = '0' + (n % 10);
84
85 if (write(STDOUT_FILENO, &digit, 1) == -1)
86 {
87 // do nothing
88 }
89}
90
95static void exit_print_int(int n)
96{
97 if (n < 0)
98 {
99 if (write(STDOUT_FILENO, "-", 1) == -1)
100 {
101 // do nothing
102 }
103
104 n = -n;
105 }
107}
108
113static void exit_print_string(const char *str)
114{
115 if (!str)
116 return;
117
118 if (write(STDOUT_FILENO, str, strlen(str)) == -1)
119 {
120 // do nothing
121 }
122}
123
132{
133}
134
140{
141 exit_print_string("Caught signal ");
142 exit_print_int(sig);
144#ifdef HAVE_DECL_SYS_SIGLIST
145 exit_print_string(sys_siglist[sig]);
146#elif (defined(__sun__) && defined(__svr4__))
147 exit_print_string(_sys_siglist[sig]);
148#elif (defined(__alpha) && defined(__osf__))
149 exit_print_string(__sys_siglist[sig]);
150#endif
151 exit_print_string("... Exiting\n");
152 exit(0);
153}
154
165{
166 if (sig_fn)
167 SigHandler = sig_fn;
168
169 if (exit_fn)
170 ExitHandler = exit_fn;
171
172 if (segv_fn)
173 SegvHandler = segv_fn;
174
175 struct sigaction act = { 0 };
176 struct sigaction old_act = { 0 };
177
178 sigemptyset(&act.sa_mask);
179 act.sa_flags = 0;
180 act.sa_handler = SIG_IGN;
181 sigaction(SIGPIPE, &act, NULL);
182
183 act.sa_handler = SegvHandler;
184 sigaction(SIGSEGV, &act, &old_act);
185 OldSegvHandler = old_act.sa_handler;
186
187 act.sa_handler = ExitHandler;
188 sigaction(SIGTERM, &act, NULL);
189 sigaction(SIGHUP, &act, NULL);
190 sigaction(SIGQUIT, &act, NULL);
191
192 /* we want to avoid race conditions */
193 sigaddset(&act.sa_mask, SIGTSTP);
194
195 act.sa_handler = SigHandler;
196
197 /* we want SIGALRM to abort the current syscall, so we do this before
198 * setting the SA_RESTART flag below. currently this is only used to
199 * timeout on a connect() call in a reasonable amount of time. */
200 sigaction(SIGALRM, &act, NULL);
201
202/* we also don't want to mess with interrupted system calls */
203#ifdef SA_RESTART
204 act.sa_flags = SA_RESTART;
205#endif
206
207 sigaction(SIGCONT, &act, NULL);
208 sigaction(SIGTSTP, &act, NULL);
209 sigaction(SIGINT, &act, NULL);
210 sigaction(SIGWINCH, &act, NULL);
211
212 /* POSIX doesn't allow us to ignore SIGCHLD,
213 * so we just install a dummy handler for it */
214 act.sa_handler = mutt_sig_empty_handler;
215 /* don't need to block any other signals here */
216 sigemptyset(&act.sa_mask);
217 /* we don't want to mess with stopped children */
218 act.sa_flags |= SA_NOCLDSTOP;
219 sigaction(SIGCHLD, &act, NULL);
220}
221
229{
230 if (SignalsBlocked)
231 return;
232
233 sigemptyset(&Sigset);
234 sigaddset(&Sigset, SIGTERM);
235 sigaddset(&Sigset, SIGHUP);
236 sigaddset(&Sigset, SIGTSTP);
237 sigaddset(&Sigset, SIGINT);
238 sigaddset(&Sigset, SIGWINCH);
239 sigprocmask(SIG_BLOCK, &Sigset, 0);
240 SignalsBlocked = true;
241}
242
247{
248 if (!SignalsBlocked)
249 return;
250
251 sigprocmask(SIG_UNBLOCK, &Sigset, 0);
252 SignalsBlocked = false;
253}
254
262{
264 return;
265
266 struct sigaction sa = { 0 };
267
268 /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */
269 sa.sa_handler = SIG_IGN;
270 sa.sa_flags = 0;
271 sigemptyset(&sa.sa_mask);
272 sigaction(SIGINT, &sa, &SysOldInt);
273 sigaction(SIGQUIT, &sa, &SysOldQuit);
274
275 sigemptyset(&SigsetSys);
276 sigaddset(&SigsetSys, SIGCHLD);
277 sigprocmask(SIG_BLOCK, &SigsetSys, 0);
278 SysSignalsBlocked = true;
279}
280
285void mutt_sig_unblock_system(bool restore)
286{
288 return;
289
290 sigprocmask(SIG_UNBLOCK, &SigsetSys, NULL);
291 if (restore)
292 {
293 sigaction(SIGQUIT, &SysOldQuit, NULL);
294 sigaction(SIGINT, &SysOldInt, NULL);
295 }
296 else
297 {
298 struct sigaction sa = { 0 };
299
300 sa.sa_handler = SIG_DFL;
301 sigemptyset(&sa.sa_mask);
302 sa.sa_flags = 0;
303 sigaction(SIGQUIT, &sa, NULL);
304 sigaction(SIGINT, &sa, NULL);
305 }
306
307 SysSignalsBlocked = false;
308}
309
317{
318 struct sigaction sa = { 0 };
319
320 sa.sa_handler = SigHandler;
321#ifdef SA_RESTART
322 if (!allow)
323 sa.sa_flags |= SA_RESTART;
324#endif
325 sigaction(SIGINT, &sa, NULL);
326}
327
338{
339 struct sigaction sa = { 0 };
340
341 sa.sa_handler = SIG_DFL;
342 sa.sa_flags = 0;
343 sigemptyset(&sa.sa_mask);
344
345 /* These signals are set to SIG_IGN and must be reset */
346 sigaction(SIGPIPE, &sa, NULL);
347
348 /* These technically don't need to be reset, but the code has been
349 * doing so for a long time. */
350 sigaction(SIGTERM, &sa, NULL);
351 sigaction(SIGTSTP, &sa, NULL);
352 sigaction(SIGCONT, &sa, NULL);
353}
354
362void assertion_dump(const char *file, int line, const char *func, const char *cond)
363{
364 endwin();
366 printf("%s:%d:%s() -- assertion failed (%s)\n", file, line, func, cond);
367}
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:164
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:362
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:70
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:131
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:337
static void exit_print_uint(unsigned int n)
AS-safe version of printf("%u", n)
Definition: signal.c:76
volatile sig_atomic_t SigInt
true after SIGINT is received
Definition: signal.c:69
sig_handler_t OldSegvHandler
Keep the old SEGV handler, it could have been set by ASAN.
Definition: signal.c:67
void mutt_sig_block_system(void)
Block signals before calling exec()
Definition: signal.c:261
int endwin(void)
void mutt_sig_block(void)
Block signals during critical operations.
Definition: signal.c:228
void mutt_sig_unblock(void)
Restore previously blocked signals.
Definition: signal.c:246
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:95
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:285
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:113
void mutt_sig_allow_interrupt(bool allow)
Allow/disallow Ctrl-C (SIGINT)
Definition: signal.c:316
void mutt_sig_exit_handler(int sig)
Notify the user and shutdown gracefully.
Definition: signal.c:139