]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Add fatal exception hook for running diagnostic code after a
authorJeff Trawick <trawick@apache.org>
Wed, 28 Jan 2004 21:22:21 +0000 (21:22 +0000)
committerJeff Trawick <trawick@apache.org>
Wed, 28 Jan 2004 21:22:21 +0000 (21:22 +0000)
crash.

Reviewed by: Bill Stoddard, Mads Toftum

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@102436 13f79535-47bb-0310-9956-ffa450edef68

STATUS
src/CHANGES
src/include/ap_config.h
src/include/http_conf_globals.h
src/include/httpd.h
src/main/http_core.c
src/main/http_main.c
src/support/httpd.exp

diff --git a/STATUS b/STATUS
index fd317486d85f17fd668acb562b1a5b5b2639c9e0..96a464b04721585ac05dec4a6768b9281c85eff8 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -1,5 +1,5 @@
 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:
 
@@ -49,16 +49,6 @@ RELEASE SHOWSTOPPERS:
 
 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
index b7afc546789961285f1162ebcd3cb3648207e7df..6c37c81846b343000132ee6e78b2654c0358aa9a 100644 (file)
@@ -1,5 +1,8 @@
 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]
 
index 62bc79bc884fb79474e0d8cd9f5bf05cd67f9aae..17235c5cd6d52701ff03398fdad7779f0b60833d 100644 (file)
@@ -193,6 +193,7 @@ typedef int rlim_t;
 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
@@ -299,6 +300,7 @@ typedef int rlim_t;
 #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
@@ -521,6 +523,7 @@ typedef int pid_t;
 #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
index dba479f7fab56fc6e83797e7ba86c9eb9718fc68..e102481f695bb182b45ec71cc395636e75211dec 100644 (file)
@@ -100,6 +100,9 @@ extern API_VAR_EXPORT char *ap_pid_fname;
 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;
 
index 9e758eaf4eb8d230e515de593758e281f87d21c3..682ba12c9e73803ac3f6ffd2f131b324a418b369 100644 (file)
@@ -1226,6 +1226,32 @@ API_EXPORT(extern const char *) ap_psignature(const char *prefix, request_rec *r
 #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
index dfb78d1ca432cf7309897c249fcc0a0402d6bd97..80c36a88688e09a07793439e3e7bdce137b4fc05 100644 (file)
@@ -2248,6 +2248,32 @@ static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy, char *arg)
     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);
@@ -3628,6 +3654,10 @@ static const command_rec core_cmds[] = {
 #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
index 38795f18717d8590ec7467eedebca6054cf9490f..9b6142a94a69d7444bfd4df1ca3a0758c7692edd 100644 (file)
@@ -260,6 +260,9 @@ API_VAR_EXPORT int ap_daemons_limit=0;
 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);
@@ -3110,12 +3113,63 @@ static void siglist_init(void)
 }
 #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
@@ -4188,6 +4242,9 @@ static void common_init(void)
 
     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);
 
@@ -5121,6 +5178,9 @@ static void standalone_main(int argc, char **argv)
        }
 #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());
index fc01e8f333f50eae41c931df9cbecb1455553b80..8ea7057c4ff82b8c150ed456dd0fc86f2ffcc6f5 100644 (file)
@@ -9,6 +9,7 @@ ap_SHA1Update_binary
 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