From dda6629622e8546e3d9311f8897bdcbe6f0c1269 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 4 Dec 2023 18:12:10 +0100 Subject: [PATCH 1/4] json: add macro for automatically defining a dispatcher for an enum --- src/shared/json.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/shared/json.h b/src/shared/json.h index 975cf562a9..acf045c21e 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -428,6 +428,28 @@ assert_cc(sizeof(uint32_t) == sizeof(unsigned)); assert_cc(sizeof(int32_t) == sizeof(int)); #define json_dispatch_int json_dispatch_int32 +#define JSON_DISPATCH_ENUM_DEFINE(name, type, func) \ + int name(const char *n, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { \ + type *c = ASSERT_PTR(userdata); \ + \ + assert(variant); \ + \ + if (json_variant_is_null(variant)) { \ + *c = (type) -EINVAL; \ + return 0; \ + } \ + \ + if (!json_variant_is_string(variant)) \ + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(n)); \ + \ + type cc = func(json_variant_string(variant)); \ + if (cc < 0) \ + return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Value of JSON field '%s' not recognized.", strna(n)); \ + \ + *c = cc; \ + return 0; \ + } + static inline int json_dispatch_level(JsonDispatchFlags flags) { /* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as From 8618ff1368844936eccdfc58afeed0f29f863551 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 5 Jan 2024 12:00:35 +0100 Subject: [PATCH 2/4] test: add unit test for JSON_DISPATCH_ENUM_DEFINE() --- src/test/test-json.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/test/test-json.c b/src/test/test-json.c index 4ceb084c0c..42e8532417 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -9,6 +9,7 @@ #include "json-internal.h" #include "json.h" #include "math-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "tests.h" @@ -824,6 +825,56 @@ TEST(json_dispatch) { assert_se(foobar.l == INT16_MIN); } +typedef enum mytestenum { + myfoo, mybar, mybaz, _mymax, _myinvalid = -EINVAL, +} mytestenum; + +static const char *mytestenum_table[_mymax] = { + [myfoo] = "myfoo", + [mybar] = "mybar", + [mybaz] = "mybaz", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(mytestenum, mytestenum); + +static JSON_DISPATCH_ENUM_DEFINE(dispatch_mytestenum, mytestenum, mytestenum_from_string); + +TEST(json_dispatch_enum_define) { + + struct data { + mytestenum a, b, c, d; + } data = { + .a = _myinvalid, + .b = _myinvalid, + .c = _myinvalid, + .d = mybar, + }; + + _cleanup_(json_variant_unrefp) JsonVariant *j = NULL; + + assert_se(json_build(&j, JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("a", JSON_BUILD_STRING("mybaz")), + JSON_BUILD_PAIR("b", JSON_BUILD_STRING("mybar")), + JSON_BUILD_PAIR("c", JSON_BUILD_STRING("myfoo")), + JSON_BUILD_PAIR("d", JSON_BUILD_NULL))) >= 0); + + assert_se(json_dispatch(j, + (const JsonDispatch[]) { + { "a", _JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, a), 0 }, + { "b", _JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, b), 0 }, + { "c", _JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, c), 0 }, + { "d", _JSON_VARIANT_TYPE_INVALID, dispatch_mytestenum, offsetof(struct data, d), 0 }, + {}, + }, + /* flags= */ 0, + &data) >= 0); + + assert(data.a == mybaz); + assert(data.b == mybar); + assert(data.c == myfoo); + assert(data.d < 0); +} + TEST(json_sensitive) { _cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL, *v = NULL; _cleanup_free_ char *s = NULL; From 19f32829299c02ec3c35dc58d2f8019ff75a952b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 5 Jan 2024 12:06:52 +0100 Subject: [PATCH 3/4] user-record: port over to JSON_DISPATCH_ENUM_DEFINE() --- src/shared/user-record.c | 45 +++++----------------------------------- 1 file changed, 5 insertions(+), 40 deletions(-) diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 3fe3e80b83..548d86c031 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -535,43 +535,8 @@ static int json_dispatch_environment(const char *name, JsonVariant *variant, Jso return strv_free_and_replace(*l, n); } -int json_dispatch_user_disposition(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { - UserDisposition *disposition = userdata, k; - - if (json_variant_is_null(variant)) { - *disposition = _USER_DISPOSITION_INVALID; - return 0; - } - - if (!json_variant_is_string(variant)) - return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); - - k = user_disposition_from_string(json_variant_string(variant)); - if (k < 0) - return json_log(variant, flags, k, "Disposition type '%s' not known.", json_variant_string(variant)); - - *disposition = k; - return 0; -} - -static int json_dispatch_storage(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { - UserStorage *storage = userdata, k; - - if (json_variant_is_null(variant)) { - *storage = _USER_STORAGE_INVALID; - return 0; - } - - if (!json_variant_is_string(variant)) - return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); - - k = user_storage_from_string(json_variant_string(variant)); - if (k < 0) - return json_log(variant, flags, k, "Storage type '%s' not known.", json_variant_string(variant)); - - *storage = k; - return 0; -} +JSON_DISPATCH_ENUM_DEFINE(json_dispatch_user_disposition, UserDisposition, user_disposition_from_string); +static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_user_storage, UserStorage, user_storage_from_string); static int json_dispatch_tasks_or_memory_max(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { uint64_t *limit = userdata, k; @@ -1055,7 +1020,7 @@ static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatch { "fileSystemUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, file_system_uuid), 0 }, { "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 }, { "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 }, - { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 }, + { "storage", JSON_VARIANT_STRING, json_dispatch_user_storage, offsetof(UserRecord, storage), 0 }, { "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE }, { "luksCipher", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher), JSON_SAFE }, { "luksCipherMode", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_cipher_mode), JSON_SAFE }, @@ -1185,7 +1150,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 }, { "notBeforeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 }, { "notAfterUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 }, - { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 }, + { "storage", JSON_VARIANT_STRING, json_dispatch_user_storage, offsetof(UserRecord, storage), 0 }, { "diskSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 }, { "diskSizeRelative", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 }, { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 }, @@ -1540,7 +1505,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla { "locked", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, locked), 0 }, { "notBeforeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_before_usec), 0 }, { "notAfterUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, not_after_usec), 0 }, - { "storage", JSON_VARIANT_STRING, json_dispatch_storage, offsetof(UserRecord, storage), 0 }, + { "storage", JSON_VARIANT_STRING, json_dispatch_user_storage, offsetof(UserRecord, storage), 0 }, { "diskSize", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size), 0 }, { "diskSizeRelative", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(UserRecord, disk_size_relative), 0 }, { "skeletonDirectory", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, skeleton_directory), 0 }, From 00096a35491dc0e3755705531f727677e5d0fa04 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 5 Jan 2024 11:50:47 +0100 Subject: [PATCH 4/4] oomd: make use of new JSON_DISPATCH_ENUM_DEFINE() macro --- src/oom/oomd-manager.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c index 23c3ae64ab..839936ce7c 100644 --- a/src/oom/oomd-manager.c +++ b/src/oom/oomd-manager.c @@ -30,30 +30,17 @@ static void managed_oom_message_destroy(ManagedOOMMessage *message) { free(message->property); } -static int managed_oom_mode(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) { - ManagedOOMMode *mode = userdata, m; - const char *s; - - assert(mode); - assert_se(s = json_variant_string(v)); - - m = managed_oom_mode_from_string(s); - if (m < 0) - return json_log(v, flags, m, "%s is not a valid ManagedOOMMode", s); - - *mode = m; - return 0; -} +static JSON_DISPATCH_ENUM_DEFINE(dispatch_managed_oom_mode, ManagedOOMMode, managed_oom_mode_from_string); static int process_managed_oom_message(Manager *m, uid_t uid, JsonVariant *parameters) { JsonVariant *c, *cgroups; int r; static const JsonDispatch dispatch_table[] = { - { "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMMessage, mode), JSON_MANDATORY }, - { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMMessage, path), JSON_MANDATORY }, - { "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMMessage, property), JSON_MANDATORY }, - { "limit", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(ManagedOOMMessage, limit), 0 }, + { "mode", JSON_VARIANT_STRING, dispatch_managed_oom_mode, offsetof(ManagedOOMMessage, mode), JSON_MANDATORY }, + { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMMessage, path), JSON_MANDATORY }, + { "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMMessage, property), JSON_MANDATORY }, + { "limit", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint32, offsetof(ManagedOOMMessage, limit), 0 }, {}, };