lib-signals.c revision a8632b9f8566d88ba5bd19ba3131226c67b11671
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2001-2010 Dovecot authors, see the included COPYING file */
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 "". */
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, };
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstatic siginfo_t pending_signals[MAX_SIGNAL_VALUE+1];
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenconst char *lib_signal_code_to_str(int signo, int sicode)
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen return "kill";
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return "kernel";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "timer";
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* If SEGV_MAPERR is supported, the rest of them must be too.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FreeBSD 6 at least doesn't support these. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "address not mapped";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "invalid permissions";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "invalid address alignment";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "nonexistent physical address";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return "object-specific hardware error";
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainenstatic void sig_handler(int signo, siginfo_t *si, void *context ATTR_UNUSED)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen /* Solaris can leave this to NULL */
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) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen else if (pending_signals[signo].si_signo == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void sig_ignore(int signo ATTR_UNUSED, siginfo_t *si ATTR_UNUSED,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if we used SIG_IGN instead of this function,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen the system call might be restarted */
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainenstatic void signal_read(void *context ATTR_UNUSED)
3b80595fcf2001cf7b2fcc6290823e38f4a142fcTimo Sirainen if (sigprocmask(SIG_BLOCK, &fullset, &oldset) < 0)
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. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memcpy(signals, pending_signals, sizeof(signals));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(pending_signals, 0, sizeof(pending_signals));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (ret < 0) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* call the delayed handlers after signals are copied and unblocked */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen for (signo = 0; signo < MAX_SIGNAL_VALUE; signo++) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen for (h = signal_handlers[signo]; h != NULL; h = h->next) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void lib_signals_set(int signo, bool ignore)
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen act.sa_sigaction = ignore ? sig_ignore : sig_handler;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen act.sa_handler = ignore ? sig_ignore : sig_handler;
a94936bafd127680184da114c6a177b37ff656e5Timo Sirainenvoid lib_signals_set_handler(int signo, bool delayed,
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen i_panic("Trying to set signal %d handler, but max is %d",
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen if (signal_handlers[signo] == NULL && signals_initialized)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* first delayed handler */
3776ed607821b502468bdfd5a4533af3002125d1Timo Sirainen /* atomically set to signal_handlers[] list */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid lib_signals_ignore(int signo, bool restart_syscalls)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("Trying to ignore signal %d, but max is %d",
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainenvoid lib_signals_unset_handler(int signo, signal_handler_t *handler,
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen struct signal_handler *h, **p;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen for (p = &signal_handlers[signo]; *p != NULL; p = &(*p)->next) {
06a5ffa611efd86ffb9acc8beb0fe66e7bd844e4Timo Sirainen if ((*p)->handler == handler && (*p)->context == context) {
24815ed8224a0647926b49b9a1f716efb2a57148Timo Sirainen i_panic("lib_signals_unset_handler(%d, %p, %p): handler not found",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL);
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen /* add signals that were already registered */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen io_sig = io_add(sig_pipe_fd[0], IO_READ, signal_read, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < MAX_SIGNAL_VALUE; i++) {
f7992ce3ff735b8eb2f59b07f1d565dafcc0452eTimo Sirainen /* atomically remove from signal_handlers[] list */