cb51cbd859aaa94a9e2668aebb279bba62fa1aec
[ira/wip.git] / lib / util / 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 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 */
31 static struct {
32         const char *name;
33         void (*fault_handler)(int sig);
34 } fault_handlers;
35
36 static 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 /**
154 report 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 /**
173 catch 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 /**
186 setup 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 }