/* Signal handling routines.
*
* IRC Services is copyright (c) 1996-2007 Andrew Church.
* E-mail: <achurch@achurch.org>
* Parts written by Andrew Kempe and others.
* This program is free but copyrighted software; see the file COPYING for
* details.
*/
#include "services.h"
#include <setjmp.h>
/*************************************************************************/
/* If we get a signal, use this to jump out of the main loop. */
static sigjmp_buf *panic_ptr = NULL;
/*************************************************************************/
/*************************************************************************/
/* Various signal handlers. */
/*************************************************************************/
/* SIGHUP = rehash configuration files */
static void sighup_handler(int sig_unused)
{
#ifdef CLEAN_COMPILE
sig_unused = sig_unused;
#endif
log("Received SIGHUP, rehashing.");
wallops(NULL, "Rehashing configuration files (received SIGHUP)");
reconfigure();
signal(SIGHUP, sighup_handler);
}
/*************************************************************************/
/* SIGTERM = save databases and shut down */
static void sigterm_handler(int sig_unused)
{
#ifdef CLEAN_COMPILE
sig_unused = sig_unused;
#endif
save_data = 1;
delayed_quit = 1;
signal(SIGTERM, SIG_IGN);
signal(SIGHUP, SIG_IGN);
log("Received SIGTERM, exiting.");
strscpy(quitmsg, "Shutting down on SIGTERM", sizeof(quitmsg));
siglongjmp(*panic_ptr, 1);
}
/*************************************************************************/
/* SIGUSR2 = close and reopen log file */
static void sigusr2_handler(int sig_unused)
{
#ifdef CLEAN_COMPILE
sig_unused = sig_unused;
#endif
log("Received SIGUSR2, cycling log file.");
if (log_is_open()) {
close_log();
open_log();
}
signal(SIGUSR2, sigusr2_handler);
}
/*************************************************************************/
/* If we get a weird signal, come here. */
static void weirdsig_handler(int signum)
{
static int dying = 0; /* Flag to avoid infinite recursion */
if (dying++) {
/* Double signal, give up. Set `servsock' to NULL to avoid a
* message going out that way, just in case the socket code is
* confused/broken */
servsock = NULL;
if (signum == SIGUSR2) {
fatal("Out of memory while shutting down");
} else {
#if HAVE_STRSIGNAL
fatal("Caught signal %d (%s) while shutting down", signum,
strsignal(signum));
#else
fatal("Caught signal %d while shutting down", signum);
#endif
}
}
/* Avoid spurious keyboard signals killing us while shutting down */
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
/* If we died processing a message, let people know about it */
if (signum != SIGINT && signum != SIGQUIT) {
if (*inbuf) {
log("PANIC! signal %d, buffer = %s", signum, inbuf);
/* Cut off if this would make IRC command >510 characters. */
if (strlen(inbuf) > 448) {
inbuf[446] = '>';
inbuf[447] = '>';
inbuf[448] = 0;
}
wallops(NULL, "PANIC! buffer = %s\r\n", inbuf);
} else {
log("PANIC! signal %d (no buffer)", signum);
wallops(NULL, "PANIC! signal %d (no buffer)", signum);
}
}
/* Pick an appropriate quit message */
if (signum == SIGUSR1) {
strscpy(quitmsg, "Out of memory!", sizeof(quitmsg));
quitting = 1;
} else {
#if HAVE_STRSIGNAL
snprintf(quitmsg, sizeof(quitmsg),
"Services terminating: %s", strsignal(signum));
#else
snprintf(quitmsg, sizeof(quitmsg),
"Services terminating on signal %d", signum);
#endif
quitting = 1;
}
/* Actually quit */
if (panic_ptr) {
siglongjmp(*panic_ptr, 1);
} else {
log("%s", quitmsg);
if (isatty(2))
fprintf(stderr, "%s\n", quitmsg);
exit(1);
}
}
/*************************************************************************/
/*************************************************************************/
/* Set up signal handlers. Catch certain signals to let us do things or
* panic as necessary, and ignore all others.
*/
void init_signals(void)
{
int i;
/* Start out with special signals disabled */
disable_signals();
/* Set all signals to "ignore" */
for (i = 1; i <= NSIG; i++) {
#ifdef DUMPCORE
if (i != SIGSEGV)
#endif
if (i != SIGPROF && i != SIGCHLD)
signal(i, SIG_IGN);
}
/* Specify particular signals we want to catch */
signal(SIGINT, weirdsig_handler);
signal(SIGTERM, weirdsig_handler);
signal(SIGQUIT, weirdsig_handler);
#ifndef DUMPCORE
signal(SIGSEGV, weirdsig_handler);
#endif
signal(SIGBUS, weirdsig_handler);
signal(SIGQUIT, weirdsig_handler);
signal(SIGHUP, weirdsig_handler);
signal(SIGILL, weirdsig_handler);
signal(SIGTRAP, weirdsig_handler);
signal(SIGFPE, weirdsig_handler);
#ifdef SIGIOT
signal(SIGIOT, weirdsig_handler);
#endif
/* This is our "out-of-memory" panic switch */
signal(SIGUSR1, weirdsig_handler);
/* Other special handlers */
signal(SIGHUP, sighup_handler);
signal(SIGTERM, sigterm_handler);
signal(SIGUSR2, sigusr2_handler);
}
/*************************************************************************/
/* Helper routine for SIGSETJMP() macro; saves a pointer to the environment
* buffer locally. */
void do_sigsetjmp(sigjmp_buf *bufptr)
{
panic_ptr = bufptr;
}
/*************************************************************************/
/* Enable or disable receipt of certain signals (in particular, those which
* cause us to take actions other than simply terminating the program, to
* avoid such signals happening at inopportune times and causing things to
* break).
*/
void enable_signals(void)
{
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGHUP);
sigaddset(&sigs, SIGTERM);
sigaddset(&sigs, SIGUSR2);
sigprocmask(SIG_UNBLOCK, &sigs, NULL);
}
void disable_signals(void)
{
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGHUP);
sigaddset(&sigs, SIGTERM);
sigaddset(&sigs, SIGUSR2);
sigprocmask(SIG_BLOCK, &sigs, NULL);
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1