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