debug Explain the behaviour of setup_logging() more clearly
[sfrench/samba-autobuild/.git] / source3 / lib / debug.c
index 51bb0d754182a99d880d2c56f11e2e772e346a80..f9f4cae000b1c7994a57cfd46a8dfae021f23733 100644 (file)
@@ -20,6 +20,7 @@
 */
 
 #include "includes.h"
+#include "librpc/gen_ndr/messaging.h"
 
 /* -------------------------------------------------------------------------- **
  * Defines...
  *   a newline.
  */
 
+/* state variables for the debug system */
+static struct {
+       int fd;   /* The log file handle */
+       enum debug_logtype logtype; /* The type of logging we are doing: eg stdout, file, stderr */
+       const char *prog_name;
+       bool reopening_logs;
+} state;
+
 /* -------------------------------------------------------------------------- **
  * External variables.
  *
- *  dbf           - Global debug file handle.
  *  debugf        - Debug file name.
  *  DEBUGLEVEL    - System-wide debug message limit.  Messages with message-
  *                  levels higher than DEBUGLEVEL will not be processed.
  */
 
-XFILE   *dbf        = NULL;
 static char *debugf = NULL;
 bool    debug_warn_unknown_class = True;
 bool    debug_auto_add_unknown_class = True;
-bool    AllowDebugChange = True;
 
 /*
    used to check if the user specified a
@@ -90,11 +96,9 @@ bool    AllowDebugChange = True;
 */
 bool    override_logfile;
 
-static TALLOC_CTX *tmp_debug_ctx;
-
 /*
  * This is to allow assignment to DEBUGLEVEL before the debug
- * system has been initialised.
+ * system has been initialized.
  */
 static int debug_all_class_hack = 1;
 static bool debug_all_class_isset_hack = True;
@@ -110,10 +114,6 @@ int     DEBUGLEVEL = &debug_all_class_hack;
 /* -------------------------------------------------------------------------- **
  * Internal variables.
  *
- *  stdout_logging  - Default False, if set to True then dbf will be set to
- *                    stdout and debug output will go to dbf only, and not
- *                    to syslog.  Set in setup_logging() and read in Debug1().
- *
  *  debug_count     - Number of debug messages that have been output.
  *                    Used to check log size.
  *
@@ -134,7 +134,6 @@ int     DEBUGLEVEL = &debug_all_class_hack;
  *                    are unable to open a new log file for some reason.
  */
 
-static bool    stdout_logging = False;
 static int     debug_count    = 0;
 #ifdef WITH_SYSLOG
 static int     syslog_level   = 0;
@@ -183,6 +182,8 @@ static char **classname_table = NULL;
  Free memory pointed to by global pointers.
 ****************************************************************************/
 
+static bool initialized;
+
 void gfree_debugsyms(void)
 {
        int i;
@@ -194,13 +195,23 @@ void gfree_debugsyms(void)
                SAFE_FREE( classname_table );
        }
 
-       if ( DEBUGLEVEL_CLASS != &debug_all_class_hack )
+       if ( DEBUGLEVEL_CLASS != &debug_all_class_hack ) {
                SAFE_FREE( DEBUGLEVEL_CLASS );
+               DEBUGLEVEL_CLASS = &debug_all_class_hack;
+       }
 
-       if ( DEBUGLEVEL_CLASS_ISSET != &debug_all_class_isset_hack )
+       if ( DEBUGLEVEL_CLASS_ISSET != &debug_all_class_isset_hack ) {
                SAFE_FREE( DEBUGLEVEL_CLASS_ISSET );
+               DEBUGLEVEL_CLASS_ISSET = &debug_all_class_isset_hack;
+       }
 
        SAFE_FREE(format_bufr);
+
+       debug_num_classes = 0;
+
+       debug_level = DEBUGLEVEL_CLASS;
+
+       initialized = false;
 }
 
 /****************************************************************************
@@ -457,17 +468,14 @@ bool debug_parse_levels(const char *params_str)
        /* Just in case */
        debug_init();
 
-       if (AllowDebugChange == False)
-               return True;
-
-       params = str_list_make(params_str, NULL);
+       params = str_list_make_v3(talloc_tos(), params_str, NULL);
 
        if (debug_parse_params(params)) {
                debug_dump_status(5);
-               str_list_free(&params);
+               TALLOC_FREE(params);
                return True;
        } else {
-               str_list_free(&params);
+               TALLOC_FREE(params);
                return False;
        }
 }
@@ -476,7 +484,7 @@ bool debug_parse_levels(const char *params_str)
  Receive a "set debug level" message.
 ****************************************************************************/
 
