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