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