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