APACHE 1.3 STATUS: -*-text-*-
- Last modified at [$Date: 2004/01/28 18:26:38 $]
+ Last modified at [$Date: 2004/01/28 21:22:20 $]
Release:
RELEASE NON-SHOWSTOPPERS BUT WOULD BE REAL NICE TO WRAP THESE UP:
- * fatal exception hook feature
- discussion:
- Message-Id: <400D4774.9020304@attglobal.net>
- and followups
- patch to consider:
- http://www.apache.org/~trawick/13_fatal_exception_patch.20040124
- proof-of-concept modules described at
- http://www.apache.org/~trawick/exception_hook_13.html
- +1: trawick, stoddard
-
* isn't ap_die() broken with recognizing recursive errors
Message-Id: <3F8C56E3.8050501@attglobal.net>
+1: jeff, jim
Changes with Apache 1.3.30
+ *) Add fatal exception hook for running diagnostic code after a
+ crash. [Jeff Trawick]
+
*) Make REMOTE_PORT variable available in mod_rewrite.
PR 25772. [André Malo]
int gethostname(char *name, int namelen);
#define HAVE_SYSLOG 1
#define SYS_SIGLIST _sys_siglist
+#define AP_ENABLE_EXCEPTION_HOOK
#elif defined(IRIX)
#undef HAVE_GMTOFF
#elif AIX >= 420
#define NET_SIZE_T size_t
#endif
+#define AP_ENABLE_EXCEPTION_HOOK
#elif defined(ULTRIX)
/* we don't want to use sys/resource.h under
#if !defined(__GLIBC__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1)
typedef int rlim_t;
#endif
+#define AP_ENABLE_EXCEPTION_HOOK
#elif defined(SCO)
#undef HAVE_GMTOFF
extern API_VAR_EXPORT char *ap_scoreboard_fname;
extern API_VAR_EXPORT char *ap_lock_fname;
extern API_VAR_EXPORT char *ap_server_argv0;
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+extern int ap_exception_hook_enabled;
+#endif
extern enum server_token_type ap_server_tokens;
#endif
#define strtoul strtoul_is_not_a_portable_function_use_strtol_instead
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+/* The exception hook allows a module to run from the server's signal
+ * handler, and perform tasks such as logging the current request or
+ * getting a backtrace or performing other diagnostic functions. All
+ * operating system requirements for running in a signal handler must
+ * be respected, or the process may not exit properly.
+ *
+ * AP_ENABLE_EXCEPTION_HOOK is already defined for platforms that have
+ * been tested. It likely will work on other platforms. In order to
+ * test, define AP_ENABLE_EXCEPTION_HOOK at configure time.
+ */
+typedef struct ap_exception_info_t {
+ int sig;
+ pid_t pid;
+} ap_exception_info_t;
+
+/* Register a function to be called after a fatal exception (on *X systems, a
+ * "synchronous signal" such as SIGSEGV, SIGILL, etc.).
+ *
+ * Returns 0 on success, non-zero on failure.
+ * If EnableExceptionHook directive is not set to "on", this function will
+ * report failure and no such hooks will be called.
+ */
+API_EXPORT(extern int) ap_add_fatal_exception_hook(void (*fn)(ap_exception_info_t *));
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
+
#ifdef __cplusplus
}
#endif
return NULL;
}
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+static const char *set_exception_hook(cmd_parms *cmd, void *dummy, 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) {
+ ap_exception_hook_enabled = 1;
+ }
+ else if (strcasecmp(arg, "off") == 0) {
+ ap_exception_hook_enabled = 0;
+ }
+ else {
+ return "parameter must be 'on' or 'off'";
+ }
+
+ return NULL;
+}
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
+
static const char *set_pidfile(cmd_parms *cmd, void *dummy, char *arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
#endif
"are compiled in"
},
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+{ "EnableExceptionHook", set_exception_hook, NULL, RSRC_CONF, TAKE1,
+ "Controls whether exception hook may be called after a crash" },
+#endif
/* EBCDIC Conversion directives: */
#ifdef CHARSET_EBCDIC
API_VAR_EXPORT time_t ap_restart_time=0;
API_VAR_EXPORT int ap_suexec_enabled = 0;
API_VAR_EXPORT int ap_listenbacklog=0;
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+int ap_exception_hook_enabled=0;
+#endif
struct accept_mutex_methods_s {
void (*child_init)(pool *p);
}
#endif /* platform has sys_siglist[] */
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+typedef struct except_hook_t {
+ struct except_hook_t *next;
+ void (*fn)(ap_exception_info_t *);
+} except_hook_t;
+
+static except_hook_t *except_hooks;
+
+static void except_hook_cleanup(void *ignored)
+{
+ except_hooks = NULL;
+}
+
+API_EXPORT(int) ap_add_fatal_exception_hook(void (*fn)(ap_exception_info_t *))
+{
+ except_hook_t *new;
+
+ ap_assert(pconf);
+
+ if (!ap_exception_hook_enabled) {
+ return 1;
+ }
+
+ new = ap_palloc(pconf, sizeof(except_hook_t));
+ new->next = except_hooks;
+ new->fn = fn;
+ except_hooks = new;
+
+ return 0;
+}
+
+static void run_fatal_exception_hook(int sig)
+{
+ except_hook_t *cur_hook = except_hooks;
+ ap_exception_info_t ei = {0};
+
+ if (ap_exception_hook_enabled &&
+ geteuid() != 0) {
+ ei.sig = sig;
+ ei.pid = getpid();
+
+ while (cur_hook) {
+ cur_hook->fn(&ei);
+ cur_hook = cur_hook->next;
+ }
+ }
+}
+#endif /* AP_ENABLE_EXCEPTION_HOOK */
/* handle all varieties of core dumping signals */
static void sig_coredump(int sig)
{
chdir(ap_coredump_dir);
signal(sig, SIG_DFL);
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+ run_fatal_exception_hook(sig);
+#endif
#if !defined(WIN32) && !defined(NETWARE)
kill(getpid(), sig);
#else
pglobal = ap_init_alloc();
pconf = ap_make_sub_pool(pglobal);
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+ ap_register_cleanup(pconf, NULL, except_hook_cleanup, ap_null_cleanup);
+#endif
plog = ap_make_sub_pool(pglobal);
ptrans = ap_make_sub_pool(pconf);
}
#endif
ap_clear_pool(pconf);
+#ifdef AP_ENABLE_EXCEPTION_HOOK
+ ap_register_cleanup(pconf, NULL, except_hook_cleanup, ap_null_cleanup);
+#endif
ptrans = ap_make_sub_pool(pconf);
ap_init_mutex_method(ap_default_mutex_method());
ap_SHA1Update
ap_add_cgi_vars
ap_add_common_vars
+ap_add_fatal_exception_hook
ap_add_file_conf
ap_add_module
ap_add_named_module