]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/sighandlers.c
Make sighandlers.{c|h} compatible with ansi2knr
[ngircd-alex.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
58 Signal_Block(int sig)
59 {
60 #ifdef HAVE_SIGPROCMASK
61         sigset_t set;
62
63         sigemptyset(&set);
64         sigaddset(&set, sig);
65
66         sigprocmask(SIG_BLOCK, &set, NULL);
67 #else
68         sigblock(sig);
69 #endif
70 }
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 NGIRCd_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 nick name 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 nick name 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, "Can't change \"ServerName\" on runtime! Ignored new name.");
116         }
117         if (old_nicklen != Conf_MaxNickLength) {
118                 Conf_MaxNickLength = old_nicklen;
119                 Log(LOG_ERR, "Can't change \"MaxNickLength\" on runtime! Ignored new value.");
120         }
121
122         /* Create new pre-defined channels */
123         Channel_InitPredefined( );
124
125         if (!ConnSSL_InitLibrary())
126                 Log(LOG_WARNING, "Re-Initializing SSL failed, using old keys");
127
128         /* Start listening on sockets */
129         Conn_InitListeners( );
130
131         /* Sync configuration with established connections */
132         Conn_SyncServerStruct( );
133
134         Log( LOG_NOTICE|LOG_snotice, "Re-reading of configuration done." );
135 } /* NGIRCd_Rehash */
136
137
138
139 /**
140  * Signal handler of ngIRCd.
141  * This function is called whenever ngIRCd catches a signal sent by the
142  * user and/or the system to it. For example SIGTERM and SIGHUP.
143  *
144  * It blocks the signal and queues it for later execution by Signal_Handler_BH.
145  * @param Signal Number of the signal to handle.
146  */
147 static void
148 Signal_Handler(int Signal)
149 {
150         switch (Signal) {
151         case SIGTERM:
152         case SIGINT:
153         case SIGQUIT:
154                 /* shut down sever */
155                 NGIRCd_SignalQuit = true;
156                 return;
157         case SIGHUP:
158                 break;
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 /**
201  * Signal processing handler of ngIRCd.
202  * This function is called from the main conn event loop in (io_dispatch)
203  * whenever ngIRCd has queued a signal.
204  *
205  * This function runs in normal context, not from the real signal handler,
206  * thus its not necessary to only use functions that are signal safe.
207  * @param Signal Number of the signal that was queued.
208  */
209 static void
210 Signal_Handler_BH(int Signal)
211 {
212         switch (Signal) {
213         case SIGHUP:
214                 /* re-read configuration */
215                 NGIRCd_Rehash();
216                 break;
217 #ifdef DEBUG
218         case SIGUSR2:
219                 if (NGIRCd_Debug)
220                         Dump_State();
221                 break;
222         default:
223                 Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
224 #endif
225         }
226         Signal_Unblock(Signal);
227 }
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 = 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", strerror(errno));
247                 exit(1);
248         }
249
250         Log(LOG_EMERG, "EOF on signal pipe");
251         exit(1);
252 }
253
254
255 static const int signals_catch[] = { SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2 };
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 sucessful.
260  */
261 bool
262 Signals_Init(void)
263 {
264         size_t i;
265 #ifdef HAVE_SIGACTION
266         struct sigaction saction;
267 #endif
268
269         if (pipe(signalpipe))
270                 return false;
271
272         if (!io_setnonblock(signalpipe[0]) ||
273             !io_setnonblock(signalpipe[1]))
274                 return false;
275         if (!io_setcloexec(signalpipe[0]) ||
276             !io_setcloexec(signalpipe[1]))
277                 return false;
278 #ifdef HAVE_SIGACTION
279         memset( &saction, 0, sizeof( saction ));
280         saction.sa_handler = Signal_Handler;
281 #ifdef SA_RESTART
282         saction.sa_flags |= SA_RESTART;
283 #endif
284 #ifdef SA_NOCLDWAIT
285         saction.sa_flags |= SA_NOCLDWAIT;
286 #endif
287
288         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
289                 sigaction(signals_catch[i], &saction, NULL);
290
291         /* we handle write errors properly; ignore SIGPIPE */
292         saction.sa_handler = SIG_IGN;
293         sigaction(SIGPIPE, &saction, NULL);
294 #else
295         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
296                 signal(signals_catch[i], Signal_Handler);
297
298         signal(SIGPIPE, SIG_IGN);
299 #endif
300         return io_event_create(signalpipe[0], IO_WANTREAD, Signal_Callback);
301 } /* Signals_Init */
302
303
304 /**
305  * Restores signals to their default behaviour.
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                 sigaction(signals_catch[i], &saction, NULL);
327         signal(SIGPIPE, SIG_DFL);
328 #endif
329         close(signalpipe[1]);
330         close(signalpipe[0]);
331 }
332
333 /* -eof- */