r1374: Fix signed/unsigned warnings (actually found by g++) after unsigned int
[kamenim/samba.git] / source4 / lib / fault.c
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 static void (*cont_fn)(void *);
24
25 /* the registered fault handler */
26 static struct {
27         const char *name;
28         void (*fault_handler)(int sig);
29 } fault_handlers;
30
31
32 #ifdef HAVE_BACKTRACE
33 #include <execinfo.h>
34 #define BACKTRACE_STACK_SIZE 64
35 #elif HAVE_LIBEXC_H
36 #include <libexc.h>
37 #endif
38
39 static void call_backtrace(void)
40 {
41 #ifdef HAVE_BACKTRACE
42 #define BACKTRACE_STACK_SIZE 64
43         void *backtrace_stack[BACKTRACE_STACK_SIZE];
44         size_t backtrace_size;
45         char **backtrace_strings;
46
47         /* get the backtrace (stack frames) */
48         backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
49         backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
50
51         DEBUG(0, ("BACKTRACE: %lu stack frames:\n", 
52                   (unsigned long)backtrace_size));
53         
54         if (backtrace_strings) {
55                 int i;
56
57                 for (i = 0; i < backtrace_size; i++)
58                         DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
59
60                 /* Leak the backtrace_strings, rather than risk what free() might do */
61         }
62
63 #elif HAVE_LIBEXC
64
65 #define NAMESIZE 32 /* Arbitrary */
66
67         /* The IRIX libexc library provides an API for unwinding the stack. See
68          * libexc(3) for details. Apparantly trace_back_stack leaks memory, but
69          * since we are about to abort anyway, it hardly matters.
70          *
71          * Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
72          * will fail with a nasty message upon failing to open the /proc entry.
73          */
74         {
75                 uint64_t        addrs[BACKTRACE_STACK_SIZE];
76                 char *          names[BACKTRACE_STACK_SIZE];
77                 char            namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
78
79                 int             i;
80                 int             levels;
81
82                 ZERO_ARRAY(addrs);
83                 ZERO_ARRAY(names);
84                 ZERO_ARRAY(namebuf);
85
86                 for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
87                         names[i] = namebuf + (i * NAMESIZE);
88                 }
89
90                 levels = trace_back_stack(0, addrs, names,
91                                 BACKTRACE_STACK_SIZE, NAMESIZE);
92
93                 DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
94                 for (i = 0; i < levels; i++) {
95                         DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
96                 }
97      }
98 #undef NAMESIZE
99 #endif
100 }
101
102 /*******************************************************************
103  Something really nasty happened - panic !
104 ********************************************************************/
105 void smb_panic(const char *why)
106 {
107         const char *cmd = lp_panic_action();
108         int result;
109
110         if (cmd && *cmd) {
111                 DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmd));
112                 result = system(cmd);
113
114                 if (result == -1)
115                         DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
116                                   strerror(errno)));
117                 else
118                         DEBUG(0, ("smb_panic(): action returned status %d\n",
119                                   WEXITSTATUS(result)));
120         }
121         DEBUG(0,("PANIC: %s\n", why));
122
123         call_backtrace();
124
125 #ifdef SIGABRT
126         CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
127 #endif
128         abort();
129 }
130
131 /*******************************************************************
132 report a fault
133 ********************************************************************/
134 static void fault_report(int sig)
135 {
136         static int counter;
137         
138         if (counter) _exit(1);
139
140         DEBUG(0,("===============================================================\n"));
141         DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),SAMBA_VERSION_STRING));
142         DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
143         DEBUG(0,("===============================================================\n"));
144
145         smb_panic("internal error");
146
147         if (cont_fn) {
148                 cont_fn(NULL);
149 #ifdef SIGSEGV
150                 CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
151 #endif
152 #ifdef SIGBUS
153                 CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
154 #endif
155 #ifdef SIGABRT
156                 CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
157 #endif
158                 return; /* this should cause a core dump */
159         }
160         exit(1);
161 }
162
163 /****************************************************************************
164 catch serious errors
165 ****************************************************************************/
166 static void sig_fault(int sig)
167 {
168         if (fault_handlers.fault_handler) {
169                 /* we have a fault handler, call it. It may not return. */
170                 fault_handlers.fault_handler(sig);
171         }
172         /* If it returns or doean't exist, use regular reporter */
173         fault_report(sig);
174 }
175
176 /*******************************************************************
177 setup our fault handlers
178 ********************************************************************/
179 void fault_setup(void (*fn)(void *))
180 {
181         cont_fn = fn;
182
183 #ifdef SIGSEGV
184         CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
185 #endif
186 #ifdef SIGBUS
187         CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
188 #endif
189 #ifdef SIGABRT
190         CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
191 #endif
192 }
193
194 /*
195   register a fault handler. 
196   Should only be called once in the execution of smbd.
197 */
198 BOOL register_fault_handler(const char *name, void (*fault_handler)(int sig))
199 {
200         if (fault_handlers.name != NULL) {
201                 /* it's already registered! */
202                 DEBUG(2,("fault handler '%s' already registered - failed '%s'\n", 
203                          fault_handlers.name, name));
204                 return False;
205         }
206
207         fault_handlers.name = name;
208         fault_handlers.fault_handler = fault_handler;
209
210         DEBUG(2,("fault handler '%s' registered\n", name));
211         return True;
212 }