1 |
/* |
2 |
* Boa, an http server |
3 |
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com> |
4 |
* Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org> |
5 |
* Some changes Copyright (C) 1996-99 Jon Nelson <jnelson@boa.org> |
6 |
* Some changes Copyright (C) 1997 Alain Magloire <alain.magloire@rcsm.ee.mcgill.ca> |
7 |
* Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org> |
8 |
* |
9 |
* This program is free software; you can redistribute it and/or modify |
10 |
* it under the terms of the GNU General Public License as published by |
11 |
* the Free Software Foundation; either version 1, or (at your option) |
12 |
* any later version. |
13 |
* |
14 |
* This program is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 |
* GNU General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU General Public License |
20 |
* along with this program; if not, write to the Free Software |
21 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 |
* |
23 |
*/ |
24 |
|
25 |
/* $Id: signals.c,v 1.7 2002/09/25 10:33:19 nmav Exp $*/ |
26 |
|
27 |
#include "boa.h" |
28 |
#ifdef HAVE_SYS_WAIT_H |
29 |
#include <sys/wait.h> /* wait */ |
30 |
#endif |
31 |
#include <signal.h> /* signal */ |
32 |
#include "ssl.h" |
33 |
|
34 |
#ifdef ENABLE_SMP |
35 |
# include <pthread.h> |
36 |
|
37 |
extern pthread_t father_id; |
38 |
|
39 |
#endif |
40 |
|
41 |
extern server_params *global_server_params; |
42 |
extern int global_server_params_size; |
43 |
|
44 |
void sigsegv(int); |
45 |
void sigbus(int); |
46 |
void sigterm(int); |
47 |
void sighup(int); |
48 |
void sigint(int); |
49 |
void sigchld(int); |
50 |
void sigalrm(int); |
51 |
void sigusr1(int); |
52 |
|
53 |
/* |
54 |
* Name: init_signals |
55 |
* Description: Sets up signal handlers for all our friends. |
56 |
*/ |
57 |
|
58 |
void init_signals(void) |
59 |
{ |
60 |
struct sigaction sa; |
61 |
|
62 |
sa.sa_flags = 0; |
63 |
|
64 |
sigemptyset(&sa.sa_mask); |
65 |
sigaddset(&sa.sa_mask, SIGSEGV); |
66 |
sigaddset(&sa.sa_mask, SIGBUS); |
67 |
sigaddset(&sa.sa_mask, SIGTERM); |
68 |
sigaddset(&sa.sa_mask, SIGHUP); |
69 |
sigaddset(&sa.sa_mask, SIGINT); |
70 |
sigaddset(&sa.sa_mask, SIGPIPE); |
71 |
sigaddset(&sa.sa_mask, SIGCHLD); |
72 |
sigaddset(&sa.sa_mask, SIGALRM); |
73 |
sigaddset(&sa.sa_mask, SIGUSR1); |
74 |
sigaddset(&sa.sa_mask, SIGUSR2); |
75 |
|
76 |
sa.sa_handler = sigsegv; |
77 |
sigaction(SIGSEGV, &sa, NULL); |
78 |
|
79 |
sa.sa_handler = sigbus; |
80 |
sigaction(SIGBUS, &sa, NULL); |
81 |
|
82 |
sa.sa_handler = SIG_IGN; |
83 |
sigaction(SIGPIPE, &sa, NULL); |
84 |
|
85 |
sa.sa_handler = sigchld; |
86 |
sigaction(SIGCHLD, &sa, NULL); |
87 |
|
88 |
sa.sa_handler = sigterm; |
89 |
sigaction(SIGTERM, &sa, NULL); |
90 |
|
91 |
sa.sa_handler = sighup; |
92 |
sigaction(SIGHUP, &sa, NULL); |
93 |
|
94 |
sa.sa_handler = sigint; |
95 |
sigaction(SIGINT, &sa, NULL); |
96 |
|
97 |
sa.sa_handler = sigalrm; |
98 |
sigaction(SIGALRM, &sa, NULL); |
99 |
|
100 |
sa.sa_handler = sigusr1; |
101 |
sigaction(SIGUSR1, &sa, NULL); |
102 |
|
103 |
sa.sa_handler = SIG_IGN; |
104 |
sigaction(SIGUSR2, &sa, NULL); |
105 |
} |
106 |
|
107 |
/* Blocks all signals that should be handled by |
108 |
* the main thread, so that other threads are |
109 |
* not annoyed. |
110 |
*/ |
111 |
void block_main_signals() |
112 |
{ |
113 |
sigset_t sigset; |
114 |
|
115 |
sigemptyset( &sigset); |
116 |
sigaddset( &sigset, SIGALRM); |
117 |
sigaddset( &sigset, SIGUSR1); |
118 |
sigaddset( &sigset, SIGTERM); |
119 |
sigaddset( &sigset, SIGHUP); |
120 |
sigaddset( &sigset, SIGINT); |
121 |
|
122 |
sigprocmask( SIG_BLOCK, &sigset, NULL); |
123 |
} |
124 |
|
125 |
void unblock_main_signals() |
126 |
{ |
127 |
sigset_t sigset; |
128 |
|
129 |
sigemptyset( &sigset); |
130 |
sigaddset( &sigset, SIGALRM); |
131 |
sigaddset( &sigset, SIGUSR1); |
132 |
sigaddset( &sigset, SIGTERM); |
133 |
sigaddset( &sigset, SIGHUP); |
134 |
sigaddset( &sigset, SIGINT); |
135 |
|
136 |
sigprocmask( SIG_UNBLOCK, &sigset, NULL); |
137 |
} |
138 |
|
139 |
void sigsegv(int dummy) |
140 |
{ |
141 |
time(¤t_time); |
142 |
log_error_time(); |
143 |
fprintf(stderr, "caught SIGSEGV, dumping core in %s\n", tempdir); |
144 |
fclose(stderr); |
145 |
chdir(tempdir); |
146 |
abort(); |
147 |
} |
148 |
|
149 |
void sigbus(int dummy) |
150 |
{ |
151 |
server_params* params = &global_server_params[0]; |
152 |
|
153 |
/* Note that in multithreaded cases the SIGBUS is catched |
154 |
* by the same thread that did the violation. So the following |
155 |
* code should be ok. |
156 |
*/ |
157 |
|
158 |
#ifdef ENABLE_SMP |
159 |
pthread_t tid = pthread_self(); |
160 |
int i; |
161 |
|
162 |
for (i=0;i<global_server_params_size;i++) { |
163 |
if (pthread_equal( global_server_params[i].tid, tid)) { |
164 |
params = &global_server_params[i]; |
165 |
break; |
166 |
} |
167 |
} |
168 |
#endif |
169 |
|
170 |
if (params->handle_sigbus) { |
171 |
longjmp(params->env, dummy); |
172 |
} |
173 |
time(¤t_time); |
174 |
log_error_time(); |
175 |
fprintf(stderr, "caught SIGBUS, dumping core in %s\n", tempdir); |
176 |
fclose(stderr); |
177 |
chdir(tempdir); |
178 |
abort(); |
179 |
} |
180 |
|
181 |
#define SET_PTH_SIGFLAG( flag, val) \ |
182 |
global_server_params[0].flag = val |
183 |
|
184 |
#ifdef ENABLE_SMP |
185 |
# define SET_LOCAL_PTH_SIGFLAG( flag, val) \ |
186 |
{ pthread_t tid = pthread_self(); int i; \ |
187 |
for (i=0;i<global_server_params_size;i++) { \ |
188 |
if ( pthread_equal( global_server_params[i].tid, tid)) { \ |
189 |
global_server_params[i].flag = val; \ |
190 |
break; \ |
191 |
} \ |
192 |
} \ |
193 |
} |
194 |
|
195 |
#else |
196 |
# define SET_LOCAL_PTH_SIGFLAG SET_PTH_SIGFLAG |
197 |
#endif |
198 |
|
199 |
void sigterm(int dummy) |
200 |
{ |
201 |
SET_PTH_SIGFLAG( sigterm_flag, 1); |
202 |
} |
203 |
|
204 |
|
205 |
void sigterm_stage1_run() /* lame duck mode */ |
206 |
{ |
207 |
#ifdef ENABLE_SMP |
208 |
int i; |
209 |
#endif |
210 |
|
211 |
time(¤t_time); |
212 |
log_error_time(); |
213 |
fputs("caught SIGTERM, starting shutdown\n", stderr); |
214 |
|
215 |
#ifdef ENABLE_SMP |
216 |
/* remember that the first thread is actual the main process. |
217 |
*/ |
218 |
for (i=1;i<global_server_params_size;i++) { |
219 |
/* terminate all threads */ |
220 |
int ret; |
221 |
|
222 |
if ((ret=pthread_cancel( global_server_params[i].tid)) != 0) { |
223 |
log_error_time(); |
224 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n" , (int)global_server_params[i].tid, ret); |
225 |
exit(1); |
226 |
} |
227 |
} |
228 |
#endif |
229 |
|
230 |
if ( global_server_params[0].server_s[0].socket != -1) { |
231 |
FD_CLR(global_server_params[0].server_s[0].socket, &global_server_params[0].block_read_fdset); |
232 |
close(global_server_params[0].server_s[0].socket); |
233 |
} |
234 |
|
235 |
if ( global_server_params[0].server_s[1].socket != -1) { |
236 |
FD_CLR(global_server_params[0].server_s[1].socket, &global_server_params[0].block_read_fdset); |
237 |
close(global_server_params[0].server_s[1].socket); |
238 |
} |
239 |
|
240 |
SET_PTH_SIGFLAG( sigterm_flag, 2); |
241 |
} |
242 |
|
243 |
|
244 |
void sigterm_stage2_run() /* lame duck mode */ |
245 |
{ |
246 |
int i; |
247 |
|
248 |
log_error_time(); |
249 |
fprintf(stderr, |
250 |
"exiting Boa normally (uptime %d seconds)\n", |
251 |
(int) (current_time - start_time)); |
252 |
chdir(tempdir); |
253 |
clear_common_env(); |
254 |
dump_mime(); |
255 |
dump_passwd(); |
256 |
dump_virthost(); |
257 |
dump_directory_index(); |
258 |
|
259 |
for (i=0;i<global_server_params_size;i++) { |
260 |
free_requests( &global_server_params[i]); |
261 |
} |
262 |
|
263 |
exit(0); |
264 |
} |
265 |
|
266 |
|
267 |
void sighup(int dummy) |
268 |
{ |
269 |
SET_PTH_SIGFLAG( sighup_flag, 1); |
270 |
} |
271 |
|
272 |
void sighup_run() |
273 |
{ |
274 |
int i; |
275 |
|
276 |
SET_PTH_SIGFLAG( sighup_flag, 0); |
277 |
|
278 |
time(¤t_time); |
279 |
log_error_time(); |
280 |
fputs("caught SIGHUP, restarting\n", stderr); |
281 |
|
282 |
#ifdef ENABLE_SMP |
283 |
/* Kill all threads! */ |
284 |
|
285 |
for (i=1;i<global_server_params_size;i++) { |
286 |
int ret; |
287 |
if ((ret=pthread_cancel( global_server_params[i].tid)) != 0) { |
288 |
log_error_time(); |
289 |
fprintf(stderr, "Could not cancel thread: %d. errno = %d.\n" , (int)global_server_params[i].tid, ret); |
290 |
exit(1); |
291 |
} |
292 |
} |
293 |
|
294 |
log_error_time(); |
295 |
fputs("Destroyed the pool of threads.\n", stderr); |
296 |
|
297 |
for (i=0;i<global_server_params_size;i++) { |
298 |
free_requests( &global_server_params[i]); |
299 |
} |
300 |
|
301 |
#endif |
302 |
for (i=0;i<global_server_params_size;i++) { |
303 |
FD_ZERO(&global_server_params[i].block_read_fdset); |
304 |
FD_ZERO(&global_server_params[i].block_write_fdset); |
305 |
} |
306 |
|
307 |
/* Philosophy change for 0.92: don't close and attempt reopen of logfiles, |
308 |
* since usual permission structure prevents such reopening. |
309 |
*/ |
310 |
|
311 |
/* clear_common_env(); NEVER DO THIS */ |
312 |
dump_mime(); |
313 |
dump_passwd(); |
314 |
dump_virthost(); |
315 |
dump_directory_index(); |
316 |
|
317 |
log_error_time(); |
318 |
fputs("re-reading configuration files\n", stderr); |
319 |
read_config_files(); |
320 |
|
321 |
/* We now need to dispatch the threads again */ |
322 |
smp_reinit(); |
323 |
mmap_reinit(); |
324 |
|
325 |
log_error_time(); |
326 |
fputs("successful restart\n", stderr); |
327 |
|
328 |
} |
329 |
|
330 |
void sigint(int dummy) |
331 |
{ |
332 |
time(¤t_time); |
333 |
log_error_time(); |
334 |
fputs("caught SIGINT: shutting down\n", stderr); |
335 |
fclose(stderr); |
336 |
chdir(tempdir); |
337 |
exit(1); |
338 |
} |
339 |
|
340 |
void sigchld(int dummy) |
341 |
{ |
342 |
SET_LOCAL_PTH_SIGFLAG( sigchld_flag, 1); |
343 |
} |
344 |
|
345 |
void sigchld_run(void) |
346 |
{ |
347 |
int status; |
348 |
pid_t pid; |
349 |
|
350 |
SET_LOCAL_PTH_SIGFLAG( sigchld_flag, 0); |
351 |
|
352 |
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
353 |
if (verbose_cgi_logs) { |
354 |
time(¤t_time); |
355 |
log_error_time(); |
356 |
fprintf(stderr, "reaping child %d: status %d\n", (int) pid, status); |
357 |
} |
358 |
return; |
359 |
} |
360 |
|
361 |
void sigalrm(int dummy) |
362 |
{ |
363 |
SET_PTH_SIGFLAG( sigalrm_flag, 1); |
364 |
} |
365 |
|
366 |
void sigusr1(int dummy) |
367 |
{ |
368 |
SET_PTH_SIGFLAG( sigusr1_flag, 1); |
369 |
} |
370 |
|
371 |
extern int ssl_params_refresh; |
372 |
extern int boa_ssl; |
373 |
|
374 |
void sigalrm_run(void) |
375 |
{ |
376 |
SET_PTH_SIGFLAG( sigalrm_flag, 0); |
377 |
|
378 |
#ifdef ENABLE_SSL |
379 |
if (boa_ssl) |
380 |
ssl_regenerate_params(); |
381 |
#endif |
382 |
|
383 |
if (boa_ssl && ssl_params_refresh) |
384 |
alarm( ssl_params_refresh); |
385 |
} |
386 |
|
387 |
void sigusr1_run(void) |
388 |
{ |
389 |
int i; |
390 |
|
391 |
SET_PTH_SIGFLAG( sigusr1_flag, 0); |
392 |
|
393 |
time(¤t_time); |
394 |
|
395 |
for (i=0;i<global_server_params_size;i++) { |
396 |
log_error_time(); |
397 |
fprintf(stderr, "Thread %d: %ld requests, %ld errors\n", |
398 |
i+1, global_server_params[i].status.requests, |
399 |
global_server_params[i].status.errors); |
400 |
} |
401 |
|
402 |
show_hash_stats(); |
403 |
|
404 |
} |
405 |
|