2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2024 Alexander Barton (alex@barton.de) and Contributors.
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.
16 * Signal Handlers: Actions to be performed when the program
25 #include <sys/types.h>
30 # include <sys/socket.h>
41 #include "sighandlers.h"
43 static int signalpipe[2];
45 static const int signals_catch[] = {
46 SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2
53 LogDebug("--- Internal server state: %s ---",
54 Client_ID(Client_ThisServer()));
56 LogDebug("time()=%llu", (unsigned long long)time(NULL));
58 LogDebug("time()=%lu", (unsigned long)time(NULL));
63 LogDebug("--- End of state dump ---");
70 #ifdef HAVE_SIGPROCMASK
76 sigprocmask(SIG_BLOCK, &set, NULL);
83 Signal_Unblock(int sig)
85 #ifdef HAVE_SIGPROCMASK
91 sigprocmask(SIG_UNBLOCK, &set, NULL);
93 int old = sigblock(0) & ~sig;
99 * Reload the server configuration file.
104 char old_name[CLIENT_ID_LEN];
105 unsigned old_nicklen;
107 Log( LOG_NOTICE|LOG_snotice, "Re-reading configuration NOW!" );
108 Signal_NotifySvcMgr("RELOADING=1\n");
110 /* Remember old server name and nickname length */
111 strlcpy( old_name, Conf_ServerName, sizeof old_name );
112 old_nicklen = Conf_MaxNickLength;
114 /* Re-read configuration ... */
115 if (!Conf_Rehash()) {
116 Signal_NotifySvcMgr("READY=1\n");
120 /* Close down all listening sockets */
121 Conn_ExitListeners( );
123 /* Recover old server name and nickname length: these values can't
124 * be changed during run-time */
125 if (strcmp(old_name, Conf_ServerName) != 0 ) {
126 strlcpy(Conf_ServerName, old_name, sizeof Conf_ServerName);
128 "Can't change server name (\"Name\") on runtime! Ignored new name.");
130 if (old_nicklen != Conf_MaxNickLength) {
131 Conf_MaxNickLength = old_nicklen;
133 "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
136 /* Create new pre-defined channels */
137 Channel_InitPredefined( );
139 if (!ConnSSL_InitLibrary())
141 "Re-Initializing of SSL failed!");
143 /* Start listening on sockets */
144 Conn_InitListeners( );
146 /* Sync configuration with established connections */
147 Conn_SyncServerStruct( );
149 Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
150 Signal_NotifySvcMgr("READY=1\n");
154 * Signal handler of ngIRCd.
155 * This function is called whenever ngIRCd catches a signal sent by the
156 * user and/or the system to it. For example SIGTERM and SIGHUP.
158 * It blocks the signal and queues it for later execution by Signal_Handler_BH.
159 * @param Signal Number of the signal to handle.
162 Signal_Handler(int Signal)
164 if (Signal != SIGCHLD) {
165 #ifdef HAVE_STRSIGNAL
166 Log(LOG_INFO, "Got signal \"%s\" ...", strsignal(Signal));
168 Log(LOG_INFO, "Got signal %d ...", Signal);
176 /* shut down sever */
177 NGIRCd_SignalQuit = true;
180 /* child-process exited, avoid zombies */
181 while (waitpid( -1, NULL, WNOHANG) > 0)
185 if (! NGIRCd_Debug) {
186 Log(LOG_INFO|LOG_snotice,
187 "Got SIGUSR1, debug mode activated.");
189 strcpy(NGIRCd_DebugLevel, "2");
191 NGIRCd_Sniffer = true;
193 strcpy(NGIRCd_DebugLevel, "1");
197 Log(LOG_INFO|LOG_snotice,
198 "Got SIGUSR1, debug mode deactivated.");
199 strcpy(NGIRCd_DebugLevel, "");
200 NGIRCd_Debug = false;
202 NGIRCd_Sniffer = false;
209 * other signal: queue for later execution.
210 * This has the advantage that we are not restricted
211 * to functions that can be called safely from signal handlers.
213 if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
214 Signal_Block(Signal);
215 } /* Signal_Handler */
218 * Signal processing handler of ngIRCd.
219 * This function is called from the main conn event loop in (io_dispatch)
220 * whenever ngIRCd has queued a signal.
222 * This function runs in normal context, not from the real signal handler,
223 * thus its not necessary to only use functions that are signal safe.
224 * @param Signal Number of the signal that was queued.
227 Signal_Handler_BH(int Signal)
231 /* re-read configuration */
236 Log(LOG_INFO|LOG_snotice,
237 "Got SIGUSR2, dumping internal state ...");
242 LogDebug("Got signal %d! Ignored.", Signal);
244 Signal_Unblock(Signal);
248 Signal_Callback(int fd, short UNUSED what)
254 ret = (int)read(fd, &sig, sizeof(sig));
255 if (ret == sizeof(int))
256 Signal_Handler_BH(sig);
257 } while (ret == sizeof(int));
260 if (errno == EAGAIN || errno == EINTR)
263 Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
268 Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
273 * Initialize the signal handlers, catch
274 * those signals we are interested in and sets SIGPIPE to be ignored.
275 * @return true if initialization was successful.
281 #ifdef HAVE_SIGACTION
282 struct sigaction saction;
284 if (signalpipe[0] > 0 || signalpipe[1] > 0)
287 if (pipe(signalpipe))
290 if (!io_setnonblock(signalpipe[0]) ||
291 !io_setnonblock(signalpipe[1]))
293 if (!io_setcloexec(signalpipe[0]) ||
294 !io_setcloexec(signalpipe[1]))
296 #ifdef HAVE_SIGACTION
297 memset( &saction, 0, sizeof( saction ));
298 saction.sa_handler = Signal_Handler;
300 saction.sa_flags |= SA_RESTART;
303 saction.sa_flags |= SA_NOCLDWAIT;
306 for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
307 sigaction(signals_catch[i], &saction, NULL);
309 /* we handle write errors properly; ignore SIGPIPE */
310 saction.sa_handler = SIG_IGN;
311 sigaction(SIGPIPE, &saction, NULL);
313 for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
314 signal(signals_catch[i], Signal_Handler);
316 signal(SIGPIPE, SIG_IGN);
318 return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
322 * Restores signals to their default behavior.
324 * This should be called after a fork() in the new
325 * child prodcess, especially when we are about to call
326 * 3rd party code (e.g. PAM).
332 #ifdef HAVE_SIGACTION
333 struct sigaction saction;
335 memset(&saction, 0, sizeof(saction));
336 saction.sa_handler = SIG_DFL;
338 for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
339 sigaction(signals_catch[i], &saction, NULL);
340 sigaction(SIGPIPE, &saction, NULL);
342 for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
343 signal(signals_catch[i], SIG_DFL);
344 signal(SIGPIPE, SIG_DFL);
346 close(signalpipe[1]);
347 close(signalpipe[0]);
348 signalpipe[0] = signalpipe[1] = 0;
352 * Notify the service manager using the "sd_notify" protocol.
354 * This function is based on the example notify() function shown in the
355 * sd_notify(3) manual page, with one significant difference: we keep the file
356 * descriptor open to reduce overhead when called multiple times.
358 * @param message: The message to pass to the service manager including "\n".
361 #if !defined(HAVE_SYS_UN_H) || !defined(SOCK_CLOEXEC)
362 Signal_NotifySvcMgr(UNUSED const char *message)
366 Signal_NotifySvcMgr(const char *message)
368 struct sockaddr_un socket_addr;
369 const char *socket_path;
370 size_t path_length, message_length;
371 static int fd = NONE;
373 assert(message != NULL);
374 assert(message[0] != '\0');
377 /* No socket to the service manager open: Check if a path name
378 * is given in the environment and try to open it! */
379 socket_path = getenv("NOTIFY_SOCKET");
381 return; /* No socket specified, nothing to do. */
383 /* Only AF_UNIX is supported, with path or abstract sockets */
384 if (socket_path[0] != '/' && socket_path[0] != '@') {
386 "Failed to notify service manager: Unsupported socket path!");
390 path_length = strlen(socket_path);
392 /* Ensure there is room for NUL byte */
393 if (path_length >= sizeof(socket_addr.sun_path)) {
395 "Failed to notify service manager: Socket path too long!");
399 memset(&socket_addr, 0, sizeof(struct sockaddr_un));
400 socket_addr.sun_family = AF_UNIX;
401 memcpy(socket_addr.sun_path, socket_path, path_length);
403 /* Support for abstract socket */
404 if (socket_addr.sun_path[0] == '@')
405 socket_addr.sun_path[0] = 0;
407 fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
410 "Failed to notify service manager: %s [socket()]",
415 if (connect(fd, (struct sockaddr *)&socket_addr,
416 sizeof(struct sockaddr_un)) != 0) {
418 "Failed to notify service manager: %s [connect()]",
426 message_length = strlen(message);
427 ssize_t written = write(fd, message, message_length);
428 if (written != (ssize_t)message_length) {
430 "Failed to notify service manager: %s [write()]",