aboutsummaryrefslogtreecommitdiff
path: root/examples/dte/signals.c
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
commitdcacc00e3750300617ba6e16eb346713f91a783a (patch)
tree38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/dte/signals.c
parent58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff)
downloadcrep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz
Remove testing data
Diffstat (limited to 'examples/dte/signals.c')
-rw-r--r--examples/dte/signals.c169
1 files changed, 0 insertions, 169 deletions
diff --git a/examples/dte/signals.c b/examples/dte/signals.c
deleted file mode 100644
index e1a7155..0000000
--- a/examples/dte/signals.c
+++ /dev/null
@@ -1,169 +0,0 @@
1#include "compat.h"
2#include <errno.h>
3#include <string.h>
4#include <unistd.h>
5#include "signals.h"
6#include "util/debug.h"
7#include "util/exitcode.h"
8#include "util/log.h"
9#include "util/macros.h"
10
11volatile sig_atomic_t resized = 0;
12
13static const int ignored_signals[] = {
14 SIGINT, // Terminal interrupt (see: VINTR in termios(3))
15 SIGQUIT, // Terminal quit (see: VQUIT in termios(3))
16 SIGTSTP, // Terminal stop (see: VSUSP in termios(3))
17 SIGXFSZ, // File size limit exceeded (see: RLIMIT_FSIZE in getrlimit(3))
18 SIGPIPE, // Broken pipe (see: EPIPE error in write(3))
19 SIGUSR1, // User signal 1 (terminates by default, for no good reason)
20 SIGUSR2, // User signal 2 (as above)
21};
22
23static const int default_signals[] = {
24 SIGABRT, // Terminate (cleanup already done)
25 SIGCHLD, // Ignore (see: wait(3))
26 SIGURG, // Ignore
27 SIGTTIN, // Stop
28 SIGTTOU, // Stop
29 SIGCONT, // Continue
30};
31
32static const int fatal_signals[] = {
33 SIGBUS,
34 SIGFPE,
35 SIGILL,
36 SIGSEGV,
37 SIGSYS,
38 SIGTRAP,
39 SIGXCPU,
40 SIGALRM,
41 SIGVTALRM,
42 SIGHUP,
43 SIGTERM,
44#ifdef SIGPROF
45 SIGPROF,
46#endif
47#ifdef SIGEMT
48 SIGEMT,
49#endif
50};
51
52void handle_sigwinch(int UNUSED_ARG(signum))
53{
54 resized = 1;
55}
56
57static noreturn COLD void handle_fatal_signal(int signum)
58{
59 LOG_CRITICAL("received signal %d (%s)", signum, strsignal(signum));
60
61 // If `signum` is SIGHUP, there's no point in trying to clean up the
62 // state of the (disconnected) terminal
63 if (signum != SIGHUP) {
64 fatal_error_cleanup();
65 }
66
67 // Restore and unblock `signum` and then re-raise it, to ensure the
68 // termination status (as seen by e.g. waitpid(3) in the parent) is
69 // set appropriately
70 struct sigaction sa = {.sa_handler = SIG_DFL};
71 if (
72 sigemptyset(&sa.sa_mask) == 0
73 && sigaction(signum, &sa, NULL) == 0
74 && sigaddset(&sa.sa_mask, signum) == 0
75 && sigprocmask(SIG_UNBLOCK, &sa.sa_mask, NULL) == 0
76 ) {
77 raise(signum);
78 }
79
80 // This is here just to make extra certain the handler never returns.
81 // If everything is working correctly, this code should be unreachable.
82 raise(SIGKILL);
83 _exit(EX_OSERR);
84}
85
86// strsignal(3) is fine in situations where a signal is being reported
87// as terminating a process, but it tends to be confusing in most other
88// circumstances, where the signal name (not description) is usually
89// clearer
90static const char *signum_to_str(int signum)
91{
92#if HAVE_SIG2STR
93 static char buf[SIG2STR_MAX + 3];
94 if (sig2str(signum, buf + 3) == 0) {
95 return memcpy(buf, "SIG", 3);
96 }
97#elif HAVE_SIGABBREV_NP
98 static char buf[16];
99 const char *abbr = sigabbrev_np(signum);
100 if (abbr && memccpy(buf + 3, abbr, '\0', sizeof(buf) - 3)) {
101 return memcpy(buf, "SIG", 3);
102 }
103#endif
104
105 const char *str = strsignal(signum);
106 return likely(str) ? str : "??";
107}
108
109static void do_sigaction(int sig, const struct sigaction *action)
110{
111 struct sigaction old_action;
112 if (unlikely(sigaction(sig, action, &old_action) != 0)) {
113 const char *err = strerror(errno);
114 LOG_ERROR("failed to set disposition for signal %d: %s", sig, err);
115 return;
116 }
117 if (unlikely(old_action.sa_handler == SIG_IGN)) {
118 const char *str = signum_to_str(sig);
119 LOG_WARNING("ignored signal was inherited: %d (%s)", sig, str);
120 }
121}
122
123/*
124 * "A program that uses these functions should be written to catch all
125 * signals and take other appropriate actions to ensure that when the
126 * program terminates, whether planned or not, the terminal device's
127 * state is restored to its original state."
128 *
129 * (https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)
130 */
131void set_signal_handlers(void)
132{
133 struct sigaction action = {.sa_handler = handle_fatal_signal};
134 sigfillset(&action.sa_mask);
135 for (size_t i = 0; i < ARRAYLEN(fatal_signals); i++) {
136 do_sigaction(fatal_signals[i], &action);
137 }
138
139 // "The default actions for the realtime signals in the range SIGRTMIN
140 // to SIGRTMAX shall be to terminate the process abnormally."
141 // (POSIX.1-2017 ยง2.4.3)
142#if defined(SIGRTMIN) && defined(SIGRTMAX)
143 for (int s = SIGRTMIN, max = SIGRTMAX; s <= max; s++) {
144 do_sigaction(s, &action);
145 }
146#endif
147
148 action.sa_handler = SIG_IGN;
149 for (size_t i = 0; i < ARRAYLEN(ignored_signals); i++) {
150 do_sigaction(ignored_signals[i], &action);
151 }
152
153 action.sa_handler = SIG_DFL;
154 for (size_t i = 0; i < ARRAYLEN(default_signals); i++) {
155 do_sigaction(default_signals[i], &action);
156 }
157
158#if defined(SIGWINCH)
159 LOG_INFO("setting SIGWINCH handler");
160 action.sa_handler = handle_sigwinch;
161 do_sigaction(SIGWINCH, &action);
162#endif
163
164 // Set signal mask explicitly, to avoid any possibility of
165 // inheriting blocked signals
166 sigset_t mask;
167 sigemptyset(&mask);
168 sigprocmask(SIG_SETMASK, &mask, NULL);
169}