]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
varlink,json: introduce new varlink_dispatch() helper
authorLennart Poettering <lennart@poettering.net>
Wed, 1 Nov 2023 17:36:12 +0000 (18:36 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 2 Nov 2023 01:19:21 +0000 (01:19 +0000)
varlink_dispatch() is a simple wrapper around json_dispatch() that
returns clean, standards-compliant InvalidParameter error back to
clients, if the specified JSON cannot be parsed properly.

For this json_dispatch() is extended to return the offending field's
name. Because it already has quite a few parameters, I then renamed
json_dispatch() to json_dispatch_full() and made json_dispatch() a
wrapper around it that passes the new argument as NULL. While doing so I
figured we should also get rid of the bad= argument in the short
wrapper, since it's only used in the OCI code.

To simplify the OCI code this adds a second wrapper oci_dispatch()
around json_dispatch_full(), that fills in bad= the way we want.

Net result: instead of one json_dispatch() call there are now:

1. json_dispatch_full() for the fully feature mother of all dispathers.
2. json_dispatch() for the simpler version that you want to use most of
   the time.
3. varlink_dispatch() that generates nice Varlink errors
4. oci_dispatch() that does the OCI specific error handling

And that's all there is.

24 files changed:
src/core/core-varlink.c
src/fuzz/fuzz-bootspec.c
src/hibernate-resume/hibernate-resume-config.c
src/home/homed-varlink.c
src/machine/machined-varlink.c
src/nspawn/nspawn-oci.c
src/nss-resolve/nss-resolve.c
src/oom/oomd-manager.c
src/pcrextend/pcrextend.c
src/resolve/resolvectl.c
src/resolve/resolved-dns-rr.c
src/resolve/resolved-varlink.c
src/shared/group-record.c
src/shared/json.c
src/shared/json.h
src/shared/user-record.c
src/shared/userdb.c
src/shared/varlink-io.systemd.service.c
src/shared/varlink.c
src/shared/varlink.h
src/sysext/sysext.c
src/test/test-varlink.c
src/userdb/userwork.c
src/varlinkctl/varlinkctl.c

index bc741dc47f567a07909db943d8b3c6cc6f47710f..cd913817d2b897927c79d7406ba72460de51c4e6 100644 (file)
@@ -287,8 +287,8 @@ static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, Var
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, "io.systemd.DynamicUser"))
@@ -394,8 +394,8 @@ static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, Va
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, "io.systemd.DynamicUser"))
@@ -470,8 +470,8 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, "io.systemd.DynamicUser"))
index 7a8578776457487b777e4b4f4de6062cea152fa6..0c61cbe39ebd2471ce49a024b08d7ea932b706d0 100644 (file)
@@ -96,7 +96,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         if (r < 0)
                 return 0;
 
-        r = json_dispatch(v, data_dispatch, NULL, 0, &config);
+        r = json_dispatch(v, data_dispatch, 0, &config);
         if (r < 0)
                 return 0;
 
index 6d0987eedd1b013481c7eeed7c06d144bc2beef8..ebc993e4ed20c12386983e15884fb6a36757e1b2 100644 (file)
@@ -173,7 +173,7 @@ static int get_efi_hibernate_location(EFIHibernateLocation **ret) {
         if (!e)
                 return log_oom();
 
-        r = json_dispatch(v, dispatch_table, NULL, JSON_LOG, e);
+        r = json_dispatch(v, dispatch_table, JSON_LOG, e);
         if (r < 0)
                 return r;
 
index 540a61255451f2b4b6855efe0ce1cd53af0edba5..1cef25f5631c7c1f44830640b6d81efbbeb764a8 100644 (file)
@@ -90,8 +90,8 @@ int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, VarlinkMet
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, m->userdb_service))
@@ -204,8 +204,8 @@ int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, VarlinkMe
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, m->userdb_service))
@@ -270,8 +270,8 @@ int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, VarlinkMet
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, m->userdb_service))
index 4b72ee9b0a3eaa5033b8d99b1553c6b0f1d9f703..6ca98e27cf4288147af915837f6604e135ba0649 100644 (file)
@@ -157,8 +157,8 @@ static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, Var
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, "io.systemd.Machine"))
@@ -322,8 +322,8 @@ static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, Va
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, "io.systemd.Machine"))
@@ -367,8 +367,8 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!streq_ptr(p.service, "io.systemd.Machine"))
index 8075dd68299bf26e5b87c26310c7d6c0d67b883d..8f1ac7ccaddfae49d9b358da8b8be30b3482ff3a 100644 (file)
@@ -79,6 +79,10 @@ static int oci_unexpected(const char *name, JsonVariant *v, JsonDispatchFlags fl
                         "Unexpected OCI element '%s' of type '%s'.", name, json_variant_type_to_string(json_variant_type(v)));
 }
 
