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