2011-03-23 02:25:01 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-04 11:50:46 +04:00
Critical Fault handling
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
2009-02-25 03:42:18 +03:00
Copyright ( C ) Tim Prouty 2009
2011-03-23 02:25:01 +03:00
1996-05-04 11:50:46 +04:00
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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1996-05-04 11:50:46 +04:00
( at your option ) any later version .
2011-03-23 02:25:01 +03:00
1996-05-04 11:50:46 +04:00
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 .
2011-03-23 02:25:01 +03:00
1996-05-04 11:50:46 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-05-04 11:50:46 +04:00
*/
# include "includes.h"
2009-09-15 08:48:49 +04:00
# ifdef HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
# endif
2006-04-04 04:27:50 +04:00
# ifdef HAVE_SYS_PRCTL_H
# include <sys/prctl.h>
# endif
2007-11-16 01:19:52 +03:00
static char * corepath ;
1996-05-04 11:50:46 +04:00
/*******************************************************************
report a fault
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fault_report ( int sig )
{
1998-08-11 17:55:16 +04:00
static int counter ;
if ( counter ) _exit ( 1 ) ;
counter + + ;
2006-04-04 04:27:50 +04:00
DEBUGSEP ( 0 ) ;
2009-01-16 00:27:52 +03:00
DEBUG ( 0 , ( " INTERNAL ERROR: Signal %d in pid %d (%s) " , sig , ( int ) sys_getpid ( ) , samba_version_string ( ) ) ) ;
2005-08-17 10:01:38 +04:00
DEBUG ( 0 , ( " \n Please read the Trouble-Shooting section of the Samba3-HOWTO \n " ) ) ;
DEBUG ( 0 , ( " \n From: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf \n " ) ) ;
2006-04-04 04:27:50 +04:00
DEBUGSEP ( 0 ) ;
2011-03-23 02:25:01 +03:00
1998-08-21 15:37:40 +04:00
smb_panic ( " internal error " ) ;
1996-05-04 11:50:46 +04:00
2011-03-22 06:05:23 +03:00
/* smb_panic() never returns, so this is really redundent */
1998-08-11 17:55:16 +04:00
exit ( 1 ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
catch serious errors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void sig_fault ( int sig )
{
1998-08-11 17:55:16 +04:00
fault_report ( sig ) ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
setup our fault handlers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-03-22 06:05:23 +03:00
void fault_setup ( void )
1996-05-04 11:50:46 +04:00
{
# ifdef SIGSEGV
2010-02-19 17:32:45 +03:00
CatchSignal ( SIGSEGV , sig_fault ) ;
1996-05-04 11:50:46 +04:00
# endif
# ifdef SIGBUS
2010-02-19 17:32:45 +03:00
CatchSignal ( SIGBUS , sig_fault ) ;
1996-05-04 11:50:46 +04:00
# endif
2004-01-22 04:50:58 +03:00
# ifdef SIGABRT
2010-02-19 17:32:45 +03:00
CatchSignal ( SIGABRT , sig_fault ) ;
2004-01-22 04:50:58 +03:00
# endif
1996-05-04 11:50:46 +04:00
}
2006-04-04 04:27:50 +04:00
2009-02-25 01:45:46 +03:00
/**
* Build up the default corepath as " <logbase>/cores/<progname> "
*/
static char * get_default_corepath ( const char * logbase , const char * progname )
{
char * tmp_corepath ;
/* Setup core dir in logbase. */
tmp_corepath = talloc_asprintf ( NULL , " %s/cores " , logbase ) ;
if ( ! tmp_corepath )
return NULL ;
if ( ( mkdir ( tmp_corepath , 0700 ) = = - 1 ) & & errno ! = EEXIST )
goto err_out ;
if ( chmod ( tmp_corepath , 0700 ) = = - 1 )
goto err_out ;
talloc_free ( tmp_corepath ) ;
/* Setup progname-specific core subdir */
tmp_corepath = talloc_asprintf ( NULL , " %s/cores/%s " , logbase , progname ) ;
if ( ! tmp_corepath )
return NULL ;
if ( mkdir ( tmp_corepath , 0700 ) = = - 1 & & errno ! = EEXIST )
goto err_out ;
if ( chown ( tmp_corepath , getuid ( ) , getgid ( ) ) = = - 1 )
goto err_out ;
if ( chmod ( tmp_corepath , 0700 ) = = - 1 )
goto err_out ;
return tmp_corepath ;
err_out :
talloc_free ( tmp_corepath ) ;
return NULL ;
}
2009-02-25 03:42:18 +03:00
/**
* Get the FreeBSD corepath .
*
* On FreeBSD the current working directory is ignored when creating a core
* file . Instead the core directory is controlled via sysctl . This consults
* the value of " kern.corefile " so the correct corepath can be printed out
* before dump_core ( ) calls abort .
*/
# if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
static char * get_freebsd_corepath ( void )
{
char * tmp_corepath = NULL ;
char * end = NULL ;
size_t len = 128 ;
int ret ;
/* Loop with increasing sizes so we don't allocate too much. */
do {
if ( len > 1024 ) {
goto err_out ;
}
tmp_corepath = ( char * ) talloc_realloc ( NULL , tmp_corepath ,
char , len ) ;
if ( ! tmp_corepath ) {
return NULL ;
}
ret = sysctlbyname ( " kern.corefile " , tmp_corepath , & len , NULL ,
0 ) ;
if ( ret = = - 1 ) {
if ( errno ! = ENOMEM ) {
DEBUG ( 0 , ( " sysctlbyname failed getting "
" kern.corefile %s \n " ,
strerror ( errno ) ) ) ;
goto err_out ;
}
/* Not a large enough array, try a bigger one. */
len = len < < 1 ;
}
} while ( ret = = - 1 ) ;
/* Strip off the common filename expansion */
if ( ( end = strrchr_m ( tmp_corepath , ' / ' ) ) ) {
* end = ' \0 ' ;
}
return tmp_corepath ;
err_out :
if ( tmp_corepath ) {
talloc_free ( tmp_corepath ) ;
}
return NULL ;
}
# endif
2010-07-23 14:22:23 +04:00
# if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
/**
* Get the Linux corepath .
*
* On Linux the contents of / proc / sys / kernel / core_pattern indicates the
* location of the core path .
*/
static char * get_linux_corepath ( void )
{
char * end ;
int fd ;
char * result ;
fd = open ( " /proc/sys/kernel/core_pattern " , O_RDONLY , 0 ) ;
if ( fd = = - 1 ) {
return NULL ;
}
result = afdgets ( fd , NULL , 0 ) ;
close ( fd ) ;
if ( result = = NULL ) {
return NULL ;
}
if ( result [ 0 ] ! = ' / ' ) {
/*
* No absolute path , use the default ( cwd )
*/
TALLOC_FREE ( result ) ;
return NULL ;
}
/* Strip off the common filename expansion */
end = strrchr_m ( result , ' / ' ) ;
if ( ( end ! = result ) /* this would be the only / */
& & ( end ! = NULL ) ) {
* end = ' \0 ' ;
}
return result ;
}
# endif
2009-02-25 03:42:18 +03:00
/**
* Try getting system - specific corepath if one exists .
*
* If the system doesn ' t define a corepath , then the default is used .
*/
static char * get_corepath ( const char * logbase , const char * progname )
{
2009-04-23 12:42:43 +04:00
# if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
2010-07-23 14:22:23 +04:00
char * tmp_corepath = NULL ;
tmp_corepath = get_freebsd_corepath ( ) ;
2009-02-25 03:42:18 +03:00
2010-07-23 14:22:23 +04:00
/* If this has been set correctly, we're done. */
if ( tmp_corepath ) {
return tmp_corepath ;
}
# endif
2009-04-23 12:42:43 +04:00
2010-07-23 14:22:23 +04:00
# if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
2009-04-23 12:42:43 +04:00
char * tmp_corepath = NULL ;
2010-07-23 14:22:23 +04:00
tmp_corepath = get_linux_corepath ( ) ;
2009-02-25 03:42:18 +03:00
/* If this has been set correctly, we're done. */
if ( tmp_corepath ) {
return tmp_corepath ;
}
2009-04-23 12:42:43 +04:00
# endif
2009-02-25 03:42:18 +03:00
/* Fall back to the default. */
return get_default_corepath ( logbase , progname ) ;
}
2006-04-04 04:27:50 +04:00
/*******************************************************************
make all the preparations to safely dump a core file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void dump_core_setup ( const char * progname )
{
2007-11-16 01:19:52 +03:00
char * logbase = NULL ;
char * end = NULL ;
2006-04-04 04:27:50 +04:00
if ( lp_logfile ( ) & & * lp_logfile ( ) ) {
2007-11-16 01:19:52 +03:00
if ( asprintf ( & logbase , " %s " , lp_logfile ( ) ) < 0 ) {
return ;
}
2006-04-04 04:27:50 +04:00
if ( ( end = strrchr_m ( logbase , ' / ' ) ) ) {
* end = ' \0 ' ;
}
} else {
2009-02-25 01:45:46 +03:00
/* We will end up here if the log file is given on the command
2006-04-04 04:27:50 +04:00
* line by the - l option but the " log file " option is not set
* in smb . conf .
*/
2007-12-10 22:30:37 +03:00
if ( asprintf ( & logbase , " %s " , get_dyn_LOGFILEBASE ( ) ) < 0 ) {
2007-11-16 01:19:52 +03:00
return ;
}
2006-04-04 04:27:50 +04:00
}
SMB_ASSERT ( progname ! = NULL ) ;
2009-02-25 03:42:18 +03:00
corepath = get_corepath ( logbase , progname ) ;
2009-02-25 01:45:46 +03:00
if ( ! corepath ) {
DEBUG ( 0 , ( " Unable to setup corepath for %s: %s \n " , progname ,
strerror ( errno ) ) ) ;
goto out ;
2009-01-01 05:06:57 +03:00
}
2006-04-04 04:27:50 +04:00
2007-11-16 01:19:52 +03:00
2006-04-04 04:27:50 +04:00
# ifdef HAVE_GETRLIMIT
# ifdef RLIMIT_CORE
{
struct rlimit rlp ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
rlp . rlim_cur = MAX ( 16 * 1024 * 1024 , rlp . rlim_cur ) ;
setrlimit ( RLIMIT_CORE , & rlp ) ;
getrlimit ( RLIMIT_CORE , & rlp ) ;
DEBUG ( 3 , ( " Maximum core file size limits now %d(soft) %d(hard) \n " ,
( int ) rlp . rlim_cur , ( int ) rlp . rlim_max ) ) ;
}
# endif
# endif
/* FIXME: if we have a core-plus-pid facility, configurably set
* this up here .
*/
2009-02-25 01:45:46 +03:00
out :
SAFE_FREE ( logbase ) ;
2006-04-04 04:27:50 +04:00
}
void dump_core ( void )
{
2007-09-14 15:07:02 +04:00
static bool called ;
if ( called ) {
DEBUG ( 0 , ( " dump_core() called recursive \n " ) ) ;
exit ( 1 ) ;
}
called = true ;
2006-05-16 06:50:49 +04:00
/* Note that even if core dumping has been disabled, we still set up
* the core path . This is to handle the case where core dumping is
* turned on in smb . conf and the relevant daemon is not restarted .
*/
if ( ! lp_enable_core_files ( ) ) {
2007-04-06 23:17:15 +04:00
DEBUG ( 0 , ( " Exiting on internal error (core file administratively disabled) \n " ) ) ;
2006-05-16 06:50:49 +04:00
exit ( 1 ) ;
}
2006-11-07 20:18:00 +03:00
# if DUMP_CORE
2007-04-17 21:17:19 +04:00
/* If we're running as non root we might not be able to dump the core
* file to the corepath . There must not be an unbecome_root ( ) before
* we call abort ( ) . */
2010-02-13 10:18:53 +03:00
if ( geteuid ( ) ! = sec_initial_uid ( ) ) {
2007-04-17 21:17:19 +04:00
become_root ( ) ;
}
2008-06-13 13:56:40 +04:00
if ( corepath = = NULL ) {
DEBUG ( 0 , ( " Can not dump core: corepath not set up \n " ) ) ;
exit ( 1 ) ;
}
2006-04-04 04:27:50 +04:00
if ( * corepath ! = ' \0 ' ) {
/* The chdir might fail if we dump core before we finish
* processing the config file .
*/
if ( chdir ( corepath ) ! = 0 ) {
2006-11-07 20:18:00 +03:00
DEBUG ( 0 , ( " unable to change to %s \n " , corepath ) ) ;
2006-04-04 04:27:50 +04:00
DEBUGADD ( 0 , ( " refusing to dump core \n " ) ) ;
exit ( 1 ) ;
}
DEBUG ( 0 , ( " dumping core in %s \n " , corepath ) ) ;
}
umask ( ~ ( 0700 ) ) ;
dbgflush ( ) ;
2010-09-20 08:19:19 +04:00
# if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
/* On Linux we lose the ability to dump core when we change our user
* ID . We know how to dump core safely , so let ' s make sure we have our
* dumpable flag set .
*/
prctl ( PR_SET_DUMPABLE , 1 ) ;
# endif
2006-04-04 04:27:50 +04:00
/* Ensure we don't have a signal handler for abort. */
# ifdef SIGABRT
2010-02-19 17:32:45 +03:00
CatchSignal ( SIGABRT , SIG_DFL ) ;
2006-04-04 04:27:50 +04:00
# endif
abort ( ) ;
2006-11-07 20:18:00 +03:00
# else /* DUMP_CORE */
exit ( 1 ) ;
# endif /* DUMP_CORE */
2006-04-04 04:27:50 +04:00
}