-static void debug_message(struct messaging_context *msg_ctx,
+void debug_message(struct messaging_context *msg_ctx,
                          void *private_data, 
                          uint32_t msg_type, 
                          struct server_id src,
@@ -530,13 +538,12 @@ Init debugging (one time stuff)
 
 void debug_init(void)
 {
-       static bool initialised = False;
        const char **p;
 
-       if (initialised)
+       if (initialized)
                return;
 
-       initialised = True;
+       initialized = true;
 
        for(p = default_classname_table; *p; p++) {
                debug_add_class(*p);
@@ -554,42 +561,40 @@ void debug_register_msgs(struct messaging_context *msg_ctx)
                           debuglevel_message);
 }
 
-/***************************************************************************
- Get ready for syslog stuff
-**************************************************************************/
+/**
+  control the name of the logfile and whether logging will be to stdout, stderr
+  or a file, and set up syslog
 
-void setup_logging(const char *pname, bool interactive)
+  new_log indicates the destination for the debug log (an enum in
+  order of precedence - once set to DEBUG_FILE, it is not possible to
+  reset to DEBUG_STDOUT for example.  This makes it easy to override
+  for debug to stderr on the command line, as the smb.conf cannot
+  reset it back to file-based logging
+*/
+void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
 {
        debug_init();
-
-       /* reset to allow multiple setup calls, going from interactive to
-          non-interactive */
-       stdout_logging = False;
-       if (dbf) {
-               x_fflush(dbf);
-               (void) x_fclose(dbf);
+       if (state.logtype < new_logtype) {
+               state.logtype = new_logtype;
        }
-
-       dbf = NULL;
-
-       if (interactive) {
-               stdout_logging = True;
-               dbf = x_stdout;
-               x_setbuf( x_stdout, NULL );
+       if (prog_name) {
+               state.prog_name = prog_name;
        }
+       reopen_logs();
+
+       if (state.logtype == DEBUG_FILE) {
 #ifdef WITH_SYSLOG
-       else {
-               const char *p = strrchr_m( pname,'/' );
+               const char *p = strrchr_m( prog_name,'/' );
                if (p)
-                       pname = p + 1;
+                       prog_name = p + 1;
 #ifdef LOG_DAEMON
-               openlog( pname, LOG_PID, SYSLOG_FACILITY );
+               openlog( prog_name, LOG_PID, SYSLOG_FACILITY );
 #else
                /* for old systems that have no facility codes. */
-               openlog( pname, LOG_PID );
+               openlog( prog_name, LOG_PID );
 #endif
-       }
 #endif
+       }
 }
 
 /***************************************************************************
@@ -602,6 +607,13 @@ void debug_set_logfile(const char *name)
        debugf = SMB_STRDUP(name);
 }
 
+static void debug_close_fd(int fd)
+{
+       if (fd > 2) {
+               close(fd);
+       }
+}
+
 /**************************************************************************
  reopen the log files
  note that we now do this unconditionally
@@ -610,16 +622,36 @@ void debug_set_logfile(const char *name)
  Fix from dgibson@linuxcare.com.
 **************************************************************************/
 
-bool reopen_logs( void )
+/**
+  reopen the log file (usually called because the log file name might have changed)
+*/
+bool reopen_logs(void)
 {
-       char *fname = NULL;
        mode_t oldumask;
-       XFILE *new_dbf = NULL;
-       XFILE *old_dbf = NULL;
+       int new_fd = 0;
+       int old_fd = 0;
        bool ret = True;
 
-       if (stdout_logging)
-               return True;
+       char *fname = NULL;
+       if (state.reopening_logs) {
+               return true;
+       }
+
+       switch (state.logtype) {
+       case DEBUG_STDOUT:
+               debug_close_fd(state.fd);
+               state.fd = 1;
+               return true;
+
+       case DEBUG_DEFAULT_STDERR:
+       case DEBUG_STDERR:
+               debug_close_fd(state.fd);
+               state.fd = 2;
+               return true;
+
+       case DEBUG_FILE:
+               break;
+       }
 
        oldumask = umask( 022 );
 
@@ -643,21 +675,17 @@ bool reopen_logs( void )
        }
 
        debugf = fname;
-       new_dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);
+       new_fd = open( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644);
 
-       if (!new_dbf) {
+       if (new_fd == -1) {
                log_overflow = True;
                DEBUG(0, ("Unable to open new log file %s: %s\n", debugf, strerror(errno)));
                log_overflow = False;
-               if (dbf)
-                       x_fflush(dbf);
                ret = False;
        } else {
-               x_setbuf(new_dbf, NULL);
-               old_dbf = dbf;
-               dbf = new_dbf;
-               if (old_dbf)
-                       (void) x_fclose(old_dbf);
+               old_fd = state.fd;
+               state.fd = new_fd;
+               debug_close_fd(old_fd);
        }
 
        /* Fix from klausr@ITAP.Physik.Uni-Stuttgart.De
@@ -667,8 +695,8 @@ bool reopen_logs( void )
        force_check_log_size();
        (void)umask(oldumask);
 
-       /* Take over stderr to catch ouput into logs */
-       if (dbf && sys_dup2(x_fileno(dbf), 2) == -1) {
+       /* Take over stderr to catch output into logs */
+       if (state.fd > 0 && dup2(state.fd, 2) == -1) {
                close_low_fds(True); /* Close stderr too, if dup2 can't point it
                                        at the logfile */
        }
@@ -697,7 +725,7 @@ bool need_to_check_log_size( void )
                return( False );
 
        maxlog = lp_max_log_size() * 1024;
-       if( !dbf || maxlog <= 0 ) {
+       if ( state.fd > 0 || maxlog <= 0 ) {
                debug_count = 0;
                return(False);
        }
@@ -718,7 +746,7 @@ void check_log_size( void )
         *  loop check do a new check as root.
         */
 
-       if( geteuid() != 0 )
+       if( geteuid() != sec_initial_uid() )
                return;
 
        if(log_overflow || !need_to_check_log_size() )
@@ -726,9 +754,10 @@ void check_log_size( void )
 
        maxlog = lp_max_log_size() * 1024;
 
-       if( sys_fstat( x_fileno( dbf ), &st ) == 0 && st.st_size > maxlog ) {
+       if(sys_fstat(state.fd, &st, false) == 0
+          && st.st_ex_size > maxlog ) {
                (void)reopen_logs();
-               if( dbf && get_file_size( debugf ) > maxlog ) {
+               if( state.fd > 0 && get_file_size( debugf ) > maxlog ) {
                        char *name = NULL;
 
                        if (asprintf(&name, "%s.old", debugf ) < 0) {
@@ -745,10 +774,10 @@ void check_log_size( void )
        }
 
        /*
-        * Here's where we need to panic if dbf == NULL..
+        * Here's where we need to panic if state.fd == 0 or -1 (invalid values)
         */
 
-       if(dbf == NULL) {
+       if (state.fd <= 0) {
                /* This code should only be reached in very strange
                 * circumstances. If we merely fail to open the new log we
                 * should stick with the old one. ergo this should only be
@@ -756,8 +785,9 @@ void check_log_size( void )
                 * startup or when the log level is increased from zero.
                 * -dwg 6 June 2000
                 */
-               dbf = x_fopen( "/dev/console", O_WRONLY, 0);
-               if(dbf) {
+               int fd = open( "/dev/console", O_WRONLY, 0);
+               if (fd != -1) {
+                       state.fd = fd;
                        DEBUG(0,("check_log_size: open of debug file %s failed - using console.\n",
                                        debugf ));
                } else {
@@ -782,10 +812,10 @@ void check_log_size( void )
 
        debug_count++;
 
-       if( stdout_logging ) {
+       if ( state.logtype != DEBUG_FILE ) {
                va_start( ap, format_str );
-               if(dbf)
-                       (void)x_vfprintf( dbf, format_str, ap );
+               if (state.fd > 0)
+                       (void)vdprintf( state.fd, format_str, ap );
                va_end( ap );
                errno = old_errno;
                goto done;
@@ -800,17 +830,15 @@ void check_log_size( void )
        if( !lp_syslog_only() )
 #endif
        {
-               if( !dbf ) {
+               if( state.fd <= 0 ) {
                        mode_t oldumask = umask( 022 );
-
-                       dbf = x_fopen( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
+                       int fd = open( debugf, O_WRONLY|O_APPEND|O_CREAT, 0644 );
                        (void)umask( oldumask );
-                       if( dbf ) {
-                               x_setbuf( dbf, NULL );
-                       } else {
+                       if(fd == -1) {
                                errno = old_errno;
                                goto done;
                        }
+                       state.fd = fd;
                }
        }
 
@@ -819,7 +847,7 @@ void check_log_size( void )
                /* map debug levels to syslog() priorities
                 * note that not all DEBUG(0, ...) calls are
                 * necessarily errors */
-               static int priority_map[] = {
+               static const int priority_map[4] = {
                        LOG_ERR,     /* 0 */
                        LOG_WARNING, /* 1 */
                        LOG_NOTICE,  /* 2 */
@@ -827,17 +855,24 @@ void check_log_size( void )
                };
                int     priority;
                char *msgbuf = NULL;
+               int ret;
 
-               if( syslog_level >= ( sizeof(priority_map) / sizeof(priority_map[0]) ) || syslog_level < 0)
+               if( syslog_level >= ARRAY_SIZE(priority_map) || syslog_level < 0)
                        priority = LOG_DEBUG;
                else
                        priority = priority_map[syslog_level];
 
+               /*
+                * Specify the facility to interoperate with other syslog
+                * callers (vfs_full_audit for example).
+                */
+               priority |= SYSLOG_FACILITY;
+
                va_start(ap, format_str);
-               vasprintf(&msgbuf, format_str, ap);
+               ret = vasprintf(&msgbuf, format_str, ap);
                va_end(ap);
 
-               if (msgbuf) {
+               if (ret != -1) {
                        syslog(priority, "%s", msgbuf);
                }
                SAFE_FREE(msgbuf);
@@ -851,16 +886,12 @@ void check_log_size( void )
 #endif
        {
                va_start( ap, format_str );
-               if(dbf)
-                       (void)x_vfprintf( dbf, format_str, ap );
+               if (state.fd > 0)
+                       (void)vdprintf( state.fd, format_str, ap );
                va_end( ap );
-               if(dbf)
-                       (void)x_fflush( dbf );
        }
 
  done:
-       TALLOC_FREE(tmp_debug_ctx);
-
        errno = old_errno;
 
        return( 0 );
@@ -899,7 +930,7 @@ static void bufr_print( void )
 static void format_debug_text( const char *msg )
 {
        size_t i;
-       bool timestamp = (!stdout_logging && (lp_timestamp_logs() || !(lp_loaded())));
+       bool timestamp = (state.logtype == DEBUG_FILE && (lp_timestamp_logs() || !(lp_loaded())));
 
        if (!format_bufr) {
                debug_init();
@@ -943,8 +974,6 @@ static void format_debug_text( const char *msg )
 void dbgflush( void )
 {
        bufr_print();
-       if(dbf)
-               (void)x_fflush( dbf );
 }
 
 /***************************************************************************
@@ -970,7 +999,7 @@ void dbgflush( void )
 
 ****************************************************************************/
 
-bool dbghdr(int level, int cls, const char *file, const char *func, int line)
+bool dbghdrclass(int level, int cls, const char *location, const char *func)
 {
        /* Ensure we don't lose any real errno value. */
        int old_errno = errno;
@@ -994,8 +1023,9 @@ bool dbghdr(int level, int cls, const char *file, const char *func, int line)
 #endif
 
        /* Don't print a header if we're logging to stdout. */
-       if( stdout_logging )
+       if ( state.logtype != DEBUG_FILE ) {
                return( True );
+       }
 
        /* Print the header if timestamps are turned on.  If parameters are
         * not yet loaded, then default to timestamps on.
@@ -1028,12 +1058,14 @@ bool dbghdr(int level, int cls, const char *file, const char *func, int line)
                /* Print it all out at once to prevent split syslog output. */
                if( lp_debug_prefix_timestamp() ) {
                    (void)Debug1( "[%s, %2d%s] ",
-                       current_timestring(lp_debug_hires_timestamp()), level,
-                       header_str);
+                       current_timestring(talloc_tos(),
+                                          lp_debug_hires_timestamp()),
+                       level, header_str);
                } else {
-                   (void)Debug1( "[%s, %2d%s] %s:%s(%d)\n",
-                       current_timestring(lp_debug_hires_timestamp()), level,
-                       header_str, file, func, line );
+                   (void)Debug1( "[%s, %2d%s] %s(%s)\n",
+                       current_timestring(talloc_tos(),
+                                          lp_debug_hires_timestamp()),
+                       level, header_str, location, func );
                }
        }
 
@@ -1041,6 +1073,12 @@ bool dbghdr(int level, int cls, const char *file, const char *func, int line)
        return( True );
 }
 
+bool dbghdr(int level, const char *location, const char *func)
+{
+       /* For compatibility with Samba 4, which doesn't have debug classes */
+       return dbghdrclass(level, 0, location, func);
+}
+
 /***************************************************************************
  Add text to the body of the "current" debug message via the format buffer.
 
@@ -1059,12 +1097,13 @@ bool dbghdr(int level, int cls, const char *file, const char *func, int line)
        va_list ap;
        char *msgbuf = NULL;
        bool ret = true;
+       int res;
 
        va_start(ap, format_str);
-       vasprintf(&msgbuf, format_str, ap);
+       res = vasprintf(&msgbuf, format_str, ap);
        va_end(ap);
 
-       if (msgbuf) {
+       if (res != -1) {
                format_debug_text(msgbuf);
        } else {
                ret = false;
@@ -1072,14 +1111,3 @@ bool dbghdr(int level, int cls, const char *file, const char *func, int line)
        SAFE_FREE(msgbuf);
        return ret;
 }
-
-/*
- * Get us a temporary talloc context usable just for DEBUG arguments
- */
-TALLOC_CTX *debug_ctx(void)
-{
-        if (tmp_debug_ctx == NULL) {
-                tmp_debug_ctx = talloc_named_const(NULL, 0, "debug_ctx");
-        }
-        return tmp_debug_ctx;
-}