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