ctdb-build: Add generation of Samba-style version.h
[Samba.git] / ctdb / lib / util / fault.c
blobd53eecdb428a29f3f6aa3e7f8d100b1cd1aad2f4
1 /*
2 Unix SMB/CIFS implementation.
3 Critical Fault handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/wait.h"
22 #include "system/filesys.h"
24 /**
25 * @file
26 * @brief Fault handling
29 /* the registered fault handler */
30 static struct {
31 const char *name;
32 void (*fault_handler)(int sig);
33 } fault_handlers;
35 static const char *progname;
37 #ifdef HAVE_BACKTRACE
38 #include <execinfo.h>
39 #elif HAVE_LIBEXC_H
40 #include <libexc.h>
41 #endif
43 /**
44 * Write backtrace to debug log
46 _PUBLIC_ void call_backtrace(void)
48 #ifdef HAVE_BACKTRACE
49 #ifndef BACKTRACE_STACK_SIZE
50 #define BACKTRACE_STACK_SIZE 64
51 #endif
52 void *backtrace_stack[BACKTRACE_STACK_SIZE];
53 size_t backtrace_size;
54 char **backtrace_strings;
56 /* get the backtrace (stack frames) */
57 backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
58 backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
60 DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
61 (unsigned long)backtrace_size));
63 if (backtrace_strings) {
64 int i;
66 for (i = 0; i < backtrace_size; i++)
67 DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
69 /* Leak the backtrace_strings, rather than risk what free() might do */
72 #elif HAVE_LIBEXC
74 #define NAMESIZE 32 /* Arbitrary */
75 #ifndef BACKTRACE_STACK_SIZE
76 #define BACKTRACE_STACK_SIZE 64
77 #endif
79 /* The IRIX libexc library provides an API for unwinding the stack. See
80 * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
81 * since we are about to abort anyway, it hardly matters.
83 * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
84 * will fail with a nasty message upon failing to open the /proc entry.
87 uint64_t addrs[BACKTRACE_STACK_SIZE];
88 char * names[BACKTRACE_STACK_SIZE];
89 char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
91 int i;
92 int levels;
94 ZERO_ARRAY(addrs);
95 ZERO_ARRAY(names);
96 ZERO_ARRAY(namebuf);
98 for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
99 names[i] = namebuf + (i * NAMESIZE);
102 levels = trace_back_stack(0, addrs, names,
103 BACKTRACE_STACK_SIZE, NAMESIZE);
105 DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
106 for (i = 0; i < levels; i++) {
107 DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
110 #undef NAMESIZE
111 #else
112 DEBUG(0, ("call_backtrace: not implemented\n"));
113 #endif
116 _PUBLIC_ const char *panic_action = NULL;
117 _PUBLIC_ void (*pre_panic_action_hook)(void) = NULL;
118 _PUBLIC_ void (*post_panic_action_hook)(void) = NULL;
121 Something really nasty happened - panic !
123 _PUBLIC_ void smb_panic(const char *why)
125 int result;
127 if (panic_action && *panic_action) {
128 char pidstr[20];
129 char cmdstring[200];
130 strlcpy(cmdstring, panic_action, sizeof(cmdstring));
131 snprintf(pidstr, sizeof(pidstr), "%u", getpid());
132 all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
133 if (progname) {
134 all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
136 DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
138 if (pre_panic_action_hook) {
139 pre_panic_action_hook();
142 result = system(cmdstring);
144 if (post_panic_action_hook) {
145 post_panic_action_hook();
148 if (result == -1)
149 DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
150 strerror(errno)));
151 else
152 DEBUG(0, ("smb_panic(): action returned status %d\n",
153 WEXITSTATUS(result)));
155 DEBUG(0,("PANIC: %s\n", why));
157 call_backtrace();
159 #ifdef SIGABRT
160 CatchSignal(SIGABRT, SIG_DFL);
161 #endif
162 abort();
166 report a fault
168 _NORETURN_ static void fault_report(int sig)
170 static int counter;
172 if (counter) _exit(1);
174 DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
175 DEBUG(0,("INTERNAL ERROR: Signal %d in %s pid %d",sig, progname, (int)getpid()));
176 DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
177 DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
179 smb_panic("internal error");
181 exit(1);
185 catch serious errors
187 _NORETURN_ static void sig_fault(int sig)
189 if (fault_handlers.fault_handler) {
190 /* we have a fault handler, call it. It may not return. */
191 fault_handlers.fault_handler(sig);
193 /* If it returns or doesn't exist, use regular reporter */
194 fault_report(sig);
198 setup our fault handlers
200 _PUBLIC_ void fault_setup(void)
202 #ifdef SIGSEGV
203 CatchSignal(SIGSEGV, sig_fault);
204 #endif
205 #ifdef SIGBUS
206 CatchSignal(SIGBUS, sig_fault);
207 #endif
208 #ifdef SIGABRT
209 CatchSignal(SIGABRT, sig_fault);
210 #endif
211 #ifdef SIGFPE
212 CatchSignal(SIGFPE, sig_fault);
213 #endif
217 register a fault handler.
218 Should only be called once in the execution of smbd.
220 _PUBLIC_ bool register_fault_handler(const char *name,
221 void (*fault_handler)(int sig))
223 if (fault_handlers.name != NULL) {
224 /* it's already registered! */
225 DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
226 fault_handlers.name, name));
227 return false;
230 fault_handlers.name = name;
231 fault_handlers.fault_handler = fault_handler;
233 DEBUG(2,("fault handler '%s' registered\n", name));
234 return true;