Merge pull request #30784 from poettering/json-dispatch-enum
json: add macro for automatically defining a dispatcher for an enum
This commit is contained in:
+5
-18
@@ -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 },
|
||||
{},
|
||||
};
|
||||
|
||||
|
||||
@@ -429,6 +429,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
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user