source: branches/samba-3.5.x/lib/util/fault.c@ 717

Last change on this file since 717 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 5.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Critical Fault handling
4 Copyright (C) Andrew Tridgell 1992-1998
5
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.
10
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.
15
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/>.
18*/
19
20#include "includes.h"
21#include "version.h"
22#include "system/wait.h"
23#include "system/filesys.h"
24
25/**
26 * @file
27 * @brief Fault handling
28 */
29
30/* the registered fault handler */
31static struct {
32 const char *name;
33 void (*fault_handler)(int sig);
34} fault_handlers;
35
36static const char *progname;
37
38#ifdef HAVE_BACKTRACE
39#include <execinfo.h>
40#elif HAVE_LIBEXC_H
41#include <libexc.h>
42#endif
43
44/**
45 * Write backtrace to debug log
46 */
47_PUBLIC_ void call_backtrace(void)
48{
49#ifdef HAVE_BACKTRACE
50#ifndef BACKTRACE_STACK_SIZE
51#define BACKTRACE_STACK_SIZE 64
52#endif
53 void *backtrace_stack[BACKTRACE_STACK_SIZE];
54 size_t backtrace_size;
55 char **backtrace_strings;
56
57 /* get the backtrace (stack frames) */
58 backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
59 backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
60
61 DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
62 (unsigned long)backtrace_size));
63
64 if (backtrace_strings) {
65 int i;
66
67 for (i = 0; i < backtrace_size; i++)
68 DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
69
70 /* Leak the backtrace_strings, rather than risk what free() might do */
71 }
72
73#elif HAVE_LIBEXC
74
75#define NAMESIZE 32 /* Arbitrary */
76#ifndef BACKTRACE_STACK_SIZE
77#define BACKTRACE_STACK_SIZE 64
78#endif
79
80 /* The IRIX libexc library provides an API for unwinding the stack. See
81 * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
82 * since we are about to abort anyway, it hardly matters.
83 *
84 * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
85 * will fail with a nasty message upon failing to open the /proc entry.
86 */
87 {
88 uint64_t addrs[BACKTRACE_STACK_SIZE];
89 char * names[BACKTRACE_STACK_SIZE];
90 char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
91
92 int i;
93 int levels;
94
95 ZERO_ARRAY(addrs);
96 ZERO_ARRAY(names);
97 ZERO_ARRAY(namebuf);
98
99 for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
100 names[i] = namebuf + (i * NAMESIZE);
101 }
102
103 levels = trace_back_stack(0, addrs, names,
104 BACKTRACE_STACK_SIZE, NAMESIZE);
105
106 DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
107 for (i = 0; i < levels; i++) {
108 DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
109 }
110 }
111#undef NAMESIZE
112#endif
113}
114
115_PUBLIC_ const char *panic_action = NULL;
116
117/**
118 Something really nasty happened - panic !
119**/
120_PUBLIC_ _NORETURN_ void smb_panic(const char *why)
121{
122 int result;
123
124 if (panic_action && *panic_action) {
125 char pidstr[20];
126 char cmdstring[200];
127 safe_strcpy(cmdstring, panic_action, sizeof(cmdstring));
128 snprintf(pidstr, sizeof(pidstr), "%u", getpid());
129 all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
130 if (progname) {
131 all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
132 }
133 DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
134 result = system(cmdstring);
135
136 if (result == -1)
137 DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
138 strerror(errno)));
139 else
140 DEBUG(0, ("smb_panic(): action returned status %d\n",
141 WEXITSTATUS(result)));
142 }
143 DEBUG(0,("PANIC: %s\n", why));
144
145 call_backtrace();
146
147#ifdef SIGABRT
148 CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
149#endif
150 abort();
151}
152
153/**
154report a fault
155**/
156_NORETURN_ static void fault_report(int sig)
157{
158 static int counter;
159
160 if (counter) _exit(1);
161
162 DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
163 DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),SAMBA_VERSION_STRING));
164 DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
165 DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
166
167 smb_panic("internal error");
168
169 exit(1);
170}
171
172/**
173catch serious errors
174**/
175_NORETURN_ static void sig_fault(int sig)
176{
177 if (fault_handlers.fault_handler) {
178 /* we have a fault handler, call it. It may not return. */
179 fault_handlers.fault_handler(sig);
180 }
181 /* If it returns or doesn't exist, use regular reporter */
182 fault_report(sig);
183}
184
185/**
186setup our fault handlers
187**/
188_PUBLIC_ void fault_setup(const char *pname)
189{
190 if (progname == NULL) {
191 progname = pname;
192 }
193#ifdef SIGSEGV
194 CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
195#endif
196#ifdef SIGBUS
197 CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
198#endif
199#ifdef SIGABRT
200 CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
201#endif
202#ifdef SIGFPE
203 CatchSignal(SIGFPE,SIGNAL_CAST sig_fault);
204#endif
205}
206
207/**
208 register a fault handler.
209 Should only be called once in the execution of smbd.
210*/
211_PUBLIC_ bool register_fault_handler(const char *name,
212 void (*fault_handler)(int sig))
213{
214 if (fault_handlers.name != NULL) {
215 /* it's already registered! */
216 DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
217 fault_handlers.name, name));
218 return false;
219 }
220
221 fault_handlers.name = name;
222 fault_handlers.fault_handler = fault_handler;
223
224 DEBUG(2,("fault handler '%s' registered\n", name));
225 return true;
226}
Note: See TracBrowser for help on using the repository browser.