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