FreeRDP
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 
40 int freerdp_handle_signals(void)
41 {
42  errno = ENOSYS;
43  return -1;
44 }
45 
46 BOOL freerdp_add_signal_cleanup_handler(void* context, freerdp_signal_handler_t fkt)
47 {
48  return FALSE;
49 }
50 
51 BOOL 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 
60 static BOOL handlers_registered = FALSE;
61 static pthread_mutex_t signal_handler_lock = PTHREAD_MUTEX_INITIALIZER;
62 
63 typedef struct
64 {
65  void* context;
66  freerdp_signal_handler_t handler;
67 } cleanup_handler_t;
68 
69 static size_t cleanup_handler_count = 0;
70 static cleanup_handler_t cleanup_handlers[20] = { 0 };
71 
72 static 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 
83 static 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 
94 static void term_handler(int signum)
95 {
96  static BOOL recursive = FALSE;
97 
98  if (!recursive)
99  {
100  recursive = TRUE;
101  WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
102  }
103 
104  lock();
105  for (size_t x = 0; x < cleanup_handler_count; x++)
106  {
107  const cleanup_handler_t empty = { 0 };
108  cleanup_handler_t* cur = &cleanup_handlers[x];
109  if (cur->handler)
110  cur->handler(signum, strsignal(signum), cur->context);
111  *cur = empty;
112  }
113  cleanup_handler_count = 0;
114  unlock();
115 }
116 
117 static void fatal_handler(int signum)
118 {
119  struct sigaction default_sigaction;
120  sigset_t this_mask;
121  static BOOL recursive = FALSE;
122 
123  if (!recursive)
124  {
125  recursive = TRUE;
126  WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
127 
128  winpr_log_backtrace(TAG, WLOG_ERROR, 20);
129  }
130 
131  default_sigaction.sa_handler = SIG_DFL;
132  sigfillset(&(default_sigaction.sa_mask));
133  default_sigaction.sa_flags = 0;
134  sigaction(signum, &default_sigaction, NULL);
135  sigemptyset(&this_mask);
136  sigaddset(&this_mask, signum);
137  pthread_sigmask(SIG_UNBLOCK, &this_mask, NULL);
138  (void)raise(signum);
139 }
140 
141 static const int term_signals[] = { SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM };
142 
143 static const int fatal_signals[] = { SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL,
144  SIGSEGV, SIGTSTP, SIGTTIN, SIGTTOU, SIGUSR1, SIGUSR2,
145 #ifdef SIGPOLL
146  SIGPOLL,
147 #endif
148 #ifdef SIGPROF
149  SIGPROF,
150 #endif
151 #ifdef SIGSYS
152  SIGSYS,
153 #endif
154  SIGTRAP,
155 #ifdef SIGVTALRM
156  SIGVTALRM,
157 #endif
158  SIGXCPU, SIGXFSZ };
159 
160 static BOOL register_handlers(const int* signals, size_t count, void (*handler)(int))
161 {
162  WINPR_ASSERT(signals || (count == 0));
163  WINPR_ASSERT(handler);
164 
165  sigset_t orig_set = { 0 };
166  struct sigaction saction = { 0 };
167 
168  pthread_sigmask(SIG_BLOCK, &(saction.sa_mask), &orig_set);
169 
170  sigfillset(&(saction.sa_mask));
171  sigdelset(&(saction.sa_mask), SIGCONT);
172 
173  saction.sa_handler = handler;
174  saction.sa_flags = 0;
175 
176  for (size_t x = 0; x < count; x++)
177  {
178  struct sigaction orig_sigaction = { 0 };
179  if (sigaction(signals[x], NULL, &orig_sigaction) == 0)
180  {
181  if (orig_sigaction.sa_handler != SIG_IGN)
182  {
183  sigaction(signals[x], &saction, NULL);
184  }
185  }
186  }
187 
188  pthread_sigmask(SIG_SETMASK, &orig_set, NULL);
189 
190  return TRUE;
191 }
192 
193 int freerdp_handle_signals(void)
194 {
195  int rc = -1;
196 
197  lock();
198 
199  WLog_DBG(TAG, "Registering signal hook...");
200 
201  if (!register_handlers(fatal_signals, ARRAYSIZE(fatal_signals), fatal_handler))
202  goto fail;
203  if (!register_handlers(term_signals, ARRAYSIZE(term_signals), term_handler))
204  goto fail;
205 
206  /* Ignore SIGPIPE signal. */
207  (void)signal(SIGPIPE, SIG_IGN);
208  handlers_registered = TRUE;
209  rc = 0;
210 fail:
211  unlock();
212  return rc;
213 }
214 
215 BOOL freerdp_add_signal_cleanup_handler(void* context, freerdp_signal_handler_t handler)
216 {
217  BOOL rc = FALSE;
218  lock();
219  if (handlers_registered)
220  {
221  if (cleanup_handler_count < ARRAYSIZE(cleanup_handlers))
222  {
223  cleanup_handler_t* cur = &cleanup_handlers[cleanup_handler_count++];
224  cur->context = context;
225  cur->handler = handler;
226  }
227  else
228  WLog_WARN(TAG, "Failed to register cleanup handler, only %" PRIuz " handlers supported",
229  ARRAYSIZE(cleanup_handlers));
230  }
231  rc = TRUE;
232  unlock();
233  return rc;
234 }
235 
236 BOOL freerdp_del_signal_cleanup_handler(void* context, freerdp_signal_handler_t handler)
237 {
238  BOOL rc = FALSE;
239  lock();
240  if (handlers_registered)
241  {
242  for (size_t x = 0; x < cleanup_handler_count; x++)
243  {
244  cleanup_handler_t* cur = &cleanup_handlers[x];
245  if ((cur->context == context) && (cur->handler == handler))
246  {
247  const cleanup_handler_t empty = { 0 };
248  for (size_t y = x + 1; y < cleanup_handler_count - 1; y++)
249  {
250  *cur++ = cleanup_handlers[y];
251  }
252 
253  *cur = empty;
254  cleanup_handler_count--;
255  break;
256  }
257  }
258  }
259  rc = TRUE;
260  unlock();
261  return rc;
262 }
263 
264 #endif