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