2010-09-11 00:19:01 +02:00
|
|
|
/*
|
|
|
|
* ngIRCd -- The Next Generation IRC Daemon
|
2014-03-17 02:13:15 +01:00
|
|
|
* Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
|
2010-09-11 00:19:01 +02:00
|
|
|
*
|
|
|
|
* 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>
|
2014-03-17 02:28:39 +01:00
|
|
|
#include <time.h>
|
2010-09-11 00:19:01 +02:00
|
|
|
|
2010-09-11 00:27:21 +02:00
|
|
|
#include "conn.h"
|
|
|
|
#include "channel.h"
|
|
|
|
#include "conf.h"
|
2010-09-11 00:19:01 +02:00
|
|
|
#include "io.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "ngircd.h"
|
|
|
|
|
2014-03-17 18:02:57 +01:00
|
|
|
#include "sighandlers.h"
|
|
|
|
|
2010-09-11 00:19:01 +02:00
|
|
|
static int signalpipe[2];
|
|
|
|
|
2010-09-14 00:30:45 +02:00
|
|
|
static const int signals_catch[] = {
|
|
|
|
SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
|
|
|
|
};
|
|
|
|
|
2008-04-09 19:03:24 +02:00
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
static void
|
|
|
|
Dump_State(void)
|
|
|
|
{
|
2010-09-10 21:10:17 +02:00
|
|
|
Log(LOG_DEBUG, "--- Internal server state: %s ---",
|
|
|
|
Client_ID(Client_ThisServer()));
|
2008-04-09 19:03:24 +02:00
|
|
|
Log(LOG_DEBUG, "time()=%ld", time(NULL));
|
|
|
|
Conf_DebugDump();
|
2010-09-10 21:11:25 +02:00
|
|
|
Conn_DebugDump();
|
2008-04-09 19:03:24 +02:00
|
|
|
Client_DebugDump();
|
|
|
|
Log(LOG_DEBUG, "--- End of state dump ---");
|
|
|
|
} /* Dump_State */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-09-14 00:29:34 +02:00
|
|
|
static void
|
|
|
|
Signal_Block(int sig)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
#ifdef HAVE_SIGPROCMASK
|
|
|
|
sigset_t set;
|
|
|
|
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, sig);
|
|
|
|
|
|
|
|
sigprocmask(SIG_BLOCK, &set, NULL);
|
2010-09-11 11:33:27 +02:00
|
|
|
#else
|
|
|
|
sigblock(sig);
|
2010-09-11 00:19:01 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-09-14 00:29:34 +02:00
|
|
|
static void
|
|
|
|
Signal_Unblock(int sig)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
#ifdef HAVE_SIGPROCMASK
|
|
|
|
sigset_t set;
|
|
|
|
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, sig);
|
|
|
|
|
|
|
|
sigprocmask(SIG_UNBLOCK, &set, NULL);
|
2010-09-11 11:33:27 +02:00
|
|
|
#else
|
|
|
|
int old = sigblock(0) & ~sig;
|
|
|
|
sigsetmask(old);
|
2010-09-11 00:19:01 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-09-11 00:27:21 +02:00
|
|
|
/**
|
|
|
|
* Reload the server configuration file.
|
|
|
|
*/
|
|
|
|
static void
|
2010-09-14 00:30:45 +02:00
|
|
|
Rehash(void)
|
2010-09-11 00:27:21 +02:00
|
|
|
{
|
|
|
|
char old_name[CLIENT_ID_LEN];
|
|
|
|
unsigned old_nicklen;
|
|
|
|
|
|
|
|
Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
|
|
|
|
|
2012-11-02 14:30:19 +01:00
|
|
|
/* Remember old server name and nickname length */
|
2010-09-11 00:27:21 +02:00
|
|
|
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( );
|
|
|
|
|
2012-11-02 14:30:19 +01:00
|
|
|
/* Recover old server name and nickname length: these values can't
|
2010-09-11 00:27:21 +02:00
|
|
|
* be changed during run-time */
|
|
|
|
if (strcmp(old_name, Conf_ServerName) != 0 ) {
|
|
|
|
strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
|
2013-02-13 00:26:16 +01:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Can't change \"ServerName\" on runtime! Ignored new name.");
|
2010-09-11 00:27:21 +02:00
|
|
|
}
|
|
|
|
if (old_nicklen != Conf_MaxNickLength) {
|
|
|
|
Conf_MaxNickLength = old_nicklen;
|
2013-02-13 00:26:16 +01:00
|
|
|
Log(LOG_ERR,
|
|
|
|
"Can't change \"MaxNickLength\" on runtime! Ignored new value.");
|
2010-09-11 00:27:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create new pre-defined channels */
|
|
|
|
Channel_InitPredefined( );
|
|
|
|
|
|
|
|
if (!ConnSSL_InitLibrary())
|
2013-02-13 00:26:16 +01:00
|
|
|
Log(LOG_WARNING,
|
|
|
|
"Re-Initializing of SSL failed, using old keys!");
|
2010-09-11 00:27:21 +02:00
|
|
|
|
|
|
|
/* Start listening on sockets */
|
|
|
|
Conn_InitListeners( );
|
|
|
|
|
|
|
|
/* Sync configuration with established connections */
|
|
|
|
Conn_SyncServerStruct( );
|
|
|
|
|
|
|
|
Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
|
2010-09-14 00:30:45 +02:00
|
|
|
} /* Rehash */
|
2010-09-11 00:27:21 +02:00
|
|
|
|
2010-09-11 00:19:01 +02:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2010-09-14 00:29:34 +02:00
|
|
|
static void
|
|
|
|
Signal_Handler(int Signal)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
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;
|
2008-04-09 19:03:24 +02:00
|
|
|
#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
|
2010-09-11 00:19:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2010-09-14 00:29:34 +02:00
|
|
|
static void
|
|
|
|
Signal_Handler_BH(int Signal)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
switch (Signal) {
|
2010-09-11 00:27:21 +02:00
|
|
|
case SIGHUP:
|
|
|
|
/* re-read configuration */
|
2010-09-14 00:30:45 +02:00
|
|
|
Rehash();
|
2010-09-11 00:27:21 +02:00
|
|
|
break;
|
2010-09-11 00:19:01 +02:00
|
|
|
#ifdef DEBUG
|
2008-04-09 19:03:24 +02:00
|
|
|
case SIGUSR2:
|
2012-06-08 22:08:52 +02:00
|
|
|
if (NGIRCd_Debug) {
|
|
|
|
Log(LOG_INFO|LOG_snotice,
|
|
|
|
"Got SIGUSR2, dumping internal state ...");
|
2008-04-09 19:03:24 +02:00
|
|
|
Dump_State();
|
2012-06-08 22:08:52 +02:00
|
|
|
}
|
2008-04-09 19:03:24 +02:00
|
|
|
break;
|
2010-09-11 00:19:01 +02:00
|
|
|
default:
|
|
|
|
Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
Signal_Unblock(Signal);
|
|
|
|
}
|
|
|
|
|
2010-09-14 00:29:34 +02:00
|
|
|
static void
|
|
|
|
Signal_Callback(int fd, short UNUSED what)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
int sig, ret;
|
|
|
|
(void) what;
|
|
|
|
|
|
|
|
do {
|
2010-09-22 14:15:46 +02:00
|
|
|
ret = (int)read(fd, &sig, sizeof(sig));
|
2010-09-11 00:19:01 +02:00
|
|
|
if (ret == sizeof(int))
|
|
|
|
Signal_Handler_BH(sig);
|
|
|
|
} while (ret == sizeof(int));
|
|
|
|
|
|
|
|
if (ret == -1) {
|
|
|
|
if (errno == EAGAIN || errno == EINTR)
|
|
|
|
return;
|
|
|
|
|
2013-02-13 00:26:16 +01:00
|
|
|
Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
|
|
|
|
strerror(errno));
|
2010-09-11 00:19:01 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2013-02-13 00:26:16 +01:00
|
|
|
Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
|
2010-09-11 00:19:01 +02:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the signal handlers, catch
|
|
|
|
* those signals we are interested in and sets SIGPIPE to be ignored.
|
2013-08-04 13:33:10 +02:00
|
|
|
* @return true if initialization was successful.
|
2010-09-11 00:19:01 +02:00
|
|
|
*/
|
2010-09-14 00:29:34 +02:00
|
|
|
bool
|
|
|
|
Signals_Init(void)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
#ifdef HAVE_SIGACTION
|
|
|
|
struct sigaction saction;
|
|
|
|
#endif
|
2010-09-14 23:53:59 +02:00
|
|
|
if (signalpipe[0] > 0 || signalpipe[1] > 0)
|
|
|
|
return true;
|
2010-09-11 00:19:01 +02:00
|
|
|
|
|
|
|
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
|
2010-09-14 00:29:34 +02:00
|
|
|
return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
|
|
|
|
} /* Signals_Init */
|
2010-09-11 00:19:01 +02:00
|
|
|
|
|
|
|
/**
|
2013-08-04 13:33:10 +02:00
|
|
|
* Restores signals to their default behavior.
|
2010-09-11 00:19:01 +02:00
|
|
|
*
|
|
|
|
* 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).
|
|
|
|
*/
|
2010-09-14 00:29:34 +02:00
|
|
|
void
|
|
|
|
Signals_Exit(void)
|
2010-09-11 00:19:01 +02:00
|
|
|
{
|
|
|
|
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++)
|
2010-09-22 14:10:09 +02:00
|
|
|
signal(signals_catch[i], SIG_DFL);
|
2010-09-11 00:19:01 +02:00
|
|
|
signal(SIGPIPE, SIG_DFL);
|
|
|
|
#endif
|
|
|
|
close(signalpipe[1]);
|
|
|
|
close(signalpipe[0]);
|
2012-09-11 15:44:31 +02:00
|
|
|
signalpipe[0] = signalpipe[1] = 0;
|
2010-09-11 00:19:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* -eof- */
|