Annotation of ircnowd/src/ngircd/sighandlers.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2015 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * Signal Handlers: Actions to be performed when the program
! 17: * receives a signal.
! 18: */
! 19:
! 20: #include <errno.h>
! 21: #include <unistd.h>
! 22: #include <stdlib.h>
! 23: #include <string.h>
! 24: #include <signal.h>
! 25: #include <sys/types.h>
! 26: #include <sys/wait.h>
! 27: #include <time.h>
! 28:
! 29: #include "conn.h"
! 30: #include "channel.h"
! 31: #include "conf.h"
! 32: #include "io.h"
! 33: #include "log.h"
! 34: #include "ngircd.h"
! 35:
! 36: #include "sighandlers.h"
! 37:
! 38: static int signalpipe[2];
! 39:
! 40: static const int signals_catch[] = {
! 41: SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
! 42: };
! 43:
! 44: #ifdef DEBUG
! 45:
! 46: static void
! 47: Dump_State(void)
! 48: {
! 49: Log(LOG_DEBUG, "--- Internal server state: %s ---",
! 50: Client_ID(Client_ThisServer()));
! 51: #ifdef HAVE_LONG_LONG
! 52: Log(LOG_DEBUG, "time()=%llu", (unsigned long long)time(NULL));
! 53: #else
! 54: Log(LOG_DEBUG, "time()=%lu", (unsigned long)time(NULL));
! 55: #endif
! 56: Conf_DebugDump();
! 57: Conn_DebugDump();
! 58: Client_DebugDump();
! 59: Log(LOG_DEBUG, "--- End of state dump ---");
! 60: } /* Dump_State */
! 61:
! 62: #endif
! 63:
! 64: static void
! 65: Signal_Block(int sig)
! 66: {
! 67: #ifdef HAVE_SIGPROCMASK
! 68: sigset_t set;
! 69:
! 70: sigemptyset(&set);
! 71: sigaddset(&set, sig);
! 72:
! 73: sigprocmask(SIG_BLOCK, &set, NULL);
! 74: #else
! 75: sigblock(sig);
! 76: #endif
! 77: }
! 78:
! 79: static void
! 80: Signal_Unblock(int sig)
! 81: {
! 82: #ifdef HAVE_SIGPROCMASK
! 83: sigset_t set;
! 84:
! 85: sigemptyset(&set);
! 86: sigaddset(&set, sig);
! 87:
! 88: sigprocmask(SIG_UNBLOCK, &set, NULL);
! 89: #else
! 90: int old = sigblock(0) & ~sig;
! 91: sigsetmask(old);
! 92: #endif
! 93: }
! 94:
! 95: /**
! 96: * Reload the server configuration file.
! 97: */
! 98: static void
! 99: Rehash(void)
! 100: {
! 101: char old_name[CLIENT_ID_LEN];
! 102: unsigned old_nicklen;
! 103:
! 104: Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
! 105:
! 106: /* Remember old server name and nickname length */
! 107: strlcpy( old_name, Conf_ServerName, sizeof old_name );
! 108: old_nicklen = Conf_MaxNickLength;
! 109:
! 110: /* Re-read configuration ... */
! 111: if (!Conf_Rehash( ))
! 112: return;
! 113:
! 114: /* Close down all listening sockets */
! 115: Conn_ExitListeners( );
! 116:
! 117: /* Recover old server name and nickname length: these values can't
! 118: * be changed during run-time */
! 119: if (strcmp(old_name, Conf_ServerName) != 0 ) {
! 120: strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
! 121: Log(LOG_ERR,
! 122: "Can't change server name (\"Name\") on runtime! Ignored new name.");
! 123: }
! 124: if (old_nicklen != Conf_MaxNickLength) {
! 125: Conf_MaxNickLength = old_nicklen;
! 126: Log(LOG_ERR,
! 127: "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
! 128: }
! 129:
! 130: /* Create new pre-defined channels */
! 131: Channel_InitPredefined( );
! 132:
! 133: if (!ConnSSL_InitLibrary())
! 134: Log(LOG_WARNING,
! 135: "Re-Initializing of SSL failed!");
! 136:
! 137: /* Start listening on sockets */
! 138: Conn_InitListeners( );
! 139:
! 140: /* Sync configuration with established connections */
! 141: Conn_SyncServerStruct( );
! 142:
! 143: Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
! 144: } /* Rehash */
! 145:
! 146: /**
! 147: * Signal handler of ngIRCd.
! 148: * This function is called whenever ngIRCd catches a signal sent by the
! 149: * user and/or the system to it. For example SIGTERM and SIGHUP.
! 150: *
! 151: * It blocks the signal and queues it for later execution by Signal_Handler_BH.
! 152: * @param Signal Number of the signal to handle.
! 153: */
! 154: static void
! 155: Signal_Handler(int Signal)
! 156: {
! 157: if (Signal != SIGCHLD) {
! 158: #ifdef HAVE_STRSIGNAL
! 159: Log(LOG_INFO, "Got signal \"%s\" ...", strsignal(Signal));
! 160: #else
! 161: Log(LOG_INFO, "Got signal %d ...", Signal);
! 162: #endif
! 163: }
! 164:
! 165: switch (Signal) {
! 166: case SIGTERM:
! 167: case SIGINT:
! 168: case SIGQUIT:
! 169: /* shut down sever */
! 170: NGIRCd_SignalQuit = true;
! 171: return;
! 172: case SIGCHLD:
! 173: /* child-process exited, avoid zombies */
! 174: while (waitpid( -1, NULL, WNOHANG) > 0)
! 175: ;
! 176: return;
! 177: #ifdef DEBUG
! 178: case SIGUSR1:
! 179: if (! NGIRCd_Debug) {
! 180: Log(LOG_INFO|LOG_snotice,
! 181: "Got SIGUSR1, debug mode activated.");
! 182: #ifdef SNIFFER
! 183: strcpy(NGIRCd_DebugLevel, "2");
! 184: NGIRCd_Debug = true;
! 185: NGIRCd_Sniffer = true;
! 186: #else
! 187: strcpy(NGIRCd_DebugLevel, "1");
! 188: NGIRCd_Debug = true;
! 189: #endif /* SNIFFER */
! 190: } else {
! 191: Log(LOG_INFO|LOG_snotice,
! 192: "Got SIGUSR1, debug mode deactivated.");
! 193: strcpy(NGIRCd_DebugLevel, "");
! 194: NGIRCd_Debug = false;
! 195: #ifdef SNIFFER
! 196: NGIRCd_Sniffer = false;
! 197: #endif /* SNIFFER */
! 198: }
! 199: return;
! 200: #endif
! 201: }
! 202:
! 203: /*
! 204: * other signal: queue for later execution.
! 205: * This has the advantage that we are not restricted
! 206: * to functions that can be called safely from signal handlers.
! 207: */
! 208: if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
! 209: Signal_Block(Signal);
! 210: } /* Signal_Handler */
! 211:
! 212: /**
! 213: * Signal processing handler of ngIRCd.
! 214: * This function is called from the main conn event loop in (io_dispatch)
! 215: * whenever ngIRCd has queued a signal.
! 216: *
! 217: * This function runs in normal context, not from the real signal handler,
! 218: * thus its not necessary to only use functions that are signal safe.
! 219: * @param Signal Number of the signal that was queued.
! 220: */
! 221: static void
! 222: Signal_Handler_BH(int Signal)
! 223: {
! 224: switch (Signal) {
! 225: case SIGHUP:
! 226: /* re-read configuration */
! 227: Rehash();
! 228: break;
! 229: #ifdef DEBUG
! 230: case SIGUSR2:
! 231: if (NGIRCd_Debug) {
! 232: Log(LOG_INFO|LOG_snotice,
! 233: "Got SIGUSR2, dumping internal state ...");
! 234: Dump_State();
! 235: }
! 236: break;
! 237: default:
! 238: Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
! 239: #endif
! 240: }
! 241: Signal_Unblock(Signal);
! 242: }
! 243:
! 244: static void
! 245: Signal_Callback(int fd, short UNUSED what)
! 246: {
! 247: int sig, ret;
! 248: (void) what;
! 249:
! 250: do {
! 251: ret = (int)read(fd, &sig, sizeof(sig));
! 252: if (ret == sizeof(int))
! 253: Signal_Handler_BH(sig);
! 254: } while (ret == sizeof(int));
! 255:
! 256: if (ret == -1) {
! 257: if (errno == EAGAIN || errno == EINTR)
! 258: return;
! 259:
! 260: Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
! 261: strerror(errno));
! 262: exit(1);
! 263: }
! 264:
! 265: Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
! 266: exit(1);
! 267: }
! 268:
! 269: /**
! 270: * Initialize the signal handlers, catch
! 271: * those signals we are interested in and sets SIGPIPE to be ignored.
! 272: * @return true if initialization was successful.
! 273: */
! 274: bool
! 275: Signals_Init(void)
! 276: {
! 277: size_t i;
! 278: #ifdef HAVE_SIGACTION
! 279: struct sigaction saction;
! 280: #endif
! 281: if (signalpipe[0] > 0 || signalpipe[1] > 0)
! 282: return true;
! 283:
! 284: if (pipe(signalpipe))
! 285: return false;
! 286:
! 287: if (!io_setnonblock(signalpipe[0]) ||
! 288: !io_setnonblock(signalpipe[1]))
! 289: return false;
! 290: if (!io_setcloexec(signalpipe[0]) ||
! 291: !io_setcloexec(signalpipe[1]))
! 292: return false;
! 293: #ifdef HAVE_SIGACTION
! 294: memset( &saction, 0, sizeof( saction ));
! 295: saction.sa_handler = Signal_Handler;
! 296: #ifdef SA_RESTART
! 297: saction.sa_flags |= SA_RESTART;
! 298: #endif
! 299: #ifdef SA_NOCLDWAIT
! 300: saction.sa_flags |= SA_NOCLDWAIT;
! 301: #endif
! 302:
! 303: for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
! 304: sigaction(signals_catch[i], &saction, NULL);
! 305:
! 306: /* we handle write errors properly; ignore SIGPIPE */
! 307: saction.sa_handler = SIG_IGN;
! 308: sigaction(SIGPIPE, &saction, NULL);
! 309: #else
! 310: for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
! 311: signal(signals_catch[i], Signal_Handler);
! 312:
! 313: signal(SIGPIPE, SIG_IGN);
! 314: #endif
! 315: return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
! 316: } /* Signals_Init */
! 317:
! 318: /**
! 319: * Restores signals to their default behavior.
! 320: *
! 321: * This should be called after a fork() in the new
! 322: * child prodcess, especially when we are about to call
! 323: * 3rd party code (e.g. PAM).
! 324: */
! 325: void
! 326: Signals_Exit(void)
! 327: {
! 328: size_t i;
! 329: #ifdef HAVE_SIGACTION
! 330: struct sigaction saction;
! 331:
! 332: memset(&saction, 0, sizeof(saction));
! 333: saction.sa_handler = SIG_DFL;
! 334:
! 335: for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
! 336: sigaction(signals_catch[i], &saction, NULL);
! 337: sigaction(SIGPIPE, &saction, NULL);
! 338: #else
! 339: for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
! 340: signal(signals_catch[i], SIG_DFL);
! 341: signal(SIGPIPE, SIG_DFL);
! 342: #endif
! 343: close(signalpipe[1]);
! 344: close(signalpipe[0]);
! 345: signalpipe[0] = signalpipe[1] = 0;
! 346: }
! 347:
! 348: /* -eof- */
CVSweb