2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
Critical Fault handling
Copyright ( C ) Andrew Tridgell 1992 - 1998
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 01:53:07 +00:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 01:53:07 +00:00
*/
# include "includes.h"
2005-01-18 09:30:43 +00:00
# include "version.h"
2004-11-02 04:17:30 +00:00
# include "system/wait.h"
2005-02-10 05:09:35 +00:00
# include "system/filesys.h"
2003-08-13 01:53:07 +00:00
2006-02-28 13:12:39 +00:00
/**
* @ file
* @ brief Fault handling
*/
2003-08-13 01:53:07 +00:00
/* the registered fault handler */
static struct {
const char * name ;
void ( * fault_handler ) ( int sig ) ;
} fault_handlers ;
2005-07-21 12:11:52 +00:00
static const char * progname ;
2003-08-13 01:53:07 +00:00
2004-06-30 19:46:28 +00:00
# ifdef HAVE_BACKTRACE
# include <execinfo.h>
# elif HAVE_LIBEXC_H
# include <libexc.h>
# endif
2006-02-28 13:12:39 +00:00
/**
* Write backtrace to debug log
*/
2006-03-05 17:15:19 +00:00
_PUBLIC_ void call_backtrace ( void )
2004-06-30 19:46:28 +00:00
{
# ifdef HAVE_BACKTRACE
2006-08-24 09:49:09 +00:00
# ifndef BACKTRACE_STACK_SIZE
2004-06-30 19:46:28 +00:00
# define BACKTRACE_STACK_SIZE 64
2006-08-24 09:49:09 +00:00
# endif
2004-06-30 19:46:28 +00:00
void * backtrace_stack [ BACKTRACE_STACK_SIZE ] ;
size_t backtrace_size ;
char * * backtrace_strings ;
/* get the backtrace (stack frames) */
backtrace_size = backtrace ( backtrace_stack , BACKTRACE_STACK_SIZE ) ;
backtrace_strings = backtrace_symbols ( backtrace_stack , backtrace_size ) ;
DEBUG ( 0 , ( " BACKTRACE: %lu stack frames: \n " ,
( unsigned long ) backtrace_size ) ) ;
if ( backtrace_strings ) {
int i ;
for ( i = 0 ; i < backtrace_size ; i + + )
DEBUGADD ( 0 , ( " #%u %s \n " , i , backtrace_strings [ i ] ) ) ;
/* Leak the backtrace_strings, rather than risk what free() might do */
}
# elif HAVE_LIBEXC
# define NAMESIZE 32 /* Arbitrary */
2006-08-24 09:49:09 +00:00
# ifndef BACKTRACE_STACK_SIZE
# define BACKTRACE_STACK_SIZE 64
# endif
2004-06-30 19:46:28 +00:00
/* The IRIX libexc library provides an API for unwinding the stack. See
* libexc ( 3 ) for details . Apparantly trace_back_stack leaks memory , but
* since we are about to abort anyway , it hardly matters .
*
* Note that if we paniced due to a SIGSEGV or SIGBUS ( or similar ) this
* will fail with a nasty message upon failing to open the / proc entry .
*/
{
uint64_t addrs [ BACKTRACE_STACK_SIZE ] ;
char * names [ BACKTRACE_STACK_SIZE ] ;
char namebuf [ BACKTRACE_STACK_SIZE * NAMESIZE ] ;
int i ;
int levels ;
ZERO_ARRAY ( addrs ) ;
ZERO_ARRAY ( names ) ;
ZERO_ARRAY ( namebuf ) ;
for ( i = 0 ; i < BACKTRACE_STACK_SIZE ; i + + ) {
names [ i ] = namebuf + ( i * NAMESIZE ) ;
}
levels = trace_back_stack ( 0 , addrs , names ,
BACKTRACE_STACK_SIZE , NAMESIZE ) ;
DEBUG ( 0 , ( " BACKTRACE: %d stack frames: \n " , levels ) ) ;
for ( i = 0 ; i < levels ; i + + ) {
DEBUGADD ( 0 , ( " #%d 0x%llx %s \n " , i , addrs [ i ] , names [ i ] ) ) ;
}
}
# undef NAMESIZE
# endif
}
2006-03-20 00:28:12 +00:00
_PUBLIC_ const char * panic_action = NULL ;
2006-02-28 13:12:39 +00:00
/**
2004-06-30 19:46:28 +00:00
Something really nasty happened - panic !
2006-02-28 13:12:39 +00:00
* */
2007-06-01 12:01:53 +00:00
_PUBLIC_ _NORETURN_ void smb_panic ( const char * why )
2004-06-30 19:46:28 +00:00
{
int result ;
2006-03-20 00:28:12 +00:00
if ( panic_action & & * panic_action ) {
2005-07-21 12:11:52 +00:00
char pidstr [ 20 ] ;
char cmdstring [ 200 ] ;
2006-03-20 00:28:12 +00:00
safe_strcpy ( cmdstring , panic_action , sizeof ( cmdstring ) ) ;
2005-07-21 12:11:52 +00:00
snprintf ( pidstr , sizeof ( pidstr ) , " %u " , getpid ( ) ) ;
all_string_sub ( cmdstring , " %PID% " , pidstr , sizeof ( cmdstring ) ) ;
if ( progname ) {
all_string_sub ( cmdstring , " %PROG% " , progname , sizeof ( cmdstring ) ) ;
}
DEBUG ( 0 , ( " smb_panic(): calling panic action [%s] \n " , cmdstring ) ) ;
result = system ( cmdstring ) ;
2004-06-30 19:46:28 +00:00
if ( result = = - 1 )
DEBUG ( 0 , ( " smb_panic(): fork failed in panic action: %s \n " ,
strerror ( errno ) ) ) ;
else
DEBUG ( 0 , ( " smb_panic(): action returned status %d \n " ,
WEXITSTATUS ( result ) ) ) ;
}
DEBUG ( 0 , ( " PANIC: %s \n " , why ) ) ;
call_backtrace ( ) ;
# ifdef SIGABRT
CatchSignal ( SIGABRT , SIGNAL_CAST SIG_DFL ) ;
# endif
abort ( ) ;
}
2006-02-28 13:12:39 +00:00
/**
2003-08-13 01:53:07 +00:00
report a fault
2006-02-28 13:12:39 +00:00
* */
2007-09-07 15:08:14 +00:00
_NORETURN_ static void fault_report ( int sig )
2003-08-13 01:53:07 +00:00
{
static int counter ;
if ( counter ) _exit ( 1 ) ;
2005-06-11 05:06:32 +00:00
DEBUG ( 0 , ( " =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= \n " ) ) ;
2004-01-28 12:47:52 +00:00
DEBUG ( 0 , ( " INTERNAL ERROR: Signal %d in pid %d (%s) " , sig , ( int ) getpid ( ) , SAMBA_VERSION_STRING ) ) ;
2003-08-13 01:53:07 +00:00
DEBUG ( 0 , ( " \n Please read the file BUGS.txt in the distribution \n " ) ) ;
2005-06-11 05:06:32 +00:00
DEBUG ( 0 , ( " =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= \n " ) ) ;
2003-08-13 01:53:07 +00:00
smb_panic ( " internal error " ) ;
exit ( 1 ) ;
}
2006-02-28 13:12:39 +00:00
/**
2003-08-13 01:53:07 +00:00
catch serious errors
2006-02-28 13:12:39 +00:00
* */
2007-09-07 15:08:14 +00:00
_NORETURN_ static void sig_fault ( int sig )
2003-08-13 01:53:07 +00:00
{
if ( fault_handlers . fault_handler ) {
/* we have a fault handler, call it. It may not return. */
fault_handlers . fault_handler ( sig ) ;
}
2008-02-11 12:39:47 +01:00
/* If it returns or doesn't exist, use regular reporter */
2003-08-13 01:53:07 +00:00
fault_report ( sig ) ;
}
2006-02-28 13:12:39 +00:00
/**
2003-08-13 01:53:07 +00:00
setup our fault handlers
2006-02-28 13:12:39 +00:00
* */
2006-03-05 17:15:19 +00:00
_PUBLIC_ void fault_setup ( const char * pname )
2003-08-13 01:53:07 +00:00
{
2005-07-21 12:11:52 +00:00
if ( progname = = NULL ) {
progname = pname ;
}
2003-08-13 01:53:07 +00:00
# ifdef SIGSEGV
CatchSignal ( SIGSEGV , SIGNAL_CAST sig_fault ) ;
# endif
# ifdef SIGBUS
CatchSignal ( SIGBUS , SIGNAL_CAST sig_fault ) ;
# endif
2004-06-30 19:46:28 +00:00
# ifdef SIGABRT
CatchSignal ( SIGABRT , SIGNAL_CAST sig_fault ) ;
# endif
2005-07-21 14:04:13 +00:00
# ifdef SIGFPE
CatchSignal ( SIGFPE , SIGNAL_CAST sig_fault ) ;
# endif
2003-08-13 01:53:07 +00:00
}
2006-02-28 13:12:39 +00:00
/**
2003-08-13 01:53:07 +00:00
register a fault handler .
Should only be called once in the execution of smbd .
*/
2007-10-14 12:52:32 +02:00
_PUBLIC_ bool register_fault_handler ( const char * name ,
void ( * fault_handler ) ( int sig ) )
2003-08-13 01:53:07 +00:00
{
if ( fault_handlers . name ! = NULL ) {
/* it's already registered! */
DEBUG ( 2 , ( " fault handler '%s' already registered - failed '%s' \n " ,
fault_handlers . name , name ) ) ;
2007-08-27 17:21:16 +00:00
return false ;
2003-08-13 01:53:07 +00:00
}
fault_handlers . name = name ;
fault_handlers . fault_handler = fault_handler ;
DEBUG ( 2 , ( " fault handler '%s' registered \n " , name ) ) ;
2007-08-27 17:21:16 +00:00
return true ;
2003-08-13 01:53:07 +00:00
}