root/lib/util/fault.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. call_backtrace
  2. smb_panic
  3. fault_report
  4. sig_fault
  5. fault_setup
  6. register_fault_handler

   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)
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */