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