Rizin
unix-like reverse engineering framework and cli tools
signals.c
Go to the documentation of this file.
1 //
5 //
6 // Author: Lasse Collin
7 //
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
10 //
12 
13 #include "private.h"
14 
15 
16 volatile sig_atomic_t user_abort = false;
17 
18 
19 #if !(defined(_WIN32) && !defined(__CYGWIN__))
20 
24 static volatile sig_atomic_t exit_signal = 0;
25 
29 
33 static bool signals_are_initialized = false;
34 
36 static size_t signals_block_count = 0;
37 
38 
39 static void
41 {
42  exit_signal = sig;
43  user_abort = true;
44 
45 #ifndef TUKLIB_DOSLIKE
47 #endif
48 
49  return;
50 }
51 
52 
53 extern void
55 {
56  // List of signals for which we establish the signal handler.
57  static const int sigs[] = {
58  SIGINT,
59  SIGTERM,
60 #ifdef SIGHUP
61  SIGHUP,
62 #endif
63 #ifdef SIGPIPE
64  SIGPIPE,
65 #endif
66 #ifdef SIGXCPU
67  SIGXCPU,
68 #endif
69 #ifdef SIGXFSZ
70  SIGXFSZ,
71 #endif
72  };
73 
74  // Mask of the signals for which we have established a signal handler.
75  sigemptyset(&hooked_signals);
76  for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i)
77  sigaddset(&hooked_signals, sigs[i]);
78 
79 #ifdef SIGALRM
80  // Add also the signals from message.c to hooked_signals.
81  for (size_t i = 0; message_progress_sigs[i] != 0; ++i)
83 #endif
84 
85  // Using "my_sa" because "sa" may conflict with a sockaddr variable
86  // from system headers on Solaris.
87  struct sigaction my_sa;
88 
89  // All the signals that we handle we also blocked while the signal
90  // handler runs.
91  my_sa.sa_mask = hooked_signals;
92 
93  // Don't set SA_RESTART, because we want EINTR so that we can check
94  // for user_abort and cleanup before exiting. We block the signals
95  // for which we have established a handler when we don't want EINTR.
96  my_sa.sa_flags = 0;
97  my_sa.sa_handler = &signal_handler;
98 
99  for (size_t i = 0; i < ARRAY_SIZE(sigs); ++i) {
100  // If the parent process has left some signals ignored,
101  // we don't unignore them.
102  struct sigaction old;
103  if (sigaction(sigs[i], NULL, &old) == 0
104  && old.sa_handler == SIG_IGN)
105  continue;
106 
107  // Establish the signal handler.
108  if (sigaction(sigs[i], &my_sa, NULL))
110  }
111 
113 
114  return;
115 }
116 
117 
118 #ifndef __VMS
119 extern void
121 {
123  if (signals_block_count++ == 0) {
124  const int saved_errno = errno;
125  mythread_sigmask(SIG_BLOCK, &hooked_signals, NULL);
126  errno = saved_errno;
127  }
128  }
129 
130  return;
131 }
132 
133 
134 extern void
136 {
139 
140  if (--signals_block_count == 0) {
141  const int saved_errno = errno;
142  mythread_sigmask(SIG_UNBLOCK, &hooked_signals, NULL);
143  errno = saved_errno;
144  }
145  }
146 
147  return;
148 }
149 #endif
150 
151 
152 extern void
154 {
155  const int sig = (int)exit_signal;
156 
157  if (sig != 0) {
158 #if defined(TUKLIB_DOSLIKE) || defined(__VMS)
159  // Don't raise(), set only exit status. This avoids
160  // printing unwanted message about SIGINT when the user
161  // presses C-c.
163 #else
164  struct sigaction sa;
165  sa.sa_handler = SIG_DFL;
166  sigfillset(&sa.sa_mask);
167  sa.sa_flags = 0;
168  sigaction(sig, &sa, NULL);
169  raise(sig);
170 #endif
171  }
172 
173  return;
174 }
175 
176 #else
177 
178 // While Windows has some very basic signal handling functions as required
179 // by C89, they are not really used, and e.g. SIGINT doesn't work exactly
180 // the way it does on POSIX (Windows creates a new thread for the signal
181 // handler). Instead, we use SetConsoleCtrlHandler() to catch user
182 // pressing C-c, because that seems to be the recommended way to do it.
183 //
184 // NOTE: This doesn't work under MSYS. Trying with SIGINT doesn't work
185 // either even if it appeared to work at first. So test using Windows
186 // console window.
187 
188 static BOOL WINAPI
190 {
191  // Since we don't get a signal number which we could raise() at
192  // signals_exit() like on POSIX, just set the exit status to
193  // indicate an error, so that we cannot return with zero exit status.
195  user_abort = true;
196  return TRUE;
197 }
198 
199 
200 extern void
201 signals_init(void)
202 {
203  if (!SetConsoleCtrlHandler(&signal_handler, TRUE))
205 
206  return;
207 }
208 
209 #endif
#define ARRAY_SIZE(a)
lzma_index ** i
Definition: index.h:629
#define NULL
Definition: cris-opc.c:27
void io_write_to_user_abort_pipe(void)
Write a byte to user_abort_pipe[1].
Definition: file_io.c:135
#define lzma_attribute(attr)
Definition: lzma.h:259
assert(limit<=UINT32_MAX/2)
void message_signal_handler(void)
Definition: message.c:796
const int message_progress_sigs[]
Signals used for progress message handling.
int type
Definition: mipsasm.c:17
#define TRUE
Definition: mybfd.h:103
static void mythread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
Definition: mythread.h:87
static int
Definition: sfsocketcall.h:114
int sigset_t
Definition: sftypes.h:63
volatile sig_atomic_t user_abort
Definition: signals.c:16
static size_t signals_block_count
signals_block() and signals_unblock() can be called recursively.
Definition: signals.c:36
static volatile sig_atomic_t exit_signal
Definition: signals.c:24
void signals_init(void)
Definition: signals.c:54
static bool signals_are_initialized
Definition: signals.c:33
void signals_unblock(void)
Unblock the signals blocked by signals_block().
Definition: signals.c:135
void signals_block(void)
Definition: signals.c:120
void signals_exit(void)
Definition: signals.c:153
static sigset_t hooked_signals
Definition: signals.c:28
static void signal_handler(int sig)
Definition: signals.c:40
void set_exit_status(enum exit_status_type new_status)
Definition: main.c:31
Common includes, definitions, and prototypes.
@ E_ERROR
Definition: transport.h:23
#define SIGHUP
Definition: win.h:86
DWORD