diff options
Diffstat (limited to 'source3/lib/fault.c')
-rw-r--r-- | source3/lib/fault.c | 173 |
1 files changed, 131 insertions, 42 deletions
diff --git a/source3/lib/fault.c b/source3/lib/fault.c index 8c4a45bbc9..efd1dddfd4 100644 --- a/source3/lib/fault.c +++ b/source3/lib/fault.c @@ -2,6 +2,7 @@ Unix SMB/CIFS implementation. Critical Fault handling Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Tim Prouty 2009 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 @@ -87,6 +88,128 @@ void fault_setup(void (*fn)(void *)) #endif } +/** + * 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; +} + +/** + * 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 + +/** + * 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) +{ + char *tmp_corepath = NULL; + + /* @todo: Add support for the linux corepath. */ +#if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME)) + tmp_corepath = get_freebsd_corepath(); +#endif + + /* If this has been set correctly, we're done. */ + if (tmp_corepath) { + return tmp_corepath; + } + + /* Fall back to the default. */ + return get_default_corepath(logbase, progname); +} + /******************************************************************* make all the preparations to safely dump a core file ********************************************************************/ @@ -104,7 +227,7 @@ void dump_core_setup(const char *progname) *end = '\0'; } } else { - /* We will end up here is the log file is given on the command + /* We will end up here if the log file is given on the command * line by the -l option but the "log file" option is not set * in smb.conf. */ @@ -115,49 +238,13 @@ void dump_core_setup(const char *progname) SMB_ASSERT(progname != NULL); - if (asprintf(&corepath, "%s/cores", logbase) < 0) { - SAFE_FREE(logbase); - return; - } - if (mkdir(corepath,0700) == -1) { - if (errno != EEXIST) { - SAFE_FREE(corepath); - SAFE_FREE(logbase); - return; - } - } - if (chmod(corepath,0700) == -1) { - SAFE_FREE(corepath); - SAFE_FREE(logbase); - return; - } - - SAFE_FREE(corepath); - if (asprintf(&corepath, "%s/cores/%s", - logbase, progname) < 0) { - SAFE_FREE(logbase); - return; - } - if (mkdir(corepath,0700) == -1) { - if (errno != EEXIST) { - SAFE_FREE(corepath); - SAFE_FREE(logbase); - return; - } - } - - if (chown(corepath,getuid(),getgid()) == -1) { - SAFE_FREE(corepath); - SAFE_FREE(logbase); - return; - } - if (chmod(corepath,0700) == -1) { - SAFE_FREE(corepath); - SAFE_FREE(logbase); - return; + corepath = get_corepath(logbase, progname); + if (!corepath) { + DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname, + strerror(errno))); + goto out; } - SAFE_FREE(logbase); #ifdef HAVE_GETRLIMIT #ifdef RLIMIT_CORE @@ -184,6 +271,8 @@ void dump_core_setup(const char *progname) /* FIXME: if we have a core-plus-pid facility, configurably set * this up here. */ + out: + SAFE_FREE(logbase); } void dump_core(void) |