/src/httpd/server/mpm_unix.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | /* The purpose of this file is to store the code that MOST mpm's will need |
18 | | * this does not mean a function only goes into this file if every MPM needs |
19 | | * it. It means that if a function is needed by more than one MPM, and |
20 | | * future maintenance would be served by making the code common, then the |
21 | | * function belongs here. |
22 | | * |
23 | | * This is going in src/main because it is not platform specific, it is |
24 | | * specific to multi-process servers, but NOT to Unix. Which is why it |
25 | | * does not belong in src/os/unix |
26 | | */ |
27 | | |
28 | | #ifndef WIN32 |
29 | | |
30 | | #include "apr.h" |
31 | | #include "apr_thread_proc.h" |
32 | | #include "apr_signal.h" |
33 | | #include "apr_strings.h" |
34 | | #define APR_WANT_STRFUNC |
35 | | #include "apr_want.h" |
36 | | #include "apr_getopt.h" |
37 | | #include "apr_optional.h" |
38 | | #include "apr_allocator.h" |
39 | | |
40 | | #include "httpd.h" |
41 | | #include "http_config.h" |
42 | | #include "http_core.h" |
43 | | #include "http_log.h" |
44 | | #include "http_main.h" |
45 | | #include "mpm_common.h" |
46 | | #include "ap_mpm.h" |
47 | | #include "ap_listen.h" |
48 | | #include "scoreboard.h" |
49 | | #include "util_mutex.h" |
50 | | |
51 | | #ifdef HAVE_PWD_H |
52 | | #include <pwd.h> |
53 | | #endif |
54 | | #ifdef HAVE_GRP_H |
55 | | #include <grp.h> |
56 | | #endif |
57 | | #if APR_HAVE_UNISTD_H |
58 | | #include <unistd.h> |
59 | | #endif |
60 | | |
61 | | |
62 | | /* we know core's module_index is 0 */ |
63 | | #undef APLOG_MODULE_INDEX |
64 | | #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX |
65 | | |
66 | | typedef enum { |
67 | | DO_NOTHING, |
68 | | SEND_SIGTERM, |
69 | | SEND_SIGTERM_NOLOG, |
70 | | SEND_SIGKILL, |
71 | | GIVEUP |
72 | | } action_t; |
73 | | |
74 | | typedef struct extra_process_t { |
75 | | struct extra_process_t *next; |
76 | | pid_t pid; |
77 | | ap_generation_t gen; |
78 | | } extra_process_t; |
79 | | |
80 | | static extra_process_t *extras; |
81 | | |
82 | | AP_DECLARE(void) ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen) |
83 | 0 | { |
84 | 0 | extra_process_t *p = (extra_process_t *)ap_malloc(sizeof(extra_process_t)); |
85 | |
|
86 | 0 | p->next = extras; |
87 | 0 | p->pid = pid; |
88 | 0 | p->gen = gen; |
89 | 0 | extras = p; |
90 | 0 | } |
91 | | |
92 | | AP_DECLARE(int) ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *old_gen) |
93 | 0 | { |
94 | 0 | extra_process_t *cur = extras; |
95 | 0 | extra_process_t *prev = NULL; |
96 | |
|
97 | 0 | while (cur && cur->pid != pid) { |
98 | 0 | prev = cur; |
99 | 0 | cur = cur->next; |
100 | 0 | } |
101 | |
|
102 | 0 | if (cur) { |
103 | 0 | if (prev) { |
104 | 0 | prev->next = cur->next; |
105 | 0 | } |
106 | 0 | else { |
107 | 0 | extras = cur->next; |
108 | 0 | } |
109 | 0 | *old_gen = cur->gen; |
110 | 0 | free(cur); |
111 | 0 | return 1; /* found */ |
112 | 0 | } |
113 | 0 | else { |
114 | | /* we don't know about any such process */ |
115 | 0 | return 0; |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | static int reclaim_one_pid(pid_t pid, action_t action) |
120 | 0 | { |
121 | 0 | apr_proc_t proc; |
122 | 0 | apr_status_t waitret; |
123 | 0 | apr_exit_why_e why; |
124 | 0 | int status; |
125 | | |
126 | | /* Ensure pid sanity. */ |
127 | 0 | if (pid < 1) { |
128 | 0 | return 1; |
129 | 0 | } |
130 | | |
131 | 0 | proc.pid = pid; |
132 | 0 | waitret = apr_proc_wait(&proc, &status, &why, APR_NOWAIT); |
133 | 0 | if (waitret != APR_CHILD_NOTDONE) { |
134 | 0 | if (waitret == APR_CHILD_DONE) |
135 | 0 | ap_process_child_status(&proc, why, status); |
136 | 0 | return 1; |
137 | 0 | } |
138 | | |
139 | 0 | switch(action) { |
140 | 0 | case DO_NOTHING: |
141 | 0 | break; |
142 | | |
143 | 0 | case SEND_SIGTERM: |
144 | | /* ok, now it's being annoying */ |
145 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, |
146 | 0 | 0, ap_server_conf, APLOGNO(00045) |
147 | 0 | "child process %" APR_PID_T_FMT |
148 | 0 | " still did not exit, " |
149 | 0 | "sending a SIGTERM", |
150 | 0 | pid); |
151 | | /* FALLTHROUGH */ |
152 | 0 | case SEND_SIGTERM_NOLOG: |
153 | 0 | kill(pid, SIGTERM); |
154 | 0 | break; |
155 | | |
156 | 0 | case SEND_SIGKILL: |
157 | 0 | ap_log_error(APLOG_MARK, APLOG_ERR, |
158 | 0 | 0, ap_server_conf, APLOGNO(00046) |
159 | 0 | "child process %" APR_PID_T_FMT |
160 | 0 | " still did not exit, " |
161 | 0 | "sending a SIGKILL", |
162 | 0 | pid); |
163 | 0 | kill(pid, SIGKILL); |
164 | 0 | break; |
165 | | |
166 | 0 | case GIVEUP: |
167 | | /* gave it our best shot, but alas... If this really |
168 | | * is a child we are trying to kill and it really hasn't |
169 | | * exited, we will likely fail to bind to the port |
170 | | * after the restart. |
171 | | */ |
172 | 0 | ap_log_error(APLOG_MARK, APLOG_ERR, |
173 | 0 | 0, ap_server_conf, APLOGNO(00047) |
174 | 0 | "could not make child process %" APR_PID_T_FMT |
175 | 0 | " exit, " |
176 | 0 | "attempting to continue anyway", |
177 | 0 | pid); |
178 | 0 | break; |
179 | 0 | } |
180 | | |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | | AP_DECLARE(void) ap_reclaim_child_processes(int terminate, |
185 | | ap_reclaim_callback_fn_t *mpm_callback) |
186 | 0 | { |
187 | 0 | apr_time_t waittime = 1024 * 16; |
188 | 0 | int i; |
189 | 0 | extra_process_t *cur_extra; |
190 | 0 | int not_dead_yet; |
191 | 0 | int max_daemons; |
192 | 0 | apr_time_t starttime = apr_time_now(); |
193 | | /* this table of actions and elapsed times tells what action is taken |
194 | | * at which elapsed time from starting the reclaim |
195 | | */ |
196 | 0 | struct { |
197 | 0 | action_t action; |
198 | 0 | apr_time_t action_time; |
199 | 0 | } action_table[] = { |
200 | 0 | {DO_NOTHING, 0}, /* dummy entry for iterations where we reap |
201 | | * children but take no action against |
202 | | * stragglers |
203 | | */ |
204 | 0 | {SEND_SIGTERM_NOLOG, 0}, /* skipped if terminate == 0 */ |
205 | 0 | {SEND_SIGTERM, apr_time_from_sec(3)}, |
206 | 0 | {SEND_SIGTERM, apr_time_from_sec(5)}, |
207 | 0 | {SEND_SIGTERM, apr_time_from_sec(7)}, |
208 | 0 | {SEND_SIGKILL, apr_time_from_sec(9)}, |
209 | 0 | {GIVEUP, apr_time_from_sec(10)} |
210 | 0 | }; |
211 | 0 | int cur_action; /* index of action we decided to take this |
212 | | * iteration |
213 | | */ |
214 | 0 | int next_action = terminate ? 1 : 2; /* index of first real action */ |
215 | |
|
216 | 0 | ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons); |
217 | |
|
218 | 0 | do { |
219 | 0 | if (action_table[next_action].action_time > 0) { |
220 | 0 | apr_sleep(waittime); |
221 | | /* don't let waittime get longer than 1 second; otherwise, we don't |
222 | | * react quickly to the last child exiting, and taking action can |
223 | | * be delayed |
224 | | */ |
225 | 0 | waittime = waittime * 4; |
226 | 0 | if (waittime > apr_time_from_sec(1)) { |
227 | 0 | waittime = apr_time_from_sec(1); |
228 | 0 | } |
229 | 0 | } |
230 | | |
231 | | /* see what action to take, if any */ |
232 | 0 | if (action_table[next_action].action_time <= apr_time_now() - starttime) { |
233 | 0 | cur_action = next_action; |
234 | 0 | ++next_action; |
235 | 0 | } |
236 | 0 | else { |
237 | 0 | cur_action = 0; /* nothing to do */ |
238 | 0 | } |
239 | | |
240 | | /* now see who is done */ |
241 | 0 | not_dead_yet = 0; |
242 | 0 | for (i = 0; i < max_daemons; ++i) { |
243 | 0 | process_score *ps = ap_get_scoreboard_process(i); |
244 | 0 | pid_t pid = ps->pid; |
245 | |
|
246 | 0 | if (pid == 0) { |
247 | 0 | continue; /* not every scoreboard entry is in use */ |
248 | 0 | } |
249 | | |
250 | 0 | if (reclaim_one_pid(pid, action_table[cur_action].action)) { |
251 | 0 | mpm_callback(i, 0, 0); |
252 | 0 | } |
253 | 0 | else { |
254 | 0 | ++not_dead_yet; |
255 | 0 | } |
256 | 0 | } |
257 | |
|
258 | 0 | cur_extra = extras; |
259 | 0 | while (cur_extra) { |
260 | 0 | ap_generation_t old_gen; |
261 | 0 | extra_process_t *next = cur_extra->next; |
262 | 0 | pid_t pid = cur_extra->pid; |
263 | |
|
264 | 0 | if (reclaim_one_pid(pid, action_table[cur_action].action)) { |
265 | 0 | if (ap_unregister_extra_mpm_process(pid, &old_gen) == 1) { |
266 | | /* cur_extra dangling pointer from here. */ |
267 | 0 | mpm_callback(-1, pid, old_gen); |
268 | 0 | } |
269 | 0 | else { |
270 | 0 | AP_DEBUG_ASSERT(1 == 0); |
271 | 0 | } |
272 | 0 | } |
273 | 0 | else { |
274 | 0 | ++not_dead_yet; |
275 | 0 | } |
276 | 0 | cur_extra = next; |
277 | 0 | } |
278 | 0 | #if APR_HAS_OTHER_CHILD |
279 | 0 | apr_proc_other_child_refresh_all(APR_OC_REASON_RESTART); |
280 | 0 | #endif |
281 | |
|
282 | 0 | } while (not_dead_yet > 0 && |
283 | 0 | action_table[cur_action].action != GIVEUP); |
284 | 0 | } |
285 | | |
286 | | AP_DECLARE(void) ap_relieve_child_processes(ap_reclaim_callback_fn_t *mpm_callback) |
287 | 0 | { |
288 | 0 | int i; |
289 | 0 | extra_process_t *cur_extra; |
290 | 0 | int max_daemons; |
291 | |
|
292 | 0 | ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons); |
293 | | |
294 | | /* now see who is done */ |
295 | 0 | for (i = 0; i < max_daemons; ++i) { |
296 | 0 | process_score *ps = ap_get_scoreboard_process(i); |
297 | 0 | pid_t pid = ps->pid; |
298 | |
|
299 | 0 | if (pid == 0) { |
300 | 0 | continue; /* not every scoreboard entry is in use */ |
301 | 0 | } |
302 | | |
303 | 0 | if (reclaim_one_pid(pid, DO_NOTHING)) { |
304 | 0 | mpm_callback(i, 0, 0); |
305 | 0 | } |
306 | 0 | } |
307 | |
|
308 | 0 | cur_extra = extras; |
309 | 0 | while (cur_extra) { |
310 | 0 | ap_generation_t old_gen; |
311 | 0 | extra_process_t *next = cur_extra->next; |
312 | 0 | pid_t pid = cur_extra->pid; |
313 | |
|
314 | 0 | if (reclaim_one_pid(pid, DO_NOTHING)) { |
315 | 0 | if (ap_unregister_extra_mpm_process(pid, &old_gen) == 1) { |
316 | | /* cur_extra dangling pointer from here. */ |
317 | 0 | mpm_callback(-1, pid, old_gen); |
318 | 0 | } |
319 | 0 | else { |
320 | 0 | AP_DEBUG_ASSERT(1 == 0); |
321 | 0 | } |
322 | 0 | } |
323 | 0 | cur_extra = next; |
324 | 0 | } |
325 | 0 | } |
326 | | |
327 | | /* Before sending the signal to the pid this function verifies that |
328 | | * the pid is a member of the current process group; either using |
329 | | * apr_proc_wait(), where waitpid() guarantees to fail for non-child |
330 | | * processes; or by using getpgid() directly, if available. */ |
331 | | AP_DECLARE(apr_status_t) ap_mpm_safe_kill(pid_t pid, int sig) |
332 | 0 | { |
333 | | #ifndef HAVE_GETPGID |
334 | | apr_proc_t proc; |
335 | | apr_status_t rv; |
336 | | apr_exit_why_e why; |
337 | | int status; |
338 | | |
339 | | /* Ensure pid sanity */ |
340 | | if (pid < 1) { |
341 | | return APR_EINVAL; |
342 | | } |
343 | | |
344 | | proc.pid = pid; |
345 | | rv = apr_proc_wait(&proc, &status, &why, APR_NOWAIT); |
346 | | if (rv == APR_CHILD_DONE) { |
347 | | /* The child already died - log the termination status if |
348 | | * necessary: */ |
349 | | ap_process_child_status(&proc, why, status); |
350 | | return APR_EINVAL; |
351 | | } |
352 | | else if (rv != APR_CHILD_NOTDONE) { |
353 | | /* The child is already dead and reaped, or was a bogus pid - |
354 | | * log this either way. */ |
355 | | ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ap_server_conf, APLOGNO(00048) |
356 | | "cannot send signal %d to pid %ld (non-child or " |
357 | | "already dead)", sig, (long)pid); |
358 | | return APR_EINVAL; |
359 | | } |
360 | | #else |
361 | 0 | pid_t pg; |
362 | | |
363 | | /* Ensure pid sanity. */ |
364 | 0 | if (pid < 1) { |
365 | 0 | return APR_EINVAL; |
366 | 0 | } |
367 | | |
368 | 0 | pg = getpgid(pid); |
369 | 0 | if (pg == -1) { |
370 | | /* Process already dead... */ |
371 | 0 | return errno; |
372 | 0 | } |
373 | | |
374 | 0 | if (pg != getpgrp()) { |
375 | 0 | ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf, APLOGNO(00049) |
376 | 0 | "refusing to send signal %d to pid %ld outside " |
377 | 0 | "process group", sig, (long)pid); |
378 | 0 | return APR_EINVAL; |
379 | 0 | } |
380 | 0 | #endif |
381 | | |
382 | 0 | return kill(pid, sig) ? errno : APR_SUCCESS; |
383 | 0 | } |
384 | | |
385 | | |
386 | | AP_DECLARE(int) ap_process_child_status(apr_proc_t *pid, apr_exit_why_e why, |
387 | | int status) |
388 | 0 | { |
389 | 0 | int signum = status; |
390 | 0 | const char *sigdesc; |
391 | | |
392 | | /* Child died... if it died due to a fatal error, |
393 | | * we should simply bail out. The caller needs to |
394 | | * check for bad rc from us and exit, running any |
395 | | * appropriate cleanups. |
396 | | * |
397 | | * If the child died due to a resource shortage, |
398 | | * the parent should limit the rate of forking |
399 | | */ |
400 | 0 | if (APR_PROC_CHECK_EXIT(why)) { |
401 | 0 | if (status == APEXIT_CHILDSICK) { |
402 | 0 | return status; |
403 | 0 | } |
404 | | |
405 | 0 | if (status == APEXIT_CHILDFATAL) { |
406 | 0 | ap_log_error(APLOG_MARK, APLOG_ALERT, |
407 | 0 | 0, ap_server_conf, APLOGNO(00050) |
408 | 0 | "Child %" APR_PID_T_FMT |
409 | 0 | " returned a Fatal error... Apache is exiting!", |
410 | 0 | pid->pid); |
411 | 0 | return APEXIT_CHILDFATAL; |
412 | 0 | } |
413 | | |
414 | 0 | return 0; |
415 | 0 | } |
416 | | |
417 | 0 | if (APR_PROC_CHECK_SIGNALED(why)) { |
418 | 0 | sigdesc = apr_signal_description_get(signum); |
419 | |
|
420 | 0 | switch (signum) { |
421 | 0 | case SIGTERM: |
422 | 0 | case SIGHUP: |
423 | 0 | case AP_SIG_GRACEFUL: |
424 | 0 | case SIGKILL: |
425 | 0 | break; |
426 | | |
427 | 0 | default: |
428 | 0 | if (APR_PROC_CHECK_CORE_DUMP(why)) { |
429 | 0 | ap_log_error(APLOG_MARK, APLOG_NOTICE, |
430 | 0 | 0, ap_server_conf, APLOGNO(00051) |
431 | 0 | "child pid %ld exit signal %s (%d), " |
432 | 0 | "possible coredump in %s", |
433 | 0 | (long)pid->pid, sigdesc, signum, |
434 | 0 | ap_coredump_dir); |
435 | 0 | } |
436 | 0 | else { |
437 | 0 | ap_log_error(APLOG_MARK, APLOG_NOTICE, |
438 | 0 | 0, ap_server_conf, APLOGNO(00052) |
439 | 0 | "child pid %ld exit signal %s (%d)", |
440 | 0 | (long)pid->pid, sigdesc, signum); |
441 | 0 | } |
442 | 0 | } |
443 | 0 | } |
444 | 0 | return 0; |
445 | 0 | } |
446 | | |
447 | | AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod) |
448 | 0 | { |
449 | 0 | apr_status_t rv; |
450 | |
|
451 | 0 | *pod = apr_palloc(p, sizeof(**pod)); |
452 | 0 | rv = apr_file_pipe_create_ex(&((*pod)->pod_in), &((*pod)->pod_out), |
453 | 0 | APR_WRITE_BLOCK, p); |
454 | 0 | if (rv != APR_SUCCESS) { |
455 | 0 | return rv; |
456 | 0 | } |
457 | | |
458 | 0 | apr_file_pipe_timeout_set((*pod)->pod_in, 0); |
459 | 0 | (*pod)->p = p; |
460 | | |
461 | | /* close these before exec. */ |
462 | 0 | apr_file_inherit_unset((*pod)->pod_in); |
463 | 0 | apr_file_inherit_unset((*pod)->pod_out); |
464 | |
|
465 | 0 | return APR_SUCCESS; |
466 | 0 | } |
467 | | |
468 | | AP_DECLARE(apr_status_t) ap_mpm_pod_check(ap_pod_t *pod) |
469 | 0 | { |
470 | 0 | char c; |
471 | 0 | apr_size_t len = 1; |
472 | 0 | apr_status_t rv; |
473 | |
|
474 | 0 | rv = apr_file_read(pod->pod_in, &c, &len); |
475 | |
|
476 | 0 | if ((rv == APR_SUCCESS) && (len == 1)) { |
477 | 0 | return APR_SUCCESS; |
478 | 0 | } |
479 | | |
480 | 0 | if (rv != APR_SUCCESS) { |
481 | 0 | return rv; |
482 | 0 | } |
483 | | |
484 | 0 | return AP_NORESTART; |
485 | 0 | } |
486 | | |
487 | | AP_DECLARE(apr_status_t) ap_mpm_pod_close(ap_pod_t *pod) |
488 | 0 | { |
489 | 0 | apr_status_t rv; |
490 | |
|
491 | 0 | rv = apr_file_close(pod->pod_out); |
492 | 0 | if (rv != APR_SUCCESS) { |
493 | 0 | return rv; |
494 | 0 | } |
495 | | |
496 | 0 | rv = apr_file_close(pod->pod_in); |
497 | 0 | if (rv != APR_SUCCESS) { |
498 | 0 | return rv; |
499 | 0 | } |
500 | | |
501 | 0 | return APR_SUCCESS; |
502 | 0 | } |
503 | | |
504 | | static apr_status_t pod_signal_internal(ap_pod_t *pod) |
505 | 0 | { |
506 | 0 | apr_status_t rv; |
507 | 0 | char char_of_death = '!'; |
508 | 0 | apr_size_t one = 1; |
509 | |
|
510 | 0 | rv = apr_file_write(pod->pod_out, &char_of_death, &one); |
511 | 0 | if (rv != APR_SUCCESS) { |
512 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00053) |
513 | 0 | "write pipe_of_death"); |
514 | 0 | } |
515 | |
|
516 | 0 | return rv; |
517 | 0 | } |
518 | | |
519 | | AP_DECLARE(apr_status_t) ap_mpm_podx_open(apr_pool_t *p, ap_pod_t **pod) |
520 | 0 | { |
521 | 0 | apr_status_t rv; |
522 | |
|
523 | 0 | *pod = apr_palloc(p, sizeof(**pod)); |
524 | 0 | rv = apr_file_pipe_create(&((*pod)->pod_in), &((*pod)->pod_out), p); |
525 | 0 | if (rv != APR_SUCCESS) { |
526 | 0 | return rv; |
527 | 0 | } |
528 | | /* |
529 | | apr_file_pipe_timeout_set((*pod)->pod_in, 0); |
530 | | */ |
531 | 0 | (*pod)->p = p; |
532 | | |
533 | | /* close these before exec. */ |
534 | 0 | apr_file_inherit_unset((*pod)->pod_in); |
535 | 0 | apr_file_inherit_unset((*pod)->pod_out); |
536 | |
|
537 | 0 | return APR_SUCCESS; |
538 | 0 | } |
539 | | |
540 | | AP_DECLARE(int) ap_mpm_podx_check(ap_pod_t *pod) |
541 | 0 | { |
542 | 0 | char c; |
543 | 0 | apr_os_file_t fd; |
544 | 0 | int rc; |
545 | | |
546 | | /* we need to surface EINTR so we'll have to grab the |
547 | | * native file descriptor and do the OS read() ourselves |
548 | | */ |
549 | 0 | apr_os_file_get(&fd, pod->pod_in); |
550 | 0 | rc = read(fd, &c, 1); |
551 | 0 | if (rc == 1) { |
552 | 0 | switch (c) { |
553 | 0 | case AP_MPM_PODX_RESTART_CHAR: |
554 | 0 | return AP_MPM_PODX_RESTART; |
555 | 0 | case AP_MPM_PODX_GRACEFUL_CHAR: |
556 | 0 | return AP_MPM_PODX_GRACEFUL; |
557 | 0 | } |
558 | 0 | } |
559 | 0 | return AP_MPM_PODX_NORESTART; |
560 | 0 | } |
561 | | |
562 | | AP_DECLARE(apr_status_t) ap_mpm_podx_close(ap_pod_t *pod) |
563 | 0 | { |
564 | 0 | apr_status_t rv; |
565 | |
|
566 | 0 | rv = apr_file_close(pod->pod_out); |
567 | 0 | if (rv != APR_SUCCESS) { |
568 | 0 | return rv; |
569 | 0 | } |
570 | | |
571 | 0 | rv = apr_file_close(pod->pod_in); |
572 | 0 | if (rv != APR_SUCCESS) { |
573 | 0 | return rv; |
574 | 0 | } |
575 | 0 | return rv; |
576 | 0 | } |
577 | | |
578 | | static apr_status_t podx_signal_internal(ap_pod_t *pod, |
579 | | ap_podx_restart_t graceful) |
580 | 0 | { |
581 | 0 | apr_status_t rv; |
582 | 0 | apr_size_t one = 1; |
583 | 0 | char char_of_death = ' '; |
584 | 0 | switch (graceful) { |
585 | 0 | case AP_MPM_PODX_RESTART: |
586 | 0 | char_of_death = AP_MPM_PODX_RESTART_CHAR; |
587 | 0 | break; |
588 | 0 | case AP_MPM_PODX_GRACEFUL: |
589 | 0 | char_of_death = AP_MPM_PODX_GRACEFUL_CHAR; |
590 | 0 | break; |
591 | 0 | case AP_MPM_PODX_NORESTART: |
592 | 0 | break; |
593 | 0 | } |
594 | | |
595 | 0 | rv = apr_file_write(pod->pod_out, &char_of_death, &one); |
596 | 0 | if (rv != APR_SUCCESS) { |
597 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(02404) |
598 | 0 | "write pipe_of_death"); |
599 | 0 | } |
600 | 0 | return rv; |
601 | 0 | } |
602 | | |
603 | | AP_DECLARE(apr_status_t) ap_mpm_podx_signal(ap_pod_t * pod, |
604 | | ap_podx_restart_t graceful) |
605 | 0 | { |
606 | 0 | return podx_signal_internal(pod, graceful); |
607 | 0 | } |
608 | | |
609 | | AP_DECLARE(void) ap_mpm_podx_killpg(ap_pod_t * pod, int num, |
610 | | ap_podx_restart_t graceful) |
611 | 0 | { |
612 | 0 | int i; |
613 | 0 | apr_status_t rv = APR_SUCCESS; |
614 | |
|
615 | 0 | for (i = 0; i < num && rv == APR_SUCCESS; i++) { |
616 | 0 | rv = podx_signal_internal(pod, graceful); |
617 | 0 | } |
618 | 0 | } |
619 | | |
620 | | /* This function connects to the server and sends enough data to |
621 | | * ensure the child wakes up and processes a new connection. This |
622 | | * permits the MPM to skip the poll when there is only one listening |
623 | | * socket, because it provides a alternate way to unblock an accept() |
624 | | * when the pod is used. */ |
625 | | static apr_status_t dummy_connection(ap_pod_t *pod) |
626 | 0 | { |
627 | 0 | const char *data; |
628 | 0 | apr_status_t rv; |
629 | 0 | apr_socket_t *sock; |
630 | 0 | apr_pool_t *p; |
631 | 0 | apr_size_t len; |
632 | 0 | ap_listen_rec *lp; |
633 | | |
634 | | /* create a temporary pool for the socket. pconf stays around too long */ |
635 | 0 | rv = apr_pool_create(&p, pod->p); |
636 | 0 | if (rv != APR_SUCCESS) { |
637 | 0 | return rv; |
638 | 0 | } |
639 | 0 | apr_pool_tag(p, "dummy_connection"); |
640 | | |
641 | | /* If possible, find a listener which is configured for |
642 | | * plain-HTTP, not SSL; using an SSL port would either be |
643 | | * expensive to do correctly (performing a complete SSL handshake) |
644 | | * or cause log spam by doing incorrectly (simply sending EOF). */ |
645 | 0 | lp = ap_listeners; |
646 | 0 | while (lp && lp->protocol && ap_cstr_casecmp(lp->protocol, "http") != 0) { |
647 | 0 | lp = lp->next; |
648 | 0 | } |
649 | 0 | if (!lp) { |
650 | 0 | lp = ap_listeners; |
651 | 0 | } |
652 | |
|
653 | 0 | rv = apr_socket_create(&sock, lp->bind_addr->family, SOCK_STREAM, 0, p); |
654 | 0 | if (rv != APR_SUCCESS) { |
655 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00054) |
656 | 0 | "get socket to connect to listener"); |
657 | 0 | apr_pool_destroy(p); |
658 | 0 | return rv; |
659 | 0 | } |
660 | | |
661 | | /* on some platforms (e.g., FreeBSD), the kernel won't accept many |
662 | | * queued connections before it starts blocking local connects... |
663 | | * we need to keep from blocking too long and instead return an error, |
664 | | * because the MPM won't want to hold up a graceful restart for a |
665 | | * long time |
666 | | */ |
667 | 0 | rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); |
668 | 0 | if (rv != APR_SUCCESS) { |
669 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, APLOGNO(00055) |
670 | 0 | "set timeout on socket to connect to listener"); |
671 | 0 | apr_socket_close(sock); |
672 | 0 | apr_pool_destroy(p); |
673 | 0 | return rv; |
674 | 0 | } |
675 | | |
676 | 0 | rv = apr_socket_connect(sock, lp->bind_addr); |
677 | 0 | if (rv != APR_SUCCESS) { |
678 | 0 | int log_level = APLOG_WARNING; |
679 | |
|
680 | 0 | if (APR_STATUS_IS_TIMEUP(rv)) { |
681 | | /* probably some server processes bailed out already and there |
682 | | * is nobody around to call accept and clear out the kernel |
683 | | * connection queue; usually this is not worth logging |
684 | | */ |
685 | 0 | log_level = APLOG_DEBUG; |
686 | 0 | } |
687 | |
|
688 | 0 | ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, APLOGNO(00056) |
689 | 0 | "connect to listener on %pI", lp->bind_addr); |
690 | 0 | apr_pool_destroy(p); |
691 | 0 | return rv; |
692 | 0 | } |
693 | | |
694 | 0 | if (lp->protocol && ap_cstr_casecmp(lp->protocol, "https") == 0) { |
695 | | /* Send a TLS 1.0 close_notify alert. This is perhaps the |
696 | | * "least wrong" way to open and cleanly terminate an SSL |
697 | | * connection. It should "work" without noisy error logs if |
698 | | * the server actually expects SSLv3/TLSv1. With |
699 | | * SSLv23_server_method() OpenSSL's SSL_accept() fails |
700 | | * ungracefully on receipt of this message, since it requires |
701 | | * an 11-byte ClientHello message and this is too short. */ |
702 | 0 | static const unsigned char tls10_close_notify[7] = { |
703 | 0 | '\x15', /* TLSPlainText.type = Alert (21) */ |
704 | 0 | '\x03', '\x01', /* TLSPlainText.version = {3, 1} */ |
705 | 0 | '\x00', '\x02', /* TLSPlainText.length = 2 */ |
706 | 0 | '\x01', /* Alert.level = warning (1) */ |
707 | 0 | '\x00' /* Alert.description = close_notify (0) */ |
708 | 0 | }; |
709 | 0 | data = (const char *)tls10_close_notify; |
710 | 0 | len = sizeof(tls10_close_notify); |
711 | 0 | } |
712 | 0 | else /* ... XXX other request types here? */ { |
713 | | /* Create an HTTP request string. We include a User-Agent so |
714 | | * that administrators can track down the cause of the |
715 | | * odd-looking requests in their logs. A complete request is |
716 | | * used since kernel-level filtering may require that much |
717 | | * data before returning from accept(). */ |
718 | 0 | data = apr_pstrcat(p, "OPTIONS * HTTP/1.0\r\nUser-Agent: ", |
719 | 0 | ap_get_server_description(), |
720 | 0 | " (internal dummy connection)\r\n\r\n", NULL); |
721 | 0 | len = strlen(data); |
722 | 0 | } |
723 | |
|
724 | 0 | apr_socket_send(sock, data, &len); |
725 | 0 | apr_socket_close(sock); |
726 | 0 | apr_pool_destroy(p); |
727 | |
|
728 | 0 | return rv; |
729 | 0 | } |
730 | | |
731 | | AP_DECLARE(apr_status_t) ap_mpm_pod_signal(ap_pod_t *pod) |
732 | 0 | { |
733 | 0 | apr_status_t rv; |
734 | |
|
735 | 0 | rv = pod_signal_internal(pod); |
736 | 0 | if (rv != APR_SUCCESS) { |
737 | 0 | return rv; |
738 | 0 | } |
739 | | |
740 | 0 | return dummy_connection(pod); |
741 | 0 | } |
742 | | |
743 | | void ap_mpm_pod_killpg(ap_pod_t *pod, int num) |
744 | 0 | { |
745 | 0 | int i; |
746 | 0 | apr_status_t rv = APR_SUCCESS; |
747 | | |
748 | | /* we don't write anything to the pod here... we assume |
749 | | * that the would-be reader of the pod has another way to |
750 | | * see that it is time to die once we wake it up |
751 | | * |
752 | | * writing lots of things to the pod at once is very |
753 | | * problematic... we can fill the kernel pipe buffer and |
754 | | * be blocked until somebody consumes some bytes or |
755 | | * we hit a timeout... if we hit a timeout we can't just |
756 | | * keep trying because maybe we'll never successfully |
757 | | * write again... but then maybe we'll leave would-be |
758 | | * readers stranded (a number of them could be tied up for |
759 | | * a while serving time-consuming requests) |
760 | | */ |
761 | | /* Recall: we only worry about IDLE child processes here */ |
762 | 0 | for (i = 0; i < num && rv == APR_SUCCESS; i++) { |
763 | 0 | if (ap_scoreboard_image->servers[i][0].status != SERVER_READY || |
764 | 0 | ap_scoreboard_image->servers[i][0].pid == 0) { |
765 | 0 | continue; |
766 | 0 | } |
767 | 0 | rv = dummy_connection(pod); |
768 | 0 | } |
769 | 0 | } |
770 | | |
771 | | static const char *dash_k_arg = NULL; |
772 | | static const char *dash_k_arg_noarg = "noarg"; |
773 | | |
774 | | static int send_signal(pid_t pid, int sig) |
775 | 0 | { |
776 | 0 | if (kill(pid, sig) < 0) { |
777 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP, errno, NULL, APLOGNO(00057) |
778 | 0 | "sending signal to server"); |
779 | 0 | return 1; |
780 | 0 | } |
781 | 0 | return 0; |
782 | 0 | } |
783 | | |
784 | | int ap_signal_server(int *exit_status, apr_pool_t *pconf) |
785 | 0 | { |
786 | 0 | apr_status_t rv; |
787 | 0 | pid_t otherpid; |
788 | 0 | int running = 0; |
789 | 0 | const char *status; |
790 | |
|
791 | 0 | *exit_status = 0; |
792 | |
|
793 | 0 | rv = ap_read_pid(pconf, ap_pid_fname, &otherpid); |
794 | 0 | if (rv != APR_SUCCESS) { |
795 | 0 | if (!APR_STATUS_IS_ENOENT(rv)) { |
796 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, NULL, APLOGNO(00058) |
797 | 0 | "Error retrieving pid file %s", ap_pid_fname); |
798 | 0 | ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, APLOGNO(00059) |
799 | 0 | "Remove it before continuing if it is corrupted."); |
800 | 0 | *exit_status = 1; |
801 | 0 | return 1; |
802 | 0 | } |
803 | 0 | status = "httpd (no pid file) not running"; |
804 | 0 | } |
805 | 0 | else { |
806 | | /* With containerization, httpd may get the same PID at each startup, |
807 | | * handle it as if it were not running (it obviously can't). |
808 | | */ |
809 | 0 | if (otherpid != getpid() && kill(otherpid, 0) == 0) { |
810 | 0 | running = 1; |
811 | 0 | status = apr_psprintf(pconf, |
812 | 0 | "httpd (pid %" APR_PID_T_FMT ") already " |
813 | 0 | "running", otherpid); |
814 | 0 | } |
815 | 0 | else { |
816 | 0 | status = apr_psprintf(pconf, |
817 | 0 | "httpd (pid %" APR_PID_T_FMT "?) not running", |
818 | 0 | otherpid); |
819 | 0 | } |
820 | 0 | } |
821 | | |
822 | 0 | if (!strcmp(dash_k_arg, "start") || dash_k_arg == dash_k_arg_noarg) { |
823 | 0 | if (running) { |
824 | 0 | printf("%s\n", status); |
825 | 0 | return 1; |
826 | 0 | } |
827 | 0 | } |
828 | | |
829 | 0 | if (!strcmp(dash_k_arg, "stop")) { |
830 | 0 | if (!running) { |
831 | 0 | printf("%s\n", status); |
832 | 0 | } |
833 | 0 | else { |
834 | 0 | send_signal(otherpid, SIGTERM); |
835 | 0 | } |
836 | 0 | return 1; |
837 | 0 | } |
838 | | |
839 | 0 | if (!strcmp(dash_k_arg, "restart")) { |
840 | 0 | if (!running) { |
841 | 0 | printf("httpd not running, trying to start\n"); |
842 | 0 | } |
843 | 0 | else { |
844 | 0 | *exit_status = send_signal(otherpid, SIGHUP); |
845 | 0 | return 1; |
846 | 0 | } |
847 | 0 | } |
848 | | |
849 | 0 | if (!strcmp(dash_k_arg, "graceful")) { |
850 | 0 | if (!running) { |
851 | 0 | printf("httpd not running, trying to start\n"); |
852 | 0 | } |
853 | 0 | else { |
854 | 0 | *exit_status = send_signal(otherpid, AP_SIG_GRACEFUL); |
855 | 0 | return 1; |
856 | 0 | } |
857 | 0 | } |
858 | | |
859 | 0 | if (!strcmp(dash_k_arg, "graceful-stop")) { |
860 | 0 | if (!running) { |
861 | 0 | printf("%s\n", status); |
862 | 0 | } |
863 | 0 | else { |
864 | 0 | *exit_status = send_signal(otherpid, AP_SIG_GRACEFUL_STOP); |
865 | 0 | } |
866 | 0 | return 1; |
867 | 0 | } |
868 | | |
869 | 0 | return 0; |
870 | 0 | } |
871 | | |
872 | | void ap_mpm_rewrite_args(process_rec *process) |
873 | 0 | { |
874 | 0 | apr_array_header_t *mpm_new_argv; |
875 | 0 | apr_status_t rv; |
876 | 0 | apr_getopt_t *opt; |
877 | 0 | char optbuf[3]; |
878 | 0 | const char *optarg; |
879 | |
|
880 | 0 | mpm_new_argv = apr_array_make(process->pool, process->argc, |
881 | 0 | sizeof(const char **)); |
882 | 0 | *(const char **)apr_array_push(mpm_new_argv) = process->argv[0]; |
883 | 0 | apr_getopt_init(&opt, process->pool, process->argc, process->argv); |
884 | 0 | opt->errfn = NULL; |
885 | 0 | optbuf[0] = '-'; |
886 | | /* option char returned by apr_getopt() will be stored in optbuf[1] */ |
887 | 0 | optbuf[2] = '\0'; |
888 | 0 | while ((rv = apr_getopt(opt, "k:" AP_SERVER_BASEARGS, |
889 | 0 | optbuf + 1, &optarg)) == APR_SUCCESS) { |
890 | 0 | switch(optbuf[1]) { |
891 | 0 | case 'k': |
892 | 0 | if (!dash_k_arg) { |
893 | 0 | if (!strcmp(optarg, "start") || !strcmp(optarg, "stop") || |
894 | 0 | !strcmp(optarg, "restart") || !strcmp(optarg, "graceful") || |
895 | 0 | !strcmp(optarg, "graceful-stop")) { |
896 | 0 | dash_k_arg = optarg; |
897 | 0 | break; |
898 | 0 | } |
899 | 0 | } |
900 | 0 | default: |
901 | 0 | *(const char **)apr_array_push(mpm_new_argv) = |
902 | 0 | apr_pstrdup(process->pool, optbuf); |
903 | 0 | if (optarg) { |
904 | 0 | *(const char **)apr_array_push(mpm_new_argv) = optarg; |
905 | 0 | } |
906 | 0 | } |
907 | 0 | } |
908 | | |
909 | | /* back up to capture the bad argument */ |
910 | 0 | if (rv == APR_BADCH || rv == APR_BADARG) { |
911 | 0 | opt->ind--; |
912 | 0 | } |
913 | |
|
914 | 0 | while (opt->ind < opt->argc) { |
915 | 0 | *(const char **)apr_array_push(mpm_new_argv) = |
916 | 0 | apr_pstrdup(process->pool, opt->argv[opt->ind++]); |
917 | 0 | } |
918 | |
|
919 | 0 | process->argc = mpm_new_argv->nelts; |
920 | 0 | process->argv = (const char * const *)mpm_new_argv->elts; |
921 | |
|
922 | 0 | if (NULL == dash_k_arg) { |
923 | 0 | dash_k_arg = dash_k_arg_noarg; |
924 | 0 | } |
925 | |
|
926 | 0 | APR_REGISTER_OPTIONAL_FN(ap_signal_server); |
927 | 0 | } |
928 | | |
929 | | static pid_t parent_pid, my_pid; |
930 | | static apr_pool_t *pconf; |
931 | | |
932 | | #if AP_ENABLE_EXCEPTION_HOOK |
933 | | |
934 | | static int exception_hook_enabled; |
935 | | |
936 | | const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy, |
937 | | const char *arg) |
938 | | { |
939 | | const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); |
940 | | if (err != NULL) { |
941 | | return err; |
942 | | } |
943 | | |
944 | | if (cmd->server->is_virtual) { |
945 | | return "EnableExceptionHook directive not allowed in <VirtualHost>"; |
946 | | } |
947 | | |
948 | | if (strcasecmp(arg, "on") == 0) { |
949 | | exception_hook_enabled = 1; |
950 | | } |
951 | | else if (strcasecmp(arg, "off") == 0) { |
952 | | exception_hook_enabled = 0; |
953 | | } |
954 | | else { |
955 | | return "parameter must be 'on' or 'off'"; |
956 | | } |
957 | | |
958 | | return NULL; |
959 | | } |
960 | | |
961 | | static void run_fatal_exception_hook(int sig) |
962 | | { |
963 | | ap_exception_info_t ei = {0}; |
964 | | |
965 | | if (exception_hook_enabled && |
966 | | geteuid() != 0 && |
967 | | my_pid != parent_pid) { |
968 | | ei.sig = sig; |
969 | | ei.pid = my_pid; |
970 | | ap_run_fatal_exception(&ei); |
971 | | } |
972 | | } |
973 | | #endif /* AP_ENABLE_EXCEPTION_HOOK */ |
974 | | |
975 | | /* handle all varieties of core dumping signals */ |
976 | | static void sig_coredump(int sig) |
977 | 0 | { |
978 | 0 | apr_filepath_set(ap_coredump_dir, pconf); |
979 | 0 | apr_signal(sig, SIG_DFL); |
980 | | #if AP_ENABLE_EXCEPTION_HOOK |
981 | | run_fatal_exception_hook(sig); |
982 | | #endif |
983 | | /* linuxthreads issue calling getpid() here: |
984 | | * This comparison won't match if the crashing thread is |
985 | | * some module's thread that runs in the parent process. |
986 | | * The fallout, which is limited to linuxthreads: |
987 | | * The special log message won't be written when such a |
988 | | * thread in the parent causes the parent to crash. |
989 | | */ |
990 | 0 | if (getpid() == parent_pid) { |
991 | 0 | ap_log_error(APLOG_MARK, APLOG_NOTICE, |
992 | 0 | 0, ap_server_conf, APLOGNO(00060) |
993 | 0 | "seg fault or similar nasty error detected " |
994 | 0 | "in the parent process"); |
995 | | /* XXX we can probably add some rudimentary cleanup code here, |
996 | | * like getting rid of the pid file. If any additional bad stuff |
997 | | * happens, we are protected from recursive errors taking down the |
998 | | * system since this function is no longer the signal handler GLA |
999 | | */ |
1000 | 0 | } |
1001 | 0 | kill(getpid(), sig); |
1002 | | /* At this point we've got sig blocked, because we're still inside |
1003 | | * the signal handler. When we leave the signal handler it will |
1004 | | * be unblocked, and we'll take the signal... and coredump or whatever |
1005 | | * is appropriate for this particular Unix. In addition the parent |
1006 | | * will see the real signal we received -- whereas if we called |
1007 | | * abort() here, the parent would only see SIGABRT. |
1008 | | */ |
1009 | 0 | } |
1010 | | |
1011 | | AP_DECLARE(apr_status_t) ap_fatal_signal_child_setup(server_rec *s) |
1012 | 0 | { |
1013 | 0 | my_pid = getpid(); |
1014 | 0 | return APR_SUCCESS; |
1015 | 0 | } |
1016 | | |
1017 | | /* We can't call sig_coredump (ap_log_error) once pconf is destroyed, so |
1018 | | * avoid double faults by restoring each default signal handler on cleanup. |
1019 | | */ |
1020 | | static apr_status_t fatal_signal_cleanup(void *unused) |
1021 | 0 | { |
1022 | 0 | (void)unused; |
1023 | |
|
1024 | 0 | apr_signal(SIGSEGV, SIG_DFL); |
1025 | 0 | #ifdef SIGBUS |
1026 | 0 | apr_signal(SIGBUS, SIG_DFL); |
1027 | 0 | #endif /* SIGBUS */ |
1028 | | #ifdef SIGABORT |
1029 | | apr_signal(SIGABORT, SIG_DFL); |
1030 | | #endif /* SIGABORT */ |
1031 | 0 | #ifdef SIGABRT |
1032 | 0 | apr_signal(SIGABRT, SIG_DFL); |
1033 | 0 | #endif /* SIGABRT */ |
1034 | 0 | #ifdef SIGILL |
1035 | 0 | apr_signal(SIGILL, SIG_DFL); |
1036 | 0 | #endif /* SIGILL */ |
1037 | 0 | #ifdef SIGFPE |
1038 | 0 | apr_signal(SIGFPE, SIG_DFL); |
1039 | 0 | #endif /* SIGFPE */ |
1040 | |
|
1041 | 0 | return APR_SUCCESS; |
1042 | 0 | } |
1043 | | |
1044 | | AP_DECLARE(apr_status_t) ap_fatal_signal_setup(server_rec *s, |
1045 | | apr_pool_t *in_pconf) |
1046 | 0 | { |
1047 | 0 | #ifndef NO_USE_SIGACTION |
1048 | 0 | struct sigaction sa; |
1049 | |
|
1050 | 0 | memset(&sa, 0, sizeof sa); |
1051 | 0 | sigemptyset(&sa.sa_mask); |
1052 | |
|
1053 | 0 | #if defined(SA_ONESHOT) |
1054 | 0 | sa.sa_flags = SA_ONESHOT; |
1055 | | #elif defined(SA_RESETHAND) |
1056 | | sa.sa_flags = SA_RESETHAND; |
1057 | | #endif |
1058 | |
|
1059 | 0 | sa.sa_handler = sig_coredump; |
1060 | 0 | if (sigaction(SIGSEGV, &sa, NULL) < 0) |
1061 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00061) "sigaction(SIGSEGV)"); |
1062 | 0 | #ifdef SIGBUS |
1063 | 0 | if (sigaction(SIGBUS, &sa, NULL) < 0) |
1064 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00062) "sigaction(SIGBUS)"); |
1065 | 0 | #endif |
1066 | | #ifdef SIGABORT |
1067 | | if (sigaction(SIGABORT, &sa, NULL) < 0) |
1068 | | ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00063) "sigaction(SIGABORT)"); |
1069 | | #endif |
1070 | 0 | #ifdef SIGABRT |
1071 | 0 | if (sigaction(SIGABRT, &sa, NULL) < 0) |
1072 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00064) "sigaction(SIGABRT)"); |
1073 | 0 | #endif |
1074 | 0 | #ifdef SIGILL |
1075 | 0 | if (sigaction(SIGILL, &sa, NULL) < 0) |
1076 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00065) "sigaction(SIGILL)"); |
1077 | 0 | #endif |
1078 | 0 | #ifdef SIGFPE |
1079 | 0 | if (sigaction(SIGFPE, &sa, NULL) < 0) |
1080 | 0 | ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, APLOGNO(00066) "sigaction(SIGFPE)"); |
1081 | 0 | #endif |
1082 | |
|
1083 | | #else /* NO_USE_SIGACTION */ |
1084 | | |
1085 | | apr_signal(SIGSEGV, sig_coredump); |
1086 | | #ifdef SIGBUS |
1087 | | apr_signal(SIGBUS, sig_coredump); |
1088 | | #endif /* SIGBUS */ |
1089 | | #ifdef SIGABORT |
1090 | | apr_signal(SIGABORT, sig_coredump); |
1091 | | #endif /* SIGABORT */ |
1092 | | #ifdef SIGABRT |
1093 | | apr_signal(SIGABRT, sig_coredump); |
1094 | | #endif /* SIGABRT */ |
1095 | | #ifdef SIGILL |
1096 | | apr_signal(SIGILL, sig_coredump); |
1097 | | #endif /* SIGILL */ |
1098 | | #ifdef SIGFPE |
1099 | | apr_signal(SIGFPE, sig_coredump); |
1100 | | #endif /* SIGFPE */ |
1101 | | |
1102 | | #endif /* NO_USE_SIGACTION */ |
1103 | |
|
1104 | 0 | pconf = in_pconf; |
1105 | 0 | parent_pid = my_pid = getpid(); |
1106 | 0 | apr_pool_cleanup_register(pconf, NULL, fatal_signal_cleanup, |
1107 | 0 | fatal_signal_cleanup); |
1108 | |
|
1109 | 0 | return APR_SUCCESS; |
1110 | 0 | } |
1111 | | |
1112 | | #endif /* WIN32 */ |