From 9cba540514fd42ef9cabc9ad6f5e88227a02203e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 18 Dec 2009 12:32:38 +0100 Subject: lib/util: import fault/backtrace handling from samba. metze (This used to be ctdb commit 8171d66f0061fe23ed6dfef87ffe63bfc19596eb) --- ctdb/lib/util/fault.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 ctdb/lib/util/fault.c (limited to 'ctdb/lib/util/fault.c') diff --git a/ctdb/lib/util/fault.c b/ctdb/lib/util/fault.c new file mode 100644 index 0000000000..9262af20b0 --- /dev/null +++ b/ctdb/lib/util/fault.c @@ -0,0 +1,228 @@ +/* + Unix SMB/CIFS implementation. + Critical Fault handling + Copyright (C) Andrew Tridgell 1992-1998 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "system/wait.h" +#include "system/filesys.h" + +/** + * @file + * @brief Fault handling + */ + +/* the registered fault handler */ +static struct { + const char *name; + void (*fault_handler)(int sig); +} fault_handlers; + +static const char *progname; + +#ifdef HAVE_BACKTRACE +#include +#elif HAVE_LIBEXC_H +#include +#endif + +/** + * Write backtrace to debug log + */ +_PUBLIC_ void call_backtrace(void) +{ +#ifdef HAVE_BACKTRACE +#ifndef BACKTRACE_STACK_SIZE +#define BACKTRACE_STACK_SIZE 64 +#endif + void *backtrace_stack[BACKTRACE_STACK_SIZE]; + size_t backtrace_size; + char **backtrace_strings; + + /* get the backtrace (stack frames) */ + backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE); + backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size); + + DEBUG(0, ("BACKTRACE: %lu stack frames:\n", + (unsigned long)backtrace_size)); + + if (backtrace_strings) { + int i; + + for (i = 0; i < backtrace_size; i++) + DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i])); + + /* Leak the backtrace_strings, rather than risk what free() might do */ + } + +#elif HAVE_LIBEXC + +#define NAMESIZE 32 /* Arbitrary */ +#ifndef BACKTRACE_STACK_SIZE +#define BACKTRACE_STACK_SIZE 64 +#endif + + /* The IRIX libexc library provides an API for unwinding the stack. See + * libexc(3) for details. Apparantly trace_back_stack leaks memory, but + * since we are about to abort anyway, it hardly matters. + * + * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this + * will fail with a nasty message upon failing to open the /proc entry. + */ + { + uint64_t addrs[BACKTRACE_STACK_SIZE]; + char * names[BACKTRACE_STACK_SIZE]; + char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE]; + + int i; + int levels; + + ZERO_ARRAY(addrs); + ZERO_ARRAY(names); + ZERO_ARRAY(namebuf); + + for (i = 0; i < BACKTRACE_STACK_SIZE; i++) { + names[i] = namebuf + (i * NAMESIZE); + } + + levels = trace_back_stack(0, addrs, names, + BACKTRACE_STACK_SIZE, NAMESIZE); + + DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels)); + for (i = 0; i < levels; i++) { + DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i])); + } + } +#undef NAMESIZE +#else + DEBUG(0, ("call_backstrace: not implemented\n")); +#error bla +#endif +} + +_PUBLIC_ const char *panic_action = NULL; + +/** + Something really nasty happened - panic ! +**/ +_PUBLIC_ void smb_panic(const char *why) +{ + int result; + + if (panic_action && *panic_action) { + char pidstr[20]; + char cmdstring[200]; + strlcpy(cmdstring, panic_action, sizeof(cmdstring)); + snprintf(pidstr, sizeof(pidstr), "%u", getpid()); + all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring)); + if (progname) { + all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring)); + } + DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring)); + result = system(cmdstring); + + if (result == -1) + DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n", + strerror(errno))); + else + DEBUG(0, ("smb_panic(): action returned status %d\n", + WEXITSTATUS(result))); + } + DEBUG(0,("PANIC: %s\n", why)); + + call_backtrace(); + +#ifdef SIGABRT + CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL); +#endif + abort(); +} + +/** +report a fault +**/ +_NORETURN_ static void fault_report(int sig) +{ + static int counter; + + if (counter) _exit(1); + + DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n")); + DEBUG(0,("INTERNAL ERROR: Signal %d in %s pid %d",sig, progname, (int)getpid())); + DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n")); + DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n")); + + smb_panic("internal error"); + + exit(1); +} + +/** +catch serious errors +**/ +_NORETURN_ static void sig_fault(int sig) +{ + if (fault_handlers.fault_handler) { + /* we have a fault handler, call it. It may not return. */ + fault_handlers.fault_handler(sig); + } + /* If it returns or doesn't exist, use regular reporter */ + fault_report(sig); +} + +/** +setup our fault handlers +**/ +_PUBLIC_ void fault_setup(const char *pname) +{ + if (progname == NULL) { + progname = pname; + } +#ifdef SIGSEGV + CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault); +#endif +#ifdef SIGBUS + CatchSignal(SIGBUS,SIGNAL_CAST sig_fault); +#endif +#ifdef SIGABRT + CatchSignal(SIGABRT,SIGNAL_CAST sig_fault); +#endif +#ifdef SIGFPE + CatchSignal(SIGFPE,SIGNAL_CAST sig_fault); +#endif +} + +/** + register a fault handler. + Should only be called once in the execution of smbd. +*/ +_PUBLIC_ bool register_fault_handler(const char *name, + void (*fault_handler)(int sig)) +{ + if (fault_handlers.name != NULL) { + /* it's already registered! */ + DEBUG(2,("fault handler '%s' already registered - failed '%s'\n", + fault_handlers.name, name)); + return false; + } + + fault_handlers.name = name; + fault_handlers.fault_handler = fault_handler; + + DEBUG(2,("fault handler '%s' registered\n", name)); + return true; +} -- cgit From 78b78fc478dcd4d283a0b699eccc85be898d5c93 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 12 Jan 2010 12:17:00 +0100 Subject: lib/util: add pre and post panic action hooks metze (This used to be ctdb commit e366e77ba170d2c27110c56004ae1adf97abef9e) --- ctdb/lib/util/fault.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'ctdb/lib/util/fault.c') diff --git a/ctdb/lib/util/fault.c b/ctdb/lib/util/fault.c index 9262af20b0..5febf1ae29 100644 --- a/ctdb/lib/util/fault.c +++ b/ctdb/lib/util/fault.c @@ -115,6 +115,8 @@ _PUBLIC_ void call_backtrace(void) } _PUBLIC_ const char *panic_action = NULL; +_PUBLIC_ void (*pre_panic_action_hook)(void) = NULL; +_PUBLIC_ void (*post_panic_action_hook)(void) = NULL; /** Something really nasty happened - panic ! @@ -133,8 +135,17 @@ _PUBLIC_ void smb_panic(const char *why) all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring)); } DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring)); + + if (pre_panic_action_hook) { + pre_panic_action_hook(); + } + result = system(cmdstring); + if (post_panic_action_hook) { + post_panic_action_hook(); + } + if (result == -1) DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n", strerror(errno))); -- cgit From 4b32457822613b53fed452a7db0419408a6149b1 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Fri, 19 Feb 2010 12:44:07 +0100 Subject: libutil: Remove obsolete signal type cast. (This used to be ctdb commit 8dd377b6a4d188af086f9a5b41a1b48e44eda6f3) --- ctdb/lib/util/fault.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'ctdb/lib/util/fault.c') diff --git a/ctdb/lib/util/fault.c b/ctdb/lib/util/fault.c index 5febf1ae29..31ac165ac4 100644 --- a/ctdb/lib/util/fault.c +++ b/ctdb/lib/util/fault.c @@ -158,7 +158,7 @@ _PUBLIC_ void smb_panic(const char *why) call_backtrace(); #ifdef SIGABRT - CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL); + CatchSignal(SIGABRT, SIG_DFL); #endif abort(); } @@ -204,16 +204,16 @@ _PUBLIC_ void fault_setup(const char *pname) progname = pname; } #ifdef SIGSEGV - CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault); + CatchSignal(SIGSEGV, sig_fault); #endif #ifdef SIGBUS - CatchSignal(SIGBUS,SIGNAL_CAST sig_fault); + CatchSignal(SIGBUS, sig_fault); #endif #ifdef SIGABRT - CatchSignal(SIGABRT,SIGNAL_CAST sig_fault); + CatchSignal(SIGABRT, sig_fault); #endif #ifdef SIGFPE - CatchSignal(SIGFPE,SIGNAL_CAST sig_fault); + CatchSignal(SIGFPE, sig_fault); #endif } -- cgit From e6208ea45321b8dd801d7123ae15f612f75d857f Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Thu, 23 May 2013 23:42:23 -0500 Subject: util: Do not stop build if backtracing is not supported Signed-off-by: Amitay Isaacs (This used to be ctdb commit b091f09ea01482823bd850d1d4e2329e0a19c959) --- ctdb/lib/util/fault.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ctdb/lib/util/fault.c') diff --git a/ctdb/lib/util/fault.c b/ctdb/lib/util/fault.c index 31ac165ac4..3dddd0ecb2 100644 --- a/ctdb/lib/util/fault.c +++ b/ctdb/lib/util/fault.c @@ -109,8 +109,7 @@ _PUBLIC_ void call_backtrace(void) } #undef NAMESIZE #else - DEBUG(0, ("call_backstrace: not implemented\n")); -#error bla + DEBUG(0, ("call_backtrace: not implemented\n")); #endif } -- cgit