From 1136e9a25956db37edf1c59f8461296ba160b6f5 Mon Sep 17 00:00:00 2001 From: Matthieu Patou Date: Sun, 19 May 2013 10:02:14 -0700 Subject: [PATCH] param: add debug header template This parameter allow to customize the header that we put in the log, it can also be used so that we have some headers when logging to stdout Signed-off-by: Matthieu Patou Signed-off-by: Jeremy Allison --- lib/param/loadparm.c | 4 +- lib/param/param_functions.c | 1 + lib/param/param_table.c | 9 ++ lib/util/debug.c | 367 ++++++++++++++++++++++++++++++++++++++------ lib/util/debug.h | 1 + lib/util/debug_s3.c | 4 + source3/include/proto.h | 1 + 7 files changed, 342 insertions(+), 45 deletions(-) diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 455c5e6..30771fb 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -500,7 +500,7 @@ const char **lpcfg_parm_string_list(TALLOC_CTX *mem_ctx, const char *value = lpcfg_get_parametric(lp_ctx, service, type, option); if (value != NULL) - return (const char **)str_list_make(mem_ctx, value, separator); + return (const char * const *)str_list_make(mem_ctx, value, separator); return NULL; } @@ -2225,6 +2225,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "allow dns updates", "secure only"); lpcfg_do_global_parameter(lp_ctx, "dns forwarder", ""); + lpcfg_do_global_parameter(lp_ctx, "debug header template", ""); for (i = 0; parm_table[i].label; i++) { if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) { @@ -2319,6 +2320,7 @@ static bool lpcfg_update(struct loadparm_context *lp_ctx) settings.debug_pid = lp_ctx->globals->bDebugPid; settings.debug_uid = lp_ctx->globals->bDebugUid; settings.debug_class = lp_ctx->globals->bDebugClass; + settings.debug_header_template = lp_ctx->globals->szDebugHeaderTemplate; debug_set_settings(&settings); /* FIXME: This is a bit of a hack, but we can't use a global, since diff --git a/lib/param/param_functions.c b/lib/param/param_functions.c index fed2e95..3bab733 100644 --- a/lib/param/param_functions.c +++ b/lib/param/param_functions.c @@ -234,6 +234,7 @@ FN_GLOBAL_BOOL(wins_proxy, bWINSproxy) FN_GLOBAL_CONST_STRING(afs_username_map, szAfsUsernameMap) FN_GLOBAL_CONST_STRING(ctdbd_socket, ctdbdSocket) FN_GLOBAL_CONST_STRING(dedicated_keytab_file, szDedicatedKeytabFile) +FN_GLOBAL_CONST_STRING(debug_header_template, szDebugHeaderTemplate) FN_GLOBAL_CONST_STRING(dnsdomain, szRealm_lower) FN_GLOBAL_CONST_STRING(dns_forwarder, dns_forwarder) FN_GLOBAL_CONST_STRING(dos_charset, dos_charset) diff --git a/lib/param/param_table.c b/lib/param/param_table.c index 1b1497c..1cdec84 100644 --- a/lib/param/param_table.c +++ b/lib/param/param_table.c @@ -1250,6 +1250,15 @@ static struct parm_struct parm_table[] = { .enum_list = NULL, .flags = FLAG_ADVANCED, }, + { + .label = "debug header template", + .type = P_STRING, + .p_class = P_GLOBAL, + .offset = GLOBAL_VAR(szDebugHeaderTemplate), + .special = NULL, + .enum_list = NULL, + .flags = FLAG_ADVANCED, + }, {N_("Protocol Options"), P_SEP, P_SEPARATOR}, diff --git a/lib/util/debug.c b/lib/util/debug.c index a46b275..004a596 100644 --- a/lib/util/debug.c +++ b/lib/util/debug.c @@ -447,12 +447,24 @@ static void debug_init(void) } } -/* 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 */ +/* This forces in some smb.conf derived values into the debug system. */ void debug_set_settings(struct debug_settings *settings) { + /* One pointer we must free. */ + TALLOC_FREE(state.settings.debug_header_template); + state.settings = *settings; + + if (settings->debug_header_template) { + /* Same pointer we must copy. */ + state.settings.debug_header_template = + talloc_strdup(NULL, + settings->debug_header_template); + /* If this allocation fails with NULL + that's ok. We just don't use the header + template. Plus we'll soon have other + problems anyway. */ + } } /** @@ -931,6 +943,233 @@ void dbgflush( void ) } /*************************************************************************** + Expand out any debug header template parameters. +***************************************************************************/ + +static void dbgexpandtemplateparams(char *dest, + unsigned int dest_len, + const char *debug_header_template, + int d_level, + int d_class, + const char *loc, + const char *func) +{ + const char *template_ptr = debug_header_template; + unsigned int dest_offset = 0; + unsigned int template_chars_eaten = 0; + int len; + + /* + * Ensure we have space for at least one non-null character, + * else what's the point ? + */ + + if (dest_len < 2) { + return; + } + + /* Ensure we have null termination, wherever we finish. */ + memset(dest, '\0', dest_len); + + for (;template_ptr[0]; template_ptr += template_chars_eaten) { + /* + * We must have at least one byte of space + * (not including terminating null). + */ + + if (dest_offset >= dest_len - 1) { + return; + } + + /* + * Only characters we escape are '%' and '\\'. + * Deal with the non escape case first - most common. + */ + + if (template_ptr[0] != '%' && template_ptr[0] != '\\') { + dest[dest_offset++] = template_ptr[0]; + template_chars_eaten = 1; + continue; + } + + /* Deal with '\n', '\r', '\s', '\t'. */ + if (template_ptr[0] == '\\') { + switch(template_ptr[1]) { + case 'n': + dest[dest_offset++] = '\n'; + template_chars_eaten = 2; + continue; + case 'r': + dest[dest_offset++] = '\r'; + template_chars_eaten = 2; + continue; + case 's': + dest[dest_offset++] = ' '; + template_chars_eaten = 2; + continue; + case 't': + dest[dest_offset++] = '\t'; + template_chars_eaten = 2; + continue; + default: + /* + * Just add '\\' and + * leave the next character + * for the next go around the loop. + */ + dest[dest_offset++] = '\\'; + template_chars_eaten = 1; + continue; + } + } + + if (template_ptr[0] != '%') { + smb_panic("dbgexpandtemplateparams bad logic\n"); + } + + switch(template_ptr[1]) { + case 'p': + /* PID */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%u", + (unsigned int)getpid()); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 't': + { + /* Timestamp */ + char *time_str = current_timestring(NULL, + state.settings.debug_hires_timestamp); + if (time_str == NULL) { + return; + } + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%s", + time_str); + talloc_free(time_str); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + } + case 'l': + /* log level */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%2d", + d_level); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 'F': + /* Location */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%s", + loc); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 'f': + /* Function */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%s", + func); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 'u': + /* Uid */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%u", + (unsigned int)getuid()); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 'U': + /* Euid */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%u", + (unsigned int)geteuid()); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + break; + case 'g': + /* Gid */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%u", + (unsigned int)getgid()); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 'G': + /* Egid */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%u", + (unsigned int)getegid()); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + case 'c': + /* class */ + len = snprintf(dest + dest_offset, + dest_len - 1 - dest_offset, + "%s", + default_classname_table[d_class]); + if (len < 0) { + return; + } + dest_offset += len; + template_chars_eaten = 2; + continue; + default: + /* + * Just add '%' and + * leave the next character + * for the next go around the loop. + */ + dest[dest_offset++] = '%'; + template_chars_eaten = 1; + continue; + } + } +} + +/*************************************************************************** Print a Debug Header. Input: level - Debug level of the message (not the system-wide debug @@ -979,56 +1218,96 @@ bool dbghdrclass(int level, int cls, const char *location, const char *func) return( true ); } - /* Print the header if timestamps are turned on. If parameters are - * not yet loaded, then default to timestamps on. + /* + * Print the header if timestamps are turned on or if there's a header + * template. If parameters are not yet loaded, then default to + * timestamps on. */ - if( state.settings.timestamp_logs || state.settings.debug_prefix_timestamp) { - bool verbose = false; + if( state.settings.timestamp_logs || + state.settings.debug_prefix_timestamp || + state.settings.debug_header_template) { char header_str[200]; + char expanded_header_str[200]; + + if (state.settings.debug_header_template) { + /* + * User defined debug header template + * overrides the other parameters. + */ + strlcpy(header_str, + state.settings.debug_header_template, + sizeof(header_str)); + } else { + unsigned int len = 0; + bool verbose = false; + /* Current size should be 57 at most right now but + leave some room. */ + char common_header[60]; - header_str[0] = '\0'; + /* + * timestamp logs, or debug prefix timestamp + * set. Create a custom debug header template + * that we will expand. + */ - if (unlikely(DEBUGLEVEL_CLASS[ cls ] >= 10)) { - verbose = true; - } + if (unlikely(DEBUGLEVEL_CLASS[ cls ] >= 10)) { + verbose = true; + } - if (verbose || state.settings.debug_pid) - slprintf(header_str,sizeof(header_str)-1,", pid=%u",(unsigned int)getpid()); + if (verbose || state.settings.debug_pid) { + strlcpy(common_header, + "[%t, %l, pid=%p", + sizeof(common_header)); + } else { + strlcpy(common_header, + "[%t, %l", + sizeof(common_header)); + } - 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_uid) { + len = strlen(common_header); + snprintf(common_header + len, + sizeof(common_header) - len - 1, + ", effective(%%u,%%g), real(%%U,%%G)"); + } - 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_class) + && (cls != DBGC_ALL)) + { + len = strlen(common_header); + snprintf(common_header + len, + sizeof(common_header) - len - 1, + ", class=%%c"); + } - /* 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); + strlcpy(header_str, + common_header, + sizeof(header_str)); + + /* + * Print it all out at once to prevent split syslog + * output. + */ + len = strlen(header_str); + if (state.settings.debug_prefix_timestamp) { + snprintf(header_str + len, + sizeof(header_str) - len - 1, + "] "); + } else { + snprintf(header_str + len, + sizeof(header_str) - len - 1, + "] %%F(%%f)\n"); + } } + + dbgexpandtemplateparams(expanded_header_str, + sizeof(expanded_header_str), + header_str, + level, + cls, + location, + func); + Debug1("%s", expanded_header_str); } errno = old_errno; diff --git a/lib/util/debug.h b/lib/util/debug.h index f7ebfc0..1991ccd 100644 --- a/lib/util/debug.h +++ b/lib/util/debug.h @@ -219,6 +219,7 @@ struct debug_settings { bool debug_pid; bool debug_uid; bool debug_class; + const char *debug_header_template; }; void setup_logging(const char *prog_name, enum debug_logtype new_logtype); diff --git a/lib/util/debug_s3.c b/lib/util/debug_s3.c index ccf577f..eabc92f 100644 --- a/lib/util/debug_s3.c +++ b/lib/util/debug_s3.c @@ -30,6 +30,7 @@ bool reopen_logs(void) { if (lp_loaded()) { struct debug_settings settings; + const char *header_template = lp_debug_header_template(); debug_set_logfile(lp_logfile(talloc_tos())); ZERO_STRUCT(settings); @@ -42,6 +43,9 @@ bool reopen_logs(void) settings.debug_pid = lp_debug_pid(); settings.debug_uid = lp_debug_uid(); settings.debug_class = lp_debug_class(); + settings.debug_header_template = + (header_template && *header_template) ? + header_template : NULL; debug_set_settings(&settings); } return reopen_logs_internal(); diff --git a/source3/include/proto.h b/source3/include/proto.h index 83ab77a..4d8deca 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1485,6 +1485,7 @@ char* lp_perfcount_module(TALLOC_CTX *ctx); void widelinks_warning(int snum); const char *lp_ncalrpc_dir(void); void _lp_set_server_role(int server_role); +const char* lp_debug_header_template(void); /* The following definitions come from param/loadparm_ctx.c */ -- 1.8.3