FreeRDP
Loading...
Searching...
No Matches
signal_posix.c
1#include <pthread.h>
2#include <stddef.h>
3#include <errno.h>
4#include <signal.h>
5#include <termios.h>
6
7#include <winpr/atexit.h>
8#include <winpr/wlog.h>
9#include <winpr/debug.h>
10
11#include <freerdp/log.h>
12#include <freerdp/utils/signal.h>
13
14#include "platform_signal.h"
15
16#define TAG FREERDP_TAG("utils.signal.posix")
17
18static pthread_mutex_t signal_handler_lock = PTHREAD_MUTEX_INITIALIZER;
19
20void fsig_lock(void)
21{
22 const int rc = pthread_mutex_lock(&signal_handler_lock);
23 if (rc != 0)
24 {
25 char ebuffer[256] = WINPR_C_ARRAY_INIT;
26 WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
27 winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
28 }
29}
30
31void fsig_unlock(void)
32{
33 const int rc = pthread_mutex_unlock(&signal_handler_lock);
34 if (rc != 0)
35 {
36 char ebuffer[256] = WINPR_C_ARRAY_INIT;
37 WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
38 winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
39 }
40}
41
42static void fatal_handler(int signum)
43{
44 struct sigaction default_sigaction;
45 sigset_t this_mask;
46 static BOOL recursive = FALSE;
47
48 if (!recursive)
49 {
50 recursive = TRUE;
51 // NOLINTNEXTLINE(concurrency-mt-unsafe)
52 WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
53
54 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
55 }
56
57 default_sigaction.sa_handler = SIG_DFL;
58 sigfillset(&(default_sigaction.sa_mask));
59 default_sigaction.sa_flags = 0;
60 sigaction(signum, &default_sigaction, nullptr);
61 sigemptyset(&this_mask);
62 sigaddset(&this_mask, signum);
63 pthread_sigmask(SIG_UNBLOCK, &this_mask, nullptr);
64 (void)raise(signum);
65}
66
67static const int term_signals[] = { SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM };
68
69static const int fatal_signals[] = { SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP,
70 SIGILL, SIGSEGV, SIGTTIN, SIGTTOU,
71#ifdef SIGPOLL
72 SIGPOLL,
73#endif
74#ifdef SIGPROF
75 SIGPROF,
76#endif
77#ifdef SIGSYS
78 SIGSYS,
79#endif
80 SIGTRAP,
81#ifdef SIGVTALRM
82 SIGVTALRM,
83#endif
84 SIGXCPU, SIGXFSZ };
85
86static BOOL register_handlers(const int* signals, size_t count, void (*handler)(int))
87{
88 WINPR_ASSERT(signals || (count == 0));
89 WINPR_ASSERT(handler);
90
91 sigset_t orig_set = WINPR_C_ARRAY_INIT;
92 struct sigaction saction = WINPR_C_ARRAY_INIT;
93
94 pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
95
96 sigfillset(&(saction.sa_mask));
97 sigdelset(&(saction.sa_mask), SIGCONT);
98
99 saction.sa_handler = handler;
100 saction.sa_flags = 0;
101
102 for (size_t x = 0; x < count; x++)
103 {
104 struct sigaction orig_sigaction = WINPR_C_ARRAY_INIT;
105 if (sigaction(signals[x], nullptr, &orig_sigaction) == 0)
106 {
107 if (orig_sigaction.sa_handler != SIG_IGN)
108 {
109 sigaction(signals[x], &saction, nullptr);
110 }
111 }
112 }
113
114 pthread_sigmask(SIG_SETMASK, &orig_set, nullptr);
115
116 return TRUE;
117}
118
119static void unregister_handlers(const int* signals, size_t count)
120{
121 WINPR_ASSERT(signals || (count == 0));
122
123 sigset_t orig_set = WINPR_C_ARRAY_INIT;
124 struct sigaction saction = WINPR_C_ARRAY_INIT;
125
126 pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
127
128 sigfillset(&(saction.sa_mask));
129 sigdelset(&(saction.sa_mask), SIGCONT);
130
131 saction.sa_handler = SIG_IGN;
132 saction.sa_flags = 0;
133
134 for (size_t x = 0; x < count; x++)
135 {
136 sigaction(signals[x], &saction, nullptr);
137 }
138
139 pthread_sigmask(SIG_SETMASK, &orig_set, nullptr);
140}
141
142static void unregister_all_handlers(void)
143{
144 unregister_handlers(fatal_signals, ARRAYSIZE(fatal_signals));
145 unregister_handlers(term_signals, ARRAYSIZE(term_signals));
146}
147
148int freerdp_handle_signals(void)
149{
150 int rc = -1;
151
152 fsig_lock();
153
154 WLog_DBG(TAG, "Registering signal hook...");
155
156 (void)winpr_atexit(unregister_all_handlers);
157 if (!register_handlers(fatal_signals, ARRAYSIZE(fatal_signals), fatal_handler))
158 goto fail;
159 if (!register_handlers(term_signals, ARRAYSIZE(term_signals), fsig_term_handler))
160 goto fail;
161
162 /* Ignore SIGPIPE signal. */
163 (void)signal(SIGPIPE, SIG_IGN);
164 fsig_handlers_registered = TRUE;
165 rc = 0;
166fail:
167 fsig_unlock();
168 return rc;
169}