123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /*
- * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2015 Alexander Barton (alex@barton.de) and Contributors.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * Please read the file COPYING, README and AUTHORS for more information.
- */
- #include "portab.h"
- /**
- * @file
- * Signal Handlers: Actions to be performed when the program
- * receives a signal.
- */
- #include <errno.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <time.h>
- #include "conn.h"
- #include "channel.h"
- #include "conf.h"
- #include "io.h"
- #include "log.h"
- #include "ngircd.h"
- #include "sighandlers.h"
- static int signalpipe[2];
- static const int signals_catch[] = {
- SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
- };
- #ifdef DEBUG
- static void
- Dump_State(void)
- {
- Log(LOG_DEBUG, "--- Internal server state: %s ---",
- Client_ID(Client_ThisServer()));
- #ifdef HAVE_LONG_LONG
- Log(LOG_DEBUG, "time()=%llu", (unsigned long long)time(NULL));
- #else
- Log(LOG_DEBUG, "time()=%lu", (unsigned long)time(NULL));
- #endif
- Conf_DebugDump();
- Conn_DebugDump();
- Client_DebugDump();
- Log(LOG_DEBUG, "--- End of state dump ---");
- } /* Dump_State */
- #endif
- static void
- Signal_Block(int sig)
- {
- #ifdef HAVE_SIGPROCMASK
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, sig);
- sigprocmask(SIG_BLOCK, &set, NULL);
- #else
- sigblock(sig);
- #endif
- }
- static void
- Signal_Unblock(int sig)
- {
- #ifdef HAVE_SIGPROCMASK
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, sig);
- sigprocmask(SIG_UNBLOCK, &set, NULL);
- #else
- int old = sigblock(0) & ~sig;
- sigsetmask(old);
- #endif
- }
- /**
- * Reload the server configuration file.
- */
- static void
- Rehash(void)
- {
- char old_name[CLIENT_ID_LEN];
- unsigned old_nicklen;
- Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
- /* Remember old server name and nickname length */
- strlcpy( old_name, Conf_ServerName, sizeof old_name );
- old_nicklen = Conf_MaxNickLength;
- /* Re-read configuration ... */
- if (!Conf_Rehash( ))
- return;
- /* Close down all listening sockets */
- Conn_ExitListeners( );
- /* Recover old server name and nickname length: these values can't
- * be changed during run-time */
- if (strcmp(old_name, Conf_ServerName) != 0 ) {
- strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
- Log(LOG_ERR,
- "Can't change \"ServerName\" on runtime! Ignored new name.");
- }
- if (old_nicklen != Conf_MaxNickLength) {
- Conf_MaxNickLength = old_nicklen;
- Log(LOG_ERR,
- "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
- }
- /* Create new pre-defined channels */
- Channel_InitPredefined( );
- if (!ConnSSL_InitLibrary())
- Log(LOG_WARNING,
- "Re-Initializing of SSL failed, using old keys!");
- /* Start listening on sockets */
- Conn_InitListeners( );
- /* Sync configuration with established connections */
- Conn_SyncServerStruct( );
- Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
- } /* Rehash */
- /**
- * Signal handler of ngIRCd.
- * This function is called whenever ngIRCd catches a signal sent by the
- * user and/or the system to it. For example SIGTERM and SIGHUP.
- *
- * It blocks the signal and queues it for later execution by Signal_Handler_BH.
- * @param Signal Number of the signal to handle.
- */
- static void
- Signal_Handler(int Signal)
- {
- switch (Signal) {
- case SIGTERM:
- case SIGINT:
- case SIGQUIT:
- /* shut down sever */
- NGIRCd_SignalQuit = true;
- return;
- case SIGCHLD:
- /* child-process exited, avoid zombies */
- while (waitpid( -1, NULL, WNOHANG) > 0)
- ;
- return;
- #ifdef DEBUG
- case SIGUSR1:
- if (! NGIRCd_Debug) {
- Log(LOG_INFO|LOG_snotice,
- "Got SIGUSR1, debug mode activated.");
- #ifdef SNIFFER
- strcpy(NGIRCd_DebugLevel, "2");
- NGIRCd_Debug = true;
- NGIRCd_Sniffer = true;
- #else
- strcpy(NGIRCd_DebugLevel, "1");
- NGIRCd_Debug = true;
- #endif /* SNIFFER */
- } else {
- Log(LOG_INFO|LOG_snotice,
- "Got SIGUSR1, debug mode deactivated.");
- strcpy(NGIRCd_DebugLevel, "");
- NGIRCd_Debug = false;
- #ifdef SNIFFER
- NGIRCd_Sniffer = false;
- #endif /* SNIFFER */
- }
- return;
- #endif
- }
- /*
- * other signal: queue for later execution.
- * This has the advantage that we are not restricted
- * to functions that can be called safely from signal handlers.
- */
- if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
- Signal_Block(Signal);
- } /* Signal_Handler */
- /**
- * Signal processing handler of ngIRCd.
- * This function is called from the main conn event loop in (io_dispatch)
- * whenever ngIRCd has queued a signal.
- *
- * This function runs in normal context, not from the real signal handler,
- * thus its not necessary to only use functions that are signal safe.
- * @param Signal Number of the signal that was queued.
- */
- static void
- Signal_Handler_BH(int Signal)
- {
- switch (Signal) {
- case SIGHUP:
- /* re-read configuration */
- Rehash();
- break;
- #ifdef DEBUG
- case SIGUSR2:
- if (NGIRCd_Debug) {
- Log(LOG_INFO|LOG_snotice,
- "Got SIGUSR2, dumping internal state ...");
- Dump_State();
- }
- break;
- default:
- Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
- #endif
- }
- Signal_Unblock(Signal);
- }
- static void
- Signal_Callback(int fd, short UNUSED what)
- {
- int sig, ret;
- (void) what;
- do {
- ret = (int)read(fd, &sig, sizeof(sig));
- if (ret == sizeof(int))
- Signal_Handler_BH(sig);
- } while (ret == sizeof(int));
- if (ret == -1) {
- if (errno == EAGAIN || errno == EINTR)
- return;
- Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
- strerror(errno));
- exit(1);
- }
- Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
- exit(1);
- }
- /**
- * Initialize the signal handlers, catch
- * those signals we are interested in and sets SIGPIPE to be ignored.
- * @return true if initialization was successful.
- */
- bool
- Signals_Init(void)
- {
- size_t i;
- #ifdef HAVE_SIGACTION
- struct sigaction saction;
- #endif
- if (signalpipe[0] > 0 || signalpipe[1] > 0)
- return true;
- if (pipe(signalpipe))
- return false;
- if (!io_setnonblock(signalpipe[0]) ||
- !io_setnonblock(signalpipe[1]))
- return false;
- if (!io_setcloexec(signalpipe[0]) ||
- !io_setcloexec(signalpipe[1]))
- return false;
- #ifdef HAVE_SIGACTION
- memset( &saction, 0, sizeof( saction ));
- saction.sa_handler = Signal_Handler;
- #ifdef SA_RESTART
- saction.sa_flags |= SA_RESTART;
- #endif
- #ifdef SA_NOCLDWAIT
- saction.sa_flags |= SA_NOCLDWAIT;
- #endif
- for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
- sigaction(signals_catch[i], &saction, NULL);
- /* we handle write errors properly; ignore SIGPIPE */
- saction.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &saction, NULL);
- #else
- for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
- signal(signals_catch[i], Signal_Handler);
- signal(SIGPIPE, SIG_IGN);
- #endif
- return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
- } /* Signals_Init */
- /**
- * Restores signals to their default behavior.
- *
- * This should be called after a fork() in the new
- * child prodcess, especially when we are about to call
- * 3rd party code (e.g. PAM).
- */
- void
- Signals_Exit(void)
- {
- size_t i;
- #ifdef HAVE_SIGACTION
- struct sigaction saction;
- memset(&saction, 0, sizeof(saction));
- saction.sa_handler = SIG_DFL;
- for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
- sigaction(signals_catch[i], &saction, NULL);
- sigaction(SIGPIPE, &saction, NULL);
- #else
- for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
- signal(signals_catch[i], SIG_DFL);
- signal(SIGPIPE, SIG_DFL);
- #endif
- close(signalpipe[1]);
- close(signalpipe[0]);
- signalpipe[0] = signalpipe[1] = 0;
- }
- /* -eof- */
|