]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
json-util: add json_dispatch_job_id() dispatcher for job IDs
authorIvan Kruglov <mail@ikruglov.com>
Fri, 15 May 2026 10:16:00 +0000 (03:16 -0700)
committerIvan Kruglov <mail@ikruglov.com>
Mon, 18 May 2026 07:33:47 +0000 (00:33 -0700)
Job IDs are uint32_t values that are always >= 1 (the manager's ID counter starts at 1 and wraps from UINT32_MAX back to 1, never assigning 0). Add a dedicated dispatch function that validates this constraint, rejecting 0 and treating null as "unset" (0).

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
src/libsystemd/sd-json/json-util.c
src/libsystemd/sd-json/json-util.h
src/libsystemd/sd-json/test-json.c

index 40102a69989edf5e5aa7d9be80d766b90cfc7c09..c6727ac760ae488964dd2bfe04189442f7849ca5 100644 (file)
@@ -796,6 +796,27 @@ int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_jso
         return 0;
 }
 
+int json_dispatch_job_id(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
+        uint32_t *id = ASSERT_PTR(userdata);
+        uint32_t k;
+        int r;
+
+        if (sd_json_variant_is_null(variant)) {
+                *id = 0;
+                return 0;
+        }
+
+        r = sd_json_dispatch_uint32(name, variant, flags, &k);
+        if (r < 0)
+                return r;
+
+        if (k == 0)
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid job ID.", strna(name));
+
+        *id = k;
+        return 0;
+}
+
 int json_variant_compare(sd_json_variant *a, sd_json_variant *b) {
         int r;
 
index 0b5ea32f87ddd438c740b40eb0c2697a292d8ca6..48a0afa289d554a1be2ac2b11595da210077b24e 100644 (file)
@@ -132,6 +132,7 @@ int json_dispatch_ifindex(const char *name, sd_json_variant *variant, sd_json_di
 int json_dispatch_log_level(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
 int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
 int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
+int json_dispatch_job_id(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);
index 3be4b09660b140157c2dbd1cab326abf819d89b7..5d5765b35441fe619c3e3ca1990ff553e7bea747 100644 (file)
@@ -1569,6 +1569,69 @@ TEST(access_mode) {
                                   &mm), ERANGE);
 }
 
+TEST(job_id) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
+
+        ASSERT_OK(sd_json_parse("{\"a\": 1, \"b\": 4294967295, \"c\": null}",
+                                /* flags= */ 0,
+                                &v,
+                                /* reterr_line= */ NULL,
+                                /* reterr_column= */ NULL));
+
+        struct {
+                uint32_t a, b, c;
+        } data = { 99, 99, 99 };
+
+        ASSERT_OK(sd_json_dispatch(
+                                  v,
+                                  (const sd_json_dispatch_field[]) {
+                                          { "a", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_job_id, voffsetof(data, a), 0 },
+                                          { "b", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_job_id, voffsetof(data, b), 0 },
+                                          { "c", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_job_id, voffsetof(data, c), 0 },
+                                          {},
+                                  },
+                                  /* flags= */ 0,
+                                  &data));
+
+        ASSERT_EQ(data.a, UINT32_C(1));
+        ASSERT_EQ(data.b, UINT32_MAX);
+        ASSERT_EQ(data.c, UINT32_C(0));
+
+        /* Zero is not a valid job ID */
+        sd_json_variant_unrefp(&v);
+        ASSERT_OK(sd_json_parse("{\"a\": 0}",
+                                /* flags= */ 0,
+                                &v,
+                                /* reterr_line= */ NULL,
+                                /* reterr_column= */ NULL));
+
+        ASSERT_ERROR(sd_json_dispatch(
+                                  v,
+                                  (const sd_json_dispatch_field[]) {
+                                          { "a", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_job_id, voffsetof(data, a), 0 },
+                                          {},
+                                  },
+                                  /* flags= */ 0,
+                                  &data), EINVAL);
+
+        /* Negative values are not valid */
+        sd_json_variant_unrefp(&v);
+        ASSERT_OK(sd_json_parse("{\"a\": -1}",
+                                /* flags= */ 0,
+                                &v,
+                                /* reterr_line= */ NULL,
+                                /* reterr_column= */ NULL));
+
+        ASSERT_ERROR(sd_json_dispatch(
+                                  v,
+                                  (const sd_json_dispatch_field[]) {
+                                          { "a", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_job_id, voffsetof(data, a), 0 },
+                                          {},
+                                  },
+                                  /* flags= */ 0,
+                                  &data), EINVAL);
+}
+
 static void test_json_variant_compare_one(const char *a, const char *b, int expected) {
         int r;