along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "includes.h"
+#include <talloc.h>
+#include "replace.h"
#include "system/filesys.h"
#include "system/syslog.h"
-#include "lib/util/time.h"
+#include "system/locale.h"
+#include "time_basic.h"
+#include "close_low_fd.h"
+#include "memory.h"
+#include "samba_util.h" /* LIST_SEP */
+#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 */
};
+#ifdef WITH_SYSLOG
+static int debug_level_to_priority(int level)
+{
+ /*
+ * 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;
+
+ if( level >= ARRAY_SIZE(priority_map) || level < 0)
+ priority = LOG_DEBUG;
+ else
+ priority = priority_map[level];
+
+ return priority;
+}
+#endif
+
/* -------------------------------------------------------------------------- **
* External variables.
*/
static int debug_count = 0;
static int current_msg_level = 0;
-static char *format_bufr = NULL;
+static char format_bufr[FORMAT_BUFR_SIZE];
static size_t format_pos = 0;
static bool log_overflow = false;
DEBUGLEVEL_CLASS = discard_const_p(int, debug_class_list_initial);
}
- TALLOC_FREE(format_bufr);
-
debug_num_classes = 0;
state.initialized = false;
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;
}
/****************************************************************************
- 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 (; i < debug_num_classes && 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 */
for(p = default_classname_table; *p; p++) {
debug_add_class(*p);
}
- format_bufr = talloc_array(NULL, char, FORMAT_BUFR_SIZE);
- if (!format_bufr) {
- smb_panic("debug_init: unable to create buffer");
- }
}
/* This forces in some smb.conf derived values into the debug system.
state.logtype = new_logtype;
}
if (prog_name) {
+ const char *p = strrchr(prog_name, '/');
+
+ if (p) {
+ prog_name = p + 1;
+ }
+
state.prog_name = prog_name;
}
reopen_logs_internal();
if (state.logtype == DEBUG_FILE) {
#ifdef WITH_SYSLOG
- const char *p = strrchr(prog_name, '/');
- if (p)
- prog_name = p + 1;
#ifdef LOG_DAEMON
- openlog( prog_name, LOG_PID, SYSLOG_FACILITY );
+ openlog(state.prog_name, LOG_PID, SYSLOG_FACILITY );
#else
/* for old systems that have no facility codes. */
- openlog( prog_name, LOG_PID );
+ openlog(state.prog_name, LOG_PID );
#endif
#endif
}
}
}
+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 int 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 );
-
+ debug_callback_log(msg, current_msg_level);
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 );
- errno = old_errno;
+ if ( state.logtype != DEBUG_FILE ) {
+ if (state.fd > 0) {
+ write(state.fd, msg, strlen(msg));
+ }
goto done;
}
int fd = open( state.debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
(void)umask( oldumask );
if(fd == -1) {
- errno = old_errno;
goto done;
}
+ smb_set_close_on_exec(fd);
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];
+ int priority = debug_level_to_priority(current_msg_level);
/*
* Specify the facility to interoperate with other syslog
*/
priority |= SYSLOG_FACILITY;
- va_start(ap, format_str);
- ret = vasprintf(&msgbuf, format_str, ap);
- va_end(ap);
-
- if (ret != -1) {
- syslog(priority, "%s", msgbuf);
- }
- SAFE_FREE(msgbuf);
+ syslog(priority, "%s", msg);
}
#endif
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 );
+ if (state.fd > 0) {
+ write(state.fd, msg, strlen(msg));
+ }
}
done:
static void bufr_print( void )
{
format_bufr[format_pos] = '\0';
- (void)Debug1( "%s", format_bufr );
+ (void)Debug1(format_bufr);
format_pos = 0;
}
size_t i;
bool timestamp = (state.logtype == DEBUG_FILE && (state.settings.timestamp_logs));
- if (!format_bufr) {
- debug_init();
- }
+ debug_init();
for( i = 0; msg[i]; i++ ) {
/* Indent two spaces at each new line. */
}
/* 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" );
}
{
/* Ensure we don't lose any real errno value. */
int old_errno = errno;
+ bool verbose = false;
+ char header_str[300];
+ size_t hs_len;
+ struct timeval tv;
+ struct timeval_buf tvbuf;
if( format_pos ) {
/* This is a fudge. If there is stuff sitting in the format_bufr, then
/* Print the header if timestamps are turned on. If parameters are
* not yet loaded, then default to timestamps on.
*/
- if( state.settings.timestamp_logs || state.settings.debug_prefix_timestamp) {
- bool verbose = false;
- char header_str[200];
+ if (!(state.settings.timestamp_logs ||
+ state.settings.debug_prefix_timestamp)) {
+ return true;
+ }
- header_str[0] = '\0';
+ GetTimeOfDay(&tv);
+ timeval_str_buf(&tv, false, state.settings.debug_hires_timestamp,
+ &tvbuf);
- if (unlikely(DEBUGLEVEL_CLASS[ cls ] >= 10)) {
- verbose = true;
- }
+ hs_len = snprintf(header_str, sizeof(header_str), "[%s, %2d",
+ tvbuf.buf, level);
+ if (hs_len >= sizeof(header_str)) {
+ goto full;
+ }
- if (verbose || state.settings.debug_pid)
- slprintf(header_str,sizeof(header_str)-1,", pid=%u",(unsigned int)getpid());
+ if (unlikely(DEBUGLEVEL_CLASS[ cls ] >= 10)) {
+ verbose = true;
+ }
- if (verbose || state.settings.debug_uid) {
- size_t hs_len = strlen(header_str);
- slprintf(header_str + hs_len,
- sizeof(header_str) - 1 - hs_len,
- ", effective(%u, %u), real(%u, %u)",
- (unsigned int)geteuid(), (unsigned int)getegid(),
- (unsigned int)getuid(), (unsigned int)getgid());
+ if (verbose || state.settings.debug_pid) {
+ 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_class)
- && (cls != DBGC_ALL)) {
- size_t hs_len = strlen(header_str);
- slprintf(header_str + hs_len,
- sizeof(header_str) -1 - hs_len,
- ", class=%s",
- classname_table[cls]);
+ if (verbose || state.settings.debug_uid) {
+ 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;
}
+ }
- /* Print it all out at once to prevent split syslog output. */
- if( state.settings.debug_prefix_timestamp ) {
- char *time_str = current_timestring(NULL,
- state.settings.debug_hires_timestamp);
- (void)Debug1( "[%s, %2d%s] ",
- time_str,
- level, header_str);
- talloc_free(time_str);
- } else {
- char *time_str = current_timestring(NULL,
- state.settings.debug_hires_timestamp);
- (void)Debug1( "[%s, %2d%s] %s(%s)\n",
- time_str,
- level, header_str, location, func );
- talloc_free(time_str);
+ if ((verbose || state.settings.debug_class)
+ && (cls != DBGC_ALL)) {
+ 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;
}
}
+ /*
+ * 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) {
+ 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;
+ }
+ }
+
+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;
+}