+static int oci_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchFlags flags, void *userdata) {
+        return json_dispatch_full(v, table, oci_unexpected, flags, userdata, /* reterr_bad_field= */ NULL);
+}
+
 static int oci_unsupported(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
         return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
                         "Unsupported OCI element '%s' of type '%s'.", name, json_variant_type_to_string(json_variant_type(v)));
@@ -118,7 +122,7 @@ static int oci_console_size(const char *name, JsonVariant *v, JsonDispatchFlags
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, s);
+        return oci_dispatch(v, table, flags, s);
 }
 
 static int oci_absolute_path(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -246,7 +250,7 @@ static int oci_rlimits(const char *name, JsonVariant *v, JsonDispatchFlags flags
                         {}
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                r = oci_dispatch(e, table, flags, &data);
                 if (r < 0)
                         return r;
 
@@ -315,7 +319,7 @@ static int oci_capabilities(const char *name, JsonVariant *v, JsonDispatchFlags
         Settings *s = ASSERT_PTR(userdata);
         int r;
 
-        r = json_dispatch(v, table, oci_unexpected, flags, &s->full_capabilities);
+        r = oci_dispatch(v, table, flags, &s->full_capabilities);
         if (r < 0)
                 return r;
 
@@ -399,7 +403,7 @@ static int oci_user(const char *name, JsonVariant *v, JsonDispatchFlags flags, v
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+        return oci_dispatch(v, table, flags, userdata);
 }
 
 static int oci_process(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -420,7 +424,7 @@ static int oci_process(const char *name, JsonVariant *v, JsonDispatchFlags flags
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+        return oci_dispatch(v, table, flags, userdata);
 }
 
 static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -433,7 +437,7 @@ static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, v
                 {}
         };
 
-        r = json_dispatch(v, table, oci_unexpected, flags, s);
+        r = oci_dispatch(v, table, flags, s);
         if (r < 0)
                 return r;
 
@@ -535,7 +539,7 @@ static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags,
                 _cleanup_(oci_mount_data_done) oci_mount_data data = {};
                 CustomMount *m;
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                r = oci_dispatch(e, table, flags, &data);
                 if (r < 0)
                         return r;
 
@@ -635,7 +639,7 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl
                         {}
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                r = oci_dispatch(e, table, flags, &data);
                 if (r < 0)
                         return r;
 
@@ -726,7 +730,7 @@ static int oci_uid_gid_mappings(const char *name, JsonVariant *v, JsonDispatchFl
 
         assert_se(e = json_variant_by_index(v, 0));
 
-        r = json_dispatch(e, table, oci_unexpected, flags, &data);
+        r = oci_dispatch(e, table, flags, &data);
         if (r < 0)
                 return r;
 
@@ -850,7 +854,7 @@ static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags
                         .mode = 0644,
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, node);
+                r = oci_dispatch(e, table, flags, node);
                 if (r < 0)
                         goto fail_element;
 
@@ -999,7 +1003,7 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag
                         {}
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                r = oci_dispatch(e, table, flags, &data);
                 if (r < 0)
                         return r;
 
@@ -1181,7 +1185,7 @@ static int oci_cgroup_memory(const char *name, JsonVariant *v, JsonDispatchFlags
         Settings *s = ASSERT_PTR(userdata);
         int r;
 
-        r = json_dispatch(v, table, oci_unexpected, flags, &data);
+        r = oci_dispatch(v, table, flags, &data);
         if (r < 0)
                 return r;
 
@@ -1297,7 +1301,7 @@ static int oci_cgroup_cpu(const char *name, JsonVariant *v, JsonDispatchFlags fl
         Settings *s = ASSERT_PTR(userdata);
         int r;
 
-        r = json_dispatch(v, table, oci_unexpected, flags, &data);
+        r = oci_dispatch(v, table, flags, &data);
         if (r < 0) {
                 cpu_set_reset(&data.cpu_set);
                 return r;
@@ -1379,7 +1383,7 @@ static int oci_cgroup_block_io_weight_device(const char *name, JsonVariant *v, J
 
                 _cleanup_free_ char *path = NULL;
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                r = oci_dispatch(e, table, flags, &data);
                 if (r < 0)
                         return r;
 
@@ -1436,7 +1440,7 @@ static int oci_cgroup_block_io_throttle(const char *name, JsonVariant *v, JsonDi
 
                 _cleanup_free_ char *path = NULL;
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                r = oci_dispatch(e, table, flags, &data);
                 if (r < 0)
                         return r;
 
@@ -1473,7 +1477,7 @@ static int oci_cgroup_block_io(const char *name, JsonVariant *v, JsonDispatchFla
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+        return oci_dispatch(v, table, flags, userdata);
 }
 
 static int oci_cgroup_pids(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -1488,7 +1492,7 @@ static int oci_cgroup_pids(const char *name, JsonVariant *v, JsonDispatchFlags f
         uint64_t m;
         int r;
 
-        r = json_dispatch(v, table, oci_unexpected, flags, &k);
+        r = oci_dispatch(v, table, flags, &k);
         if (r < 0)
                 return r;
 
@@ -1531,7 +1535,7 @@ static int oci_resources(const char *name, JsonVariant *v, JsonDispatchFlags fla
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+        return oci_dispatch(v, table, flags, userdata);
 }
 
 static bool sysctl_key_valid(const char *s) {
@@ -1795,7 +1799,7 @@ static int oci_seccomp_args(const char *name, JsonVariant *v, JsonDispatchFlags
                         .op = 0,
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, p);
+                r = oci_dispatch(e, table, flags, p);
                 if (r < 0)
                         return r;
 
@@ -1829,7 +1833,7 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl
                         .action = UINT32_MAX,
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, &rule);
+                r = oci_dispatch(e, table, flags, &rule);
                 if (r < 0)
                         return r;
 
@@ -1888,7 +1892,7 @@ static int oci_seccomp(const char *name, JsonVariant *v, JsonDispatchFlags flags
         if (!sc)
                 return json_log(v, flags, SYNTHETIC_ERRNO(ENOMEM), "Couldn't allocate seccomp object.");
 
-        r = json_dispatch(v, table, oci_unexpected, flags, sc);
+        r = oci_dispatch(v, table, flags, sc);
         if (r < 0)
                 return r;
 
@@ -2013,7 +2017,7 @@ static int oci_linux(const char *name, JsonVariant *v, JsonDispatchFlags flags,
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+        return oci_dispatch(v, table, flags, userdata);
 }
 
 static int oci_hook_timeout(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -2070,7 +2074,7 @@ static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags f
                         .timeout = USEC_INFINITY,
                 };
 
-                r = json_dispatch(e, table, oci_unexpected, flags, new_item);
+                r = oci_dispatch(e, table, flags, new_item);
                 if (r < 0) {
                         free(new_item->path);
                         strv_free(new_item->args);
@@ -2093,7 +2097,7 @@ static int oci_hooks(const char *name, JsonVariant *v, JsonDispatchFlags flags,
                 {}
         };
 
-        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+        return oci_dispatch(v, table, flags, userdata);
 }
 
 static int oci_annotations(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
@@ -2178,7 +2182,7 @@ int oci_load(FILE *f, const char *bundle, Settings **ret) {
         if (!s->bundle)
                 return log_oom();
 
-        r = json_dispatch(oci, table, oci_unexpected, 0, s);
+        r = oci_dispatch(oci, table, 0, s);
         if (r < 0)
                 return r;
 
index 89381f56031a6e301f435756f118034e5ed7af7f..aba715724554946227474ab44b41d7b8ecb5a379 100644 (file)
@@ -274,7 +274,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
                 goto not_found;
         }
 
-        r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, json_dispatch_flags, &p);
+        r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, json_dispatch_flags, &p);
         if (r < 0)
                 goto fail;
         if (json_variant_is_blank_object(p.addresses))
@@ -284,7 +284,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
-                r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
+                r = json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
@@ -322,7 +322,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
-                r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
+                r = json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
@@ -436,7 +436,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                 goto not_found;
         }
 
-        r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, json_dispatch_flags, &p);
+        r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, json_dispatch_flags, &p);
         if (r < 0)
                 goto fail;
         if (json_variant_is_blank_object(p.addresses))
@@ -446,7 +446,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
-                r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
+                r = json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
@@ -492,7 +492,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) {
                 AddressParameters q = {};
 
-                r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
+                r = json_dispatch(entry, address_parameters_dispatch_table, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
@@ -652,7 +652,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
                 goto not_found;
         }
 
-        r = json_dispatch(rparams, resolve_address_reply_dispatch_table, NULL, json_dispatch_flags, &p);
+        r = json_dispatch(rparams, resolve_address_reply_dispatch_table, json_dispatch_flags, &p);
         if (r < 0)
                 goto fail;
         if (json_variant_is_blank_object(p.names))
@@ -663,7 +663,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
                 _cleanup_(name_parameters_destroy) NameParameters q = {};
 
-                r = json_dispatch(entry, name_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
+                r = json_dispatch(entry, name_parameters_dispatch_table, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
@@ -704,7 +704,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         JSON_VARIANT_ARRAY_FOREACH(entry, p.names) {
                 _cleanup_(name_parameters_destroy) NameParameters q = {};
 
-                r = json_dispatch(entry, name_parameters_dispatch_table, NULL, json_dispatch_flags, &q);
+                r = json_dispatch(entry, name_parameters_dispatch_table, json_dispatch_flags, &q);
                 if (r < 0)
                         goto fail;
 
index 75918a5fe7e13afc44890de0874db2e0e52b5150..a36af0e2b452c512c479fcc812ddb9e3d3297712 100644 (file)
@@ -74,7 +74,7 @@ static int process_managed_oom_message(Manager *m, uid_t uid, JsonVariant *param
                 if (!json_variant_is_object(c))
                         continue;
 
-                r = json_dispatch(c, dispatch_table, NULL, 0, &message);
+                r = json_dispatch(c, dispatch_table, 0, &message);
                 if (r == -ENOMEM)
                         return r;
                 if (r < 0)
index 17a81816db4de954802ac47ea5d0afff3a07d9dc..201ace954418493bae455f1ef10ac7eea8fca847 100644 (file)
@@ -282,8 +282,8 @@ static int vl_method_extend(Varlink *link, JsonVariant *parameters, VarlinkMetho
 
         assert(link);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (!TPM2_PCR_INDEX_VALID(p.pcr))
index 071b2d85bbcad5308ab67a4bd658e924aaa64e0e..e2d806fcea2714b416d127520c567fea0ee45324 100644 (file)
@@ -1100,7 +1100,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
                 {},
         };
 
-        r = json_dispatch(reply, statistics_dispatch_table, NULL, JSON_LOG, &statistics);
+        r = json_dispatch(reply, statistics_dispatch_table, JSON_LOG, &statistics);
         if (r < 0)
                 return r;
 
@@ -1123,7 +1123,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
                 {},
         };
 
-        r = json_dispatch(statistics.transactions, transactions_dispatch_table, NULL, JSON_LOG, &transactions);
+        r = json_dispatch(statistics.transactions, transactions_dispatch_table, JSON_LOG, &transactions);
         if (r < 0)
                 return r;
 
@@ -1140,7 +1140,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
                 {},
         };
 
-        r = json_dispatch(statistics.cache, cache_dispatch_table, NULL, JSON_LOG, &cache);
+        r = json_dispatch(statistics.cache, cache_dispatch_table, JSON_LOG, &cache);
         if (r < 0)
                 return r;
 
@@ -1159,7 +1159,7 @@ static int show_statistics(int argc, char **argv, void *userdata) {
                 {},
         };
 
-        r = json_dispatch(statistics.dnssec, dnssec_dispatch_table, NULL, JSON_LOG, &dnsssec);
+        r = json_dispatch(statistics.dnssec, dnssec_dispatch_table, JSON_LOG, &dnsssec);
         if (r < 0)
                 return r;
 
@@ -2732,7 +2732,7 @@ static void monitor_query_dump(JsonVariant *v) {
                 {}
         };
 
-        r = json_dispatch(v, dispatch_table, NULL, 0, NULL);
+        r = json_dispatch(v, dispatch_table, 0, NULL);
         if (r < 0)
                 return (void) log_warning("Received malformed monitor message, ignoring.");
 
@@ -2858,7 +2858,7 @@ static int dump_cache_item(JsonVariant *item) {
         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
         int r, c = 0;
 
-        r = json_dispatch(item, dispatch_table, NULL, JSON_LOG, &item_info);
+        r = json_dispatch(item, dispatch_table, JSON_LOG, &item_info);
         if (r < 0)
                 return r;
 
@@ -2920,7 +2920,7 @@ static int dump_cache_scope(JsonVariant *scope) {
                 {},
         };
 
-        r = json_dispatch(scope, dispatch_table, NULL, JSON_LOG, &scope_info);
+        r = json_dispatch(scope, dispatch_table, JSON_LOG, &scope_info);
         if (r < 0)
                 return r;
 
@@ -3036,7 +3036,7 @@ static int dump_server_state(JsonVariant *server) {
                 {},
         };
 
-        r = json_dispatch(server, dispatch_table, NULL, JSON_LOG|JSON_PERMISSIVE, &server_state);
+        r = json_dispatch(server, dispatch_table, JSON_LOG|JSON_PERMISSIVE, &server_state);
         if (r < 0)
                 return r;
 
index f6344542d6e8631f7ddf5b89801a0d5503364278..5a16e18eedfe75203ab1756e8505764686d1741a 100644 (file)
@@ -1869,7 +1869,7 @@ int dns_resource_key_from_json(JsonVariant *v, DnsResourceKey **ret) {
         assert(v);
         assert(ret);
 
-        r = json_dispatch(v, dispatch_table, NULL, 0, NULL);
+        r = json_dispatch(v, dispatch_table, 0, NULL);
         if (r < 0)
                 return r;
 
index c9bb616acbf18fa79839396dc0de63913e3bfe49..d0953f5d096922fb0a1c7b21b3728f4295e66777 100644 (file)
@@ -315,8 +315,8 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va
         if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY))
                 return -EINVAL;
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (p.ifindex < 0)
@@ -491,8 +491,8 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var
         if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY))
                 return -EINVAL;
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         if (p.ifindex < 0)
index 2f12ac1c22010ad46bd2f98e582ff09a1048bfef..728471b2b6617e20bfc8d579d96c58e04b71fb4e 100644 (file)
@@ -50,7 +50,7 @@ static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispa
                 {},
         };
 
-        return json_dispatch(variant, privileged_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(variant, privileged_dispatch_table, flags, userdata);
 }
 
 static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -78,7 +78,7 @@ static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatch
         if (!m)
                 return 0;
 
-        return json_dispatch(m, binding_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(m, binding_dispatch_table, flags, userdata);
 }
 
 static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -131,7 +131,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
                 if (!matching)
                         continue;
 
-                r = json_dispatch(e, per_machine_dispatch_table, NULL, flags, userdata);
+                r = json_dispatch(e, per_machine_dispatch_table, flags, userdata);
                 if (r < 0)
                         return r;
         }
@@ -164,7 +164,7 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF
         if (!m)
                 return 0;
 
-        return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(m, status_dispatch_table, flags, userdata);
 }
 
 static int group_record_augment(GroupRecord *h, JsonDispatchFlags json_flags) {
@@ -230,7 +230,7 @@ int group_record_load(
         if (r < 0)
                 return r;
 
-        r = json_dispatch(h->json, group_dispatch_table, NULL, json_flags, h);
+        r = json_dispatch(h->json, group_dispatch_table, json_flags, h);
         if (r < 0)
                 return r;
 
index cc699986706bd761e3ad472ef56b5686a4b48748..5f897a7df99d19babbf3c25b36033a0e09486eee 100644 (file)
@@ -4484,7 +4484,13 @@ static void *dispatch_userdata(const JsonDispatch *p, void *userdata) {
         return SIZE_TO_PTR(p->offset);
 }
 
-int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata) {
+int json_dispatch_full(
+                JsonVariant *v,
+                const JsonDispatch table[],
+                JsonDispatchCallback bad,
+                JsonDispatchFlags flags,
+                void *userdata,
+                const char **reterr_bad_field) {
         size_t m;
         int r, done = 0;
         bool *found;
@@ -4495,6 +4501,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                 if (flags & JSON_PERMISSIVE)
                         return 0;
 
+                if (reterr_bad_field)
+                        *reterr_bad_field = NULL;
+
                 return -EINVAL;
         }
 
@@ -4517,7 +4526,7 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                             streq_ptr(json_variant_string(key), p->name))
                                 break;
 
-                if (p->name) { /* Found a matching entry! :-) */
+                if (p->name) { /* Found a matching entry! 🙂 */
                         JsonDispatchFlags merged_flags;
 
                         merged_flags = flags | p->flags;
@@ -4532,6 +4541,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                                 if (merged_flags & JSON_PERMISSIVE)
                                         continue;
 
+                                if (reterr_bad_field)
+                                        *reterr_bad_field = p->name;
+
                                 return -EINVAL;
                         }
 
@@ -4541,6 +4553,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                                 if (merged_flags & JSON_PERMISSIVE)
                                         continue;
 
+                                if (reterr_bad_field)
+                                        *reterr_bad_field = p->name;
+
                                 return -ENOTUNIQ;
                         }
 
@@ -4552,13 +4567,16 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                                         if (merged_flags & JSON_PERMISSIVE)
                                                 continue;
 
+                                        if (reterr_bad_field)
+                                                *reterr_bad_field = json_variant_string(key);
+
                                         return r;
                                 }
                         }
 
                         done ++;
 
-                } else { /* Didn't find a matching entry! :-( */
+                } else { /* Didn't find a matching entry! ☹️ */
 
                         if (bad) {
                                 r = bad(json_variant_string(key), value, flags, userdata);
@@ -4566,6 +4584,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                                         if (flags & JSON_PERMISSIVE)
                                                 continue;
 
+                                        if (reterr_bad_field)
+                                                *reterr_bad_field = json_variant_string(key);
+
                                         return r;
                                 } else
                                         done ++;
@@ -4576,6 +4597,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                                 if (flags & JSON_PERMISSIVE)
                                         continue;
 
+                                if (reterr_bad_field)
+                                        *reterr_bad_field = json_variant_string(key);
+
                                 return -EADDRNOTAVAIL;
                         }
                 }
@@ -4590,6 +4614,9 @@ int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallba
                         if ((merged_flags & JSON_PERMISSIVE))
                                 continue;
 
+                        if (reterr_bad_field)
+                                *reterr_bad_field = p->name;
+
                         return -ENXIO;
                 }
         }
