/*
* ngIRCd -- The Next Generation IRC Daemon
+ * 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];
};
-#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)
#endif
}
-
static void
Signal_Unblock(int sig)
{
#endif
}
-
/**
* Reload the server configuration file.
*/
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( );
* 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.");
+ Log(LOG_ERR,
+ "Can't change server name (\"Name\") 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.");
+ 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 SSL failed, using old keys");
+ Log(LOG_WARNING,
+ "Re-Initializing of SSL failed!");
/* Start listening on sockets */
Conn_InitListeners( );
Conn_SyncServerStruct( );
Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
+ Signal_NotifySvcMgr("READY=1\n");
} /* Rehash */
-
/**
* Signal handler of ngIRCd.
* This function is called whenever ngIRCd catches a signal sent by the
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:
while (waitpid( -1, NULL, WNOHANG) > 0)
;
return;
-#ifdef DEBUG
case SIGUSR1:
if (! NGIRCd_Debug) {
Log(LOG_INFO|LOG_snotice,
#endif /* SNIFFER */
}
return;
-#endif
}
/*
Signal_Block(Signal);
} /* Signal_Handler */
-
/**
* Signal processing handler of ngIRCd.
* This function is called from the main conn event loop in (io_dispatch)
/* re-read configuration */
Rehash();
break;
-#ifdef DEBUG
case SIGUSR2:
if (NGIRCd_Debug) {
Log(LOG_INFO|LOG_snotice,
}
break;
default:
- Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
-#endif
+ LogDebug("Got signal %d! Ignored.", Signal);
}
Signal_Unblock(Signal);
}
-
static void
Signal_Callback(int fd, short UNUSED what)
{
if (errno == EAGAIN || errno == EINTR)
return;
- Log(LOG_EMERG, "read from signal pipe: %s", strerror(errno));
+ Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
+ strerror(errno));
exit(1);
}
- Log(LOG_EMERG, "EOF on signal pipe");
+ 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 sucessful.
+ * @return true if initialization was successful.
*/
bool
Signals_Init(void)
return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
} /* Signals_Init */
-
/**
- * Restores signals to their default behaviour.
+ * 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
signalpipe[0] = signalpipe[1] = 0;
}
-/* -eof- */
+/**
+ * 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
+}