along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
+#include "replace.h"
+#include <talloc.h>
#include "system/filesys.h"
#include "system/syslog.h"
-#include "lib/util/time_basic.h"
+#include "system/locale.h"
+#include "time_basic.h"
+#include "close_low_fd.h"
+#include "memory.h"
+#include "util_strlist.h" /* LIST_SEP */
+#include "blocking.h"
+#include "debug.h"
/* define what facility to use for syslog */
#ifndef SYSLOG_FACILITY
/* -------------------------------------------------------------------------- **
* Defines...
- *
- * FORMAT_BUFR_MAX - Index of the last byte of the format buffer;
- * format_bufr[FORMAT_BUFR_MAX] should always be reserved
- * for a terminating null byte.
*/
+/*
+ * format_bufr[FORMAT_BUFR_SIZE - 1] should always be reserved
+ * for a terminating null byte.
+ */
#define FORMAT_BUFR_SIZE 1024
-#define FORMAT_BUFR_MAX (FORMAT_BUFR_SIZE - 1)
/* -------------------------------------------------------------------------- **
* This module implements Samba's debugging utility.
.fd = 2 /* stderr by default */
};
+#if defined(WITH_SYSLOG) || defined(HAVE_LIBSYSTEMD_JOURNAL) || defined(HAVE_LIBSYSTEMD)
+static int debug_level_to_priority(int level)
+{
+ /*
+ * map debug levels to syslog() priorities
+ */
+ static const int priority_map[] = {
+ LOG_ERR, /* 0 */
+ LOG_WARNING, /* 1 */
+ LOG_NOTICE, /* 2 */
+ LOG_NOTICE, /* 3 */
+ LOG_NOTICE, /* 4 */
+ LOG_NOTICE, /* 5 */
+ LOG_INFO, /* 6 */
+ LOG_INFO, /* 7 */
+ LOG_INFO, /* 8 */
+ LOG_INFO, /* 9 */
+ };
+ int priority;
+
+ if( level >= ARRAY_SIZE(priority_map) || level < 0)
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[level];
+
+ return priority;
+}
+#endif
+
+/* -------------------------------------------------------------------------- **
+ * Debug backends. When logging to DEBUG_FILE, send the log entries to
+ * all active backends.
+ */
+
+static void debug_file_log(int msg_level,
+ const char *msg, const char *msg_no_nl)
+{
+ ssize_t ret;
+
+ check_log_size();
+ do {
+ ret = write(state.fd, msg, strlen(msg));
+ } while (ret == -1 && errno == EINTR);
+}
+
+#ifdef WITH_SYSLOG
+static void debug_syslog_reload(bool enabled, bool previously_enabled,
+ const char *prog_name, char *option)
+{
+ if (enabled && !previously_enabled) {
+#ifdef LOG_DAEMON
+ openlog(prog_name, LOG_PID, SYSLOG_FACILITY);
+#else
+ /* for old systems that have no facility codes. */
+ openlog(prog_name, LOG_PID );
+#endif
+ return;
+ }
+
+ if (!enabled && previously_enabled) {
+ closelog();
+ }
+}
+
+static void debug_syslog_log(int msg_level,
+ const char *msg, const char *msg_no_nl)
+{
+ int priority;
+
+ priority = debug_level_to_priority(msg_level);
+
+ /*
+ * Specify the facility to interoperate with other syslog
+ * callers (vfs_full_audit for example).
+ */
+ priority |= SYSLOG_FACILITY;
+
+ syslog(priority, "%s", msg);
+}
+#endif /* WITH_SYSLOG */
+
+#if defined(HAVE_LIBSYSTEMD_JOURNAL) || defined(HAVE_LIBSYSTEMD)
+#include <systemd/sd-journal.h>
+static void debug_systemd_log(int msg_level,
+ const char *msg, const char *msg_no_nl)
+{
+ sd_journal_send("MESSAGE=%s", msg_no_nl,
+ "PRIORITY=%d", debug_level_to_priority(msg_level),
+ "LEVEL=%d", msg_level,
+ NULL);
+}
+#endif
+
+#ifdef HAVE_LTTNG_TRACEF
+#include <lttng/tracef.h>
+static void debug_lttng_log(int msg_level,
+ const char *msg, const char *msg_no_nl)
+{
+ tracef(msg_no_nl);
+}
+#endif /* WITH_LTTNG_TRACEF */
+
+#ifdef HAVE_GPFS
+#include "gpfswrap.h"
+static void debug_gpfs_reload(bool enabled, bool previously_enabled,
+ const char *prog_name, char *option)
+{
+ gpfswrap_init();
+
+ if (enabled && !previously_enabled) {
+ gpfswrap_init_trace();
+ return;
+ }
+
+ if (!enabled && previously_enabled) {
+ gpfswrap_fini_trace();
+ return;
+ }
+
+ if (enabled) {
+ /*
+ * Trigger GPFS library to adjust state if necessary.
+ */
+ gpfswrap_query_trace();
+ }
+}
+
+static void debug_gpfs_log(int msg_level,
+ const char *msg, const char *msg_no_nl)
+{
+ gpfswrap_add_trace(msg_level, msg_no_nl);
+}
+#endif /* HAVE_GPFS */
+
+#define DEBUG_RINGBUF_SIZE (1024 * 1024)
+#define DEBUG_RINGBUF_SIZE_OPT "size="
+
+static char *debug_ringbuf;
+static size_t debug_ringbuf_size;
+static size_t debug_ringbuf_ofs;
+
+/* We ensure in debug_ringbuf_log() that this is always \0 terminated */
+char *debug_get_ringbuf(void)
+{
+ return debug_ringbuf;
+}
+
+/* Return the size of the ringbuf (including a \0 terminator) */
+size_t debug_get_ringbuf_size(void)
+{
+ return debug_ringbuf_size;
+}
+
+static void debug_ringbuf_reload(bool enabled, bool previously_enabled,
+ const char *prog_name, char *option)
+{
+ bool cmp;
+ size_t optlen = strlen(DEBUG_RINGBUF_SIZE_OPT);
+
+ debug_ringbuf_size = DEBUG_RINGBUF_SIZE;
+ debug_ringbuf_ofs = 0;
+
+ SAFE_FREE(debug_ringbuf);
+
+ if (!enabled) {
+ return;
+ }
+
+ if (option != NULL) {
+ cmp = strncmp(option, DEBUG_RINGBUF_SIZE_OPT, optlen);
+ if (cmp == 0) {
+ debug_ringbuf_size = (size_t)strtoull(
+ option + optlen, NULL, 10);
+ }
+ }
+
+ debug_ringbuf = calloc(debug_ringbuf_size, sizeof(char));
+ if (debug_ringbuf == NULL) {
+ return;
+ }
+}
+
+static void debug_ringbuf_log(int msg_level,
+ const char *msg,
+ const char *msg_no_nl)
+{
+ size_t msglen = strlen(msg);
+ size_t allowed_size;
+
+ if (debug_ringbuf == NULL) {
+ return;
+ }
+
+ /* Ensure the buffer is always \0 terminated */
+ allowed_size = debug_ringbuf_size - 1;
+
+ if (msglen > allowed_size) {
+ return;
+ }
+
+ if ((debug_ringbuf_ofs + msglen) < debug_ringbuf_ofs) {
+ return;
+ }
+
+ if ((debug_ringbuf_ofs + msglen) > allowed_size) {
+ debug_ringbuf_ofs = 0;
+ }
+
+ memcpy(debug_ringbuf + debug_ringbuf_ofs, msg, msglen);
+ debug_ringbuf_ofs += msglen;
+}
+
+static struct debug_backend {
+ const char *name;
+ int log_level;
+ int new_log_level;
+ void (*reload)(bool enabled, bool prev_enabled,
+ const char *prog_name, char *option);
+ void (*log)(int msg_level, const char *msg, const char *msg_no_nl);
+ char *option;
+} debug_backends[] = {
+ {
+ .name = "file",
+ .log = debug_file_log,
+ },
+#ifdef WITH_SYSLOG
+ {
+ .name = "syslog",
+ .reload = debug_syslog_reload,
+ .log = debug_syslog_log,
+ },
+#endif
+
+#if defined(HAVE_LIBSYSTEMD_JOURNAL) || defined(HAVE_LIBSYSTEMD)
+ {
+ .name = "systemd",
+ .log = debug_systemd_log,
+ },
+#endif
+
+#ifdef HAVE_LTTNG_TRACEF
+ {
+ .name = "lttng",
+ .log = debug_lttng_log,
+ },
+#endif
+
+#ifdef HAVE_GPFS
+ {
+ .name = "gpfs",
+ .reload = debug_gpfs_reload,
+ .log = debug_gpfs_log,
+ },
+#endif
+ {
+ .name = "ringbuf",
+ .log = debug_ringbuf_log,
+ .reload = debug_ringbuf_reload,
+ },
+};
+
+static struct debug_backend *debug_find_backend(const char *name)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ if (strcmp(name, debug_backends[i].name) == 0) {
+ return &debug_backends[i];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * parse "backend[:option][@loglevel]
+ */
+static void debug_backend_parse_token(char *tok)
+{
+ char *backend_name_option, *backend_name,*backend_level, *saveptr;
+ char *backend_option;
+ struct debug_backend *b;
+
+ /*
+ * First parse into backend[:option] and loglevel
+ */
+ backend_name_option = strtok_r(tok, "@\0", &saveptr);
+ if (backend_name_option == NULL) {
+ return;
+ }
+
+ backend_level = strtok_r(NULL, "\0", &saveptr);
+
+ /*
+ * Now parse backend[:option]
+ */
+ backend_name = strtok_r(backend_name_option, ":\0", &saveptr);
+ if (backend_name == NULL) {
+ return;
+ }
+
+ backend_option = strtok_r(NULL, "\0", &saveptr);
+
+ /*
+ * Find and update backend
+ */
+ b = debug_find_backend(backend_name);
+ if (b == NULL) {
+ return;
+ }
+
+ if (backend_level == NULL) {
+ b->new_log_level = MAX_DEBUG_LEVEL;
+ } else {
+ b->new_log_level = atoi(backend_level);
+ }
+
+ if (backend_option != NULL) {
+ b->option = strdup(backend_option);
+ if (b->option == NULL) {
+ return;
+ }
+ }
+}
+
+/*
+ * parse "backend1[:option1][@loglevel1] backend2[option2][@loglevel2] ... "
+ * and enable/disable backends accordingly
+ */
+static void debug_set_backends(const char *param)
+{
+ size_t str_len = strlen(param);
+ char str[str_len+1];
+ char *tok, *saveptr;
+ unsigned i;
+
+ /*
+ * initialize new_log_level to detect backends that have been
+ * disabled
+ */
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ SAFE_FREE(debug_backends[i].option);
+ debug_backends[i].new_log_level = -1;
+ }
+
+ memcpy(str, param, str_len + 1);
+
+ tok = strtok_r(str, LIST_SEP, &saveptr);
+ if (tok == NULL) {
+ return;
+ }
+
+ while (tok != NULL) {
+ debug_backend_parse_token(tok);
+ tok = strtok_r(NULL, LIST_SEP, &saveptr);
+ }
+
+ /*
+ * Let backends react to config changes
+ */
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ struct debug_backend *b = &debug_backends[i];
+
+ if (b->reload) {
+ bool enabled = b->new_log_level > -1;
+ bool previously_enabled = b->log_level > -1;
+
+ b->reload(enabled, previously_enabled, state.prog_name,
+ b->option);
+ }
+ b->log_level = b->new_log_level;
+ }
+}
+
+static void debug_backends_log(const char *msg, int msg_level)
+{
+ char msg_no_nl[FORMAT_BUFR_SIZE];
+ unsigned i;
+ int len;
+
+ /*
+ * Some backends already add an extra newline, so also provide
+ * a buffer without the newline character.
+ */
+ len = MIN(strlen(msg), FORMAT_BUFR_SIZE - 1);
+ if ((len > 0) && (msg[len - 1] == '\n')) {
+ len--;
+ }
+
+ memcpy(msg_no_nl, msg, len);
+ msg_no_nl[len] = '\0';
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ if (msg_level <= debug_backends[i].log_level) {
+ debug_backends[i].log(msg_level, msg, msg_no_nl);
+ }
+ }
+}
+
/* -------------------------------------------------------------------------- **
* External variables.
*/
*/
bool override_logfile;
+static const char *default_classname_table[] = {
+ [DBGC_ALL] = "all",
+ [DBGC_TDB] = "tdb",
+ [DBGC_PRINTDRIVERS] = "printdrivers",
+ [DBGC_LANMAN] = "lanman",
+ [DBGC_SMB] = "smb",
+ [DBGC_RPC_PARSE] = "rpc_parse",
+ [DBGC_RPC_SRV] = "rpc_srv",
+ [DBGC_RPC_CLI] = "rpc_cli",
+ [DBGC_PASSDB] = "passdb",
+ [DBGC_SAM] = "sam",
+ [DBGC_AUTH] = "auth",
+ [DBGC_WINBIND] = "winbind",
+ [DBGC_VFS] = "vfs",
+ [DBGC_IDMAP] = "idmap",
+ [DBGC_QUOTA] = "quota",
+ [DBGC_ACLS] = "acls",
+ [DBGC_LOCKING] = "locking",
+ [DBGC_MSDFS] = "msdfs",
+ [DBGC_DMAPI] = "dmapi",
+ [DBGC_REGISTRY] = "registry",
+ [DBGC_SCAVENGER] = "scavenger",
+ [DBGC_DNS] = "dns",
+ [DBGC_LDB] = "ldb",
+ [DBGC_TEVENT] = "tevent",
+ [DBGC_AUTH_AUDIT] = "auth_audit",
+ [DBGC_AUTH_AUDIT_JSON] = "auth_json_audit",
+ [DBGC_KERBEROS] = "kerberos",
+};
+
/*
* This is to allow reading of DEBUGLEVEL_CLASS before the debug
* system has been initialized.
*/
-static const int debug_class_list_initial[DBGC_MAX_FIXED + 1];
+static const int debug_class_list_initial[ARRAY_SIZE(default_classname_table)];
static int debug_num_classes = 0;
int *DEBUGLEVEL_CLASS = discard_const_p(int, debug_class_list_initial);
* white space. There must be one name for each DBGC_<class name>, and they
* must be in the table in the order of DBGC_<class name>..
*/
-static const char *default_classname_table[] = {
- "all", /* DBGC_ALL; index refs traditional DEBUGLEVEL */
- "tdb", /* DBGC_TDB */
- "printdrivers", /* DBGC_PRINTDRIVERS */
- "lanman", /* DBGC_LANMAN */
- "smb", /* DBGC_SMB */
- "rpc_parse", /* DBGC_RPC_PARSE */
- "rpc_srv", /* DBGC_RPC_SRV */
- "rpc_cli", /* DBGC_RPC_CLI */
- "passdb", /* DBGC_PASSDB */
- "sam", /* DBGC_SAM */
- "auth", /* DBGC_AUTH */
- "winbind", /* DBGC_WINBIND */
- "vfs", /* DBGC_VFS */
- "idmap", /* DBGC_IDMAP */
- "quota", /* DBGC_QUOTA */
- "acls", /* DBGC_ACLS */
- "locking", /* DBGC_LOCKING */
- "msdfs", /* DBGC_MSDFS */
- "dmapi", /* DBGC_DMAPI */
- "registry", /* DBGC_REGISTRY */
- "scavenger", /* DBGC_SCAVENGER */
- "dns", /* DBGC_DNS */
- "ldb", /* DBGC_LDB */
- NULL
-};
static char **classname_table = NULL;
void gfree_debugsyms(void)
{
+ unsigned i;
+
TALLOC_FREE(classname_table);
if ( DEBUGLEVEL_CLASS != debug_class_list_initial ) {
debug_num_classes = 0;
state.initialized = false;
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ SAFE_FREE(debug_backends[i].option);
+ }
}
/****************************************************************************
unsigned int i;
/* prepare strings */
for (i = 0; i < debug_num_classes; i++) {
- buf = talloc_asprintf_append(buf,
+ buf = talloc_asprintf_append(buf,
"%s:%d%s",
classname_table[i],
DEBUGLEVEL_CLASS[i],
Utility to translate names to debug class index's (public version).
****************************************************************************/
-int debug_lookup_classname(const char *classname)
+static int debug_lookup_classname(const char *classname)
{
int ndx;
{
char *class_name;
char *class_level;
- char *saveptr;
+ char *saveptr = NULL;
int ndx;
class_name = strtok_r(param, ":", &saveptr);
}
/****************************************************************************
- parse the debug levels from smbcontrol. Example debug level parameter:
- printdrivers:7
+ Parse the debug levels from smb.conf. Example debug level string:
+ 3 tdb:5 printdrivers:7
+ Note: the 1st param has no "name:" preceeding it.
****************************************************************************/
-static bool debug_parse_params(char **params)
+bool debug_parse_levels(const char *params_str)
{
- int i, ndx;
+ size_t str_len = strlen(params_str);
+ char str[str_len+1];
+ char *tok, *saveptr;
+ int i;
- if (!params)
- return false;
+ /* Just in case */
+ debug_init();
+
+ memcpy(str, params_str, str_len+1);
+
+ tok = strtok_r(str, LIST_SEP, &saveptr);
+ if (tok == NULL) {
+ return true;
+ }
/* Allow DBGC_ALL to be specified w/o requiring its class name e.g."10"
* v.s. "all:10", this is the traditional way to set DEBUGLEVEL
*/
- if (isdigit((int)params[0][0])) {
- DEBUGLEVEL_CLASS[DBGC_ALL] = atoi(params[0]);
- i = 1; /* start processing at the next params */
+ if (isdigit(tok[0])) {
+ DEBUGLEVEL_CLASS[DBGC_ALL] = atoi(tok);
+ tok = strtok_r(NULL, LIST_SEP, &saveptr);
} else {
DEBUGLEVEL_CLASS[DBGC_ALL] = 0;
- i = 0; /* DBGC_ALL not specified OR class name was included */
}
/* Array is debug_num_classes long */
- for (ndx = DBGC_ALL; ndx < debug_num_classes; ndx++) {
- DEBUGLEVEL_CLASS[ndx] = DEBUGLEVEL_CLASS[DBGC_ALL];
+ for (i = DBGC_ALL+1; i < debug_num_classes; i++) {
+ DEBUGLEVEL_CLASS[i] = DEBUGLEVEL_CLASS[DBGC_ALL];
}
- /* Fill in new debug class levels */
- for (; params[i]; i++) {
+ while (tok != NULL) {
bool ok;
- ok = debug_parse_param(params[i]);
+ ok = debug_parse_param(tok);
if (!ok) {
DEBUG(0,("debug_parse_params: unrecognized debug "
- "class name or format [%s]\n", params[i]));
+ "class name or format [%s]\n", tok));
return false;
}
- }
-
- return true;
-}
-
-/****************************************************************************
- Parse the debug levels from smb.conf. Example debug level string:
- 3 tdb:5 printdrivers:7
- Note: the 1st param has no "name:" preceeding it.
-****************************************************************************/
-
-bool debug_parse_levels(const char *params_str)
-{
- char **params;
- /* Just in case */
- debug_init();
+ tok = strtok_r(NULL, LIST_SEP, &saveptr);
+ }
- params = str_list_make(NULL, params_str, NULL);
+ debug_dump_status(5);
- if (debug_parse_params(params)) {
- debug_dump_status(5);
- TALLOC_FREE(params);
- return true;
- } else {
- TALLOC_FREE(params);
- return false;
- }
+ return true;
}
/* setup for logging of talloc warnings */
static void debug_init(void)
{
- const char **p;
+ size_t i;
if (state.initialized)
return;
debug_setup_talloc_log();
- for(p = default_classname_table; *p; p++) {
- debug_add_class(*p);
+ for (i = 0; i < ARRAY_SIZE(default_classname_table); i++) {
+ debug_add_class(default_classname_table[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+ debug_backends[i].log_level = -1;
+ debug_backends[i].new_log_level = -1;
}
}
-/* This forces in some smb.conf derived values into the debug system.
- * There are no pointers in this structure, so we can just
- * structure-assign it in */
-void debug_set_settings(struct debug_settings *settings)
+void debug_set_settings(struct debug_settings *settings,
+ const char *logging_param,
+ int syslog_level, bool syslog_only)
{
+ char fake_param[256];
+ size_t len = 0;
+
+ /*
+ * This forces in some smb.conf derived values into the debug
+ * system. There are no pointers in this structure, so we can
+ * just structure-assign it in
+ */
state.settings = *settings;
+
+ /*
+ * If 'logging' is not set, create backend settings from
+ * deprecated 'syslog' and 'syslog only' parameters
+ */
+ if (logging_param != NULL) {
+ len = strlen(logging_param);
+ }
+ if (len == 0) {
+ if (syslog_only) {
+ snprintf(fake_param, sizeof(fake_param),
+ "syslog@%d", syslog_level - 1);
+ } else {
+ snprintf(fake_param, sizeof(fake_param),
+ "syslog@%d file@%d", syslog_level -1,
+ MAX_DEBUG_LEVEL);
+ }
+
+ logging_param = fake_param;
+ }
+
+ debug_set_backends(logging_param);
}
/**
state.logtype = new_logtype;
}
if (prog_name) {
- state.prog_name = prog_name;
- }
- reopen_logs_internal();
-
- if (state.logtype == DEBUG_FILE) {
-#ifdef WITH_SYSLOG
const char *p = strrchr(prog_name, '/');
- if (p)
+
+ if (p) {
prog_name = p + 1;
-#ifdef LOG_DAEMON
- openlog( prog_name, LOG_PID, SYSLOG_FACILITY );
-#else
- /* for old systems that have no facility codes. */
- openlog( prog_name, LOG_PID );
-#endif
-#endif
+ }
+
+ state.prog_name = prog_name;
}
+ reopen_logs_internal();
}
/***************************************************************************
}
}
+static void debug_callback_log(const char *msg, int msg_level)
+{
+ size_t msg_len = strlen(msg);
+ char msg_copy[msg_len];
+
+ if ((msg_len > 0) && (msg[msg_len-1] == '\n')) {
+ memcpy(msg_copy, msg, msg_len-1);
+ msg_copy[msg_len-1] = '\0';
+ msg = msg_copy;
+ }
+
+ state.callback(state.callback_private, msg_level, msg);
+}
+
/**************************************************************************
reopen the log files
note that we now do this unconditionally
log_overflow = false;
ret = false;
} else {
+ smb_set_close_on_exec(new_fd);
old_fd = state.fd;
state.fd = new_fd;
debug_close_fd(old_fd);
if (dup2(state.fd, 2) == -1) {
/* Close stderr too, if dup2 can't point it -
at the logfile. There really isn't much
- that can be done on such a fundemental
+ that can be done on such a fundamental
failure... */
- close_low_fds(false, false, true);
+ close_low_fd(2);
}
}
(void)reopen_logs_internal();
if (state.fd > 2 && (fstat(state.fd, &st) == 0
&& st.st_size > maxlog)) {
- char *name = NULL;
-
- if (asprintf(&name, "%s.old", state.debugf ) < 0) {
- return;
- }
+ char name[strlen(state.debugf) + 5];
+
+ snprintf(name, sizeof(name), "%s.old", state.debugf);
+
(void)rename(state.debugf, name);
-
+
if (!reopen_logs_internal()) {
/* We failed to reopen a log - continue using the old name. */
(void)rename(name, state.debugf);
}
- SAFE_FREE(name);
}
}
*/
int fd = open( "/dev/console", O_WRONLY, 0);
if (fd != -1) {
+ smb_set_close_on_exec(fd);
state.fd = fd;
DEBUG(0,("check_log_size: open of debug file %s failed - using console.\n",
state.debugf ));
This is called by dbghdr() and format_debug_text().
************************************************************************/
-static int Debug1( const char *format_str, ... )
+static void Debug1(const char *msg)
{
- va_list ap;
int old_errno = errno;
debug_count++;
- if (state.logtype == DEBUG_CALLBACK) {
- char *msg;
- int ret;
- va_start( ap, format_str );
- ret = vasprintf( &msg, format_str, ap );
- if (ret != -1) {
- if (msg[ret - 1] == '\n') {
- msg[ret - 1] = '\0';
- }
- state.callback(state.callback_private, current_msg_level, msg);
- free(msg);
- }
- va_end( ap );
-
- goto done;
-
- } else if ( state.logtype != DEBUG_FILE ) {
- va_start( ap, format_str );
- if (state.fd > 0)
- (void)vdprintf( state.fd, format_str, ap );
- va_end( ap );
- goto done;
- }
-
-#ifdef WITH_SYSLOG
- if( !state.settings.syslog_only)
-#endif
- {
- if( state.fd <= 0 ) {
- mode_t oldumask = umask( 022 );
- int fd = open( state.debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
- (void)umask( oldumask );
- if(fd == -1) {
- goto done;
- }
- state.fd = fd;
- }
- }
-
-
-#ifdef WITH_SYSLOG
- if( current_msg_level < state.settings.syslog ) {
- /* map debug levels to syslog() priorities
- * note that not all DEBUG(0, ...) calls are
- * necessarily errors */
- static const int priority_map[4] = {
- LOG_ERR, /* 0 */
- LOG_WARNING, /* 1 */
- LOG_NOTICE, /* 2 */
- LOG_INFO, /* 3 */
- };
- int priority;
- char *msgbuf = NULL;
- int ret;
-
- if( current_msg_level >= ARRAY_SIZE(priority_map) || current_msg_level < 0)
- priority = LOG_DEBUG;
- else
- priority = priority_map[current_msg_level];
-
- /*
- * Specify the facility to interoperate with other syslog
- * callers (vfs_full_audit for example).
- */
- priority |= SYSLOG_FACILITY;
-
- va_start(ap, format_str);
- ret = vasprintf(&msgbuf, format_str, ap);
- va_end(ap);
-
- if (ret != -1) {
- syslog(priority, "%s", msgbuf);
+ switch(state.logtype) {
+ case DEBUG_CALLBACK:
+ debug_callback_log(msg, current_msg_level);
+ break;
+ case DEBUG_STDOUT:
+ case DEBUG_STDERR:
+ case DEBUG_DEFAULT_STDOUT:
+ case DEBUG_DEFAULT_STDERR:
+ if (state.fd > 0) {
+ ssize_t ret;
+ do {
+ ret = write(state.fd, msg, strlen(msg));
+ } while (ret == -1 && errno == EINTR);
}
- SAFE_FREE(msgbuf);
- }
-#endif
-
- check_log_size();
-
-#ifdef WITH_SYSLOG
- if( !state.settings.syslog_only)
-#endif
- {
- va_start( ap, format_str );
- if (state.fd > 0)
- (void)vdprintf( state.fd, format_str, ap );
- va_end( ap );
- }
+ break;
+ case DEBUG_FILE:
+ debug_backends_log(msg, current_msg_level);
+ break;
+ };
- done:
errno = old_errno;
-
- return( 0 );
}
-
/**************************************************************************
Print the buffer content via Debug1(), then reset the buffer.
Input: none
static void bufr_print( void )
{
format_bufr[format_pos] = '\0';
- (void)Debug1( "%s", format_bufr );
+ (void)Debug1(format_bufr);
format_pos = 0;
}
}
/* If there's room, copy the character to the format buffer. */
- if( format_pos < FORMAT_BUFR_MAX )
+ if (format_pos < FORMAT_BUFR_SIZE - 1)
format_bufr[format_pos++] = msg[i];
/* If a newline is encountered, print & restart. */
/* If the buffer is full dump it out, reset it, and put out a line
* continuation indicator.
*/
- if( format_pos >= FORMAT_BUFR_MAX ) {
+ if (format_pos >= FORMAT_BUFR_SIZE - 1) {
bufr_print();
(void)Debug1( " +>\n" );
}
/***************************************************************************
Print a Debug Header.
- Input: level - Debug level of the message (not the system-wide debug
- level. )
- cls - Debuglevel class of the calling module.
- file - Pointer to a string containing the name of the file
- from which this function was called, or an empty string
- if the __FILE__ macro is not implemented.
- func - Pointer to a string containing the name of the function
- from which this function was called, or an empty string
- if the __FUNCTION__ macro is not implemented.
- line - line number of the call to dbghdr, assuming __LINE__
- works.
+ Input: level - Debug level of the message (not the system-wide debug
+ level. )
+ cls - Debuglevel class of the calling module.
+ location - Pointer to a string containing the name of the file
+ from which this function was called, or an empty string
+ if the __FILE__ macro is not implemented.
+ func - Pointer to a string containing the name of the function
+ from which this function was called, or an empty string
+ if the __FUNCTION__ macro is not implemented.
- Output: Always true. This makes it easy to fudge a call to dbghdr()
- in a macro, since the function can be called as part of a test.
- Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
+ Output: Always true. This makes it easy to fudge a call to dbghdr()
+ in a macro, since the function can be called as part of a test.
+ Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
- Notes: This function takes care of setting current_msg_level.
+ Notes: This function takes care of setting current_msg_level.
****************************************************************************/
/* Ensure we don't lose any real errno value. */
int old_errno = errno;
bool verbose = false;
- char header_str[200];
+ char header_str[300];
+ size_t hs_len;
struct timeval tv;
struct timeval_buf tvbuf;
}
GetTimeOfDay(&tv);
- timeval_str_buf(&tv, state.settings.debug_hires_timestamp, &tvbuf);
+ timeval_str_buf(&tv, false, state.settings.debug_hires_timestamp,
+ &tvbuf);
- snprintf(header_str, sizeof(header_str), "[%s, %2d",
- tvbuf.buf, level);
+ hs_len = snprintf(header_str, sizeof(header_str), "[%s, %2d",
+ tvbuf.buf, level);
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
if (unlikely(DEBUGLEVEL_CLASS[ cls ] >= 10)) {
verbose = true;
}
if (verbose || state.settings.debug_pid) {
- size_t hs_len = strlen(header_str);
- snprintf(header_str + hs_len, sizeof(header_str) - hs_len,
- ", pid=%u", (unsigned int)getpid());
+ hs_len += snprintf(
+ header_str + hs_len, sizeof(header_str) - hs_len,
+ ", pid=%u", (unsigned int)getpid());
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
}
if (verbose || state.settings.debug_uid) {
- size_t hs_len = strlen(header_str);
- snprintf(header_str + hs_len, sizeof(header_str) - hs_len,
- ", effective(%u, %u), real(%u, %u)",
- (unsigned int)geteuid(), (unsigned int)getegid(),
- (unsigned int)getuid(), (unsigned int)getgid());
+ hs_len += snprintf(
+ header_str + hs_len, sizeof(header_str) - hs_len,
+ ", effective(%u, %u), real(%u, %u)",
+ (unsigned int)geteuid(), (unsigned int)getegid(),
+ (unsigned int)getuid(), (unsigned int)getgid());
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
}
if ((verbose || state.settings.debug_class)
&& (cls != DBGC_ALL)) {
- size_t hs_len = strlen(header_str);
- snprintf(header_str + hs_len,
- sizeof(header_str) - hs_len,
- ", class=%s",
- classname_table[cls]);
+ hs_len += snprintf(
+ header_str + hs_len, sizeof(header_str) - hs_len,
+ ", class=%s", classname_table[cls]);
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
}
- strlcat(header_str, "] ", sizeof(header_str));
+ /*
+ * No +=, see man man strlcat
+ */
+ hs_len = strlcat(header_str, "] ", sizeof(header_str));
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
if (!state.settings.debug_prefix_timestamp) {
- size_t hs_len = strlen(header_str);
- snprintf(header_str + hs_len,
- sizeof(header_str) - hs_len,
- "%s(%s)\n", location, func);
+ hs_len += snprintf(
+ header_str + hs_len, sizeof(header_str) - hs_len,
+ "%s(%s)\n", location, func);
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
}
- (void)Debug1("%s", header_str);
+full:
+ (void)Debug1(header_str);
errno = old_errno;
return( true );
***************************************************************************/
- bool dbgtext( const char *format_str, ... )
+static inline bool __dbgtext_va(const char *format_str, va_list ap) PRINTF_ATTRIBUTE(1,0);
+static inline bool __dbgtext_va(const char *format_str, va_list ap)
{
- va_list ap;
char *msgbuf = NULL;
bool ret = true;
int res;
- va_start(ap, format_str);
res = vasprintf(&msgbuf, format_str, ap);
- va_end(ap);
-
if (res != -1) {
format_debug_text(msgbuf);
} else {
SAFE_FREE(msgbuf);
return ret;
}
+
+bool dbgtext_va(const char *format_str, va_list ap)
+{
+ return __dbgtext_va(format_str, ap);
+}
+
+bool dbgtext(const char *format_str, ... )
+{
+ va_list ap;
+ bool ret;
+
+ va_start(ap, format_str);
+ ret = __dbgtext_va(format_str, ap);
+ va_end(ap);
+
+ return ret;
+}