~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to lib/util/fault.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}