]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-json: introduce json_variant_new_devnum() and friends
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 15 Oct 2024 00:15:19 +0000 (09:15 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 15 Oct 2024 10:09:38 +0000 (19:09 +0900)
src/libsystemd/sd-json/json-util.c
src/libsystemd/sd-json/json-util.h
src/libsystemd/sd-json/sd-json.c
src/test/test-json.c

index 0c1dea566af22f51d7547a5434399f6c514f70e0..d49a5d97f965cf6765c55e1f5af730ff8e72499f 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "alloc-util.h"
+#include "devnum-util.h"
 #include "glyph-util.h"
 #include "in-addr-util.h"
 #include "iovec-util.h"
@@ -294,3 +295,46 @@ int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dis
 
         return 0;
 }
+
+int json_variant_new_devnum(sd_json_variant **ret, dev_t devnum) {
+        if (devnum == 0)
+                return sd_json_variant_new_null(ret);
+
+        return sd_json_buildo(
+                        ret,
+                        SD_JSON_BUILD_PAIR_UNSIGNED("major", major(devnum)),
+                        SD_JSON_BUILD_PAIR_UNSIGNED("minor", minor(devnum)));
+}
+
+int json_dispatch_devnum(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+        dev_t *ret = ASSERT_PTR(userdata);
+        int r;
+
+        assert(variant);
+
+        if (sd_json_variant_is_null(variant)) {
+                *ret = 0;
+                return 0;
+        }
+
+        struct {
+                uint32_t major;
+                uint32_t minor;
+        } data;
+
+        static const sd_json_dispatch_field dispatch_table[] = {
+                { "major", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, voffsetof(data, major), SD_JSON_MANDATORY },
+                { "minor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint32, voffsetof(data, minor), SD_JSON_MANDATORY },
+                {}
+        };
+
+        r = sd_json_dispatch(variant, dispatch_table, flags, &data);
+        if (r < 0)
+                return r;
+
+        if (!DEVICE_MAJOR_VALID(data.major) || !DEVICE_MINOR_VALID(data.minor))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid device number.", strna(name));
+
+        *ret = makedev(data.major, data.minor);
+        return 0;
+}
index 6b72d0d93d2cf8bba8f563fa025c6bc1ae021645..1bc5f63abaffbe32365b16759a871a4c0fde7b04 100644 (file)
@@ -114,6 +114,7 @@ int json_dispatch_const_user_group_name(const char *name, sd_json_variant *varia
 int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
 int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
 int json_dispatch_pidref(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
+int json_dispatch_devnum(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
 
 static inline int json_variant_unbase64_iovec(sd_json_variant *v, struct iovec *ret) {
         return sd_json_variant_unbase64(v, ret ? &ret->iov_base : NULL, ret ? &ret->iov_len : NULL);
@@ -147,6 +148,7 @@ enum {
         _JSON_BUILD_RATELIMIT,
         _JSON_BUILD_TRISTATE,
         _JSON_BUILD_PIDREF,
+        _JSON_BUILD_DEVNUM,
 
         _JSON_BUILD_PAIR_INTEGER_NON_ZERO,
         _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE,
@@ -172,6 +174,7 @@ enum {
         _JSON_BUILD_PAIR_OCTESCAPE_NON_EMPTY,
         _JSON_BUILD_PAIR_TRISTATE_NON_NULL,
         _JSON_BUILD_PAIR_PIDREF_NON_NULL,
+        _JSON_BUILD_PAIR_DEVNUM,
 
         _SD_JSON_BUILD_REALLYMAX,
 };
@@ -192,6 +195,7 @@ enum {
 #define JSON_BUILD_RATELIMIT(rl) _JSON_BUILD_RATELIMIT, (const RateLimit*) { rl }
 #define JSON_BUILD_TRISTATE(i) _JSON_BUILD_TRISTATE, (int) { i }
 #define JSON_BUILD_PIDREF(p) _JSON_BUILD_PIDREF, (const PidRef*) { p }
+#define JSON_BUILD_DEVNUM(d) _JSON_BUILD_DEVNUM, (dev_t) { d }
 
 #define JSON_BUILD_PAIR_INTEGER_NON_ZERO(name, i) _JSON_BUILD_PAIR_INTEGER_NON_ZERO, (const char*) { name }, (int64_t) { i }
 #define JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE(name, i) _JSON_BUILD_PAIR_INTEGER_NON_NEGATIVE, (const char*) { name }, (int64_t) { i }
@@ -230,5 +234,7 @@ enum {
 #define JSON_BUILD_PAIR_RATELIMIT(name, rl) SD_JSON_BUILD_PAIR(name, JSON_BUILD_RATELIMIT(rl))
 #define JSON_BUILD_PAIR_TRISTATE(name, i) SD_JSON_BUILD_PAIR(name, JSON_BUILD_TRISTATE(i))
 #define JSON_BUILD_PAIR_PIDREF(name, p) SD_JSON_BUILD_PAIR(name, JSON_BUILD_PIDREF(p))
+#define JSON_BUILD_PAIR_DEVNUM(name, d) SD_JSON_BUILD_PAIR(name, JSON_BUILD_DEVNUM(d))
 
 int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref);
+int json_variant_new_devnum(sd_json_variant **ret, dev_t devnum);
index 2028f222cbcb519ffea044002d9181d46fc9f6ec..297052bdb417efadac0ac0786429c848c58f4988 100644 (file)
@@ -4224,6 +4224,34 @@ _public_ int sd_json_buildv(sd_json_variant **ret, va_list ap) {
                         break;
                 }
 
+                case _JSON_BUILD_DEVNUM: {
+                        dev_t devnum;
+
+                        if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
+                                r = -EINVAL;
+                                goto finish;
+                        }
+
+                        devnum = va_arg(ap, dev_t);
+
+                        if (current->n_suppress == 0) {
+                                r = json_variant_new_devnum(&add, devnum);
+                                if (r < 0)
+                                        goto finish;
+                        }
+
+                        n_subtract = 1;
+
+                        if (current->expect == EXPECT_TOPLEVEL)
+                                current->expect = EXPECT_END;
+                        else if (current->expect == EXPECT_OBJECT_VALUE)
+                                current->expect = EXPECT_OBJECT_KEY;
+                        else
+                                assert(current->expect == EXPECT_ARRAY_ELEMENT);
+
+                        break;
+                }
+
                 case _JSON_BUILD_TRISTATE: {
                         int tristate;
 
index 32cd2858412bac8c09cea62e1fa042ad681e049e..fdf69ac2f74a9d7a98897fbc150a1a86fd96a5fa 100644 (file)
@@ -1307,4 +1307,27 @@ TEST(pidref) {
         pidref_done(&data.pid1);
 }
 
+TEST(devnum) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+        dev_t dev = makedev(123, 456), parsed;
+
+        ASSERT_OK(json_variant_new_devnum(&v, dev));
+        ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
+        ASSERT_OK(json_dispatch_devnum("devnum", v, /* flags= */ 0, &parsed));
+        ASSERT_EQ(major(parsed), major(dev));
+        ASSERT_EQ(minor(parsed), minor(dev));
+        v = sd_json_variant_unref(v);
+
+        dev = makedev(1 << 12, 456);
+        ASSERT_OK(json_variant_new_devnum(&v, dev));
+        ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
+        ASSERT_FAIL(json_dispatch_devnum("devnum", v, /* flags= */ 0, &parsed));
+        v = sd_json_variant_unref(v);
+
+        dev = makedev(123, 1 << 20);
+        ASSERT_OK(json_variant_new_devnum(&v, dev));
+        ASSERT_OK(sd_json_variant_dump(v, SD_JSON_FORMAT_PRETTY_AUTO | SD_JSON_FORMAT_COLOR_AUTO, NULL, NULL));
+        ASSERT_FAIL(json_dispatch_devnum("devnum", v, /* flags= */ 0, &parsed));
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);