diff --git a/doc/diagnostic-options.adoc b/doc/diagnostic-options.adoc index a7f0d10cd6..1500168f1b 100644 --- a/doc/diagnostic-options.adoc +++ b/doc/diagnostic-options.adoc @@ -10,12 +10,15 @@ For example, "warning" aborts on any "warning", "critical", or "error" messages. // XXX List available domains if no list is provided? --log-domains :: Only print messages for the specified log domains, e.g. "GUI,Epan,sshdump". -List of domains must be comma-separated. +List of domains must be comma-separated. Can be negated with "!" as the first character (inverts the match). --log-debug :: Force the specified domains to log at the "debug" level. -List of domains must be comma-separated. +List of domains must be comma-separated. Can be negated with "!" as the first character (inverts the match). --log-noisy :: Force the specified domains to log at the "noisy" level. +List of domains must be comma-separated. Can be negated with "!" as the first character (inverts the match). + +--log-fatal-domains :: Abort the program if any messages are logged for the specified log domains. List of domains must be comma-separated. --log-file :: Write log messages and stderr output to the specified file. diff --git a/packaging/debian/libwsutil0.symbols b/packaging/debian/libwsutil0.symbols index ea3a2472fd..9d064e9e05 100644 --- a/packaging/debian/libwsutil0.symbols +++ b/packaging/debian/libwsutil0.symbols @@ -412,8 +412,9 @@ libwsutil.so.0 libwsutil0 #MINVER# ws_log_set_debug_filter@Base 3.5.0 ws_log_set_domain_filter@Base 3.5.0 ws_log_set_noisy_filter@Base 3.5.0 - ws_log_set_fatal@Base 3.5.0 - ws_log_set_fatal_str@Base 3.5.0 + ws_log_set_fatal_domain_filter@Base 4.1.0 + ws_log_set_fatal_level@Base 4.1.0 + ws_log_set_fatal_level_str@Base 4.1.0 ws_log_set_level@Base 3.5.0 ws_log_set_level_str@Base 3.5.0 ws_log_set_writer@Base 3.7.0 diff --git a/wsutil/wslog.c b/wsutil/wslog.c index bbb9a8c189..3868435e73 100644 --- a/wsutil/wslog.c +++ b/wsutil/wslog.c @@ -50,6 +50,12 @@ * or "warning". */ #define ENV_VAR_FATAL "WIRESHARK_LOG_FATAL" +/* Log domains that are fatal. */ +#define ENV_VAR_FATAL_DOMAIN "WIRESHARK_LOG_FATAL_DOMAIN" + +/* Alias "domain" and "domains". */ +#define ENV_VAR_FATAL_DOMAIN_S "WIRESHARK_LOG_FATAL_DOMAINS" + /* Domains that will produce debug output, regardless of log level or * domain filter. */ #define ENV_VAR_DEBUG "WIRESHARK_LOG_DEBUG" @@ -99,6 +105,9 @@ static log_filter_t *debug_filter = NULL; /* List of domains to output noisy level unconditionally. */ static log_filter_t *noisy_filter = NULL; +/* List of domains that are fatal. */ +static log_filter_t *fatal_filter = NULL; + static ws_log_writer_cb *registered_log_writer = NULL; static void *registered_log_writer_data = NULL; @@ -309,10 +318,14 @@ enum ws_log_level ws_log_set_level_str(const char *str_level) static const char *opt_level = "--log-level"; -/* Alias "domain" and "domains". */ static const char *opt_domain = "--log-domain"; +/* Alias "domain" and "domains". */ +static const char *opt_domain_s = "--log-domains"; static const char *opt_file = "--log-file"; static const char *opt_fatal = "--log-fatal"; +static const char *opt_fatal_domain = "--log-fatal-domain"; +/* Alias "domain" and "domains". */ +static const char *opt_fatal_domain_s = "--log-fatal-domains"; static const char *opt_debug = "--log-debug"; static const char *opt_noisy = "--log-noisy"; @@ -415,6 +428,25 @@ parse_console_compat_option(char *argv[], ws_log_set_level(level); } +/* Match "arg_name=value" or "arg_name value" to opt_name. */ +static bool optequal(const char *arg, const char *opt) +{ + ws_assert(arg); + ws_assert(opt); +#define ARGEND(arg) (*(arg) == '\0' || *(arg) == ' ' || *(arg) == '=') + + while (!ARGEND(arg) && *opt != '\0') { + if (*arg != *opt) { + return false; + } + arg += 1; + opt += 1; + } + if (ARGEND(arg) && *opt == '\0') { + return true; + } + return false; +} int ws_log_parse_args(int *argc_ptr, char *argv[], void (*vcmdarg_err)(const char *, va_list ap), @@ -433,31 +465,39 @@ int ws_log_parse_args(int *argc_ptr, char *argv[], /* Configure from command line. */ while (*ptr != NULL) { - if (g_str_has_prefix(*ptr, opt_level)) { + if (optequal(*ptr, opt_level)) { option = opt_level; optlen = strlen(opt_level); } - else if (g_str_has_prefix(*ptr, opt_domain)) { + else if (optequal(*ptr, opt_domain)) { option = opt_domain; optlen = strlen(opt_domain); - /* Alias "domain" and "domains". Last form wins. */ - if (*(*ptr + optlen) == 's') { - optlen += 1; - } } - else if (g_str_has_prefix(*ptr, opt_file)) { + else if (optequal(*ptr, opt_domain_s)) { + option = opt_domain; /* Alias */ + optlen = strlen(opt_domain_s); + } + else if (optequal(*ptr, opt_fatal_domain)) { + option = opt_fatal_domain; + optlen = strlen(opt_fatal_domain); + } + else if (optequal(*ptr, opt_fatal_domain_s)) { + option = opt_fatal_domain; /* Alias */ + optlen = strlen(opt_fatal_domain_s); + } + else if (optequal(*ptr, opt_file)) { option = opt_file; optlen = strlen(opt_file); } - else if (g_str_has_prefix(*ptr, opt_fatal)) { + else if (optequal(*ptr, opt_fatal)) { option = opt_fatal; optlen = strlen(opt_fatal); } - else if (g_str_has_prefix(*ptr, opt_debug)) { + else if (optequal(*ptr, opt_debug)) { option = opt_debug; optlen = strlen(opt_debug); } - else if (g_str_has_prefix(*ptr, opt_noisy)) { + else if (optequal(*ptr, opt_noisy)) { option = opt_noisy; optlen = strlen(opt_noisy); } @@ -517,6 +557,9 @@ int ws_log_parse_args(int *argc_ptr, char *argv[], else if (option == opt_domain) { ws_log_set_domain_filter(value); } + else if (option == opt_fatal_domain) { + ws_log_set_fatal_domain_filter(value); + } else if (value && option == opt_file) { FILE *fp = ws_fopen(value, "w"); if (fp == NULL) { @@ -530,7 +573,7 @@ int ws_log_parse_args(int *argc_ptr, char *argv[], } } else if (option == opt_fatal) { - if (ws_log_set_fatal_str(value) == LOG_LEVEL_NONE) { + if (ws_log_set_fatal_level_str(value) == LOG_LEVEL_NONE) { print_err(vcmdarg_err, exit_failure, "Fatal log level must be \"critical\" or " "\"warning\", not \"%s\".\n", value); @@ -626,6 +669,13 @@ void ws_log_set_domain_filter(const char *str_filter) } +void ws_log_set_fatal_domain_filter(const char *str_filter) +{ + free_log_filter(&fatal_filter); + tokenize_filter_str(&fatal_filter, str_filter, LOG_LEVEL_NONE); +} + + void ws_log_set_debug_filter(const char *str_filter) { free_log_filter(&debug_filter); @@ -640,7 +690,7 @@ void ws_log_set_noisy_filter(const char *str_filter) } -enum ws_log_level ws_log_set_fatal(enum ws_log_level level) +enum ws_log_level ws_log_set_fatal_level(enum ws_log_level level) { if (level <= LOG_LEVEL_NONE || level >= _LOG_LEVEL_LAST) return LOG_LEVEL_NONE; @@ -654,12 +704,12 @@ enum ws_log_level ws_log_set_fatal(enum ws_log_level level) } -enum ws_log_level ws_log_set_fatal_str(const char *str_level) +enum ws_log_level ws_log_set_fatal_level_str(const char *str_level) { enum ws_log_level level; level = string_to_log_level(str_level); - return ws_log_set_fatal(level); + return ws_log_set_fatal_level(level); } @@ -760,7 +810,7 @@ void ws_log_init(const char *progname, env = g_getenv(ENV_VAR_FATAL); if (env != NULL) { - if (ws_log_set_fatal_str(env) == LOG_LEVEL_NONE) { + if (ws_log_set_fatal_level_str(env) == LOG_LEVEL_NONE) { print_err(vcmdarg_err, LOG_ARGS_NOEXIT, "Ignoring invalid environment value %s=\"%s\"", ENV_VAR_FATAL, env); @@ -773,6 +823,12 @@ void ws_log_init(const char *progname, else if ((env = g_getenv(ENV_VAR_DOMAIN)) != NULL) ws_log_set_domain_filter(env); + /* Alias "domain" and "domains". The plural form wins. */ + if ((env = g_getenv(ENV_VAR_FATAL_DOMAIN_S)) != NULL) + ws_log_set_fatal_domain_filter(env); + else if ((env = g_getenv(ENV_VAR_FATAL_DOMAIN)) != NULL) + ws_log_set_fatal_domain_filter(env); + env = g_getenv(ENV_VAR_DEBUG); if (env != NULL) ws_log_set_debug_filter(env); @@ -975,6 +1031,12 @@ static void log_write_dispatch(const char *domain, enum ws_log_level level, if (level >= fatal_log_level && level != LOG_LEVEL_ECHO) { abort(); } + + if (fatal_filter != NULL) { + if (filter_contains(fatal_filter, domain) && fatal_filter->positive) { + abort(); + } + } } diff --git a/wsutil/wslog.h b/wsutil/wslog.h index 0306791d05..e194604e13 100644 --- a/wsutil/wslog.h +++ b/wsutil/wslog.h @@ -128,6 +128,14 @@ enum ws_log_level ws_log_set_level_str(const char *str_level); WS_DLL_PUBLIC void ws_log_set_domain_filter(const char *domain_filter); +/** Set a fatal domain filter from a string. + * + * Domain filter is a case insensitive list separated by ',' or ';'. Domains + * in the filter will cause the program to abort. + */ +WS_DLL_PUBLIC +void ws_log_set_fatal_domain_filter(const char *domain_filter); + /** Set a debug filter from a string. * @@ -155,7 +163,7 @@ void ws_log_set_noisy_filter(const char *str_filter); * Level LOG_LEVEL_ERROR is always fatal. */ WS_DLL_PUBLIC -enum ws_log_level ws_log_set_fatal(enum ws_log_level level); +enum ws_log_level ws_log_set_fatal_level(enum ws_log_level level); /** Set the fatal log level from a string. @@ -164,7 +172,7 @@ enum ws_log_level ws_log_set_fatal(enum ws_log_level level); * "warning" instead as arguments. */ WS_DLL_PUBLIC -enum ws_log_level ws_log_set_fatal_str(const char *str_level); +enum ws_log_level ws_log_set_fatal_level_str(const char *str_level); /** Set the active log writer.