root/source3/lib/fault.c

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

DEFINITIONS

This source file includes following definitions.
  1. fault_report
  2. sig_fault
  3. fault_setup
  4. get_default_corepath
  5. get_freebsd_corepath
  6. get_corepath
  7. dump_core_setup
  8. dump_core

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Critical Fault handling
   4    Copyright (C) Andrew Tridgell 1992-1998
   5    Copyright (C) Tim Prouty 2009
   6    
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 3 of the License, or
  10    (at your option) any later version.
  11    
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.
  16    
  17    You should have received a copy of the GNU General Public License
  18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20 
  21 #include "includes.h"
  22 
  23 #ifdef HAVE_SYS_SYSCTL_H
  24 #include <sys/sysctl.h>
  25 #endif
  26 
  27 
  28 #ifdef HAVE_SYS_PRCTL_H
  29 #include <sys/prctl.h>
  30 #endif
  31 
  32 static void (*cont_fn)(void *);
  33 static char *corepath;
  34 
  35 /*******************************************************************
  36 report a fault
  37 ********************************************************************/
  38 static void fault_report(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
  39 {
  40         static int counter;
  41 
  42         if (counter) _exit(1);
  43 
  44         counter++;
  45 
  46         DEBUGSEP(0);
  47         DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),samba_version_string()));
  48         DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba3-HOWTO\n"));
  49         DEBUG(0,("\nFrom: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf\n"));
  50         DEBUGSEP(0);
  51   
  52         smb_panic("internal error");
  53 
  54         if (cont_fn) {
  55                 cont_fn(NULL);
  56 #ifdef SIGSEGV
  57                 CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
  58 #endif
  59 #ifdef SIGBUS
  60                 CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
  61 #endif
  62 #ifdef SIGABRT
  63                 CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
  64 #endif
  65                 return; /* this should cause a core dump */
  66         }
  67         exit(1);
  68 }
  69 
  70 /****************************************************************************
  71 catch serious errors
  72 ****************************************************************************/
  73 static void sig_fault(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
  74 {
  75         fault_report(sig);
  76 }
  77 
  78 /*******************************************************************
  79 setup our fault handlers
  80 ********************************************************************/
  81 void fault_setup(void (*fn)(void *))
     /* [<][>][^][v][top][bottom][index][help] */
  82 {
  83         cont_fn = fn;
  84 
  85 #ifdef SIGSEGV
  86         CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
  87 #endif
  88 #ifdef SIGBUS
  89         CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
  90 #endif
  91 #ifdef SIGABRT
  92         CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
  93 #endif
  94 }
  95 
  96 /**
  97  * Build up the default corepath as "<logbase>/cores/<progname>"
  98  */
  99 static char *get_default_corepath(const char *logbase, const char *progname)
     /* [<][>][^][v][top][bottom][index][help] */
 100 {
 101         char *tmp_corepath;
 102 
 103         /* Setup core dir in logbase. */
 104         tmp_corepath = talloc_asprintf(NULL, "%s/cores", logbase);
 105         if (!tmp_corepath)
 106                 return NULL;
 107 
 108         if ((mkdir(tmp_corepath, 0700) == -1) && errno != EEXIST)
 109                 goto err_out;
 110 
 111         if (chmod(tmp_corepath, 0700) == -1)
 112                 goto err_out;
 113 
 114         talloc_free(tmp_corepath);
 115 
 116         /* Setup progname-specific core subdir */
 117         tmp_corepath = talloc_asprintf(NULL, "%s/cores/%s", logbase, progname);
 118         if (!tmp_corepath)
 119                 return NULL;
 120 
 121         if (mkdir(tmp_corepath, 0700) == -1 && errno != EEXIST)
 122                 goto err_out;
 123 
 124         if (chown(tmp_corepath, getuid(), getgid()) == -1)
 125                 goto err_out;
 126 
 127         if (chmod(tmp_corepath, 0700) == -1)
 128                 goto err_out;
 129 
 130         return tmp_corepath;
 131 
 132  err_out:
 133         talloc_free(tmp_corepath);
 134         return NULL;
 135 }
 136 
 137 /**
 138  * Get the FreeBSD corepath.
 139  *
 140  * On FreeBSD the current working directory is ignored when creating a core
 141  * file.  Instead the core directory is controlled via sysctl.  This consults
 142  * the value of "kern.corefile" so the correct corepath can be printed out
 143  * before dump_core() calls abort.
 144  */
 145 #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
 146 static char *get_freebsd_corepath(void)
     /* [<][>][^][v][top][bottom][index][help] */
 147 {
 148         char *tmp_corepath = NULL;
 149         char *end = NULL;
 150         size_t len = 128;
 151         int ret;
 152 
 153         /* Loop with increasing sizes so we don't allocate too much. */
 154         do {
 155                 if (len > 1024)  {
 156                         goto err_out;
 157                 }
 158 
 159                 tmp_corepath = (char *)talloc_realloc(NULL, tmp_corepath,
 160                                                       char, len);
 161                 if (!tmp_corepath) {
 162                         return NULL;
 163                 }
 164 
 165                 ret = sysctlbyname("kern.corefile", tmp_corepath, &len, NULL,
 166                                    0);
 167                 if (ret == -1) {
 168                         if (errno != ENOMEM) {
 169                                 DEBUG(0, ("sysctlbyname failed getting "
 170                                           "kern.corefile %s\n",
 171                                           strerror(errno)));
 172                                 goto err_out;
 173                         }
 174 
 175                         /* Not a large enough array, try a bigger one. */
 176                         len = len << 1;
 177                 }
 178         } while (ret == -1);
 179 
 180         /* Strip off the common filename expansion */
 181         if ((end = strrchr_m(tmp_corepath, '/'))) {
 182                 *end = '\0';
 183         }
 184 
 185         return tmp_corepath;
 186 
 187  err_out:
 188         if (tmp_corepath) {
 189                 talloc_free(tmp_corepath);
 190         }
 191         return NULL;
 192 }
 193 #endif
 194 
 195 /**
 196  * Try getting system-specific corepath if one exists.
 197  *
 198  * If the system doesn't define a corepath, then the default is used.
 199  */
 200 static char *get_corepath(const char *logbase, const char *progname)
     /* [<][>][^][v][top][bottom][index][help] */
 201 {
 202 #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
 203 
 204         /* @todo: Add support for the linux corepath. */
 205 
 206         char *tmp_corepath = NULL;
 207         tmp_corepath = get_freebsd_corepath();
 208 
 209         /* If this has been set correctly, we're done. */
 210         if (tmp_corepath) {
 211                 return tmp_corepath;
 212         }
 213 #endif
 214 
 215         /* Fall back to the default. */
 216         return get_default_corepath(logbase, progname);
 217 }
 218 
 219 /*******************************************************************
 220 make all the preparations to safely dump a core file
 221 ********************************************************************/
 222 
 223 void dump_core_setup(const char *progname)
     /* [<][>][^][v][top][bottom][index][help] */
 224 {
 225         char *logbase = NULL;
 226         char *end = NULL;
 227 
 228         if (lp_logfile() && *lp_logfile()) {
 229                 if (asprintf(&logbase, "%s", lp_logfile()) < 0) {
 230                         return;
 231                 }
 232                 if ((end = strrchr_m(logbase, '/'))) {
 233                         *end = '\0';
 234                 }
 235         } else {
 236                 /* We will end up here if the log file is given on the command
 237                  * line by the -l option but the "log file" option is not set
 238                  * in smb.conf.
 239                  */
 240                 if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
 241                         return;
 242                 }
 243         }
 244 
 245         SMB_ASSERT(progname != NULL);
 246 
 247         corepath = get_corepath(logbase, progname);
 248         if (!corepath) {
 249                 DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname,
 250                           strerror(errno)));
 251                 goto out;
 252         }
 253 
 254 
 255 #ifdef HAVE_GETRLIMIT
 256 #ifdef RLIMIT_CORE
 257         {
 258                 struct rlimit rlp;
 259                 getrlimit(RLIMIT_CORE, &rlp);
 260                 rlp.rlim_cur = MAX(16*1024*1024,rlp.rlim_cur);
 261                 setrlimit(RLIMIT_CORE, &rlp);
 262                 getrlimit(RLIMIT_CORE, &rlp);
 263                 DEBUG(3,("Maximum core file size limits now %d(soft) %d(hard)\n",
 264                          (int)rlp.rlim_cur,(int)rlp.rlim_max));
 265         }
 266 #endif
 267 #endif
 268 
 269 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
 270         /* On Linux we lose the ability to dump core when we change our user
 271          * ID. We know how to dump core safely, so let's make sure we have our
 272          * dumpable flag set.
 273          */
 274         prctl(PR_SET_DUMPABLE, 1);
 275 #endif
 276 
 277         /* FIXME: if we have a core-plus-pid facility, configurably set
 278          * this up here.
 279          */
 280  out:
 281         SAFE_FREE(logbase);
 282 }
 283 
 284  void dump_core(void)
     /* [<][>][^][v][top][bottom][index][help] */
 285 {
 286         static bool called;
 287 
 288         if (called) {
 289                 DEBUG(0, ("dump_core() called recursive\n"));
 290                 exit(1);
 291         }
 292         called = true;
 293 
 294         /* Note that even if core dumping has been disabled, we still set up
 295          * the core path. This is to handle the case where core dumping is
 296          * turned on in smb.conf and the relevant daemon is not restarted.
 297          */
 298         if (!lp_enable_core_files()) {
 299                 DEBUG(0, ("Exiting on internal error (core file administratively disabled)\n"));
 300                 exit(1);
 301         }
 302 
 303 #if DUMP_CORE
 304         /* If we're running as non root we might not be able to dump the core
 305          * file to the corepath.  There must not be an unbecome_root() before
 306          * we call abort(). */
 307         if (geteuid() != 0) {
 308                 become_root();
 309         }
 310 
 311         if (corepath == NULL) {
 312                 DEBUG(0, ("Can not dump core: corepath not set up\n"));
 313                 exit(1);
 314         }
 315 
 316         if (*corepath != '\0') {
 317                 /* The chdir might fail if we dump core before we finish
 318                  * processing the config file.
 319                  */
 320                 if (chdir(corepath) != 0) {
 321                         DEBUG(0, ("unable to change to %s\n", corepath));
 322                         DEBUGADD(0, ("refusing to dump core\n"));
 323                         exit(1);
 324                 }
 325 
 326                 DEBUG(0,("dumping core in %s\n", corepath));
 327         }
 328 
 329         umask(~(0700));
 330         dbgflush();
 331 
 332         /* Ensure we don't have a signal handler for abort. */
 333 #ifdef SIGABRT
 334         CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
 335 #endif
 336 
 337         abort();
 338 
 339 #else /* DUMP_CORE */
 340         exit(1);
 341 #endif /* DUMP_CORE */
 342 }
 343 

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