]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/fault.c
Merge master
[netatalk.git] / libatalk / 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 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 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <sys/types.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <signal.h>
33 #ifdef HAVE_BACKTRACE_SYMBOLS
34 #include <execinfo.h>
35 #endif
36 #include <atalk/logger.h>
37
38 #ifndef SIGNAL_CAST
39 #define SIGNAL_CAST (void (*)(int))
40 #endif
41 #ifndef SAFE_FREE /* Oh no this is also defined in tdb.h */
42 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
43 #endif
44 #define BACKTRACE_STACK_SIZE 64
45
46 static void (*cont_fn)(void *);
47
48 /*******************************************************************
49  Catch a signal. This should implement the following semantics:
50
51  1) The handler remains installed after being called.
52  2) The signal should be blocked during handler execution.
53 ********************************************************************/
54
55 static void (*CatchSignal(int signum,void (*handler)(int )))(int)
56 {
57 #ifdef HAVE_SIGACTION
58         struct sigaction act;
59         struct sigaction oldact;
60
61         ZERO_STRUCT(act);
62
63         act.sa_handler = handler;
64 #if 0 
65         /*
66          * We *want* SIGALRM to interrupt a system call.
67          */
68         if(signum != SIGALRM)
69                 act.sa_flags = SA_RESTART;
70 #endif
71         sigemptyset(&act.sa_mask);
72         sigaddset(&act.sa_mask,signum);
73         sigaction(signum,&act,&oldact);
74         return oldact.sa_handler;
75 #else /* !HAVE_SIGACTION */
76         /* FIXME: need to handle sigvec and systems with broken signal() */
77         return signal(signum, handler);
78 #endif
79 }
80
81 /*******************************************************************
82  Something really nasty happened - panic !
83 ********************************************************************/
84
85 void netatalk_panic(const char *why)
86 {
87 #ifdef HAVE_BACKTRACE_SYMBOLS
88         void *backtrace_stack[BACKTRACE_STACK_SIZE];
89         size_t backtrace_size;
90         char **backtrace_strings;
91
92         /* get the backtrace (stack frames) */
93         backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
94         backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
95
96         LOG(log_severe, logtype_default, "PANIC: %s", why);
97         LOG(log_severe, logtype_default, "BACKTRACE: %d stack frames:", backtrace_size);
98         
99         if (backtrace_strings) {
100                 size_t i;
101
102                 for (i = 0; i < backtrace_size; i++)
103                         LOG(log_severe, logtype_default, " #%u %s", i, backtrace_strings[i]);
104
105                 SAFE_FREE(backtrace_strings);
106         }
107 #endif
108 }
109
110
111 /*******************************************************************
112 report a fault
113 ********************************************************************/
114 static void fault_report(int sig)
115 {
116         static int counter;
117
118         if (counter)
119         abort();
120
121         counter++;
122
123         LOG(log_severe, logtype_default, "===============================================================");
124         LOG(log_severe, logtype_default, "INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),VERSION);
125         LOG(log_severe, logtype_default, "===============================================================");
126   
127         netatalk_panic("internal error");
128
129         if (cont_fn) {
130                 cont_fn(NULL);
131 #ifdef SIGSEGV
132                 CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
133 #endif
134 #ifdef SIGBUS
135                 CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
136 #endif
137                 return; /* this should cause a core dump */
138         }
139     abort();
140 }
141
142 /****************************************************************************
143 catch serious errors
144 ****************************************************************************/
145 static void sig_fault(int sig)
146 {
147         fault_report(sig);
148 }
149
150 /*******************************************************************
151 setup our fault handlers
152 ********************************************************************/
153 void fault_setup(void (*fn)(void *))
154 {
155         cont_fn = fn;
156
157 #ifdef SIGSEGV
158         CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
159 #endif
160 #ifdef SIGBUS
161         CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
162 #endif
163 }
164