]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/sighandlers.c
ngIRCd Release 27
[ngircd-alex.git] / src / ngircd / sighandlers.c
index effef44d8fb8b391e1b222eb2eaabee296632e48..00f5ae8555708e1c616f54a5263916a14311720b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2024 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
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <time.h>
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/socket.h>
+# include <sys/un.h>
+#endif
 
-#include "imp.h"
 #include "conn.h"
-#include "conf-ssl.h"
 #include "channel.h"
 #include "conf.h"
 #include "io.h"
 #include "log.h"
 #include "ngircd.h"
+
 #include "sighandlers.h"
 
 static int signalpipe[2];
@@ -41,21 +46,23 @@ 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 ---",
+       LogDebug("--- Internal server state: %s ---",
            Client_ID(Client_ThisServer()));
-       Log(LOG_DEBUG, "time()=%ld", time(NULL));
+#ifdef HAVE_LONG_LONG
+       LogDebug("time()=%llu", (unsigned long long)time(NULL));
+#else
+       LogDebug("time()=%lu", (unsigned long)time(NULL));
+#endif
        Conf_DebugDump();
        Conn_DebugDump();
        Client_DebugDump();
-       Log(LOG_DEBUG, "--- End of state dump ---");
+       LogDebug("--- End of state dump ---");
 } /* Dump_State */
 
-#endif
 
 static void
 Signal_Block(int sig)
@@ -98,14 +105,17 @@ Rehash(void)
        unsigned old_nicklen;
 
        Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
+       Signal_NotifySvcMgr("RELOADING=1\n");
 
        /* 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( ))
+       if (!Conf_Rehash()) {
+               Signal_NotifySvcMgr("READY=1\n");
                return;
+       }
 
        /* Close down all listening sockets */
        Conn_ExitListeners( );
@@ -115,7 +125,7 @@ Rehash(void)
        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.");
+                   "Can't change server name (\"Name\") on runtime! Ignored new name.");
        }
        if (old_nicklen != Conf_MaxNickLength) {
                Conf_MaxNickLength = old_nicklen;
@@ -128,7 +138,7 @@ Rehash(void)
 
        if (!ConnSSL_InitLibrary())
                Log(LOG_WARNING,
-                   "Re-Initializing of SSL failed, using old keys!");
+                   "Re-Initializing of SSL failed!");
 
        /* Start listening on sockets */
        Conn_InitListeners( );
@@ -137,6 +147,7 @@ Rehash(void)
        Conn_SyncServerStruct( );
 
        Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
+       Signal_NotifySvcMgr("READY=1\n");
 } /* Rehash */
 
 /**
@@ -150,6 +161,14 @@ Rehash(void)
 static void
 Signal_Handler(int Signal)
 {
+       if (Signal != SIGCHLD) {
+#ifdef HAVE_STRSIGNAL
+               Log(LOG_INFO, "Got signal \"%s\" ...", strsignal(Signal));
+#else
+               Log(LOG_INFO, "Got signal %d ...", Signal);
+#endif
+       }
+
        switch (Signal) {
        case SIGTERM:
        case SIGINT:
@@ -162,7 +181,6 @@ Signal_Handler(int Signal)
                while (waitpid( -1, NULL, WNOHANG) > 0)
                        ;
                return;
-#ifdef DEBUG
        case SIGUSR1:
                if (! NGIRCd_Debug) {
                        Log(LOG_INFO|LOG_snotice,
@@ -185,7 +203,6 @@ Signal_Handler(int Signal)
 #endif /* SNIFFER */
                }
                return;
-#endif
        }
 
        /*
@@ -214,7 +231,6 @@ Signal_Handler_BH(int Signal)
                /* re-read configuration */
                Rehash();
                break;
-#ifdef DEBUG
        case SIGUSR2:
                if (NGIRCd_Debug) {
                        Log(LOG_INFO|LOG_snotice,
@@ -223,8 +239,7 @@ Signal_Handler_BH(int Signal)
                }
                break;
        default:
-               Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
-#endif
+               LogDebug("Got signal %d! Ignored.", Signal);
        }
        Signal_Unblock(Signal);
 }
@@ -333,4 +348,104 @@ Signals_Exit(void)
        signalpipe[0] = signalpipe[1] = 0;
 }
 
-/* -eof- */
+/**
+ * Check if the service manager of the system can be notified.
+ *
+ * @returns true if notifying the service manager is theoretically possible.
+ */
+GLOBAL bool
+Signal_NotifySvcMgr_Possible(void)
+{
+#if !defined(HAVE_SYS_UN_H) || !defined(SOCK_CLOEXEC)
+       return false;
+#else
+       return getenv("NOTIFY_SOCKET") != NULL;
+#endif
+}
+
+/**
+ * Notify the service manager using the "sd_notify" protocol.
+ *
+ * This function is based on the example notify() function shown in the
+ * sd_notify(3) manual page, with one significant difference: we keep the file
+ * descriptor open to reduce overhead when called multiple times.
+ *
+ * @param message: The message to pass to the service manager including "\n".
+ */
+GLOBAL void
+#if !defined(HAVE_SYS_UN_H) || !defined(SOCK_CLOEXEC)
+Signal_NotifySvcMgr(UNUSED const char *message)
+{
+       return;
+#else
+Signal_NotifySvcMgr(const char *message)
+{
+       struct sockaddr_un socket_addr;
+       const char *socket_path;
+       size_t path_length, message_length;
+       static int fd = NONE;
+
+       assert(message != NULL);
+       assert(message[0] != '\0');
+
+       if (fd == NONE) {
+               /* No socket to the service manager open: Check if a path name
+                * is given in the environment and try to open it! */
+               socket_path = getenv("NOTIFY_SOCKET");
+               if (!socket_path)
+                       return; /* No socket specified, nothing to do. */
+
+               /* Only AF_UNIX is supported, with path or abstract sockets */
+               if (socket_path[0] != '/' && socket_path[0] != '@') {
+                       Log(LOG_CRIT,
+                       "Failed to notify service manager: Unsupported socket path!");
+                       return;
+               }
+
+               path_length = strlen(socket_path);
+
+               /* Ensure there is room for NUL byte */
+               if (path_length >= sizeof(socket_addr.sun_path)) {
+                       Log(LOG_CRIT,
+                       "Failed to notify service manager: Socket path too long!");
+                       return;
+               }
+
+               memset(&socket_addr, 0, sizeof(struct sockaddr_un));
+               socket_addr.sun_family = AF_UNIX;
+               memcpy(socket_addr.sun_path, socket_path, path_length);
+
+               /* Support for abstract socket */
+               if (socket_addr.sun_path[0] == '@')
+                       socket_addr.sun_path[0] = 0;
+
+               fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+               if (fd < 0) {
+                       Log(LOG_CRIT,
+                           "Failed to notify service manager: %s [socket()]",
+                           strerror(errno));
+                       return;
+               }
+
+               if (connect(fd, (struct sockaddr *)&socket_addr,
+                           sizeof(struct sockaddr_un)) != 0) {
+                       Log(LOG_CRIT,
+                           "Failed to notify service manager: %s [connect()]",
+                           strerror(errno));
+                       close(fd);
+                       fd = NONE;
+                       return;
+               }
+       }
+
+       message_length = strlen(message);
+       ssize_t written = write(fd, message, message_length);
+       if (written != (ssize_t)message_length) {
+               Log(LOG_CRIT,
+                       "Failed to notify service manager: %s [write()]",
+                       strerror(errno));
+               close(fd);
+               fd = NONE;
+       }
+#endif
+}