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