From fbcb1dafbfba7a2b3c23c614de9a66ba23630e32 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 11 Mar 2021 17:54:18 +0200 Subject: [PATCH] lib: Add event_reason_code() for building reason codes easily --- src/lib/lib-event.c | 61 ++++++++++++++++++++++++++++++++++++++++ src/lib/lib-event.h | 15 ++++++++++ src/lib/test-lib-event.c | 61 ++++++++++++++++++++++++++++++++++++++++ src/lib/test-lib.inc | 2 ++ 4 files changed, 139 insertions(+) diff --git a/src/lib/lib-event.c b/src/lib/lib-event.c index 587fb2b5e3..d0afec3740 100644 --- a/src/lib/lib-event.c +++ b/src/lib/lib-event.c @@ -10,6 +10,8 @@ #include "strescape.h" #include "ioloop-private.h" +#include + enum event_code { EVENT_CODE_ALWAYS_LOG_SOURCE = 'a', EVENT_CODE_CATEGORY = 'c', @@ -557,6 +559,65 @@ void event_reason_end(struct event_reason **_reason) i_free(reason); } +const char *event_reason_code(const char *module, const char *name) +{ + return event_reason_code_prefix(module, "", name); +} + +static bool event_reason_code_module_validate(const char *module) +{ + const char *p; + + for (p = module; *p != '\0'; p++) { + if (*p == ' ' || *p == '-' || *p == ':') + return FALSE; + if (i_isupper(*p)) + return FALSE; + } + return TRUE; +} + +const char *event_reason_code_prefix(const char *module, + const char *name_prefix, const char *name) +{ + const char *p; + + i_assert(module[0] != '\0'); + i_assert(name[0] != '\0'); + + if (!event_reason_code_module_validate(module)) { + i_panic("event_reason_code_prefix(): " + "Invalid module '%s'", module); + } + if (!event_reason_code_module_validate(name_prefix)) { + i_panic("event_reason_code_prefix(): " + "Invalid name_prefix '%s'", name_prefix); + } + + string_t *str = t_str_new(strlen(module) + 1 + + strlen(name_prefix) + strlen(name)); + str_append(str, module); + str_append_c(str, ':'); + str_append(str, name_prefix); + + for (p = name; *p != '\0'; p++) { + switch (*p) { + case ' ': + case '-': + str_append_c(str, '_'); + break; + case ':': + i_panic("event_reason_code_prefix(): " + "name has ':' (%s, %s%s)", + module, name_prefix, name); + default: + str_append_c(str, i_tolower(*p)); + break; + } + } + return str_c(str); +} + static struct event * event_set_log_prefix(struct event *event, const char *prefix, bool append) { diff --git a/src/lib/lib-event.h b/src/lib/lib-event.h index 82483518df..9d92901a31 100644 --- a/src/lib/lib-event.h +++ b/src/lib/lib-event.h @@ -213,6 +213,21 @@ event_reason_begin(const char *reason_code, const char *source_filename, /* Finish the reason event. It pops the global event, which means it must be at the top of the stack. */ void event_reason_end(struct event_reason **reason); +/* Generate a reason code as :. This function does some + sanity checks and conversions to make sure the reason codes are reasonable: + + - Assert-crash if module has space, '-', ':' or uppercase characters. + - Assert-crash if module is empty + - Convert name to lowercase. + - Replace all space and '-' in name with '_'. + - Assert-crash if name has ':' + - assert-crash if name is empty +*/ +const char *event_reason_code(const char *module, const char *name); +/* Same as event_reason_code(), but concatenate name_prefix and name. + The name_prefix must not contain spaces, '-', ':' or uppercase characters. */ +const char *event_reason_code_prefix(const char *module, + const char *name_prefix, const char *name); /* Set the appended log prefix string for this event. All the parent events' log prefixes will be concatenated together when logging. The log type diff --git a/src/lib/test-lib-event.c b/src/lib/test-lib-event.c index b0d9532ff4..cfc4106377 100644 --- a/src/lib/test-lib-event.c +++ b/src/lib/test-lib-event.c @@ -29,7 +29,68 @@ static void test_event_strlist(void) test_end(); } +static void test_lib_event_reason_code(void) +{ + test_begin("event reason codes"); + test_assert_strcmp(event_reason_code("foo", "bar"), "foo:bar"); + test_assert_strcmp(event_reason_code("foo", "B A-r"), "foo:b_a_r"); + test_assert_strcmp(event_reason_code_prefix("foo", "x", "bar"), "foo:xbar"); + test_assert_strcmp(event_reason_code_prefix("foo", "", "bar"), "foo:bar"); + test_end(); +} + void test_lib_event(void) { test_event_strlist(); + test_lib_event_reason_code(); +} + +enum fatal_test_state fatal_lib_event(unsigned int stage) +{ + switch (stage) { + case 0: + test_begin("event reason codes - asserts"); + /* module: uppercase */ + test_expect_fatal_string("Invalid module"); + (void)event_reason_code("FOO", "bar"); + return FATAL_TEST_FAILURE; + case 1: + /* module: space */ + test_expect_fatal_string("Invalid module"); + (void)event_reason_code("f oo", "bar"); + return FATAL_TEST_FAILURE; + case 2: + /* module: - */ + test_expect_fatal_string("Invalid module"); + (void)event_reason_code("f-oo", "bar"); + return FATAL_TEST_FAILURE; + case 3: + /* module: empty */ + test_expect_fatal_string("module[0] != '\\0'"); + (void)event_reason_code("", "bar"); + return FATAL_TEST_FAILURE; + case 4: + /* name_prefix: uppercase */ + test_expect_fatal_string("Invalid name_prefix"); + (void)event_reason_code_prefix("module", "FOO", "bar"); + return FATAL_TEST_FAILURE; + case 5: + /* name_prefix: space */ + test_expect_fatal_string("Invalid name_prefix"); + (void)event_reason_code_prefix("module", "f oo", "bar"); + return FATAL_TEST_FAILURE; + case 6: + /* name_prefix: - */ + test_expect_fatal_string("Invalid name_prefix"); + (void)event_reason_code_prefix("module", "f-oo", "bar"); + return FATAL_TEST_FAILURE; + case 7: + /* name: empty */ + test_expect_fatal_string("(name[0] != '\\0')"); + (void)event_reason_code("foo:", ""); + return FATAL_TEST_FAILURE; + default: + test_end(); + return FATAL_TEST_FINISHED; + } } diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index 462c490dff..279c2c7859 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -23,6 +23,8 @@ TEST(test_env_util) FATAL(fatal_env_util) TEST(test_event_category_register) FATAL(fatal_event_category_register) +TEST(test_lib_event) +FATAL(fatal_lib_event) TEST(test_event_filter) TEST(test_event_filter_expr) TEST(test_event_filter_merge) -- 2.47.3