debug: Move mapping from level to syslog priority to helper function
[sharpe/samba-autobuild/.git] / lib / util / debug.c
index 99ce441526b2f55928d8a53cefaa37d49cd6b0bd..351a88c5c478e12262b6513e468f9977ca062d87 100644 (file)
    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_basic.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.
@@ -97,6 +102,30 @@ static struct {
        .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.
  */
@@ -215,7 +244,7 @@ char *debug_list_class_names_and_levels(void)
        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],
@@ -300,7 +329,7 @@ int debug_add_class(const char *classname)
  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;
 
@@ -362,71 +391,59 @@ static bool debug_parse_param(char *param)
 }
 
 /****************************************************************************
- 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;
-       bool ok;
-
-       /* Just in case */
-       debug_init();
-
-       params = str_list_make(NULL, params_str, NULL);
 
-       ok = debug_parse_params(params);
-       if (ok) {
-               debug_dump_status(5);
+               tok = strtok_r(NULL, LIST_SEP, &saveptr);
        }
 
-       TALLOC_FREE(params);
-       return ok;
+       debug_dump_status(5);
+
+       return true;
 }
 
 /* setup for logging of talloc warnings */
@@ -486,20 +503,23 @@ void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
                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
        }
@@ -550,6 +570,20 @@ void debug_set_callback(void *private_ptr, debug_callback_fn fn)
        }
 }
 
+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
@@ -610,6 +644,7 @@ bool reopen_logs_internal(void)
                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);
@@ -629,7 +664,7 @@ bool reopen_logs_internal(void)
                           at the logfile.  There really isn't much
                           that can be done on such a fundamental
                           failure... */
-                       close_low_fds(false, false, true);
+                       close_low_fd(2);
                }
        }
 
@@ -714,18 +749,16 @@ void check_log_size( void )
                (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);
                }
        }
 
@@ -743,6 +776,7 @@ void check_log_size( void )
                 */
                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 ));
@@ -768,16 +802,7 @@ static int Debug1(const char *msg)
        debug_count++;
 
        if (state.logtype == DEBUG_CALLBACK) {
-               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, current_msg_level, msg);
+               debug_callback_log(msg, current_msg_level);
                goto done;
        }
 
@@ -799,6 +824,7 @@ static int Debug1(const char *msg)
                        if(fd == -1) {
                                goto done;
                        }
+                       smb_set_close_on_exec(fd);
                        state.fd = fd;
                }
        }
@@ -806,21 +832,7 @@ static int Debug1(const char *msg)
 
 #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;
-
-               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
@@ -894,7 +906,7 @@ static void format_debug_text( const char *msg )
                }
 
                /* 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. */
@@ -904,7 +916,7 @@ static void format_debug_text( const char *msg )
                /* 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" );
                }
@@ -989,7 +1001,8 @@ bool dbghdrclass(int level, int cls, const char *location, const char *func)
        }
 
        GetTimeOfDay(&tv);
-       timeval_str_buf(&tv, state.settings.debug_hires_timestamp, &tvbuf);
+       timeval_str_buf(&tv, false, state.settings.debug_hires_timestamp,
+                       &tvbuf);
 
        hs_len = snprintf(header_str, sizeof(header_str), "[%s, %2d",
                          tvbuf.buf, level);
@@ -1068,17 +1081,14 @@ full:
 
 ***************************************************************************/
 
- 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 {
@@ -1087,3 +1097,20 @@ full:
        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;
+}