Rizin
unix-like reverse engineering framework and cli tools
signals.c File Reference

Handling signals to abort operation. More...

#include "private.h"

Go to the source code of this file.

Functions

static void signal_handler (int sig)
 
void signals_init (void)
 
void signals_block (void)
 
void signals_unblock (void)
 Unblock the signals blocked by signals_block(). More...
 
void signals_exit (void)
 

Variables

volatile sig_atomic_t user_abort = false
 
static volatile sig_atomic_t exit_signal = 0
 
static sigset_t hooked_signals
 
static bool signals_are_initialized = false
 
static size_t signals_block_count = 0
 signals_block() and signals_unblock() can be called recursively. More...
 

Detailed Description

Handling signals to abort operation.

Definition in file signals.c.

Function Documentation

◆ signal_handler()

static void signal_handler ( int  sig)
static

Definition at line 40 of file signals.c.

41 {
42  exit_signal = sig;
43  user_abort = true;
44 
45 #ifndef TUKLIB_DOSLIKE
47 #endif
48 
49  return;
50 }
void io_write_to_user_abort_pipe(void)
Write a byte to user_abort_pipe[1].
Definition: file_io.c:135
volatile sig_atomic_t user_abort
Definition: signals.c:16
static volatile sig_atomic_t exit_signal
Definition: signals.c:24

References exit_signal, io_write_to_user_abort_pipe(), and user_abort.

Referenced by signals_init().

◆ signals_block()

void signals_block ( void  )

Block the signals which don't have SA_RESTART and which would just set user_abort to true. This is handy when we don't want to handle EINTR and don't want SA_RESTART either.

Definition at line 120 of file signals.c.

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 }
#define NULL
Definition: cris-opc.c:27
static void mythread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
Definition: mythread.h:87
static size_t signals_block_count
signals_block() and signals_unblock() can be called recursively.
Definition: signals.c:36
static bool signals_are_initialized
Definition: signals.c:33
static sigset_t hooked_signals
Definition: signals.c:28

References hooked_signals, mythread_sigmask(), NULL, signals_are_initialized, and signals_block_count.

Referenced by io_close(), io_open_dest(), io_open_src(), io_open_src_real(), message_progress_update(), print_filename(), progress_flush(), and vmessage().

◆ signals_exit()

void signals_exit ( void  )

If user has sent us a signal earlier to terminate the process, re-raise that signal to actually terminate the process.

Definition at line 153 of file signals.c.

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 }
static int
Definition: sfsocketcall.h:114
void set_exit_status(enum exit_status_type new_status)
Definition: main.c:31
@ E_ERROR
Definition: transport.h:23

References E_ERROR, exit_signal, int, NULL, and set_exit_status().

Referenced by main().

◆ signals_init()

void signals_init ( void  )

Initialize the signal handler, which will set user_abort to true when user e.g. presses C-c.

Definition at line 54 of file signals.c.

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 }
#define ARRAY_SIZE(a)
lzma_index ** i
Definition: index.h:629
void message_signal_handler(void)
Definition: message.c:796
const int message_progress_sigs[]
Signals used for progress message handling.
static void signal_handler(int sig)
Definition: signals.c:40
#define SIGHUP
Definition: win.h:86

References ARRAY_SIZE, hooked_signals, i, message_progress_sigs, message_signal_handler(), NULL, SIGHUP, signal_handler(), and signals_are_initialized.

Referenced by main().

◆ signals_unblock()

void signals_unblock ( void  )

Unblock the signals blocked by signals_block().

Definition at line 135 of file signals.c.

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 }
assert(limit<=UINT32_MAX/2)

References assert(), hooked_signals, mythread_sigmask(), NULL, signals_are_initialized, and signals_block_count.

Referenced by io_close(), io_open_dest(), io_open_src(), io_open_src_real(), message_progress_update(), print_filename(), progress_flush(), and vmessage().

Variable Documentation

◆ exit_signal

volatile sig_atomic_t exit_signal = 0
static

If we were interrupted by a signal, we store the signal number so that we can raise that signal to kill the program when all cleanups have been done.

Definition at line 24 of file signals.c.

Referenced by signal_handler(), and signals_exit().

◆ hooked_signals

sigset_t hooked_signals
static

Mask of signals for which we have established a signal handler to set user_abort to true.

Definition at line 28 of file signals.c.

Referenced by signals_block(), signals_init(), and signals_unblock().

◆ signals_are_initialized

bool signals_are_initialized = false
static

True once signals_init() has finished. This is used to skip blocking signals (with uninitialized hooked_signals) if signals_block() and signals_unblock() are called before signals_init() has been called.

Definition at line 33 of file signals.c.

Referenced by signals_block(), signals_init(), and signals_unblock().

◆ signals_block_count

size_t signals_block_count = 0
static

signals_block() and signals_unblock() can be called recursively.

Definition at line 36 of file signals.c.

Referenced by signals_block(), and signals_unblock().

◆ user_abort

volatile sig_atomic_t user_abort = false

If this is true, we will clean up the possibly incomplete output file, return to main() as soon as practical. That is, the code needs to poll this variable in various places.

Definition at line 16 of file signals.c.

Referenced by coder_normal(), coder_passthru(), coder_run(), io_read(), io_wait(), io_write_buf(), main(), read_name(), and signal_handler().