]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/sighandlers.c
Log received signals (using strsignal(3), when available)
[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         if (Signal != SIGCHLD) {
158 #ifdef HAVE_STRSIGNAL
159                 Log(LOG_INFO, "Got signal \"%s\" ...", strsignal(Signal));
160 #else
161                 Log(LOG_INFO, "Got signal %d ...", Signal);
162 #endif
163         }
164
165         switch (Signal) {
166         case SIGTERM:
167         case SIGINT:
168         case SIGQUIT:
169                 /* shut down sever */
170                 NGIRCd_SignalQuit = true;
171                 return;
172         case SIGCHLD:
173                 /* child-process exited, avoid zombies */
174                 while (waitpid( -1, NULL, WNOHANG) > 0)
175                         ;
176                 return;
177 #ifdef DEBUG
178         case SIGUSR1:
179                 if (! NGIRCd_Debug) {
180                         Log(LOG_INFO|LOG_snotice,
181                             "Got SIGUSR1, debug mode activated.");
182 #ifdef SNIFFER
183                         strcpy(NGIRCd_DebugLevel, "2");
184                         NGIRCd_Debug = true;
185                         NGIRCd_Sniffer = true;
186 #else
187                         strcpy(NGIRCd_DebugLevel, "1");
188                         NGIRCd_Debug = true;
189 #endif /* SNIFFER */
190                 } else {
191                         Log(LOG_INFO|LOG_snotice,
192                             "Got SIGUSR1, debug mode deactivated.");
193                         strcpy(NGIRCd_DebugLevel, "");
194                         NGIRCd_Debug = false;
195 #ifdef SNIFFER
196                         NGIRCd_Sniffer = false;
197 #endif /* SNIFFER */
198                 }
199                 return;
200 #endif
201         }
202
203         /*
204          * other signal: queue for later execution.
205          * This has the advantage that we are not restricted
206          * to functions that can be called safely from signal handlers.
207          */
208         if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
209                 Signal_Block(Signal);
210 } /* Signal_Handler */
211
212 /**
213  * Signal processing handler of ngIRCd.
214  * This function is called from the main conn event loop in (io_dispatch)
215  * whenever ngIRCd has queued a signal.
216  *
217  * This function runs in normal context, not from the real signal handler,
218  * thus its not necessary to only use functions that are signal safe.
219  * @param Signal Number of the signal that was queued.
220  */
221 static void
222 Signal_Handler_BH(int Signal)
223 {
224         switch (Signal) {
225         case SIGHUP:
226                 /* re-read configuration */
227                 Rehash();
228                 break;
229 #ifdef DEBUG
230         case SIGUSR2:
231                 if (NGIRCd_Debug) {
232                         Log(LOG_INFO|LOG_snotice,
233                             "Got SIGUSR2, dumping internal state ...");
234                         Dump_State();
235                 }
236                 break;
237         default:
238                 Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
239 #endif
240         }
241         Signal_Unblock(Signal);
242 }
243
244 static void
245 Signal_Callback(int fd, short UNUSED what)
246 {
247         int sig, ret;
248         (void) what;
249
250         do {
251                 ret = (int)read(fd, &sig, sizeof(sig));
252                 if (ret == sizeof(int))
253                         Signal_Handler_BH(sig);
254         } while (ret == sizeof(int));
255
256         if (ret == -1) {
257                 if (errno == EAGAIN || errno == EINTR)
258                         return;
259
260                 Log(LOG_EMERG, "Read from signal pipe: %s - Exiting!",
261                     strerror(errno));
262                 exit(1);
263         }
264
265         Log(LOG_EMERG, "EOF on signal pipe!? - Exiting!");
266         exit(1);
267 }
268
269 /**
270  * Initialize the signal handlers, catch
271  * those signals we are interested in and sets SIGPIPE to be ignored.
272  * @return true if initialization was successful.
273  */
274 bool
275 Signals_Init(void)
276 {
277         size_t i;
278 #ifdef HAVE_SIGACTION
279         struct sigaction saction;
280 #endif
281         if (signalpipe[0] > 0 || signalpipe[1] > 0)
282                 return true;
283
284         if (pipe(signalpipe))
285                 return false;
286
287         if (!io_setnonblock(signalpipe[0]) ||
288             !io_setnonblock(signalpipe[1]))
289                 return false;
290         if (!io_setcloexec(signalpipe[0]) ||
291             !io_setcloexec(signalpipe[1]))
292                 return false;
293 #ifdef HAVE_SIGACTION
294         memset( &saction, 0, sizeof( saction ));
295         saction.sa_handler = Signal_Handler;
296 #ifdef SA_RESTART
297         saction.sa_flags |= SA_RESTART;
298 #endif
299 #ifdef SA_NOCLDWAIT
300         saction.sa_flags |= SA_NOCLDWAIT;
301 #endif
302
303         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
304                 sigaction(signals_catch[i], &saction, NULL);
305
306         /* we handle write errors properly; ignore SIGPIPE */
307         saction.sa_handler = SIG_IGN;
308         sigaction(SIGPIPE, &saction, NULL);
309 #else
310         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
311                 signal(signals_catch[i], Signal_Handler);
312
313         signal(SIGPIPE, SIG_IGN);
314 #endif
315         return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
316 } /* Signals_Init */
317
318 /**
319  * Restores signals to their default behavior.
320  *
321  * This should be called after a fork() in the new
322  * child prodcess, especially when we are about to call
323  * 3rd party code (e.g. PAM).
324  */
325 void
326 Signals_Exit(void)
327 {
328         size_t i;
329 #ifdef HAVE_SIGACTION
330         struct sigaction saction;
331
332         memset(&saction, 0, sizeof(saction));
333         saction.sa_handler = SIG_DFL;
334
335         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
336                 sigaction(signals_catch[i], &saction, NULL);
337         sigaction(SIGPIPE, &saction, NULL);
338 #else
339         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
340                 signal(signals_catch[i], SIG_DFL);
341         signal(SIGPIPE, SIG_DFL);
342 #endif
343         close(signalpipe[1]);
344         close(signalpipe[0]);
345         signalpipe[0] = signalpipe[1] = 0;
346 }
347
348 /* -eof- */