FreeRDP
Loading...
Searching...
No Matches
signal.c
1
20#include <freerdp/config.h>
21
22#include <stddef.h>
23#include <errno.h>
24#include <string.h>
25
26#include <winpr/crt.h>
27
28#include <freerdp/utils/signal.h>
29#include <freerdp/log.h>
30
31#ifndef _WIN32
32#include <signal.h>
33#include <termios.h>
34#endif
35
36#define TAG FREERDP_TAG("utils.signal")
37
38#ifdef _WIN32
39
40int freerdp_handle_signals(void)
41{
42 errno = ENOSYS;
43 return -1;
44}
45
46BOOL freerdp_add_signal_cleanup_handler(void* context, freerdp_signal_handler_t fkt)
47{
48 return FALSE;
49}
50
51BOOL freerdp_del_signal_cleanup_handler(void* context, freerdp_signal_handler_t fkt)
52{
53 return FALSE;
54}
55#else
56
57#include <pthread.h>
58#include <winpr/debug.h>
59
60static BOOL handlers_registered = FALSE;
61static pthread_mutex_t signal_handler_lock = PTHREAD_MUTEX_INITIALIZER;
62
63typedef struct
64{
65 void* context;
66 freerdp_signal_handler_t handler;
67} cleanup_handler_t;
68
69static size_t cleanup_handler_count = 0;
70static cleanup_handler_t cleanup_handlers[20] = { 0 };
71
72static void lock(void)
73{
74 const int rc = pthread_mutex_lock(&signal_handler_lock);
75 if (rc != 0)
76 {
77 char ebuffer[256] = { 0 };
78 WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
79 winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
80 }
81}
82
83static void unlock(void)
84{
85 const int rc = pthread_mutex_unlock(&signal_handler_lock);
86 if (rc != 0)
87 {
88 char ebuffer[256] = { 0 };
89 WLog_ERR(TAG, "[pthread_mutex_lock] failed with %s [%d]",
90 winpr_strerror(rc, ebuffer, sizeof(ebuffer)), rc);
91 }
92}
93
94static void term_handler(int signum)
95{
96 static BOOL recursive = FALSE;
97
98 if (!recursive)
99 {
100 recursive = TRUE;
101 // NOLINTNEXTLINE(concurrency-mt-unsafe)
102 WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
103 }
104
105 lock();
106 for (size_t x = 0; x < cleanup_handler_count; x++)
107 {
108 const cleanup_handler_t empty = { 0 };
109 cleanup_handler_t* cur = &cleanup_handlers[x];
110 if (cur->handler)
111 {
112 // NOLINTNEXTLINE(concurrency-mt-unsafe)
113 cur->handler(signum, strsignal(signum), cur->context);
114 }
115 *cur = empty;
116 }
117 cleanup_handler_count = 0;
118 unlock();
119}
120
121static void fatal_handler(int signum)
122{
123 struct sigaction default_sigaction;
124 sigset_t this_mask;
125 static BOOL recursive = FALSE;
126
127 if (!recursive)
128 {
129 recursive = TRUE;
130 // NOLINTNEXTLINE(concurrency-mt-unsafe)
131 WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
132
133 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
134 }
135
136 default_sigaction.sa_handler = SIG_DFL;
137 sigfillset(&(default_sigaction.sa_mask));
138 default_sigaction.sa_flags = 0;
139 sigaction(signum, &default_sigaction, NULL);
140 sigemptyset(&this_mask);
141 sigaddset(&this_mask, signum);
142 pthread_sigmask(SIG_UNBLOCK, &this_mask, NULL);
143 (void)raise(signum);
144}
145
146static const int term_signals[] = { SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM };
147
148static const int fatal_signals[] = { SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL,
149 SIGSEGV, SIGTTIN, SIGTTOU, SIGUSR1, SIGUSR2,
150#ifdef SIGPOLL
151 SIGPOLL,
152#endif
153#ifdef SIGPROF
154 SIGPROF,
155#endif
156#ifdef SIGSYS
157 SIGSYS,
158#endif
159 SIGTRAP,
160#ifdef SIGVTALRM
161 SIGVTALRM,
162#endif
163 SIGXCPU, SIGXFSZ };
164
165static BOOL register_handlers(const int* signals, size_t count, void (*handler)(int))
166{
167 WINPR_ASSERT(signals || (count == 0));
168 WINPR_ASSERT(handler);
169
170 sigset_t orig_set = { 0 };
171 struct sigaction saction = { 0 };
172
173 pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
174
175 sigfillset(&(saction.sa_mask));
176 sigdelset(&(saction.sa_mask), SIGCONT);
177
178 saction.sa_handler = handler;
179 saction.sa_flags = 0;
180
181 for (size_t x = 0; x < count; x++)
182 {
183 struct sigaction orig_sigaction = { 0 };
184 if (sigaction(signals[x], NULL, &orig_sigaction) == 0)
185 {
186 if (orig_sigaction.sa_handler != SIG_IGN)
187 {
188 sigaction(signals[x], &saction, NULL);
189 }
190 }
191 }
192
193 pthread_sigmask(SIG_SETMASK, &orig_set, NULL);
194
195 return TRUE;
196}
197
198int freerdp_handle_signals(void)
199{
200 int rc = -1;
201
202 lock();
203
204 WLog_DBG(TAG, "Registering signal hook...");
205
206 if (!register_handlers(fatal_signals, ARRAYSIZE(fatal_signals), fatal_handler))
207 goto fail;
208 if (!register_handlers(term_signals, ARRAYSIZE(term_signals), term_handler))
209 goto fail;
210
211 /* Ignore SIGPIPE signal. */
212 (void)signal(SIGPIPE, SIG_IGN);
213 handlers_registered = TRUE;
214 rc = 0;
215fail:
216 unlock();
217 return rc;
218}
219
220BOOL freerdp_add_signal_cleanup_handler(void* context, freerdp_signal_handler_t handler)
221{
222 BOOL rc = FALSE;
223 lock();
224 if (handlers_registered)
225 {
226 if (cleanup_handler_count < ARRAYSIZE(cleanup_handlers))
227 {
228 cleanup_handler_t* cur = &cleanup_handlers[cleanup_handler_count++];
229 cur->context = context;
230 cur->handler = handler;
231 }
232 else
233 WLog_WARN(TAG, "Failed to register cleanup handler, only %" PRIuz " handlers supported",
234 ARRAYSIZE(cleanup_handlers));
235 }
236 rc = TRUE;
237 unlock();
238 return rc;
239}
240
241BOOL freerdp_del_signal_cleanup_handler(void* context, freerdp_signal_handler_t handler)
242{
243 BOOL rc = FALSE;
244 lock();
245 if (handlers_registered)
246 {
247 for (size_t x = 0; x < cleanup_handler_count; x++)
248 {
249 cleanup_handler_t* cur = &cleanup_handlers[x];
250 if ((cur->context == context) && (cur->handler == handler))
251 {
252 const cleanup_handler_t empty = { 0 };
253 for (size_t y = x + 1; y < cleanup_handler_count - 1; y++)
254 {
255 *cur++ = cleanup_handlers[y];
256 }
257
258 *cur = empty;
259 cleanup_handler_count--;
260 break;
261 }
262 }
263 }
264 rc = TRUE;
265 unlock();
266 return rc;
267}
268
269#endif