Changes with Apache 2.0.49
+ *) Add fatal exception hook for use by diagnostic modules. The hook
+ is only available if the --enable-exception-hook configure parm
+ is used and the EnableExceptionHook directive has been set to
+ "on". [Jeff Trawick]
+
*) Allow mod_auth_digest to work with sub-requests with different
methods than the original request. PR 25040.
[Josh Dady <jpd indecisive.com>]
APACHE 2.0 STATUS: -*-text-*-
-Last modified at [$Date: 2004/02/26 20:30:26 $]
+Last modified at [$Date: 2004/02/26 20:32:19 $]
Release:
http://cvs.apache.org/viewcvs.cgi/httpd-2.0/modules/arch/win32/mod_isapi.c?r1=1.98&r2=1.99
+1: trawick, stoddard
- * fatal exception hook and related signal handler cleanups
- This also fixes an issue for me on Solaris where the cgid daemon
- won't restart multiple times because of something different
- about the signal handling the second time it is started. With
- this patch I can "kill -SEGV" the cgid daemon process a number
- of times and the daemon will be restarted each time.
- http://www.apache.org/~trawick/fatal_exception_20.patch
- +1: trawick, stoddard, jerenkrantz, gregames
-
CURRENT RELEASE NOTES:
* Backwards compatibility is expected of future Apache 2.0 releases,
nonssl_listen_stmt_2="Listen [[::]]:@@Port@@"
fi
+AC_ARG_ENABLE(exception-hook,APACHE_HELP_STRING(--enable-exception-hook,Enable fatal exception hook),
+[
+ AC_DEFINE(AP_ENABLE_EXCEPTION_HOOK, 1,
+ [Allow modules to run hook after a fatal exception])
+])dnl
+
AC_ARG_ENABLE(maintainer-mode,APACHE_HELP_STRING(--enable-maintainer-mode,Turn on debugging and compile time warnings),
[
APR_ADDTO(CPPFLAGS, -DAP_DEBUG)
#define AP_MONCONTROL(x)
#endif
+#if AP_ENABLE_EXCEPTION_HOOK
+typedef struct ap_exception_info_t {
+ int sig;
+ pid_t pid;
+} ap_exception_info_t;
+
+AP_DECLARE_HOOK(int,fatal_exception,(ap_exception_info_t *ei))
+#endif /*AP_ENABLE_EXCEPTION_HOOK*/
+
#endif
const char *arg);
#endif
+#ifdef AP_MPM_WANT_FATAL_SIGNAL_HANDLER
+extern apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *pconf);
+extern apr_status_t ap_fatal_signal_child_setup(server_rec *s);
+#endif
+
+#if AP_ENABLE_EXCEPTION_HOOK
+extern const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
+ const char *arg);
+#endif
+
#ifdef __cplusplus
}
#endif
AP_INIT_TAKE1("MaxMemFree", ap_mpm_set_max_mem_free, NULL, RSRC_CONF,
"Maximum number of 1k blocks a particular childs allocator may hold."),
#endif
+#if AP_ENABLE_EXCEPTION_HOOK
+AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF,
+ "Controls whether exception hook may be called after a crash"),
+#endif
{ NULL }
};
exit(code);
}
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
- apr_filepath_set(ap_coredump_dir, pconf);
- apr_signal(sig, SIG_DFL);
- /* linuxthreads issue calling getpid() here:
- * This comparison won't match if the crashing thread is
- * some module's thread that runs in the parent process.
- * The fallout, which is limited to linuxthreads:
- * The special log message won't be written when such a
- * thread in the parent causes the parent to crash.
- */
- if (getpid() == parent_pid) {
- ap_log_error(APLOG_MARK, APLOG_NOTICE,
- 0, ap_server_conf,
- "seg fault or similar nasty error detected "
- "in the parent process");
-
- /* XXX we can probably add some rudimentary cleanup code here,
- * like getting rid of the pid file. If any additional bad stuff
- * happens, we are protected from recursive errors taking down the
- * system since this function is no longer the signal handler GLA
- */
- }
- kill(ap_my_pid, sig);
- /* At this point we've got sig blocked, because we're still inside
- * the signal handler. When we leave the signal handler it will
- * be unblocked, and we'll take the signal... and coredump or whatever
- * is appropriate for this particular Unix. In addition the parent
- * will see the real signal we received -- whereas if we called
- * abort() here, the parent would only see SIGABRT.
- */
-}
-
static void just_die(int sig)
{
clean_child_exit(0);
{
#ifndef NO_USE_SIGACTION
struct sigaction sa;
+#endif
+
+ if (!one_process) {
+ ap_fatal_signal_setup(ap_server_conf, pconf);
+ }
+#ifndef NO_USE_SIGACTION
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (!one_process) {
- sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
- sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
- sa.sa_flags = SA_RESETHAND;
-#endif
- if (sigaction(SIGSEGV, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGSEGV)");
-#ifdef SIGBUS
- if (sigaction(SIGBUS, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
- if (sigaction(SIGABORT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
- if (sigaction(SIGABRT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
- if (sigaction(SIGILL, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGILL)");
-#endif
- sa.sa_flags = 0;
- }
sa.sa_handler = sig_term;
if (sigaction(SIGTERM, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(" AP_SIG_GRACEFUL_STRING ")");
#else
if (!one_process) {
- apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
- apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
- apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
- apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
- apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
#ifdef SIGXCPU
apr_signal(SIGXCPU, SIG_DFL);
#endif /* SIGXCPU */
*/
ap_my_pid = getpid();
+ ap_fatal_signal_child_setup(ap_server_conf);
apr_pool_create(&pchild, pconf);
/*stuff to do before we switch id's, so we have permissions.*/
#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
#define AP_MPM_WANT_SIGNAL_SERVER
#define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
#define AP_MPM_USES_POD 1
#define AP_MPM_WANT_SET_COREDUMPDIR
#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
#define AP_MPM_WANT_SIGNAL_SERVER
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
#define AP_MPM_USES_POD
#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
exit(code);
}
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
- chdir(ap_coredump_dir);
- apr_signal(sig, SIG_DFL);
- kill(getpid(), sig);
- /* At this point we've got sig blocked, because we're still inside
- * the signal handler. When we leave the signal handler it will
- * be unblocked, and we'll take the signal... and coredump or whatever
- * is appropriate for this particular Unix. In addition the parent
- * will see the real signal we received -- whereas if we called
- * abort() here, the parent would only see SIGABRT.
- */
-}
-
static void just_die(int sig)
{
clean_child_exit(0);
{
#ifndef NO_USE_SIGACTION
struct sigaction sa;
+#endif
+ if (!one_process) {
+ ap_fatal_signal_setup(ap_server_conf, pconf);
+ }
+
+#ifndef NO_USE_SIGACTION
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (!one_process) {
- sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
- sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
- sa.sa_flags = SA_RESETHAND;
-#endif
- if (sigaction(SIGSEGV, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGSEGV)");
-#ifdef SIGBUS
- if (sigaction(SIGBUS, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
- if (sigaction(SIGABORT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
- if (sigaction(SIGABRT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
- if (sigaction(SIGILL, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGILL)");
-#endif
- sa.sa_flags = 0;
- }
sa.sa_handler = sig_term;
if (sigaction(SIGTERM, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(" AP_SIG_GRACEFUL_STRING ")");
#else
if (!one_process) {
- apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
- apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
- apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
- apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
- apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
#ifdef SIGXCPU
apr_signal(SIGXCPU, SIG_DFL);
#endif /* SIGXCPU */
ap_listen_rec *lr;
my_pid = getpid();
+ ap_fatal_signal_child_setup(ap_server_conf);
child_num = child_num_arg;
apr_pool_create(&pchild, pconf);
#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
#define AP_MPM_WANT_SIGNAL_SERVER
#define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
exit(code);
}
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
- apr_filepath_set(ap_coredump_dir, pconf);
- apr_signal(sig, SIG_DFL);
- /* linuxthreads issue calling getpid() here:
- * This comparison won't match if the crashing thread is
- * some module's thread that runs in the parent process.
- * The fallout, which is limited to linuxthreads:
- * The special log message won't be written when such a
- * thread in the parent causes the parent to crash.
- */
- if (getpid() == parent_pid) {
- ap_log_error(APLOG_MARK, APLOG_NOTICE,
- 0, ap_server_conf,
- "seg fault or similar nasty error detected "
- "in the parent process");
-
- /* XXX we can probably add some rudimentary cleanup code here,
- * like getting rid of the pid file. If any additional bad stuff
- * happens, we are protected from recursive errors taking down the
- * system since this function is no longer the signal handler GLA
- */
- }
- kill(ap_my_pid, sig);
- /* At this point we've got sig blocked, because we're still inside
- * the signal handler. When we leave the signal handler it will
- * be unblocked, and we'll take the signal... and coredump or whatever
- * is appropriate for this particular Unix. In addition the parent
- * will see the real signal we received -- whereas if we called
- * abort() here, the parent would only see SIGABRT.
- */
-}
-
static void just_die(int sig)
{
clean_child_exit(0);
{
#ifndef NO_USE_SIGACTION
struct sigaction sa;
+#endif
+
+ if (!one_process) {
+ ap_fatal_signal_setup(ap_server_conf, pconf);
+ }
+#ifndef NO_USE_SIGACTION
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (!one_process) {
- sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
- sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
- sa.sa_flags = SA_RESETHAND;
-#endif
- if (sigaction(SIGSEGV, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGSEGV)");
-#ifdef SIGBUS
- if (sigaction(SIGBUS, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
- if (sigaction(SIGABORT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
- if (sigaction(SIGABRT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
- if (sigaction(SIGILL, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGILL)");
-#endif
- sa.sa_flags = 0;
- }
sa.sa_handler = sig_term;
if (sigaction(SIGTERM, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(" AP_SIG_GRACEFUL_STRING ")");
#else
if (!one_process) {
- apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
- apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
- apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
- apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
- apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
#ifdef SIGXCPU
apr_signal(SIGXCPU, SIG_DFL);
#endif /* SIGXCPU */
* child initializes
*/
ap_my_pid = getpid();
+ ap_fatal_signal_child_setup(ap_server_conf);
apr_pool_create(&pchild, pconf);
/*stuff to do before we switch id's, so we have permissions.*/
#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
#define AP_MPM_WANT_SIGNAL_SERVER
#define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
#define AP_MPM_USES_POD 1
}
#endif
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
- chdir(ap_coredump_dir);
- apr_signal(sig, SIG_DFL);
- /* linuxthreads issue calling getpid() here:
- * This comparison won't match if the crashing thread is
- * some module's thread that runs in the parent process.
- * The fallout, which is limited to linuxthreads:
- * The special log message won't be written when such a
- * thread in the parent causes the parent to crash.
- */
- if (getpid() == parent_pid) {
- ap_log_error(APLOG_MARK, APLOG_NOTICE,
- 0, ap_server_conf,
- "seg fault or similar nasty error detected "
- "in the parent process");
- }
- kill(getpid(), sig);
- /* At this point we've got sig blocked, because we're still inside
- * the signal handler. When we leave the signal handler it will
- * be unblocked, and we'll take the signal... and coredump or whatever
- * is appropriate for this particular Unix. In addition the parent
- * will see the real signal we received -- whereas if we called
- * abort() here, the parent would only see SIGABRT.
- */
-}
-
/*****************************************************************
* Connection structures and accounting...
*/
{
#ifndef NO_USE_SIGACTION
struct sigaction sa;
+#endif
+
+ if (!one_process) {
+ ap_fatal_signal_setup(ap_server_conf, pconf);
+ }
+#ifndef NO_USE_SIGACTION
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (!one_process) {
- sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
- sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
- sa.sa_flags = SA_RESETHAND;
-#endif
- if (sigaction(SIGSEGV, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGSEGV)");
-#ifdef SIGBUS
- if (sigaction(SIGBUS, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
- if (sigaction(SIGABORT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
- if (sigaction(SIGABRT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
- if (sigaction(SIGILL, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGILL)");
-#endif
- sa.sa_flags = 0;
- }
sa.sa_handler = sig_term;
if (sigaction(SIGTERM, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(SIGTERM)");
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, "sigaction(" AP_SIG_GRACEFUL_STRING ")");
#else
if (!one_process) {
- apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
- apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
- apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
- apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
- apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
#ifdef SIGXCPU
apr_signal(SIGXCPU, SIG_DFL);
#endif /* SIGXCPU */
csd = NULL;
requests_this_child = 0;
+ ap_fatal_signal_child_setup(ap_server_conf);
+
/* Get a sub context for global allocations in this child, so that
* we can have cleanups occur when the child exits.
*/
#define AP_MPM_WANT_SET_ACCEPT_LOCK_MECH
#define AP_MPM_WANT_SIGNAL_SERVER
#define AP_MPM_WANT_SET_MAX_MEM_FREE
+#define AP_MPM_WANT_FATAL_SIGNAL_HANDLER
#define AP_MPM_DISABLE_NAGLE_ACCEPTED_SOCK
#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid)
exit(code);
}
-/* handle all varieties of core dumping signals */
-static void sig_coredump(int sig)
-{
- apr_filepath_set(ap_coredump_dir, pconf);
- apr_signal(sig, SIG_DFL);
- /* linuxthreads issue calling getpid() here:
- * This comparison won't match if the crashing thread is
- * some module's thread that runs in the parent process.
- * The fallout, which is limited to linuxthreads:
- * The special log message won't be written when such a
- * thread in the parent causes the parent to crash.
- */
- if (getpid() == parent_pid) {
- ap_log_error(APLOG_MARK, APLOG_NOTICE,
- 0, ap_server_conf,
- "seg fault or similar nasty error detected "
- "in the parent process");
-
- /* XXX we can probably add some rudimentary cleanup code here,
- * like getting rid of the pid file. If any additional bad stuff
- * happens, we are protected from recursive errors taking down the
- * system since this function is no longer the signal handler GLA
- */
- }
- kill(ap_my_pid, sig);
- /* At this point we've got sig blocked, because we're still inside
- * the signal handler. When we leave the signal handler it will
- * be unblocked, and we'll take the signal... and coredump or whatever
- * is appropriate for this particular Unix. In addition the parent
- * will see the real signal we received -- whereas if we called
- * abort() here, the parent would only see SIGABRT.
- */
-}
-
static void just_die(int sig)
{
clean_child_exit(0);
{
#ifndef NO_USE_SIGACTION
struct sigaction sa;
+#endif
+
+ if (!one_process) {
+ ap_fatal_signal_setup(ap_server_conf, pconf);
+ }
+#ifndef NO_USE_SIGACTION
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
- if (!one_process) {
- sa.sa_handler = sig_coredump;
-#if defined(SA_ONESHOT)
- sa.sa_flags = SA_ONESHOT;
-#elif defined(SA_RESETHAND)
- sa.sa_flags = SA_RESETHAND;
-#endif
- if (sigaction(SIGSEGV, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGSEGV)");
-#ifdef SIGBUS
- if (sigaction(SIGBUS, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGBUS)");
-#endif
-#ifdef SIGABORT
- if (sigaction(SIGABORT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABORT)");
-#endif
-#ifdef SIGABRT
- if (sigaction(SIGABRT, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGABRT)");
-#endif
-#ifdef SIGILL
- if (sigaction(SIGILL, &sa, NULL) < 0)
- ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
- "sigaction(SIGILL)");
-#endif
- sa.sa_flags = 0;
- }
sa.sa_handler = sig_term;
if (sigaction(SIGTERM, &sa, NULL) < 0)
ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,
"sigaction(" AP_SIG_GRACEFUL_STRING ")");
#else
if (!one_process) {
- apr_signal(SIGSEGV, sig_coredump);
-#ifdef SIGBUS
- apr_signal(SIGBUS, sig_coredump);
-#endif /* SIGBUS */
-#ifdef SIGABORT
- apr_signal(SIGABORT, sig_coredump);
-#endif /* SIGABORT */
-#ifdef SIGABRT
- apr_signal(SIGABRT, sig_coredump);
-#endif /* SIGABRT */
-#ifdef SIGILL
- apr_signal(SIGILL, sig_coredump);
-#endif /* SIGILL */
#ifdef SIGXCPU
apr_signal(SIGXCPU, SIG_DFL);
#endif /* SIGXCPU */
* child initializes
*/
ap_my_pid = getpid();
+ ap_fatal_signal_child_setup(ap_server_conf);
apr_pool_create(&pchild, pconf);
/*stuff to do before we switch id's, so we have permissions.*/
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#ifdef AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
void ap_reclaim_child_processes(int terminate)
}
#endif /* AP_MPM_WANT_SET_MAX_MEM_FREE */
+
+#ifdef AP_MPM_WANT_FATAL_SIGNAL_HANDLER
+
+static pid_t parent_pid, my_pid;
+apr_pool_t *pconf;
+
+#if AP_ENABLE_EXCEPTION_HOOK
+
+static int exception_hook_enabled;
+
+const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+
+ if (cmd->server->is_virtual) {
+ return "EnableExceptionHook directive not allowed in <VirtualHost>";
+ }
+
+ if (strcasecmp(arg, "on") == 0) {
+ exception_hook_enabled = 1;
+ }
+ else if (strcasecmp(arg, "off") == 0) {
+ exception_hook_enabled = 0;
+ }
+ else {
+ return "parameter must be 'on' or 'off'";
+ }
+
+ return NULL;
+}
+
+APR_HOOK_STRUCT(
+ APR_HOOK_LINK(fatal_exception)
+)
+
+AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
+ (ap_exception_info_t *ei), (ei), OK, DECLINED)
+
+static void run_fatal_exception_hook(int sig)
+{
+ ap_exception_info_t ei = {0};
+
+ if (exception_hook_enabled &&
+ geteuid() != 0 &&
+ my_pid != parent_pid) {
+ ei.sig = sig;
+ ei.pid = my_pid;
+ ap_run_fatal_exception(&ei);
+ }
+}
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
+
+/* handle all varieties of core dumping signals */
+static void sig_coredump(int sig)
+{
+ apr_filepath_set(ap_coredump_dir, pconf);
+ apr_signal(sig, SIG_DFL);
+#if AP_ENABLE_EXCEPTION_HOOK
+ run_fatal_exception_hook(sig);
+#endif
+ /* linuxthreads issue calling getpid() here:
+ * This comparison won't match if the crashing thread is
+ * some module's thread that runs in the parent process.
+ * The fallout, which is limited to linuxthreads:
+ * The special log message won't be written when such a
+ * thread in the parent causes the parent to crash.
+ */
+ if (getpid() == parent_pid) {
+ ap_log_error(APLOG_MARK, APLOG_NOTICE,
+ 0, ap_server_conf,
+ "seg fault or similar nasty error detected "
+ "in the parent process");
+ /* XXX we can probably add some rudimentary cleanup code here,
+ * like getting rid of the pid file. If any additional bad stuff
+ * happens, we are protected from recursive errors taking down the
+ * system since this function is no longer the signal handler GLA
+ */
+ }
+ kill(getpid(), sig);
+ /* At this point we've got sig blocked, because we're still inside
+ * the signal handler. When we leave the signal handler it will
+ * be unblocked, and we'll take the signal... and coredump or whatever
+ * is appropriate for this particular Unix. In addition the parent
+ * will see the real signal we received -- whereas if we called
+ * abort() here, the parent would only see SIGABRT.
+ */
+}
+
+apr_status_t ap_fatal_signal_child_setup(server_rec *s)
+{
+ my_pid = getpid();
+ return APR_SUCCESS;
+}
+
+apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *in_pconf)
+{
+#ifndef NO_USE_SIGACTION
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+
+#if defined(SA_ONESHOT)
+ sa.sa_flags = SA_ONESHOT;
+#elif defined(SA_RESETHAND)
+ sa.sa_flags = SA_RESETHAND;
+#else
+ sa.sa_flags = 0;
+#endif
+
+ sa.sa_handler = sig_coredump;
+ if (sigaction(SIGSEGV, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGSEGV)");
+#ifdef SIGBUS
+ if (sigaction(SIGBUS, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGBUS)");
+#endif
+#ifdef SIGABORT
+ if (sigaction(SIGABORT, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABORT)");
+#endif
+#ifdef SIGABRT
+ if (sigaction(SIGABRT, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGABRT)");
+#endif
+#ifdef SIGILL
+ if (sigaction(SIGILL, &sa, NULL) < 0)
+ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, s, "sigaction(SIGILL)");
+#endif
+
+#else /* NO_USE_SIGACTION */
+
+ apr_signal(SIGSEGV, sig_coredump);
+#ifdef SIGBUS
+ apr_signal(SIGBUS, sig_coredump);
+#endif /* SIGBUS */
+#ifdef SIGABORT
+ apr_signal(SIGABORT, sig_coredump);
+#endif /* SIGABORT */
+#ifdef SIGABRT
+ apr_signal(SIGABRT, sig_coredump);
+#endif /* SIGABRT */
+#ifdef SIGILL
+ apr_signal(SIGILL, sig_coredump);
+#endif /* SIGILL */
+
+#endif /* NO_USE_SIGACTION */
+
+ pconf = in_pconf;
+ parent_pid = my_pid = getpid();
+
+ return APR_SUCCESS;
+}
+
+#endif /* AP_MPM_WANT_FATAL_SIGNAL_HANDLER */