lib-signals.c revision a8632b9f8566d88ba5bd19ba3131226c67b11671
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2001-2010 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fd-close-on-exec.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "fd-set-nonblock.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib-signals.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <signal.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#define MAX_SIGNAL_VALUE 31
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen#if !defined(SA_SIGINFO) && !defined(SI_NOINFO)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen/* without SA_SIGINFO we don't know what the real code is. we need SI_NOINFO
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen to make sure lib_signal_code_to_str() returns "". */
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen# define SI_NOINFO -1
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen#endif
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenstruct signal_handler {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen signal_handler_t *handler;
e627cdc5ef30d87959f9510832427e33a2f1d84aTimo Sirainen void *context;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen bool delayed;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen struct signal_handler *next;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen};
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen/* Remember that these are accessed inside signal handler which may be called
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen even while we're initializing/deinitializing. Try hard to keep everything
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen in consistent state. */
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainenstatic struct signal_handler *signal_handlers[MAX_SIGNAL_VALUE+1] = { NULL, };
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainenstatic int sig_pipe_fd[2] = { -1, -1 };
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool signals_initialized = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct io *io_sig = NULL;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstatic siginfo_t pending_signals[MAX_SIGNAL_VALUE+1];
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstatic bool have_pending_signals = FALSE;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenconst char *lib_signal_code_to_str(int signo, int sicode)
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* common */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen switch (sicode) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen#ifdef SI_NOINFO
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen case SI_NOINFO:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "";
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen#endif
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen case SI_USER:
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen return "kill";
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen#ifdef SI_KERNEL
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen case SI_KERNEL:
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return "kernel";
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen#endif
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen case SI_TIMER:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "timer";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* If SEGV_MAPERR is supported, the rest of them must be too.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FreeBSD 6 at least doesn't support these. */
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen#ifdef SEGV_MAPERR
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen switch (signo) {
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen case SIGSEGV:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (sicode) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SEGV_MAPERR:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "address not mapped";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SEGV_ACCERR:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "invalid permissions";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SIGBUS:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (sicode) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case BUS_ADRALN:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "invalid address alignment";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef BUS_ADRERR /* for OSX 10.3 */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case BUS_ADRERR:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "nonexistent physical address";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef BUS_OBJERR /* for OSX 10.3 */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case BUS_OBJERR:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "object-specific hardware error";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen#endif
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return t_strdup_printf("unknown %d", sicode);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen}
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen#ifdef SA_SIGINFO
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainenstatic void sig_handler(int signo, siginfo_t *si, void *context ATTR_UNUSED)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen#else
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainenstatic void sig_handler(int signo)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen#endif
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen{
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct signal_handler *h;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen char c = 0;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen#if defined(SI_NOINFO) || !defined(SA_SIGINFO)
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen#ifndef SA_SIGINFO
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen siginfo_t *si = NULL;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen#endif
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen siginfo_t tmp_si;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (si == NULL) {
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen /* Solaris can leave this to NULL */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen memset(&tmp_si, 0, sizeof(tmp_si));
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen tmp_si.si_signo = signo;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen tmp_si.si_code = SI_NOINFO;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen si = &tmp_si;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen#endif
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (signo < 0 || signo > MAX_SIGNAL_VALUE)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen /* remember that we're inside a signal handler which might have been
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen called at any time. don't do anything that's unsafe. we might also
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen get interrupted by another signal while inside this handler. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen for (h = signal_handlers[signo]; h != NULL; h = h->next) {
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (!h->delayed)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen h->handler(si, h->context);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen else if (pending_signals[signo].si_signo == 0) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen pending_signals[signo] = *si;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (!have_pending_signals) {
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen int saved_errno = errno;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (write(sig_pipe_fd[1], &c, 1) != 1)
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen i_error("write(sigpipe) failed: %m");
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen have_pending_signals = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen errno = saved_errno;
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen#ifdef SA_SIGINFO
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void sig_ignore(int signo ATTR_UNUSED, siginfo_t *si ATTR_UNUSED,
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen void *context ATTR_UNUSED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenstatic void sig_ignore(int signo ATTR_UNUSED)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if we used SIG_IGN instead of this function,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen the system call might be restarted */
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen}
24ec3e51a1bd7aaf09c92a7ff7498e225796d7e0Timo Sirainen
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainenstatic void signal_read(void *context ATTR_UNUSED)
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen{
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen siginfo_t signals[MAX_SIGNAL_VALUE+1];
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen sigset_t fullset, oldset;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen struct signal_handler *h;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen char buf[64];
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen int signo;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ssize_t ret;
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (sigfillset(&fullset) < 0)
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_fatal("sigfillset() failed: %m");
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (sigprocmask(SIG_BLOCK, &fullset, &oldset) < 0)
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen i_fatal("sigprocmask() failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* typically we should read only a single byte, but if a signal
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen is sent while signal handler is running we might get more. */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ret = read(sig_pipe_fd[0], buf, sizeof(buf));
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (ret > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(signals, pending_signals, sizeof(signals));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(pending_signals, 0, sizeof(pending_signals));
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen have_pending_signals = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (ret < 0) {
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen if (errno != EAGAIN)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_fatal("read(sigpipe) failed: %m");
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen } else {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen i_fatal("read(sigpipe) failed: EOF");
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_fatal("sigprocmask() failed: %m");
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (ret < 0)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* call the delayed handlers after signals are copied and unblocked */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (signals[signo].si_signo == 0)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen continue;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen for (h = signal_handlers[signo]; h != NULL; h = h->next) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (h->delayed)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen h->handler(&signals[signo], h->context);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void lib_signals_set(int signo, bool ignore)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen{
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen struct sigaction act;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (sigemptyset(&act.sa_mask) < 0)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_fatal("sigemptyset(): %m");
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen#ifdef SA_SIGINFO
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen act.sa_flags = SA_SIGINFO;
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen act.sa_sigaction = ignore ? sig_ignore : sig_handler;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen#else
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen act.sa_flags = 0;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen act.sa_handler = ignore ? sig_ignore : sig_handler;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen#endif
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen if (sigaction(signo, &act, NULL) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("sigaction(%d): %m", signo);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid lib_signals_set_handler(int signo, bool delayed,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen signal_handler_t *handler, void *context)
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct signal_handler *h;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(handler != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (signo < 0 || signo > MAX_SIGNAL_VALUE) {
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen i_panic("Trying to set signal %d handler, but max is %d",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen signo, MAX_SIGNAL_VALUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen if (signal_handlers[signo] == NULL && signals_initialized)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set(signo, FALSE);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (delayed && sig_pipe_fd[0] == -1) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* first delayed handler */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (pipe(sig_pipe_fd) < 0)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen i_fatal("pipe() failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fd_set_nonblock(sig_pipe_fd[0], TRUE);
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen fd_set_nonblock(sig_pipe_fd[1], TRUE);
5ba25fa97ceebd32d8c58a2d38b0b3f7fc5e67ccTimo Sirainen fd_close_on_exec(sig_pipe_fd[0], TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fd_close_on_exec(sig_pipe_fd[1], TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (signals_initialized) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_sig = io_add(sig_pipe_fd[0], IO_READ,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen signal_read, NULL);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen h = i_new(struct signal_handler, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen h->handler = handler;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen h->context = context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen h->delayed = delayed;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen /* atomically set to signal_handlers[] list */
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen h->next = signal_handlers[signo];
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen signal_handlers[signo] = h;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid lib_signals_ignore(int signo, bool restart_syscalls)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen{
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen struct sigaction act;
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (signo < 0 || signo > MAX_SIGNAL_VALUE) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("Trying to ignore signal %d, but max is %d",
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen signo, MAX_SIGNAL_VALUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(signal_handlers[signo] == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (sigemptyset(&act.sa_mask) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("sigemptyset(): %m");
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen if (restart_syscalls) {
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen act.sa_flags = SA_RESTART;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen act.sa_handler = SIG_IGN;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef SA_SIGINFO
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen act.sa_flags = SA_SIGINFO;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen act.sa_sigaction = sig_ignore;
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen#else
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen act.sa_flags = 0;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen act.sa_handler = sig_ignore;
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen#endif
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen }
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen if (sigaction(signo, &act, NULL) < 0)
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen i_fatal("sigaction(%d): %m", signo);
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen}
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainenvoid lib_signals_unset_handler(int signo, signal_handler_t *handler,
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen void *context)
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen{
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen struct signal_handler *h, **p;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen for (p = &signal_handlers[signo]; *p != NULL; p = &(*p)->next) {
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen if ((*p)->handler == handler && (*p)->context == context) {
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen h = *p;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen *p = h->next;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen i_free(h);
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen return;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen i_panic("lib_signals_unset_handler(%d, %p, %p): handler not found",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen signo, (void *)handler, context);
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen}
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainenvoid lib_signals_reset_ioloop(void)
e107b65e7d36ae18571de61a4dbd8609b2883a21Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (io_sig != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_remove(&io_sig);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen}
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainen
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid lib_signals_init(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen signals_initialized = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen /* add signals that were already registered */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (signal_handlers[i] != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen lib_signals_set(i, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (sig_pipe_fd[0] != -1)
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid lib_signals_deinit(void)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen struct signal_handler *handlers, *h;
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen int i;
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (signal_handlers[i] != NULL) {
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen /* atomically remove from signal_handlers[] list */
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen handlers = signal_handlers[i];
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen signal_handlers[i] = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (handlers != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen h = handlers;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen handlers = h->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(h);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen }
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (io_sig != NULL)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen io_remove(&io_sig);
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (sig_pipe_fd[0] != -1) {
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (close(sig_pipe_fd[0]) < 0)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen i_error("close(sigpipe) failed: %m");
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen if (close(sig_pipe_fd[1]) < 0)
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen i_error("close(sigpipe) failed: %m");
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen }
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen}
3fe9483b2b412a14493e3120751b0e99ecfe9388Timo Sirainen