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