wslog: Add option to make a list of domains fatal

Add a command line option --log-fatal-domains= and environment variable
WIRESHARK_LOG_FATAL_DOMAINS that aborts the programs if a domain in
the list is logged to.

Negative matches for fatal log domains not implemented for now,
pending a relevant use-case.
This commit is contained in:
João Valverde 2022-09-27 22:55:27 +01:00
parent ad66a854a0
commit b7d15d0767
4 changed files with 96 additions and 22 deletions

View File

@ -10,12 +10,15 @@ For example, "warning" aborts on any "warning", "critical", or "error" messages.
// XXX List available domains if no list is provided? // XXX List available domains if no list is provided?
--log-domains <list>:: Only print messages for the specified log domains, e.g. "GUI,Epan,sshdump". --log-domains <list>:: 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 <list>:: Force the specified domains to log at the "debug" level. --log-debug <list>:: 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 <list>:: Force the specified domains to log at the "noisy" level. --log-noisy <list>:: 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 <list>:: Abort the program if any messages are logged for the specified log domains.
List of domains must be comma-separated. List of domains must be comma-separated.
--log-file <path>:: Write log messages and stderr output to the specified file. --log-file <path>:: Write log messages and stderr output to the specified file.

View File

@ -412,8 +412,9 @@ libwsutil.so.0 libwsutil0 #MINVER#
ws_log_set_debug_filter@Base 3.5.0 ws_log_set_debug_filter@Base 3.5.0
ws_log_set_domain_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_noisy_filter@Base 3.5.0
ws_log_set_fatal@Base 3.5.0 ws_log_set_fatal_domain_filter@Base 4.1.0
ws_log_set_fatal_str@Base 3.5.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@Base 3.5.0
ws_log_set_level_str@Base 3.5.0 ws_log_set_level_str@Base 3.5.0
ws_log_set_writer@Base 3.7.0 ws_log_set_writer@Base 3.7.0

View File

@ -50,6 +50,12 @@
* or "warning". */ * or "warning". */
#define ENV_VAR_FATAL "WIRESHARK_LOG_FATAL" #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 /* Domains that will produce debug output, regardless of log level or
* domain filter. */ * domain filter. */
#define ENV_VAR_DEBUG "WIRESHARK_LOG_DEBUG" #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. */ /* List of domains to output noisy level unconditionally. */
static log_filter_t *noisy_filter = NULL; 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 ws_log_writer_cb *registered_log_writer = NULL;
static void *registered_log_writer_data = 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"; static const char *opt_level = "--log-level";
/* Alias "domain" and "domains". */
static const char *opt_domain = "--log-domain"; 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_file = "--log-file";
static const char *opt_fatal = "--log-fatal"; 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_debug = "--log-debug";
static const char *opt_noisy = "--log-noisy"; static const char *opt_noisy = "--log-noisy";
@ -415,6 +428,25 @@ parse_console_compat_option(char *argv[],
ws_log_set_level(level); 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[], int ws_log_parse_args(int *argc_ptr, char *argv[],
void (*vcmdarg_err)(const char *, va_list ap), 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. */ /* Configure from command line. */
while (*ptr != NULL) { while (*ptr != NULL) {
if (g_str_has_prefix(*ptr, opt_level)) { if (optequal(*ptr, opt_level)) {
option = opt_level; option = opt_level;
optlen = strlen(opt_level); optlen = strlen(opt_level);
} }
else if (g_str_has_prefix(*ptr, opt_domain)) { else if (optequal(*ptr, opt_domain)) {
option = opt_domain; option = opt_domain;
optlen = strlen(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; option = opt_file;
optlen = strlen(opt_file); optlen = strlen(opt_file);
} }
else if (g_str_has_prefix(*ptr, opt_fatal)) { else if (optequal(*ptr, opt_fatal)) {
option = opt_fatal; option = opt_fatal;
optlen = strlen(opt_fatal); optlen = strlen(opt_fatal);
} }
else if (g_str_has_prefix(*ptr, opt_debug)) { else if (optequal(*ptr, opt_debug)) {
option = opt_debug; option = opt_debug;
optlen = strlen(opt_debug); optlen = strlen(opt_debug);
} }
else if (g_str_has_prefix(*ptr, opt_noisy)) { else if (optequal(*ptr, opt_noisy)) {
option = opt_noisy; option = opt_noisy;
optlen = strlen(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) { else if (option == opt_domain) {
ws_log_set_domain_filter(value); 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) { else if (value && option == opt_file) {
FILE *fp = ws_fopen(value, "w"); FILE *fp = ws_fopen(value, "w");
if (fp == NULL) { if (fp == NULL) {
@ -530,7 +573,7 @@ int ws_log_parse_args(int *argc_ptr, char *argv[],
} }
} }
else if (option == opt_fatal) { 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, print_err(vcmdarg_err, exit_failure,
"Fatal log level must be \"critical\" or " "Fatal log level must be \"critical\" or "
"\"warning\", not \"%s\".\n", value); "\"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) void ws_log_set_debug_filter(const char *str_filter)
{ {
free_log_filter(&debug_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) if (level <= LOG_LEVEL_NONE || level >= _LOG_LEVEL_LAST)
return LOG_LEVEL_NONE; 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; enum ws_log_level level;
level = string_to_log_level(str_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); env = g_getenv(ENV_VAR_FATAL);
if (env != NULL) { 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, print_err(vcmdarg_err, LOG_ARGS_NOEXIT,
"Ignoring invalid environment value %s=\"%s\"", "Ignoring invalid environment value %s=\"%s\"",
ENV_VAR_FATAL, env); ENV_VAR_FATAL, env);
@ -773,6 +823,12 @@ void ws_log_init(const char *progname,
else if ((env = g_getenv(ENV_VAR_DOMAIN)) != NULL) else if ((env = g_getenv(ENV_VAR_DOMAIN)) != NULL)
ws_log_set_domain_filter(env); 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); env = g_getenv(ENV_VAR_DEBUG);
if (env != NULL) if (env != NULL)
ws_log_set_debug_filter(env); 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) { if (level >= fatal_log_level && level != LOG_LEVEL_ECHO) {
abort(); abort();
} }
if (fatal_filter != NULL) {
if (filter_contains(fatal_filter, domain) && fatal_filter->positive) {
abort();
}
}
} }

View File

@ -128,6 +128,14 @@ enum ws_log_level ws_log_set_level_str(const char *str_level);
WS_DLL_PUBLIC WS_DLL_PUBLIC
void ws_log_set_domain_filter(const char *domain_filter); 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. /** 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. * Level LOG_LEVEL_ERROR is always fatal.
*/ */
WS_DLL_PUBLIC 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. /** 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. * "warning" instead as arguments.
*/ */
WS_DLL_PUBLIC 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. /** Set the active log writer.