/src/dovecot/src/lib/lib-signals.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "array.h" |
5 | | #include "ioloop.h" |
6 | | #include "write-full.h" |
7 | | #include "llist.h" |
8 | | #include "lib-signals.h" |
9 | | |
10 | | #include <stdio.h> |
11 | | #include <signal.h> |
12 | | #include <unistd.h> |
13 | | |
14 | 329k | #define MAX_SIGNAL_VALUE 63 |
15 | | |
16 | | #define SIGNAL_IS_TERMINAL(signo) \ |
17 | 0 | ((signo) == SIGINT || (signo) == SIGQUIT || (signo) == SIGTERM) |
18 | | |
19 | | #if !defined(SA_SIGINFO) && !defined(SI_NOINFO) |
20 | | /* without SA_SIGINFO we don't know what the real code is. we need SI_NOINFO |
21 | | to make sure lib_signal_code_to_str() returns "". */ |
22 | | # define SI_NOINFO -1 |
23 | | #endif |
24 | | |
25 | | struct signal_ioloop { |
26 | | struct signal_ioloop *prev, *next; |
27 | | |
28 | | int refcount; |
29 | | struct ioloop *ioloop; |
30 | | struct io *io; |
31 | | }; |
32 | | |
33 | | struct signal_handler { |
34 | | signal_handler_t *immediate_handler; |
35 | | signal_handler_t *delayed_handler; |
36 | | void *context; |
37 | | |
38 | | enum libsig_flags flags; |
39 | | struct signal_handler *next; |
40 | | struct signal_ioloop *sig_ioloop; |
41 | | |
42 | | bool expected:1; |
43 | | bool shadowed:1; |
44 | | }; |
45 | | |
46 | | volatile unsigned int signal_term_counter = 0; |
47 | | |
48 | | /* Remember that these are accessed inside signal handler which may be called |
49 | | even while we're initializing/deinitializing. Try hard to keep everything |
50 | | in consistent state. */ |
51 | | static struct signal_handler *signal_handlers[MAX_SIGNAL_VALUE+1] = { NULL, }; |
52 | | static int sig_pipe_fd[2] = { -1, -1 }; |
53 | | |
54 | | static bool signals_initialized = FALSE; |
55 | | static unsigned int signals_expected = 0; |
56 | | static struct signal_ioloop *signal_ioloops = NULL; |
57 | | |
58 | | static siginfo_t pending_signals[MAX_SIGNAL_VALUE+1]; |
59 | | static ARRAY(siginfo_t) pending_shadowed_signals; |
60 | | static bool have_pending_signals = FALSE; |
61 | | static bool have_missing_ioloops = FALSE; |
62 | | static bool ioloop_switched = FALSE; |
63 | | |
64 | | static void signal_read(void *context); |
65 | | |
66 | | bool lib_signals_eintr_retry(unsigned int term_counter) |
67 | 0 | { |
68 | 0 | return errno == EINTR && term_counter == signal_term_counter; |
69 | 0 | } |
70 | | |
71 | | const char *lib_signal_code_to_str(int signo, int sicode) |
72 | 0 | { |
73 | | /* common */ |
74 | 0 | switch (sicode) { |
75 | | #ifdef SI_NOINFO |
76 | | case SI_NOINFO: |
77 | | return ""; |
78 | | #endif |
79 | 0 | case SI_USER: |
80 | 0 | return "kill"; |
81 | 0 | #ifdef SI_KERNEL |
82 | 0 | case SI_KERNEL: |
83 | 0 | return "kernel"; |
84 | 0 | #endif |
85 | 0 | case SI_TIMER: |
86 | 0 | return "timer"; |
87 | 0 | } |
88 | | |
89 | | /* If SEGV_MAPERR is supported, the rest of them must be too. |
90 | | FreeBSD 6 at least doesn't support these. */ |
91 | 0 | #ifdef SEGV_MAPERR |
92 | 0 | switch (signo) { |
93 | 0 | case SIGSEGV: |
94 | 0 | switch (sicode) { |
95 | 0 | case SEGV_MAPERR: |
96 | 0 | return "address not mapped"; |
97 | 0 | case SEGV_ACCERR: |
98 | 0 | return "invalid permissions"; |
99 | 0 | } |
100 | 0 | break; |
101 | 0 | case SIGBUS: |
102 | 0 | switch (sicode) { |
103 | 0 | case BUS_ADRALN: |
104 | 0 | return "invalid address alignment"; |
105 | 0 | #ifdef BUS_ADRERR /* for OSX 10.3 */ |
106 | 0 | case BUS_ADRERR: |
107 | 0 | return "nonexistent physical address"; |
108 | 0 | #endif |
109 | 0 | #ifdef BUS_OBJERR /* for OSX 10.3 */ |
110 | 0 | case BUS_OBJERR: |
111 | 0 | return "object-specific hardware error"; |
112 | 0 | #endif |
113 | 0 | } |
114 | 0 | } |
115 | 0 | #endif |
116 | 0 | return t_strdup_printf("unknown %d", sicode); |
117 | 0 | } |
118 | | |
119 | | void lib_signal_delayed(const siginfo_t *si) |
120 | 0 | { |
121 | 0 | int signo = si->si_signo; |
122 | |
|
123 | 0 | if (pending_signals[signo].si_signo != 0) |
124 | 0 | return; |
125 | | |
126 | 0 | pending_signals[signo] = *si; |
127 | 0 | if (!have_pending_signals) { |
128 | 0 | char c = 0; |
129 | 0 | if (write(sig_pipe_fd[1], &c, 1) != 1) { |
130 | 0 | lib_signals_syscall_error( |
131 | 0 | "signal: write(sigpipe) failed: "); |
132 | 0 | } |
133 | 0 | have_pending_signals = TRUE; |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | | #ifdef SA_SIGINFO |
138 | | static void sig_handler(int signo, siginfo_t *si, void *context ATTR_UNUSED) |
139 | | #else |
140 | | static void sig_handler(int signo) |
141 | | #endif |
142 | 0 | { |
143 | 0 | struct signal_handler *h; |
144 | 0 | int saved_errno; |
145 | |
|
146 | | #if defined(SI_NOINFO) || !defined(SA_SIGINFO) |
147 | | #ifndef SA_SIGINFO |
148 | | siginfo_t *si = NULL; |
149 | | #endif |
150 | | siginfo_t tmp_si; |
151 | | |
152 | | if (si == NULL) { |
153 | | /* Solaris can leave this to NULL */ |
154 | | i_zero(&tmp_si); |
155 | | tmp_si.si_signo = signo; |
156 | | tmp_si.si_code = SI_NOINFO; |
157 | | si = &tmp_si; |
158 | | } |
159 | | #endif |
160 | |
|
161 | 0 | if (signo < 0 || signo > MAX_SIGNAL_VALUE) |
162 | 0 | return; |
163 | | |
164 | 0 | if (SIGNAL_IS_TERMINAL(signo)) |
165 | 0 | signal_term_counter++; |
166 | | |
167 | | /* remember that we're inside a signal handler which might have been |
168 | | called at any time. don't do anything that's unsafe. we might also |
169 | | get interrupted by another signal while inside this handler. */ |
170 | 0 | saved_errno = errno; |
171 | 0 | for (h = signal_handlers[signo]; h != NULL; h = h->next) { |
172 | 0 | if (h->immediate_handler != NULL) |
173 | 0 | h->immediate_handler(si, h->context); |
174 | 0 | else |
175 | 0 | lib_signal_delayed(si); |
176 | 0 | } |
177 | 0 | errno = saved_errno; |
178 | 0 | } |
179 | | |
180 | | #ifdef SA_SIGINFO |
181 | | static void sig_ignore(int signo ATTR_UNUSED, siginfo_t *si ATTR_UNUSED, |
182 | | void *context ATTR_UNUSED) |
183 | | #else |
184 | | static void sig_ignore(int signo ATTR_UNUSED) |
185 | | #endif |
186 | 0 | { |
187 | | /* if we used SIG_IGN instead of this function, |
188 | | the system call might be restarted */ |
189 | 0 | } |
190 | | |
191 | | static struct signal_ioloop * |
192 | | lib_signals_ioloop_find(struct ioloop *ioloop) |
193 | 0 | { |
194 | 0 | struct signal_ioloop *l; |
195 | |
|
196 | 0 | for (l = signal_ioloops; l != NULL; l = l->next) { |
197 | 0 | if (l->ioloop == ioloop) |
198 | 0 | break; |
199 | 0 | } |
200 | 0 | return l; |
201 | 0 | } |
202 | | |
203 | | static void lib_signals_init_io(struct signal_ioloop *l) |
204 | 0 | { |
205 | 0 | if (sig_pipe_fd[0] == -1) { |
206 | | /* no delayed signals */ |
207 | 0 | return; |
208 | 0 | } |
209 | | |
210 | 0 | l->io = io_add_to(l->ioloop, sig_pipe_fd[0], IO_READ, signal_read, NULL); |
211 | 0 | io_set_never_wait_alone(l->io, signals_expected == 0); |
212 | 0 | } |
213 | | |
214 | | static struct signal_ioloop * |
215 | | lib_signals_ioloop_ref(struct ioloop *ioloop) |
216 | 0 | { |
217 | 0 | struct signal_ioloop *l; |
218 | |
|
219 | 0 | l = lib_signals_ioloop_find(ioloop); |
220 | 0 | if (l == NULL) { |
221 | 0 | l = i_new(struct signal_ioloop, 1); |
222 | 0 | l->ioloop = ioloop; |
223 | 0 | lib_signals_init_io(l); |
224 | 0 | DLLIST_PREPEND(&signal_ioloops, l); |
225 | 0 | } |
226 | 0 | l->refcount++; |
227 | 0 | return l; |
228 | 0 | } |
229 | | |
230 | | static void lib_signals_ioloop_unref(struct signal_ioloop **_sig_ioloop) |
231 | 0 | { |
232 | 0 | struct signal_ioloop *sig_ioloop = *_sig_ioloop; |
233 | |
|
234 | 0 | *_sig_ioloop = NULL; |
235 | |
|
236 | 0 | if (sig_ioloop == NULL) |
237 | 0 | return; |
238 | 0 | i_assert(sig_ioloop->refcount > 0); |
239 | 0 | if (--sig_ioloop->refcount > 0) |
240 | 0 | return; |
241 | 0 | io_remove(&sig_ioloop->io); |
242 | 0 | DLLIST_REMOVE(&signal_ioloops, sig_ioloop); |
243 | 0 | i_free(sig_ioloop); |
244 | 0 | } |
245 | | |
246 | | static void signal_handler_switch_ioloop(struct signal_handler *h) |
247 | 0 | { |
248 | 0 | lib_signals_ioloop_unref(&h->sig_ioloop); |
249 | 0 | if (current_ioloop != NULL) |
250 | 0 | h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop); |
251 | 0 | else |
252 | 0 | have_missing_ioloops = TRUE; |
253 | 0 | } |
254 | | |
255 | | static void signal_handler_free(struct signal_handler *h) |
256 | 0 | { |
257 | 0 | lib_signals_ioloop_unref(&h->sig_ioloop); |
258 | 0 | i_free(h); |
259 | 0 | } |
260 | | |
261 | | static void signal_handle_shadowed(void) |
262 | 0 | { |
263 | 0 | const siginfo_t *sis; |
264 | 0 | unsigned int count, i; |
265 | |
|
266 | 0 | if (!array_is_created(&pending_shadowed_signals) || |
267 | 0 | array_count(&pending_shadowed_signals) == 0) |
268 | 0 | return; |
269 | | |
270 | 0 | sis = array_get(&pending_shadowed_signals, &count); |
271 | 0 | for (i = 0; i < count; i++) { |
272 | 0 | struct signal_handler *h; |
273 | 0 | bool shadowed = FALSE; |
274 | |
|
275 | 0 | i_assert(sis[i].si_signo > 0); |
276 | 0 | for (h = signal_handlers[sis[i].si_signo]; h != NULL; |
277 | 0 | h = h->next) { |
278 | 0 | i_assert(h->sig_ioloop != NULL); |
279 | 0 | if (h->delayed_handler == NULL || |
280 | 0 | (h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) != 0) |
281 | 0 | continue; |
282 | 0 | if (h->shadowed && |
283 | 0 | h->sig_ioloop->ioloop != current_ioloop) { |
284 | 0 | shadowed = TRUE; |
285 | 0 | continue; |
286 | 0 | } |
287 | | /* handler can be called now */ |
288 | 0 | h->shadowed = FALSE; |
289 | 0 | h->delayed_handler(&sis[i], h->context); |
290 | 0 | } |
291 | 0 | if (!shadowed) { |
292 | | /* no handlers are shadowed anymore; delete the signal |
293 | | info */ |
294 | 0 | array_delete(&pending_shadowed_signals, i, 1); |
295 | 0 | sis = array_get(&pending_shadowed_signals, &count); |
296 | 0 | } |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | | static void signal_check_shadowed(void) |
301 | 0 | { |
302 | 0 | struct signal_ioloop *sig_ioloop; |
303 | |
|
304 | 0 | if (!array_is_created(&pending_shadowed_signals) || |
305 | 0 | array_count(&pending_shadowed_signals) == 0) |
306 | 0 | return; |
307 | | |
308 | 0 | sig_ioloop = lib_signals_ioloop_find(current_ioloop); |
309 | 0 | if (sig_ioloop != NULL) |
310 | 0 | io_set_pending(sig_ioloop->io); |
311 | 0 | } |
312 | | |
313 | | static void signal_shadow(int signo, const siginfo_t *si) |
314 | 0 | { |
315 | 0 | const siginfo_t *sis; |
316 | 0 | unsigned int count, i; |
317 | | |
318 | | /* remember last signal info for handlers that cannot run in |
319 | | current ioloop */ |
320 | 0 | if (!array_is_created(&pending_shadowed_signals)) |
321 | 0 | i_array_init(&pending_shadowed_signals, 4); |
322 | 0 | sis = array_get(&pending_shadowed_signals, &count); |
323 | 0 | for (i = 0; i < count; i++) { |
324 | 0 | i_assert(sis[i].si_signo != 0); |
325 | 0 | if (sis[i].si_signo == signo) |
326 | 0 | break; |
327 | 0 | } |
328 | 0 | array_idx_set(&pending_shadowed_signals, i, si); |
329 | 0 | } |
330 | | |
331 | | static void ATTR_NULL(1) signal_read(void *context ATTR_UNUSED) |
332 | 0 | { |
333 | 0 | siginfo_t signals[MAX_SIGNAL_VALUE+1]; |
334 | 0 | sigset_t fullset, oldset; |
335 | 0 | struct signal_handler *h; |
336 | 0 | char buf[64]; |
337 | 0 | int signo; |
338 | 0 | ssize_t ret; |
339 | |
|
340 | 0 | if (ioloop_switched) { |
341 | 0 | ioloop_switched = FALSE; |
342 | | /* handle any delayed signal handlers that emerged from the |
343 | | shadow */ |
344 | 0 | signal_handle_shadowed(); |
345 | 0 | } |
346 | |
|
347 | 0 | if (sigfillset(&fullset) < 0) |
348 | 0 | i_fatal("sigfillset() failed: %m"); |
349 | 0 | if (sigprocmask(SIG_BLOCK, &fullset, &oldset) < 0) |
350 | 0 | i_fatal("sigprocmask() failed: %m"); |
351 | | |
352 | | /* typically we should read only a single byte, but if a signal is sent |
353 | | while signal handler is running we might get more. */ |
354 | 0 | ret = read(sig_pipe_fd[0], buf, sizeof(buf)); |
355 | 0 | if (ret > 0) { |
356 | 0 | memcpy(signals, pending_signals, sizeof(signals)); |
357 | 0 | memset(pending_signals, 0, sizeof(pending_signals)); |
358 | 0 | have_pending_signals = FALSE; |
359 | 0 | } else if (ret < 0) { |
360 | 0 | if (errno != EAGAIN) |
361 | 0 | i_fatal("read(sigpipe) failed: %m"); |
362 | 0 | } else { |
363 | 0 | i_fatal("read(sigpipe) failed: EOF"); |
364 | 0 | } |
365 | 0 | if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) |
366 | 0 | i_fatal("sigprocmask() failed: %m"); |
367 | | |
368 | 0 | if (ret < 0) |
369 | 0 | return; |
370 | | |
371 | | /* call the delayed handlers after signals are copied and unblocked */ |
372 | 0 | for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) { |
373 | 0 | bool shadowed = FALSE; |
374 | |
|
375 | 0 | if (signals[signo].si_signo == 0) |
376 | 0 | continue; |
377 | | |
378 | 0 | for (h = signal_handlers[signo]; h != NULL; h = h->next) { |
379 | 0 | i_assert(h->sig_ioloop != NULL); |
380 | 0 | if (h->delayed_handler == NULL) { |
381 | | /* handler already called immediately in signal |
382 | | context */ |
383 | 0 | continue; |
384 | 0 | } |
385 | 0 | if ((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) == 0 && |
386 | 0 | h->sig_ioloop->ioloop != current_ioloop) { |
387 | | /* cannot run handler in current ioloop |
388 | | (shadowed) */ |
389 | 0 | h->shadowed = TRUE; |
390 | 0 | shadowed = TRUE; |
391 | 0 | continue; |
392 | 0 | } |
393 | | /* handler can be called now */ |
394 | 0 | h->delayed_handler(&signals[signo], h->context); |
395 | 0 | } |
396 | | |
397 | 0 | if (shadowed) { |
398 | | /* remember last signal info for handlers that cannot |
399 | | run in current ioloop (shadowed) */ |
400 | 0 | signal_shadow(signo, &signals[signo]); |
401 | 0 | } |
402 | 0 | } |
403 | 0 | } |
404 | | |
405 | | static void lib_signals_update_expected_signals(bool expected) |
406 | 0 | { |
407 | 0 | struct signal_ioloop *sig_ioloop; |
408 | |
|
409 | 0 | if (expected) |
410 | 0 | signals_expected++; |
411 | 0 | else { |
412 | 0 | i_assert(signals_expected > 0); |
413 | 0 | signals_expected--; |
414 | 0 | } |
415 | | |
416 | 0 | sig_ioloop = signal_ioloops; |
417 | 0 | for (; sig_ioloop != NULL; sig_ioloop = sig_ioloop->next) { |
418 | 0 | if (sig_ioloop->io != NULL) { |
419 | 0 | io_set_never_wait_alone(sig_ioloop->io, |
420 | 0 | signals_expected == 0); |
421 | 0 | } |
422 | 0 | } |
423 | 0 | } |
424 | | |
425 | | static void lib_signals_ioloop_switch(void) |
426 | 0 | { |
427 | 0 | struct signal_handler *h; |
428 | |
|
429 | 0 | if (current_ioloop == NULL || sig_pipe_fd[0] <= 0) |
430 | 0 | return; |
431 | | |
432 | | /* initialize current_ioloop for signal handlers created before the |
433 | | first ioloop. */ |
434 | 0 | for (int signo = 0; signo < MAX_SIGNAL_VALUE; signo++) { |
435 | 0 | for (h = signal_handlers[signo]; h != NULL; h = h->next) { |
436 | 0 | if ((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) != 0) |
437 | 0 | lib_signals_ioloop_unref(&h->sig_ioloop); |
438 | 0 | if (h->sig_ioloop == NULL) |
439 | 0 | h->sig_ioloop = lib_signals_ioloop_ref(current_ioloop); |
440 | 0 | } |
441 | 0 | } |
442 | 0 | have_missing_ioloops = FALSE; |
443 | 0 | } |
444 | | |
445 | | static void lib_signals_ioloop_switched(struct ioloop *prev_ioloop ATTR_UNUSED) |
446 | 0 | { |
447 | 0 | ioloop_switched = TRUE; |
448 | |
|
449 | 0 | lib_signals_ioloop_switch(); |
450 | | |
451 | | /* check whether we can now handle any shadowed delayed signals */ |
452 | 0 | signal_check_shadowed(); |
453 | 0 | } |
454 | | |
455 | | static void lib_signals_ioloop_destroyed(struct ioloop *ioloop) |
456 | 0 | { |
457 | 0 | struct signal_ioloop *sig_ioloop; |
458 | |
|
459 | 0 | sig_ioloop = lib_signals_ioloop_find(ioloop); |
460 | 0 | if (sig_ioloop != NULL) { |
461 | 0 | io_remove(&sig_ioloop->io); |
462 | 0 | sig_ioloop->ioloop = NULL; |
463 | 0 | } |
464 | 0 | } |
465 | | |
466 | | void lib_signals_ioloop_detach(void) |
467 | 0 | { |
468 | 0 | struct signal_handler *h; |
469 | |
|
470 | 0 | for (int signo = 0; signo < MAX_SIGNAL_VALUE; signo++) { |
471 | 0 | for (h = signal_handlers[signo]; h != NULL; h = h->next) { |
472 | 0 | if (h->sig_ioloop != NULL) { |
473 | 0 | lib_signals_ioloop_unref(&h->sig_ioloop); |
474 | 0 | have_missing_ioloops = TRUE; |
475 | 0 | } |
476 | 0 | } |
477 | 0 | } |
478 | 0 | } |
479 | | |
480 | | void lib_signals_ioloop_attach(void) |
481 | 0 | { |
482 | 0 | if (have_missing_ioloops) |
483 | 0 | lib_signals_ioloop_switch(); |
484 | 0 | } |
485 | | |
486 | | static void lib_signals_set(int signo, enum libsig_flags flags) |
487 | 0 | { |
488 | 0 | struct sigaction act; |
489 | |
|
490 | 0 | if (sigemptyset(&act.sa_mask) < 0) |
491 | 0 | i_fatal("sigemptyset(): %m"); |
492 | 0 | #ifdef SA_SIGINFO |
493 | 0 | act.sa_flags = SA_SIGINFO; |
494 | 0 | act.sa_sigaction = sig_handler; |
495 | | #else |
496 | | act.sa_flags = 0; |
497 | | act.sa_handler = sig_handler; |
498 | | #endif |
499 | 0 | if ((flags & LIBSIG_FLAG_RESTART) != 0) |
500 | 0 | act.sa_flags |= SA_RESTART; |
501 | 0 | if (sigaction(signo, &act, NULL) < 0) |
502 | 0 | i_fatal("sigaction(%d): %m", signo); |
503 | 0 | } |
504 | | |
505 | | void lib_signals_set_handler(int signo, enum libsig_flags flags, |
506 | | signal_handler_t *handler, void *context) |
507 | 0 | { |
508 | 0 | if ((flags & LIBSIG_FLAG_DELAYED) == 0) |
509 | 0 | lib_signals_set_handler2(signo, flags, handler, NULL, context); |
510 | 0 | else |
511 | 0 | lib_signals_set_handler2(signo, flags, NULL, handler, context); |
512 | 0 | } |
513 | | |
514 | | void lib_signals_set_handler2(int signo, enum libsig_flags flags, |
515 | | signal_handler_t *immediate_handler, |
516 | | signal_handler_t *delayed_handler, |
517 | | void *context) |
518 | 0 | { |
519 | 0 | struct signal_handler *h; |
520 | |
|
521 | 0 | i_assert(immediate_handler != NULL || delayed_handler != NULL); |
522 | | |
523 | 0 | if (signo < 0 || signo > MAX_SIGNAL_VALUE) { |
524 | 0 | i_panic("Trying to set signal %d handler, but max is %d", |
525 | 0 | signo, MAX_SIGNAL_VALUE); |
526 | 0 | } |
527 | | |
528 | 0 | if (signal_handlers[signo] == NULL && signals_initialized) |
529 | 0 | lib_signals_set(signo, flags); |
530 | |
|
531 | 0 | h = i_new(struct signal_handler, 1); |
532 | 0 | h->immediate_handler = immediate_handler; |
533 | 0 | h->delayed_handler = delayed_handler; |
534 | 0 | h->context = context; |
535 | 0 | h->flags = flags; |
536 | | |
537 | | /* atomically set to signal_handlers[] list */ |
538 | 0 | h->next = signal_handlers[signo]; |
539 | 0 | signal_handlers[signo] = h; |
540 | |
|
541 | 0 | if (h->delayed_handler != NULL && sig_pipe_fd[0] == -1) { |
542 | | /* first delayed handler */ |
543 | 0 | if (pipe(sig_pipe_fd) < 0) |
544 | 0 | i_fatal("pipe() failed: %m"); |
545 | 0 | fd_set_nonblock(sig_pipe_fd[0], TRUE); |
546 | 0 | fd_set_nonblock(sig_pipe_fd[1], TRUE); |
547 | 0 | fd_close_on_exec(sig_pipe_fd[0], TRUE); |
548 | 0 | fd_close_on_exec(sig_pipe_fd[1], TRUE); |
549 | 0 | } |
550 | 0 | signal_handler_switch_ioloop(h); |
551 | 0 | } |
552 | | |
553 | | static void lib_signals_ignore_forced(int signo, bool restart_syscalls) |
554 | 2.55k | { |
555 | 2.55k | struct sigaction act; |
556 | | |
557 | 2.55k | if (sigemptyset(&act.sa_mask) < 0) |
558 | 0 | i_fatal("sigemptyset(): %m"); |
559 | 2.55k | if (restart_syscalls) { |
560 | 2.55k | act.sa_flags = SA_RESTART; |
561 | 2.55k | act.sa_handler = SIG_IGN; |
562 | 2.55k | } else { |
563 | 0 | #ifdef SA_SIGINFO |
564 | 0 | act.sa_flags = SA_SIGINFO; |
565 | 0 | act.sa_sigaction = sig_ignore; |
566 | | #else |
567 | | act.sa_flags = 0; |
568 | | act.sa_handler = sig_ignore; |
569 | | #endif |
570 | 0 | } |
571 | | |
572 | 2.55k | if (sigaction(signo, &act, NULL) < 0) |
573 | 0 | i_fatal("sigaction(%d): %m", signo); |
574 | 2.55k | } |
575 | | |
576 | | void lib_signals_ignore(int signo, bool restart_syscalls) |
577 | 2.55k | { |
578 | 2.55k | if (signo < 0 || signo > MAX_SIGNAL_VALUE) { |
579 | 0 | i_panic("Trying to ignore signal %d, but max is %d", |
580 | 0 | signo, MAX_SIGNAL_VALUE); |
581 | 0 | } |
582 | | |
583 | 2.55k | i_assert(signal_handlers[signo] == NULL); |
584 | | |
585 | 2.55k | lib_signals_ignore_forced(signo, restart_syscalls); |
586 | 2.55k | } |
587 | | |
588 | | void lib_signals_clear_handlers_and_ignore(int signo) |
589 | 0 | { |
590 | 0 | struct signal_handler *h; |
591 | |
|
592 | 0 | if (signal_handlers[signo] == NULL) |
593 | 0 | return; |
594 | | |
595 | 0 | lib_signals_ignore_forced(signo, TRUE); |
596 | |
|
597 | 0 | h = signal_handlers[signo]; |
598 | 0 | signal_handlers[signo] = NULL; |
599 | |
|
600 | 0 | while (h != NULL) { |
601 | 0 | struct signal_handler *h_next = h->next; |
602 | |
|
603 | 0 | if (h->expected) |
604 | 0 | signals_expected--; |
605 | 0 | signal_handler_free(h); |
606 | 0 | h = h_next; |
607 | 0 | } |
608 | 0 | } |
609 | | |
610 | | void lib_signals_unset_handler(int signo, signal_handler_t *handler, |
611 | | void *context) |
612 | 0 | { |
613 | 0 | struct signal_handler *h, **p; |
614 | |
|
615 | 0 | for (p = &signal_handlers[signo]; *p != NULL; p = &(*p)->next) { |
616 | 0 | if (((*p)->immediate_handler == handler || |
617 | 0 | (*p)->delayed_handler == handler) && |
618 | 0 | (*p)->context == context) { |
619 | 0 | if (p == &signal_handlers[signo] && |
620 | 0 | (*p)->next == NULL) { |
621 | | /* last handler is to be removed */ |
622 | 0 | lib_signals_ignore_forced(signo, TRUE); |
623 | 0 | } |
624 | 0 | h = *p; |
625 | 0 | *p = h->next; |
626 | 0 | if (h->expected) |
627 | 0 | lib_signals_update_expected_signals(FALSE); |
628 | 0 | signal_handler_free(h); |
629 | 0 | return; |
630 | 0 | } |
631 | 0 | } |
632 | | |
633 | 0 | i_panic("lib_signals_unset_handler(%d, %p, %p): handler not found", |
634 | 0 | signo, (void *)handler, context); |
635 | 0 | } |
636 | | |
637 | | void lib_signals_set_expected(int signo, bool expected, |
638 | | signal_handler_t *handler, void *context) |
639 | 0 | { |
640 | 0 | struct signal_handler *h; |
641 | |
|
642 | 0 | for (h = signal_handlers[signo]; h != NULL; h = h->next) { |
643 | 0 | if ((h->immediate_handler == handler || |
644 | 0 | h->delayed_handler == handler) && h->context == context) { |
645 | 0 | if (h->expected == expected) |
646 | 0 | return; |
647 | 0 | h->expected = expected; |
648 | 0 | lib_signals_update_expected_signals(expected); |
649 | 0 | return; |
650 | 0 | } |
651 | 0 | } |
652 | | |
653 | 0 | i_panic("lib_signals_set_expected(%d, %p, %p): handler not found", |
654 | 0 | signo, (void *)handler, context); |
655 | 0 | } |
656 | | |
657 | | void lib_signals_switch_ioloop(int signo, |
658 | | signal_handler_t *handler, void *context) |
659 | 0 | { |
660 | 0 | struct signal_handler *h; |
661 | |
|
662 | 0 | for (h = signal_handlers[signo]; h != NULL; h = h->next) { |
663 | 0 | if (h->delayed_handler == handler && h->context == context) { |
664 | 0 | i_assert((h->flags & LIBSIG_FLAG_IOLOOP_AUTOMOVE) == 0); |
665 | 0 | signal_handler_switch_ioloop(h); |
666 | | /* check whether we can now handle any shadowed delayed |
667 | | signals */ |
668 | 0 | signal_check_shadowed(); |
669 | 0 | return; |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | 0 | i_panic("lib_signals_switch_ioloop(%d, %p, %p): handler not found", |
674 | 0 | signo, (void *)handler, context); |
675 | 0 | } |
676 | | |
677 | | void lib_signals_syscall_error(const char *prefix) |
678 | 0 | { |
679 | | /* @UNSAFE: We're in a signal handler. It's very limited what is |
680 | | allowed in here. Especially strerror() isn't at least officially |
681 | | allowed. */ |
682 | 0 | char errno_buf[MAX_INT_STRLEN], *errno_str; |
683 | 0 | errno_str = dec2str_buf(errno_buf, errno); |
684 | |
|
685 | 0 | size_t prefix_len = strlen(prefix); |
686 | 0 | size_t errno_str_len = strlen(errno_str); |
687 | 0 | char buf[prefix_len + errno_str_len + 1]; |
688 | |
|
689 | 0 | memcpy(buf, prefix, prefix_len); |
690 | 0 | memcpy(buf + prefix_len, errno_str, errno_str_len); |
691 | 0 | buf[prefix_len + errno_str_len] = '\n'; |
692 | 0 | if (write_full(STDERR_FILENO, buf, |
693 | 0 | prefix_len + errno_str_len + 1) < 0) { |
694 | | /* can't really do anything */ |
695 | 0 | } |
696 | 0 | } |
697 | | |
698 | | void lib_signals_init(void) |
699 | 2.55k | { |
700 | 2.55k | int i; |
701 | | |
702 | 2.55k | signals_initialized = TRUE; |
703 | 2.55k | io_loop_add_switch_callback(lib_signals_ioloop_switched); |
704 | 2.55k | io_loop_add_destroy_callback(lib_signals_ioloop_destroyed); |
705 | | |
706 | | /* add signals that were already registered */ |
707 | 163k | for (i = 0; i < MAX_SIGNAL_VALUE; i++) { |
708 | 160k | if (signal_handlers[i] != NULL) |
709 | 0 | lib_signals_set(i, signal_handlers[i]->flags); |
710 | 160k | } |
711 | 2.55k | } |
712 | | |
713 | | void lib_signals_deinit(void) |
714 | 2.55k | { |
715 | 2.55k | int i; |
716 | | |
717 | 163k | for (i = 0; i < MAX_SIGNAL_VALUE; i++) { |
718 | 160k | if (signal_handlers[i] != NULL) |
719 | 0 | lib_signals_clear_handlers_and_ignore(i); |
720 | 160k | } |
721 | 2.55k | i_assert(signals_expected == 0); |
722 | | |
723 | 2.55k | if (sig_pipe_fd[0] != -1) { |
724 | 0 | if (close(sig_pipe_fd[0]) < 0) |
725 | 0 | i_error("close(sigpipe) failed: %m"); |
726 | 0 | if (close(sig_pipe_fd[1]) < 0) |
727 | 0 | i_error("close(sigpipe) failed: %m"); |
728 | 0 | sig_pipe_fd[0] = sig_pipe_fd[1] = -1; |
729 | 0 | } |
730 | | |
731 | 2.55k | if (array_is_created(&pending_shadowed_signals)) |
732 | 0 | array_free(&pending_shadowed_signals); |
733 | 2.55k | i_assert(signal_ioloops == NULL); |
734 | 2.55k | } |