Annotation of ircnowd/src/ngircd/sighandlers.c, Revision 1.1.1.1
1.1 tomglok 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!");
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- */
CVSweb