1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Signal handling
4 *
5 * Copyright 2011 Shea Levy <shea@shealevy.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stddef.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <winpr/crt.h>
29
30 #include <freerdp/utils/signal.h>
31 #include <freerdp/log.h>
32
33 #define TAG FREERDP_TAG("utils")
34
35 #ifdef _WIN32
36
freerdp_handle_signals(void)37 int freerdp_handle_signals(void)
38 {
39 errno = ENOSYS;
40 return -1;
41 }
42
43 #else
44
45 #include <pthread.h>
46 #include <winpr/debug.h>
47
48 volatile sig_atomic_t terminal_needs_reset = 0;
49 int terminal_fildes = 0;
50 struct termios orig_flags;
51 struct termios new_flags;
52
fatal_handler(int signum)53 static void fatal_handler(int signum)
54 {
55 struct sigaction default_sigaction;
56 sigset_t this_mask;
57 static BOOL recursive = FALSE;
58
59 if (!recursive)
60 {
61 recursive = TRUE;
62 WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum);
63
64 winpr_log_backtrace(TAG, WLOG_ERROR, 20);
65 }
66 if (terminal_needs_reset)
67 tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags);
68
69 default_sigaction.sa_handler = SIG_DFL;
70 sigfillset(&(default_sigaction.sa_mask));
71 default_sigaction.sa_flags = 0;
72 sigaction(signum, &default_sigaction, NULL);
73 sigemptyset(&this_mask);
74 sigaddset(&this_mask, signum);
75 pthread_sigmask(SIG_UNBLOCK, &this_mask, NULL);
76 raise(signum);
77 }
78
79 const int fatal_signals[] = { SIGABRT, SIGALRM, SIGBUS, SIGFPE, SIGHUP, SIGILL,
80 SIGINT, SIGKILL, SIGQUIT, SIGSEGV, SIGSTOP, SIGTERM,
81 SIGTSTP, SIGTTIN, SIGTTOU, SIGUSR1, SIGUSR2,
82 #ifdef SIGPOLL
83 SIGPOLL,
84 #endif
85 #ifdef SIGPROF
86 SIGPROF,
87 #endif
88 #ifdef SIGSYS
89 SIGSYS,
90 #endif
91 SIGTRAP,
92 #ifdef SIGVTALRM
93 SIGVTALRM,
94 #endif
95 SIGXCPU, SIGXFSZ };
96
freerdp_handle_signals(void)97 int freerdp_handle_signals(void)
98 {
99 size_t signal_index;
100 sigset_t orig_set;
101 struct sigaction orig_sigaction;
102 struct sigaction fatal_sigaction;
103 WLog_DBG(TAG, "Registering signal hook...");
104 sigfillset(&(fatal_sigaction.sa_mask));
105 sigdelset(&(fatal_sigaction.sa_mask), SIGCONT);
106 pthread_sigmask(SIG_BLOCK, &(fatal_sigaction.sa_mask), &orig_set);
107 fatal_sigaction.sa_handler = fatal_handler;
108 fatal_sigaction.sa_flags = 0;
109
110 for (signal_index = 0; signal_index < ARRAYSIZE(fatal_signals); signal_index++)
111 {
112 if (sigaction(fatal_signals[signal_index], NULL, &orig_sigaction) == 0)
113 {
114 if (orig_sigaction.sa_handler != SIG_IGN)
115 {
116 sigaction(fatal_signals[signal_index], &fatal_sigaction, NULL);
117 }
118 }
119 }
120
121 pthread_sigmask(SIG_SETMASK, &orig_set, NULL);
122 /* Ignore SIGPIPE signal. */
123 signal(SIGPIPE, SIG_IGN);
124 return 0;
125 }
126
127 #endif
128