usb_moded 0.86.0+mer64
usb_moded-sigpipe.c
Go to the documentation of this file.
1
23
24#include "usb_moded-sigpipe.h"
25
26#include "usb_moded.h"
27#include "usb_moded-log.h"
28
29#include <unistd.h>
30#include <fcntl.h>
31#include <errno.h>
32
33/* ========================================================================= *
34 * Prototypes
35 * ========================================================================= */
36
37/* ------------------------------------------------------------------------- *
38 * SIGPIPE
39 * ------------------------------------------------------------------------- */
40
41static gboolean sigpipe_read_signal_cb(GIOChannel *channel, GIOCondition condition, gpointer data);
42static void sigpipe_trap_signal_cb(int sig);
43static bool sigpipe_crate_pipe (void);
44static void sigpipe_trap_signals (void);
45bool sigpipe_init (void);
46
47/* ========================================================================= *
48 * Data
49 * ========================================================================= */
50
52static int sigpipe_fd = -1;
53
62static gboolean
63sigpipe_read_signal_cb(GIOChannel *channel,
64 GIOCondition condition,
65 gpointer data)
66{
67 LOG_REGISTER_CONTEXT;
68
69 gboolean keep_watch = FALSE;
70
71 int fd, rc, sig;
72
73 (void)data;
74
75 /* Should never happen, but we must disable the io watch
76 * if the pipe fd still goes into unexpected state ... */
77 if( condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL) )
78 goto EXIT;
79
80 if( (fd = g_io_channel_unix_get_fd(channel)) == -1 )
81 goto EXIT;
82
83 /* If the actual read fails, terminate with core dump */
84 rc = TEMP_FAILURE_RETRY(read(fd, &sig, sizeof sig));
85 if( rc != (int)sizeof sig )
86 abort();
87
88 /* handle the signal */
89 usbmoded_handle_signal(sig);
90
91 keep_watch = TRUE;
92
93EXIT:
94 if( !keep_watch )
95 log_crit("disabled signal handler io watch\n");
96
97 return keep_watch;
98}
99
104static void
105sigpipe_trap_signal_cb(int sig)
106{
107 LOG_REGISTER_CONTEXT;
108
109 /* NOTE: This function *MUST* be kept async-signal-safe! */
110
111 static volatile int exit_tries = 0;
112
113 int rc;
114
115 /* Restore signal handler */
116 signal(sig, sigpipe_trap_signal_cb);
117
118 switch( sig )
119 {
120 case SIGINT:
121 case SIGQUIT:
122 case SIGTERM:
123 /* If we receive multiple signals that should have
124 * caused the process to exit, assume that mainloop
125 * is stuck and terminate with core dump. */
126 if( ++exit_tries >= 2 )
127 abort();
128 break;
129
130 default:
131 break;
132 }
133
134 /* Transfer the signal to mainloop via pipe ... */
135 rc = TEMP_FAILURE_RETRY(write(sigpipe_fd, &sig, sizeof sig));
136
137 /* ... or terminate with core dump in case of failures */
138 if( rc != (int)sizeof sig )
139 abort();
140}
141
146static bool
147sigpipe_crate_pipe(void)
148{
149 LOG_REGISTER_CONTEXT;
150
151 bool res = false;
152 GIOChannel *chn = 0;
153 int pfd[2] = { -1, -1 };
154
155 if( pipe2(pfd, O_CLOEXEC) == -1 )
156 goto EXIT;
157
158 if( (chn = g_io_channel_unix_new(pfd[0])) == 0 )
159 goto EXIT;
160
161 if( !g_io_add_watch(chn, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
162 sigpipe_read_signal_cb, 0) )
163 goto EXIT;
164
165 g_io_channel_set_close_on_unref(chn, true), pfd[0] = -1;
166 sigpipe_fd = pfd[1], pfd[1] = -1;
167
168 res = true;
169
170EXIT:
171 if( chn ) g_io_channel_unref(chn);
172 if( pfd[0] != -1 ) close(pfd[0]);
173 if( pfd[1] != -1 ) close(pfd[1]);
174
175 return res;
176}
177
180static void
181sigpipe_trap_signals(void)
182{
183 LOG_REGISTER_CONTEXT;
184
185 static const int sig[] =
186 {
187 SIGINT,
188 SIGQUIT,
189 SIGTERM,
190 SIGHUP,
191 -1
192 };
193
194 for( size_t i = 0; sig[i] != -1; ++i )
195 {
196 signal(sig[i], sigpipe_trap_signal_cb);
197 }
198}
199
204bool
206{
207 LOG_REGISTER_CONTEXT;
208
209 bool success = false;
210
211 if( !sigpipe_crate_pipe() )
212 goto EXIT;
213
214 sigpipe_trap_signals();
215
216 success = true;
217
218EXIT:
219 return success;
220}
bool sigpipe_init(void)