Coverage Report

Created: 2026-10-28 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}