index 1cd3baaade13bc777ae0ffd16885a7cb396bbd53..c40c23487ab97fd5899e284d42e35835cc04585a 100644 (file)
@@ -396,7 +396,11 @@ typedef struct JsonDispatch {
         JsonDispatchFlags flags;
 } JsonDispatch;
 
-int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
+int json_dispatch_full(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata, const char **reterr_bad_field);
+
+static inline int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchFlags flags, void *userdata) {
+        return json_dispatch_full(v, table, NULL, flags, userdata, NULL);
+}
 
 int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
 int json_dispatch_const_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
index b51d8add1af5f75b547a491de40e842bebd33667..4913478a6e50e25662f8c96e580d54a435003a27 100644 (file)
@@ -657,7 +657,7 @@ static int dispatch_secret(const char *name, JsonVariant *variant, JsonDispatchF
                 {},
         };
 
-        return json_dispatch(variant, secret_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(variant, secret_dispatch_table, flags, userdata);
 }
 
 static int dispatch_pkcs11_uri(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -786,7 +786,7 @@ static int dispatch_pkcs11_key(const char *name, JsonVariant *variant, JsonDispa
                 k = h->pkcs11_encrypted_key + h->n_pkcs11_encrypted_key;
                 *k = (Pkcs11EncryptedKey) {};
 
-                r = json_dispatch(e, pkcs11_key_dispatch_table, NULL, flags, k);
+                r = json_dispatch(e, pkcs11_key_dispatch_table, flags, k);
                 if (r < 0) {
                         pkcs11_encrypted_key_done(k);
                         return r;
@@ -920,7 +920,7 @@ static int dispatch_fido2_hmac_salt(const char *name, JsonVariant *variant, Json
                         .client_pin = -1,
                 };
 
-                r = json_dispatch(e, fido2_hmac_salt_dispatch_table, NULL, flags, k);
+                r = json_dispatch(e, fido2_hmac_salt_dispatch_table, flags, k);
                 if (r < 0) {
                         fido2_hmac_salt_done(k);
                         return r;
@@ -960,7 +960,7 @@ static int dispatch_recovery_key(const char *name, JsonVariant *variant, JsonDis
                 k = h->recovery_key + h->n_recovery_key;
                 *k = (RecoveryKey) {};
 
-                r = json_dispatch(e, recovery_key_dispatch_table, NULL, flags, k);
+                r = json_dispatch(e, recovery_key_dispatch_table, flags, k);
                 if (r < 0) {
                         recovery_key_done(k);
                         return r;
@@ -1042,7 +1042,7 @@ static int dispatch_privileged(const char *name, JsonVariant *variant, JsonDispa
                 {},
         };
 
-        return json_dispatch(variant, privileged_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(variant, privileged_dispatch_table, flags, userdata);
 }
 
 static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
@@ -1081,7 +1081,7 @@ static int dispatch_binding(const char *name, JsonVariant *variant, JsonDispatch
         if (!m)
                 return 0;
 
-        return json_dispatch(m, binding_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(m, binding_dispatch_table, flags, userdata);
 }
 
 int per_machine_id_match(JsonVariant *ids, JsonDispatchFlags flags) {
@@ -1283,7 +1283,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
                 if (!matching)
                         continue;
 
-                r = json_dispatch(e, per_machine_dispatch_table, NULL, flags, userdata);
+                r = json_dispatch(e, per_machine_dispatch_table, flags, userdata);
                 if (r < 0)
                         return r;
         }
@@ -1332,7 +1332,7 @@ static int dispatch_status(const char *name, JsonVariant *variant, JsonDispatchF
         if (!m)
                 return 0;
 
-        return json_dispatch(m, status_dispatch_table, NULL, flags, userdata);
+        return json_dispatch(m, status_dispatch_table, flags, userdata);
 }
 
 int user_record_build_image_path(UserStorage storage, const char *user_name_and_realm, char **ret) {
@@ -1625,7 +1625,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
         if (r < 0)
                 return r;
 
-        r = json_dispatch(h->json, user_dispatch_table, NULL, json_flags, h);
+        r = json_dispatch(h->json, user_dispatch_table, json_flags, h);
         if (r < 0)
                 return r;
 
index cd67ddeec82352a9038667775466f97bd14b03c8..f60d48ace4f7297e310988469faea9eb8dbae1db 100644 (file)
@@ -199,7 +199,7 @@ static int userdb_on_query_reply(
 
                 assert_se(!iterator->found_user);
 
-                r = json_dispatch(parameters, dispatch_table, NULL, 0, &user_data);
+                r = json_dispatch(parameters, dispatch_table, 0, &user_data);
                 if (r < 0)
                         goto finish;
 
@@ -256,7 +256,7 @@ static int userdb_on_query_reply(
 
                 assert_se(!iterator->found_group);
 
-                r = json_dispatch(parameters, dispatch_table, NULL, 0, &group_data);
+                r = json_dispatch(parameters, dispatch_table, 0, &group_data);
                 if (r < 0)
                         goto finish;
 
@@ -309,7 +309,7 @@ static int userdb_on_query_reply(
                 assert(!iterator->found_user_name);
                 assert(!iterator->found_group_name);
 
-                r = json_dispatch(parameters, dispatch_table, NULL, 0, &membership_data);
+                r = json_dispatch(parameters, dispatch_table, 0, &membership_data);
                 if (r < 0)
                         goto finish;
 
index 675f949929ee435b541609aa5cd76eaa4c509599..986f3e172ca63e41e815d746f894e2a5f98190b5 100644 (file)
@@ -48,8 +48,8 @@ int varlink_method_set_log_level(Varlink *link, JsonVariant *parameters, Varlink
         if (json_variant_elements(parameters) != 2)
                 return varlink_error_invalid_parameter(link, parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &level);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &level);
+        if (r != 0)
                 return r;
 
         if (LOG_PRI(level) != level)
index ae3a1bee28f9b96078207e62cadcad8c61eae9a6..23ce56ca9f553472df7c548754153b6797609552 100644 (file)
@@ -1205,7 +1205,7 @@ static int generic_method_get_interface_description(
 
         assert(link);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &name);
+        r = json_dispatch(parameters, dispatch_table, 0, &name);
         if (r < 0)
                 return r;
 
@@ -2479,6 +2479,26 @@ int varlink_notifyb(Varlink *v, ...) {
         return varlink_notify(v, parameters);
 }
 
+int varlink_dispatch(Varlink *v, JsonVariant *parameters, const JsonDispatch table[], void *userdata) {
+        const char *bad_field = NULL;
+        int r;
+
+        assert_return(v, -EINVAL);
+        assert_return(table, -EINVAL);
+
+        /* A wrapper around json_dispatch_full() that returns a nice InvalidParameter error if we hit a problem with some field. */
+
+        r = json_dispatch_full(parameters, table, /* bad= */ NULL, /* flags= */ 0, userdata, &bad_field);
+        if (r < 0) {
+                if (bad_field)
+                        return varlink_errorb(v, VARLINK_ERROR_INVALID_PARAMETER,
+                                              JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameter", JSON_BUILD_STRING(bad_field))));
+                return r;
+        }
+
+        return 0;
+}
+
 int varlink_bind_reply(Varlink *v, VarlinkReply callback) {
         assert_return(v, -EINVAL);
 
index 516d3b5a906f5812d088f668f4507b1ad0a9a077..6ec708aba20137dfcf83ca0676d6be909ee72060 100644 (file)
@@ -115,6 +115,9 @@ int varlink_error_errno(Varlink *v, int error);
 int varlink_notify(Varlink *v, JsonVariant *parameters);
 int varlink_notifyb(Varlink *v, ...);
 
+/* Parsing incoming data via json_dispatch() and generate a nice error on parse errors */
+int varlink_dispatch(Varlink *v, JsonVariant *parameters, const JsonDispatch table[], void *userdata);
+
 /* Write outgoing fds into the socket (to be associated with the next enqueued message) */
 int varlink_push_fd(Varlink *v, int fd);
 int varlink_dup_fd(Varlink *v, int fd);
index 4d720199662e3eb5b79bba95e7c45fc5b4bc9eb4..858868c0c5147811e94cc7af127d4f1a97008efd 100644 (file)
@@ -377,8 +377,8 @@ static int vl_method_unmerge(Varlink *link, JsonVariant *parameters, VarlinkMeth
 
         assert(link);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         r = parse_image_class_parameter(link, p.class, &image_class, &hierarchies);
@@ -1115,17 +1115,12 @@ static int parse_merge_parameters(Varlink *link, JsonVariant *parameters, Method
                 { "noexec",   JSON_VARIANT_BOOLEAN, json_dispatch_boolean,      offsetof(MethodMergeParameters, noexec),    0 },
                 {}
         };
-        int r;
 
         assert(link);
         assert(parameters);
         assert(p);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, p);
-        if (r < 0)
-                return r;
-
-        return 0;
+        return varlink_dispatch(link, parameters, dispatch_table, p);
 }
 
 static int vl_method_merge(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
@@ -1142,7 +1137,7 @@ static int vl_method_merge(Varlink *link, JsonVariant *parameters, VarlinkMethod
         assert(link);
 
         r = parse_merge_parameters(link, parameters, &p);
-        if (r < 0)
+        if (r != 0)
                 return r;
 
         r = parse_image_class_parameter(link, p.class, &image_class, &hierarchies);
@@ -1245,7 +1240,7 @@ static int vl_method_refresh(Varlink *link, JsonVariant *parameters, VarlinkMeth
         assert(link);
 
         r = parse_merge_parameters(link, parameters, &p);
-        if (r < 0)
+        if (r != 0)
                 return r;
 
         r = parse_image_class_parameter(link, p.class, &image_class, &hierarchies);
@@ -1322,8 +1317,8 @@ static int vl_method_list(Varlink *link, JsonVariant *parameters, VarlinkMethodF
 
         assert(link);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         r = parse_image_class_parameter(link, p.class, &image_class, NULL);
index b66c5df8a1bb1eea980c146a3a686bd05e3bdb37..05bdf9c3fab28abbe56ff5be73b83f55f8ea194b 100644 (file)
@@ -59,13 +59,15 @@ static int method_something_more(Varlink *link, JsonVariant *parameters, Varlink
         };
 
         static const JsonDispatch dispatch_table[] = {
-                { "a",  JSON_VARIANT_INTEGER, json_dispatch_int, offsetof(struct Something, x),  JSON_MANDATORY },
+                { "a", JSON_VARIANT_INTEGER, json_dispatch_int, offsetof(struct Something, x), JSON_MANDATORY },
                 { "b", JSON_VARIANT_INTEGER, json_dispatch_int, offsetof(struct Something, y), JSON_MANDATORY},
                 {}
         };
         struct Something s = {};
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &s);
+        r = varlink_dispatch(link, parameters, dispatch_table, &s);
+        if (r != 0)
+                return r;
 
         for (int i = 0; i < 5; i++) {
                 _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
index 7413378bcba4aeedc7af35d167ab15d38e33a64c..b49dbbd52304d6770a62267c7d0e5a921703ca06 100644 (file)
@@ -148,8 +148,8 @@ static int vl_method_get_user_record(Varlink *link, JsonVariant *parameters, Var
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         r = userdb_flags_from_service(link, p.service, &userdb_flags);
@@ -284,8 +284,8 @@ static int vl_method_get_group_record(Varlink *link, JsonVariant *parameters, Va
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         r = userdb_flags_from_service(link, p.service, &userdb_flags);
@@ -367,8 +367,8 @@ static int vl_method_get_memberships(Varlink *link, JsonVariant *parameters, Var
 
         assert(parameters);
 
-        r = json_dispatch(parameters, dispatch_table, NULL, 0, &p);
-        if (r < 0)
+        r = varlink_dispatch(link, parameters, dispatch_table, &p);
+        if (r != 0)
                 return r;
 
         r = userdb_flags_from_service(link, p.service, &userdb_flags);
index 33c85b87ff33a73d803a0f8efd78d4ca2293c9b1..36556642d3d4dc9e9d2bd6b816258f8a789470d9 100644 (file)
@@ -230,7 +230,7 @@ static int verb_info(int argc, char *argv[], void *userdata) {
                 };
                 _cleanup_(get_info_data_done) GetInfoData data = {};
 
-                r = json_dispatch(reply, dispatch_table, NULL, JSON_LOG, &data);
+                r = json_dispatch(reply, dispatch_table, JSON_LOG, &data);
                 if (r < 0)
                         return r;
 
@@ -314,7 +314,7 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
                 const char *description = NULL;
                 unsigned line = 0, column = 0;
 
-                r = json_dispatch(reply, dispatch_table, NULL, JSON_LOG, &description);
+                r = json_dispatch(reply, dispatch_table, JSON_LOG, &description);
                 if (r < 0)
                         return r;