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