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