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