]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/sighandlers.c
Add new 'delayed' signal handlers.
[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 "io.h"
29 #include "log.h"
30 #include "ngircd.h"
31 #include "sighandlers.h"
32
33 static int signalpipe[2];
34
35 static void Signal_Block(int sig)
36 {
37 #ifdef HAVE_SIGPROCMASK
38         sigset_t set;
39
40         sigemptyset(&set);
41         sigaddset(&set, sig);
42
43         sigprocmask(SIG_BLOCK, &set, NULL);
44 #endif
45 }
46
47
48 static void Signal_Unblock(int sig)
49 {
50 #ifdef HAVE_SIGPROCMASK
51         sigset_t set;
52
53         sigemptyset(&set);
54         sigaddset(&set, sig);
55
56         sigprocmask(SIG_UNBLOCK, &set, NULL);
57 #endif
58 }
59
60
61 /**
62  * Signal handler of ngIRCd.
63  * This function is called whenever ngIRCd catches a signal sent by the
64  * user and/or the system to it. For example SIGTERM and SIGHUP.
65  *
66  * It blocks the signal and queues it for later execution by Signal_Handler_BH.
67  * @param Signal Number of the signal to handle.
68  */
69 static void Signal_Handler(int Signal)
70 {
71         switch (Signal) {
72         case SIGTERM:
73         case SIGINT:
74         case SIGQUIT:
75                 /* shut down sever */
76                 NGIRCd_SignalQuit = true;
77                 return;
78         case SIGHUP:
79                 /* re-read configuration */
80                 NGIRCd_SignalRehash = true;
81                 return;
82         case SIGCHLD:
83                 /* child-process exited, avoid zombies */
84                 while (waitpid( -1, NULL, WNOHANG) > 0)
85                         ;
86                 return;
87         }
88
89         /*
90          * other signal: queue for later execution.
91          * This has the advantage that we are not restricted
92          * to functions that can be called safely from signal handlers.
93          */
94         if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1)
95                 Signal_Block(Signal);
96 } /* Signal_Handler */
97
98
99 /**
100  * Signal processing handler of ngIRCd.
101  * This function is called from the main conn event loop in (io_dispatch)
102  * whenever ngIRCd has queued a signal.
103  *
104  * This function runs in normal context, not from the real signal handler,
105  * thus its not necessary to only use functions that are signal safe.
106  * @param Signal Number of the signal that was queued.
107  */
108 static void Signal_Handler_BH(int Signal)
109 {
110         switch (Signal) {
111 #ifdef DEBUG
112         default:
113                 Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal);
114 #endif
115         }
116         Signal_Unblock(Signal);
117 }
118
119 static void Sig_callback(int fd, short UNUSED what)
120 {
121         int sig, ret;
122         (void) what;
123
124         do {
125                 ret = read(fd, &sig, sizeof(sig));
126                 if (ret == sizeof(int))
127                         Signal_Handler_BH(sig);
128         } while (ret == sizeof(int));
129
130         if (ret == -1) {
131                 if (errno == EAGAIN || errno == EINTR)
132                         return;
133
134                 Log(LOG_EMERG, "read from signal pipe: %s", strerror(errno));
135                 exit(1);
136         }
137
138         Log(LOG_EMERG, "EOF on signal pipe");
139         exit(1);
140 }
141
142
143 static const int signals_catch[] = { SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2 };
144 /**
145  * Initialize the signal handlers, catch
146  * those signals we are interested in and sets SIGPIPE to be ignored.
147  * @return true if initialization was sucessful.
148  */
149 bool Signals_Init(void)
150 {
151         size_t i;
152 #ifdef HAVE_SIGACTION
153         struct sigaction saction;
154 #endif
155
156         if (pipe(signalpipe))
157                 return false;
158
159         if (!io_setnonblock(signalpipe[0]) ||
160             !io_setnonblock(signalpipe[1]))
161                 return false;
162         if (!io_setcloexec(signalpipe[0]) ||
163             !io_setcloexec(signalpipe[1]))
164                 return false;
165 #ifdef HAVE_SIGACTION
166         memset( &saction, 0, sizeof( saction ));
167         saction.sa_handler = Signal_Handler;
168 #ifdef SA_RESTART
169         saction.sa_flags |= SA_RESTART;
170 #endif
171 #ifdef SA_NOCLDWAIT
172         saction.sa_flags |= SA_NOCLDWAIT;
173 #endif
174
175         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
176                 sigaction(signals_catch[i], &saction, NULL);
177
178         /* we handle write errors properly; ignore SIGPIPE */
179         saction.sa_handler = SIG_IGN;
180         sigaction(SIGPIPE, &saction, NULL);
181 #else
182         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
183                 signal(signals_catch[i], Signal_Handler);
184
185         signal(SIGPIPE, SIG_IGN);
186 #endif
187         return io_event_create(signalpipe[0], IO_WANTREAD,
188                                         Sig_callback);
189 } /* Initialize_Signal_Handler */
190
191
192 /**
193  * Restores signals to their default behaviour.
194  *
195  * This should be called after a fork() in the new
196  * child prodcess, especially when we are about to call
197  * 3rd party code (e.g. PAM).
198  */
199 void Signals_Exit(void)
200 {
201         size_t i;
202 #ifdef HAVE_SIGACTION
203         struct sigaction saction;
204
205         memset(&saction, 0, sizeof(saction));
206         saction.sa_handler = SIG_DFL;
207
208         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
209                 sigaction(signals_catch[i], &saction, NULL);
210         sigaction(SIGPIPE, &saction, NULL);
211 #else
212         for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++)
213                 sigaction(signals_catch[i], &saction, NULL);
214         signal(SIGPIPE, SIG_DFL);
215 #endif
216         close(signalpipe[1]);
217         close(signalpipe[0]);
218 }
219
220 /* -eof- */