From 3218794f1c8e0dd73a95766e6f6cdd48da95ba8e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 16 Aug 2023 09:35:07 +0200 Subject: [PATCH 1/4] json: add json_variant_append_arrayb() helper --- src/shared/json.c | 14 ++++++++++++++ src/shared/json.h | 1 + 2 files changed, 15 insertions(+) diff --git a/src/shared/json.c b/src/shared/json.c index a6e23d82cd..9b95e42893 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -2141,6 +2141,20 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element) { return 0; } +int json_variant_append_arrayb(JsonVariant **v, ...) { + _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + va_list ap; + int r; + + va_start(ap, v); + r = json_buildv(&w, ap); + va_end(ap); + if (r < 0) + return r; + + return json_variant_append_array(v, w); +} + JsonVariant *json_variant_find(JsonVariant *haystack, JsonVariant *needle) { JsonVariant *i; diff --git a/src/shared/json.h b/src/shared/json.h index 3f86222f2a..a5eca65bf8 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -213,6 +213,7 @@ int json_variant_set_field_strv(JsonVariant **v, const char *field, char **l); JsonVariant *json_variant_find(JsonVariant *haystack, JsonVariant *needle); int json_variant_append_array(JsonVariant **v, JsonVariant *element); +int json_variant_append_arrayb(JsonVariant **v, ...); int json_variant_append_array_nodup(JsonVariant **v, JsonVariant *element); int json_variant_merge(JsonVariant **v, JsonVariant *m); From c91f581c4706af36f87f911067c4569c0ff08676 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 Aug 2023 09:28:42 +0200 Subject: [PATCH 2/4] tree-wide: use json_variant_append_arrayb() at many places --- src/boot/measure.c | 19 ++++------ src/network/networkd-json.c | 65 +++++++++++++------------------- src/resolve/resolved-dns-cache.c | 14 +++---- src/resolve/resolved-manager.c | 16 ++++---- src/resolve/resolved-varlink.c | 14 +++---- 5 files changed, 51 insertions(+), 77 deletions(-) diff --git a/src/boot/measure.c b/src/boot/measure.c index c08386d9fc..fbeb4473f7 100644 --- a/src/boot/measure.c +++ b/src/boot/measure.c @@ -693,21 +693,16 @@ static int verb_calculate(int argc, char *argv[], void *userdata) { printf("%" PRIu32 ":%s=%s\n", TPM_PCR_INDEX_KERNEL_IMAGE, pcr_states[i].bank, hd); } else { - _cleanup_(json_variant_unrefp) JsonVariant *bv = NULL, *array = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; array = json_variant_ref(json_variant_by_key(w, pcr_states[i].bank)); - r = json_build(&bv, - JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_CONDITION(!isempty(*phase), "phase", JSON_BUILD_STRING(*phase)), - JSON_BUILD_PAIR("pcr", JSON_BUILD_INTEGER(TPM_PCR_INDEX_KERNEL_IMAGE)), - JSON_BUILD_PAIR("hash", JSON_BUILD_HEX(pcr_states[i].value, pcr_states[i].value_size)) - ) - ); - if (r < 0) - return log_error_errno(r, "Failed to build JSON object: %m"); - - r = json_variant_append_array(&array, bv); + r = json_variant_append_arrayb( + &array, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_CONDITION(!isempty(*phase), "phase", JSON_BUILD_STRING(*phase)), + JSON_BUILD_PAIR("pcr", JSON_BUILD_INTEGER(TPM_PCR_INDEX_KERNEL_IMAGE)), + JSON_BUILD_PAIR("hash", JSON_BUILD_HEX(pcr_states[i].value, pcr_states[i].value_size)))); if (r < 0) return log_error_errno(r, "Failed to append JSON object to array: %m"); diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 78bf870507..7e4e4ff22f 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -140,15 +140,11 @@ static int nexthop_group_build_json(NextHop *nexthop, JsonVariant **ret) { assert(ret); HASHMAP_FOREACH(g, nexthop->group) { - _cleanup_(json_variant_unrefp) JsonVariant *e = NULL; - - r = json_build(&e, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_UNSIGNED("ID", g->id), - JSON_BUILD_PAIR_UNSIGNED("Weight", g->weight+1))); - if (r < 0) - return r; - - r = json_variant_append_array(&array, e); + r = json_variant_append_arrayb( + &array, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_UNSIGNED("ID", g->id), + JSON_BUILD_PAIR_UNSIGNED("Weight", g->weight+1))); if (r < 0) return r; } @@ -431,9 +427,6 @@ static int device_append_json(sd_device *device, JsonVariant **v) { } static int dns_append_json_one(Link *link, const struct in_addr_full *a, NetworkConfigSource s, const union in_addr_union *p, JsonVariant **array) { - _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; - int r; - assert(link); assert(a); assert(array); @@ -441,18 +434,16 @@ static int dns_append_json_one(Link *link, const struct in_addr_full *a, Network if (a->ifindex != 0 && a->ifindex != link->ifindex) return 0; - r = json_build(&v, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_INTEGER("Family", a->family), - JSON_BUILD_PAIR_IN_ADDR("Address", &a->address, a->family), - JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Port", a->port), - JSON_BUILD_PAIR_CONDITION(a->ifindex != 0, "InterfaceIndex", JSON_BUILD_INTEGER(a->ifindex)), - JSON_BUILD_PAIR_STRING_NON_EMPTY("ServerName", a->server_name), - JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)), - JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, a->family))); - if (r < 0) - return r; - - return json_variant_append_array(array, v); + return json_variant_append_arrayb( + array, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_INTEGER("Family", a->family), + JSON_BUILD_PAIR_IN_ADDR("Address", &a->address, a->family), + JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Port", a->port), + JSON_BUILD_PAIR_CONDITION(a->ifindex != 0, "InterfaceIndex", JSON_BUILD_INTEGER(a->ifindex)), + JSON_BUILD_PAIR_STRING_NON_EMPTY("ServerName", a->server_name), + JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)), + JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, a->family))); } static int dns_append_json(Link *link, JsonVariant **v) { @@ -939,23 +930,19 @@ static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) { return 0; HASHMAP_FOREACH(lease, link->dhcp_server->bound_leases_by_client_id) { - _cleanup_(json_variant_unrefp) JsonVariant *e = NULL; struct in_addr address = { .s_addr = lease->address }; - r = json_build(&e, - JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_BYTE_ARRAY( - "ClientId", - lease->client_id.data, - lease->client_id.length), - JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address), - JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease->hostname), - JSON_BUILD_PAIR_FINITE_USEC( - "ExpirationUSec", lease->expiration))); - if (r < 0) - return r; - - r = json_variant_append_array(&array, e); + r = json_variant_append_arrayb( + &array, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_BYTE_ARRAY( + "ClientId", + lease->client_id.data, + lease->client_id.length), + JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address), + JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease->hostname), + JSON_BUILD_PAIR_FINITE_USEC( + "ExpirationUSec", lease->expiration))); if (r < 0) return r; } diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 3805150d98..7a1a1620af 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -1407,7 +1407,7 @@ int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret) { _cleanup_(json_variant_unrefp) JsonVariant *l = NULL; LIST_FOREACH(by_key, j, i) { - _cleanup_(json_variant_unrefp) JsonVariant *rj = NULL, *item = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *rj = NULL; assert(j->rr); @@ -1419,13 +1419,11 @@ int dns_cache_dump_to_json(DnsCache *cache, JsonVariant **ret) { if (r < 0) return r; - r = json_build(&item, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_VARIANT("rr", rj), - JSON_BUILD_PAIR_BASE64("raw", j->rr->wire_format, j->rr->wire_format_size))); - if (r < 0) - return r; - - r = json_variant_append_array(&l, item); + r = json_variant_append_arrayb( + &l, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_VARIANT("rr", rj), + JSON_BUILD_PAIR_BASE64("raw", j->rr->wire_format, j->rr->wire_format_size))); if (r < 0) return r; } diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 43e7b95e17..ed3800ed8a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1134,7 +1134,7 @@ int manager_monitor_send( return log_error_errno(r, "Failed to convert question to JSON: %m"); DNS_ANSWER_FOREACH_ITEM(rri, answer) { - _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; r = dns_resource_record_to_json(rri->rr, &v); if (r < 0) @@ -1144,14 +1144,12 @@ int manager_monitor_send( if (r < 0) return log_error_errno(r, "Failed to generate RR wire format: %m"); - r = json_build(&w, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_CONDITION(v, "rr", JSON_BUILD_VARIANT(v)), - JSON_BUILD_PAIR("raw", JSON_BUILD_BASE64(rri->rr->wire_format, rri->rr->wire_format_size)), - JSON_BUILD_PAIR_CONDITION(rri->ifindex > 0, "ifindex", JSON_BUILD_INTEGER(rri->ifindex)))); - if (r < 0) - return log_error_errno(r, "Failed to make answer RR object: %m"); - - r = json_variant_append_array(&janswer, w); + r = json_variant_append_arrayb( + &janswer, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_CONDITION(v, "rr", JSON_BUILD_VARIANT(v)), + JSON_BUILD_PAIR("raw", JSON_BUILD_BASE64(rri->rr->wire_format, rri->rr->wire_format_size)), + JSON_BUILD_PAIR_CONDITION(rri->ifindex > 0, "ifindex", JSON_BUILD_INTEGER(rri->ifindex)))); if (r < 0) return log_debug_errno(r, "Failed to append notification entry to array: %m"); } diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index b27cf90435..1ce1a55876 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -427,7 +427,6 @@ static void vl_method_resolve_address_complete(DnsQuery *query) { question = dns_query_question_for_protocol(q, q->answer_protocol); DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { - _cleanup_(json_variant_unrefp) JsonVariant *entry = NULL; _cleanup_free_ char *normalized = NULL; r = dns_question_matches_rr(question, rr, NULL); @@ -440,14 +439,11 @@ static void vl_method_resolve_address_complete(DnsQuery *query) { if (r < 0) goto finish; - r = json_build(&entry, - JSON_BUILD_OBJECT( - JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", JSON_BUILD_INTEGER(ifindex)), - JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized)))); - if (r < 0) - goto finish; - - r = json_variant_append_array(&array, entry); + r = json_variant_append_arrayb( + &array, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", JSON_BUILD_INTEGER(ifindex)), + JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized)))); if (r < 0) goto finish; } From e931768eb4687ac5a456987fe5bea4ec87225637 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 Aug 2023 09:41:48 +0200 Subject: [PATCH 3/4] =?UTF-8?q?json:=20rename=20json=5Fappend()=20?= =?UTF-8?q?=E2=86=92=20json=5Fvariant=5Fmerge=5Fobjectb()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit json_append() is a useful wrapper around json_variant_merge(). However, I think the naming sould be cleaned up a bit of both functions. I thinker "merge" is the better word than "append", since it does decidedly more than just append: it replaces existing fields of the same name, hence "merge" sounds more appropriate. This is as opposed to the similar operations for arrays, where no such override logic is applied and we really just append, hence those functions are called "append" already. To make clearer that "merge" is about objects, and "append" about arrays, also include "object" in the name. Also, include "json_variant" in the name, like we do for almost all other functions in the JSON API that take a JSON object as primary input, and hence are kinda object methods. Finally, let's follow the logic that helpers that combine json_build() with some other operation get suffixed with "b" like we already have in some cases. Hence: json_variant_merge() → json_variant_merge_object() json_append() → json_variant_merge_objectb() This mirrors nicely the existing: json_variant_append_array() json_vairant_append_arrayb() This also drops the variant of json_append() that takes a va_arg parameter (i.e. json_appendv()). We have no user of that so far, and given the nature as a helper function only I don#t see that happening, and if it happens after all it's trivial to bring back. --- src/fuzz/fuzz-json.c | 2 +- src/home/homectl.c | 10 +++++----- src/home/homed-home.c | 2 +- src/home/user-record-util.c | 2 +- src/network/networkd-json.c | 11 ++++++---- src/shared/bootspec.c | 6 ++++-- src/shared/elf-util.c | 8 ++++---- src/shared/json.c | 40 ++++++++++++++----------------------- src/shared/json.h | 6 ++---- src/shared/userdb-dropin.c | 4 ++-- src/test/test-json.c | 8 ++++---- 11 files changed, 46 insertions(+), 53 deletions(-) diff --git a/src/fuzz/fuzz-json.c b/src/fuzz/fuzz-json.c index b2cca78501..c83ec83328 100644 --- a/src/fuzz/fuzz-json.c +++ b/src/fuzz/fuzz-json.c @@ -107,7 +107,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { log_debug_errno(r, "json_variant_filter: %d/%m", r); /* I assume we can merge v with itself… */ - r = json_variant_merge(&v, v); + r = json_variant_merge_object(&v, v); log_debug_errno(r, "json_variant_merge: %d/%m", r); r = json_variant_append_array(&v, v); diff --git a/src/home/homectl.c b/src/home/homectl.c index 55323b44e1..b121145197 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -903,7 +903,7 @@ static int apply_identity_changes(JsonVariant **_v) { if (r < 0) return log_error_errno(r, "Failed to filter identity: %m"); - r = json_variant_merge(&v, arg_identity_extra); + r = json_variant_merge_object(&v, arg_identity_extra); if (r < 0) return log_error_errno(r, "Failed to merge identities: %m"); @@ -948,7 +948,7 @@ static int apply_identity_changes(JsonVariant **_v) { if (!json_variant_equal(u, mmid)) continue; - r = json_variant_merge(&add, z); + r = json_variant_merge_object(&add, z); if (r < 0) return log_error_errno(r, "Failed to merge perMachine entry: %m"); @@ -959,7 +959,7 @@ static int apply_identity_changes(JsonVariant **_v) { if (r < 0) return log_error_errno(r, "Failed to filter perMachine: %m"); - r = json_variant_merge(&add, arg_identity_extra_this_machine); + r = json_variant_merge_object(&add, arg_identity_extra_this_machine); if (r < 0) return log_error_errno(r, "Failed to merge in perMachine fields: %m"); @@ -972,7 +972,7 @@ static int apply_identity_changes(JsonVariant **_v) { if (r < 0) return log_error_errno(r, "Failed to filter resource limits: %m"); - r = json_variant_merge(&rlv, arg_identity_extra_rlimits); + r = json_variant_merge_object(&rlv, arg_identity_extra_rlimits); if (r < 0) return log_error_errno(r, "Failed to set resource limits: %m"); @@ -1033,7 +1033,7 @@ static int apply_identity_changes(JsonVariant **_v) { if (r < 0) return log_error_errno(r, "Failed to filter identity (privileged part): %m"); - r = json_variant_merge(&privileged, arg_identity_extra_privileged); + r = json_variant_merge_object(&privileged, arg_identity_extra_privileged); if (r < 0) return log_error_errno(r, "Failed to merge identities (privileged part): %m"); diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 46d6fb589c..206f6480ac 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -2562,7 +2562,7 @@ int home_augment_status( if (r < 0) return r; - r = json_variant_merge(&m, status); + r = json_variant_merge_object(&m, status); if (r < 0) return r; diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index 58f8ecc6f0..089cbb1a1d 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -353,7 +353,7 @@ int user_record_add_binding( /* Merge the new entry with an old one, if that exists */ be = json_variant_ref(json_variant_by_key(binding, SD_ID128_TO_STRING(mid))); if (be) { - r = json_variant_merge(&be, new_binding_entry); + r = json_variant_merge_object(&be, new_binding_entry); if (r < 0) return r; diff --git a/src/network/networkd-json.c b/src/network/networkd-json.c index 7e4e4ff22f..a9e33ac627 100644 --- a/src/network/networkd-json.c +++ b/src/network/networkd-json.c @@ -26,7 +26,7 @@ static int json_append_one(JsonVariant **v, const char *name, JsonVariant *w) { assert(v); assert(name); - return json_append(v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_VARIANT_NON_NULL(name, w))); + return json_variant_merge_objectb(v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_VARIANT_NON_NULL(name, w))); } static int address_build_json(Address *address, JsonVariant **ret) { @@ -379,7 +379,8 @@ static int network_append_json(Network *network, JsonVariant **v) { if (!network) return 0; - return json_append(v, JSON_BUILD_OBJECT( + return json_variant_merge_objectb( + v, JSON_BUILD_OBJECT( JSON_BUILD_PAIR_STRING("NetworkFile", network->filename), JSON_BUILD_PAIR_STRV("NetworkFileDropins", network->dropins), JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network->required_for_online), @@ -418,7 +419,9 @@ static int device_append_json(sd_device *device, JsonVariant **v) { if (sd_device_get_property_value(device, "ID_MODEL_FROM_DATABASE", &model) < 0) (void) sd_device_get_property_value(device, "ID_MODEL", &model); - return json_append(v, JSON_BUILD_OBJECT( + return json_variant_merge_objectb( + v, + JSON_BUILD_OBJECT( JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link), JSON_BUILD_PAIR_STRV_NON_EMPTY("LinkFileDropins", link_dropins), JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path), @@ -915,7 +918,7 @@ static int captive_portal_append_json(Link *link, JsonVariant **v) { if (r <= 0) return r; - return json_append(v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal))); + return json_variant_merge_objectb(v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_STRING("CaptivePortal", captive_portal))); } static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) { diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index 6459f5d2f8..8d16b36be1 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -1428,7 +1428,8 @@ int show_boot_entries(const BootConfig *config, JsonFormatFlags json_format) { return log_oom(); } - r = json_append(&v, JSON_BUILD_OBJECT( + r = json_variant_merge_objectb( + &v, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("type", JSON_BUILD_STRING(boot_entry_type_json_to_string(e->type))), JSON_BUILD_PAIR_CONDITION(e->id, "id", JSON_BUILD_STRING(e->id)), JSON_BUILD_PAIR_CONDITION(e->path, "path", JSON_BUILD_STRING(e->path)), @@ -1451,7 +1452,8 @@ int show_boot_entries(const BootConfig *config, JsonFormatFlags json_format) { /* Sanitizers (only memory sanitizer?) do not like function call with too many * arguments and trigger false positive warnings. Let's not add too many json objects * at once. */ - r = json_append(&v, JSON_BUILD_OBJECT( + r = json_variant_merge_objectb( + &v, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("isReported", JSON_BUILD_BOOLEAN(e->reported_by_loader)), JSON_BUILD_PAIR_CONDITION(e->tries_left != UINT_MAX, "triesLeft", JSON_BUILD_UNSIGNED(e->tries_left)), JSON_BUILD_PAIR_CONDITION(e->tries_done != UINT_MAX, "triesDone", JSON_BUILD_UNSIGNED(e->tries_done)), diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c index da095935e5..7428152faa 100644 --- a/src/shared/elf-util.c +++ b/src/shared/elf-util.c @@ -403,7 +403,7 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e /* If we have a build-id, merge it in the same JSON object so that it appears all * nicely together in the logs/metadata. */ if (id_json) { - r = json_variant_merge(&v, id_json); + r = json_variant_merge_object(&v, id_json); if (r < 0) return log_error_errno(r, "json_variant_merge of package meta with buildId failed: %m"); } @@ -419,7 +419,7 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e if (r < 0) return log_error_errno(r, "Failed to build JSON object: %m"); - r = json_variant_merge(c->package_metadata, w); + r = json_variant_merge_object(c->package_metadata, w); if (r < 0) return log_error_errno(r, "json_variant_merge of package meta with buildId failed: %m"); @@ -712,7 +712,7 @@ static int parse_elf(int fd, const char *executable, char **ret, JsonVariant **r if (r < 0) return log_warning_errno(r, "Failed to build JSON object: %m"); - r = json_variant_merge(&elf_metadata, json_architecture); + r = json_variant_merge_object(&elf_metadata, json_architecture); if (r < 0) return log_warning_errno(r, "Failed to merge JSON objects: %m"); @@ -722,7 +722,7 @@ static int parse_elf(int fd, const char *executable, char **ret, JsonVariant **r #endif /* We always at least have the ELF type, so merge that (and possibly the arch). */ - r = json_variant_merge(&elf_metadata, package_metadata); + r = json_variant_merge_object(&elf_metadata, package_metadata); if (r < 0) return log_warning_errno(r, "Failed to merge JSON objects: %m"); diff --git a/src/shared/json.c b/src/shared/json.c index 9b95e42893..311b05441b 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -2013,7 +2013,7 @@ int json_variant_set_field_strv(JsonVariant **v, const char *field, char **l) { return json_variant_set_field(v, field, m); } -int json_variant_merge(JsonVariant **v, JsonVariant *m) { +int json_variant_merge_object(JsonVariant **v, JsonVariant *m) { _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; _cleanup_free_ JsonVariant **array = NULL; size_t v_elements, m_elements, k; @@ -2076,6 +2076,20 @@ int json_variant_merge(JsonVariant **v, JsonVariant *m) { return 1; } +int json_variant_merge_objectb(JsonVariant **v, ...) { + _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + va_list ap; + int r; + + va_start(ap, v); + r = json_buildv(&w, ap); + va_end(ap); + if (r < 0) + return r; + + return json_variant_merge_object(v, w); +} + int json_variant_append_array(JsonVariant **v, JsonVariant *element) { _cleanup_(json_variant_unrefp) JsonVariant *nv = NULL; bool blank; @@ -4237,30 +4251,6 @@ int json_build(JsonVariant **ret, ...) { return r; } -int json_appendv(JsonVariant **v, va_list ap) { - _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; - int r; - - assert(v); - - r = json_buildv(&w, ap); - if (r < 0) - return r; - - return json_variant_merge(v, w); -} - -int json_append(JsonVariant **v, ...) { - va_list ap; - int r; - - va_start(ap, v); - r = json_appendv(v, ap); - va_end(ap); - - return r; -} - int json_log_internal( JsonVariant *variant, int level, diff --git a/src/shared/json.h b/src/shared/json.h index a5eca65bf8..1fe67d820b 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -216,7 +216,8 @@ int json_variant_append_array(JsonVariant **v, JsonVariant *element); int json_variant_append_arrayb(JsonVariant **v, ...); int json_variant_append_array_nodup(JsonVariant **v, JsonVariant *element); -int json_variant_merge(JsonVariant **v, JsonVariant *m); +int json_variant_merge_object(JsonVariant **v, JsonVariant *m); +int json_variant_merge_objectb(JsonVariant **v, ...); int json_variant_strv(JsonVariant *v, char ***ret); @@ -350,9 +351,6 @@ enum { int json_build(JsonVariant **ret, ...); int json_buildv(JsonVariant **ret, va_list ap); - /* These two functions below are equivalent to json_build() (or json_buildv()) and json_variant_merge(). */ -int json_append(JsonVariant **v, ...); -int json_appendv(JsonVariant **v, va_list ap); /* A bitmask of flags used by the dispatch logic. Note that this is a combined bit mask, that is generated from the bit * mask originally passed into json_dispatch(), the individual bitmask associated with the static JsonDispatch callout diff --git a/src/shared/userdb-dropin.c b/src/shared/userdb-dropin.c index 533fd0f0d3..a2d48fa036 100644 --- a/src/shared/userdb-dropin.c +++ b/src/shared/userdb-dropin.c @@ -64,7 +64,7 @@ static int load_user( else if (r < 0) return r; else { - r = json_variant_merge(&v, privileged_v); + r = json_variant_merge_object(&v, privileged_v); if (r < 0) return r; @@ -208,7 +208,7 @@ static int load_group( else if (r < 0) return r; else { - r = json_variant_merge(&v, privileged_v); + r = json_variant_merge_object(&v, privileged_v); if (r < 0) return r; diff --git a/src/test/test-json.c b/src/test/test-json.c index 64024958ac..46ef5bfa96 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -648,7 +648,7 @@ TEST(variant) { test_variant_one("[ 0, -0, 0.0, -0.0, 0.000, -0.000, 0e0, -0e0, 0e+0, -0e-0, 0e-0, -0e000, 0e+000 ]", test_zeroes); } -TEST(json_append) { +TEST(json_variant_merge_objectb) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; assert_se(json_build(&v, JSON_BUILD_OBJECT( @@ -656,9 +656,9 @@ TEST(json_append) { JSON_BUILD_PAIR("c", JSON_BUILD_CONST_STRING("y")), JSON_BUILD_PAIR("a", JSON_BUILD_CONST_STRING("z")))) >= 0); - assert_se(json_append(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("b", JSON_BUILD_STRING("x")))) >= 0); - assert_se(json_append(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("c", JSON_BUILD_STRING("y")))) >= 0); - assert_se(json_append(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_STRING("z")))) >= 0); + assert_se(json_variant_merge_objectb(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("b", JSON_BUILD_STRING("x")))) >= 0); + assert_se(json_variant_merge_objectb(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("c", JSON_BUILD_STRING("y")))) >= 0); + assert_se(json_variant_merge_objectb(&w, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("a", JSON_BUILD_STRING("z")))) >= 0); assert_se(json_variant_equal(v, w)); } From f5fc7732b0663616d237a04410a70490e456a662 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 Aug 2023 09:55:48 +0200 Subject: [PATCH 4/4] json: add json_variant_set_fieldb() helper Let's a "b" helper for json_variant_set_field() that combines json_build() with json_variant_set_field(), similar to the json_variant_merge_objectb(), json_variant_append_arrayb(). --- src/home/homectl.c | 15 ++++++--------- src/home/user-record-sign.c | 15 +++++++-------- src/shared/json.c | 14 ++++++++++++++ src/shared/json.h | 1 + 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/home/homectl.c b/src/home/homectl.c index b121145197..56b3de4a95 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -2708,7 +2708,7 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_RLIMIT: { - _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *jcur = NULL, *jmax = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *jcur = NULL, *jmax = NULL; _cleanup_free_ char *field = NULL, *t = NULL; const char *eq; struct rlimit rl; @@ -2764,18 +2764,15 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to allocate maximum integer: %m"); - r = json_build(&v, - JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("cur", JSON_BUILD_VARIANT(jcur)), - JSON_BUILD_PAIR("max", JSON_BUILD_VARIANT(jmax)))); - if (r < 0) - return log_error_errno(r, "Failed to build resource limit: %m"); - t = strjoin("RLIMIT_", rlimit_to_string(l)); if (!t) return log_oom(); - r = json_variant_set_field(&arg_identity_extra_rlimits, t, v); + r = json_variant_set_fieldb( + &arg_identity_extra_rlimits, t, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("cur", JSON_BUILD_VARIANT(jcur)), + JSON_BUILD_PAIR("max", JSON_BUILD_VARIANT(jmax)))); if (r < 0) return log_error_errno(r, "Failed to set %s field: %m", rlimit_to_string(l)); diff --git a/src/home/user-record-sign.c b/src/home/user-record-sign.c index cabeb71f2e..cf72eaa556 100644 --- a/src/home/user-record-sign.c +++ b/src/home/user-record-sign.c @@ -31,7 +31,7 @@ static int user_record_signable_json(UserRecord *ur, char **ret) { int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) { _cleanup_(memstream_done) MemStream m = {}; - _cleanup_(json_variant_unrefp) JsonVariant *encoded = NULL, *v = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; _cleanup_(user_record_unrefp) UserRecord *signed_ur = NULL; _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *md_ctx = NULL; _cleanup_free_ char *text = NULL, *key = NULL; @@ -77,15 +77,14 @@ int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) { if (r < 0) return r; - r = json_build(&encoded, JSON_BUILD_ARRAY( - JSON_BUILD_OBJECT(JSON_BUILD_PAIR("data", JSON_BUILD_BASE64(signature, signature_size)), - JSON_BUILD_PAIR("key", JSON_BUILD_STRING(key))))); - if (r < 0) - return r; - v = json_variant_ref(ur->json); - r = json_variant_set_field(&v, "signature", encoded); + r = json_variant_set_fieldb( + &v, + "signature", + JSON_BUILD_ARRAY( + JSON_BUILD_OBJECT(JSON_BUILD_PAIR("data", JSON_BUILD_BASE64(signature, signature_size)), + JSON_BUILD_PAIR("key", JSON_BUILD_STRING(key))))); if (r < 0) return r; diff --git a/src/shared/json.c b/src/shared/json.c index 311b05441b..e17f89564d 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -1958,6 +1958,20 @@ int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *valu return 1; } +int json_variant_set_fieldb(JsonVariant **v, const char *field, ...) { + _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; + va_list ap; + int r; + + va_start(ap, field); + r = json_buildv(&w, ap); + va_end(ap); + if (r < 0) + return r; + + return json_variant_set_field(v, field, w); +} + int json_variant_set_field_string(JsonVariant **v, const char *field, const char *value) { _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; int r; diff --git a/src/shared/json.h b/src/shared/json.h index 1fe67d820b..1700d1d8fa 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -204,6 +204,7 @@ int json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char int json_variant_filter(JsonVariant **v, char **to_remove); int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *value); +int json_variant_set_fieldb(JsonVariant **v, const char *field, ...); int json_variant_set_field_string(JsonVariant **v, const char *field, const char *value); int json_variant_set_field_integer(JsonVariant **v, const char *field, int64_t value); int json_variant_set_field_unsigned(JsonVariant **v, const char *field, uint64_t value);