mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
Merge pull request #28376 from yuwata/json_append
Use json_append() and json_variant_append_array()
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "random-util.h"
|
||||
#include "set.h"
|
||||
#include "siphash24.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
@@ -2106,3 +2107,51 @@ bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needl
|
||||
|
||||
return set_fnmatch_one(include_patterns, needle);
|
||||
}
|
||||
|
||||
static int hashmap_entry_compare(
|
||||
struct hashmap_base_entry * const *a,
|
||||
struct hashmap_base_entry * const *b,
|
||||
compare_func_t compare) {
|
||||
|
||||
assert(a && *a);
|
||||
assert(b && *b);
|
||||
assert(compare);
|
||||
|
||||
return compare((*a)->key, (*b)->key);
|
||||
}
|
||||
|
||||
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
|
||||
_cleanup_free_ struct hashmap_base_entry **entries = NULL;
|
||||
Iterator iter;
|
||||
unsigned idx;
|
||||
size_t n = 0;
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (_hashmap_size(h) == 0) {
|
||||
*ret = NULL;
|
||||
if (ret_n)
|
||||
*ret_n = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
entries = new(struct hashmap_base_entry*, _hashmap_size(h));
|
||||
if (!entries)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH_IDX(idx, h, iter)
|
||||
entries[n++] = bucket_at(h, idx);
|
||||
|
||||
assert(n == _hashmap_size(h));
|
||||
|
||||
typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare);
|
||||
|
||||
/* Reuse the array. */
|
||||
FOREACH_ARRAY(e, entries, n)
|
||||
*e = entry_value(h, *e);
|
||||
|
||||
*ret = (void**) TAKE_PTR(entries);
|
||||
if (ret_n)
|
||||
*ret_n = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -398,6 +398,17 @@ static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) {
|
||||
return _hashmap_get_strv(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
|
||||
static inline int hashmap_dump_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
static inline int ordered_hashmap_dump_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashmaps are iterated in unpredictable order.
|
||||
* OrderedHashmaps are an exception to this. They are iterated in the order
|
||||
|
||||
@@ -1671,15 +1671,26 @@ static int message_append_cmdline(sd_bus_message *m, const char *signature, char
|
||||
|
||||
static int json_transform_one(sd_bus_message *m, JsonVariant **ret);
|
||||
|
||||
static int json_transform_array_or_struct(sd_bus_message *m, JsonVariant **ret) {
|
||||
JsonVariant **elements = NULL;
|
||||
size_t n_elements = 0;
|
||||
static int json_transform_and_append(sd_bus_message *m, JsonVariant **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *element = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
CLEANUP_ARRAY(elements, n_elements, json_variant_unref_many);
|
||||
r = json_transform_one(m, &element);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return json_variant_append_array(ret, element);
|
||||
}
|
||||
|
||||
static int json_transform_array_or_struct(sd_bus_message *m, JsonVariant **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
for (;;) {
|
||||
r = sd_bus_message_at_end(m, false);
|
||||
@@ -1688,17 +1699,16 @@ static int json_transform_array_or_struct(sd_bus_message *m, JsonVariant **ret)
|
||||
if (r > 0)
|
||||
break;
|
||||
|
||||
if (!GREEDY_REALLOC(elements, n_elements + 1))
|
||||
return log_oom();
|
||||
|
||||
r = json_transform_one(m, elements + n_elements);
|
||||
r = json_transform_and_append(m, &array);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n_elements++;
|
||||
}
|
||||
|
||||
return json_variant_new_array(ret, elements, n_elements);
|
||||
if (!array)
|
||||
return json_variant_new_array(ret, NULL, 0);
|
||||
|
||||
*ret = TAKE_PTR(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_transform_variant(sd_bus_message *m, const char *contents, JsonVariant **ret) {
|
||||
@@ -1722,15 +1732,12 @@ static int json_transform_variant(sd_bus_message *m, const char *contents, JsonV
|
||||
}
|
||||
|
||||
static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) {
|
||||
JsonVariant **elements = NULL;
|
||||
size_t n_elements = 0;
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
CLEANUP_ARRAY(elements, n_elements, json_variant_unref_many);
|
||||
|
||||
for (;;) {
|
||||
const char *contents;
|
||||
char type;
|
||||
@@ -1747,31 +1754,28 @@ static int json_transform_dict_array(sd_bus_message *m, JsonVariant **ret) {
|
||||
|
||||
assert(type == 'e');
|
||||
|
||||
if (!GREEDY_REALLOC(elements, n_elements + 2))
|
||||
return log_oom();
|
||||
|
||||
r = sd_bus_message_enter_container(m, type, contents);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = json_transform_one(m, elements + n_elements);
|
||||
r = json_transform_and_append(m, &array);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n_elements++;
|
||||
|
||||
r = json_transform_one(m, elements + n_elements);
|
||||
r = json_transform_and_append(m, &array);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n_elements++;
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
}
|
||||
|
||||
return json_variant_new_object(ret, elements, n_elements);
|
||||
if (!array)
|
||||
return json_variant_new_array(ret, NULL, 0);
|
||||
|
||||
*ret = TAKE_PTR(array);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_transform_one(sd_bus_message *m, JsonVariant **ret) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -938,22 +938,21 @@ void json_escape(
|
||||
|
||||
typedef struct JsonData {
|
||||
JsonVariant* name;
|
||||
size_t n_values;
|
||||
JsonVariant* values[];
|
||||
JsonVariant* values;
|
||||
} JsonData;
|
||||
|
||||
static JsonData* json_data_free(struct JsonData *d) {
|
||||
static JsonData* json_data_free(JsonData *d) {
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
json_variant_unref(d->name);
|
||||
|
||||
FOREACH_ARRAY(v, d->values, d->n_values)
|
||||
json_variant_unref(*v);
|
||||
json_variant_unref(d->values);
|
||||
|
||||
return mfree(d);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(JsonData*, json_data_free);
|
||||
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(json_data_hash_ops_free,
|
||||
char, string_hash_func, string_compare_func,
|
||||
JsonData, json_data_free);
|
||||
@@ -966,7 +965,7 @@ static int update_json_data(
|
||||
size_t size) {
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
JsonData *d = NULL;
|
||||
JsonData *d;
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
@@ -986,35 +985,31 @@ static int update_json_data(
|
||||
|
||||
d = hashmap_get(h, name);
|
||||
if (d) {
|
||||
JsonData *w;
|
||||
r = json_variant_append_array(&d->values, v);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append JSON value into array: %m");
|
||||
} else {
|
||||
_cleanup_(json_data_freep) JsonData *e = NULL;
|
||||
|
||||
w = realloc(d, offsetof(JsonData, values) + sizeof(JsonVariant*) * (d->n_values + 1));
|
||||
if (!w)
|
||||
e = new0(JsonData, 1);
|
||||
if (!e)
|
||||
return log_oom();
|
||||
|
||||
d = w;
|
||||
assert_se(hashmap_update(h, json_variant_string(d->name), d) >= 0);
|
||||
} else {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *n = NULL;
|
||||
|
||||
r = json_variant_new_string(&n, name);
|
||||
r = json_variant_new_string(&e->name, name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate JSON name variant: %m");
|
||||
|
||||
d = malloc0(offsetof(JsonData, values) + sizeof(JsonVariant*));
|
||||
if (!d)
|
||||
return log_oom();
|
||||
r = json_variant_append_array(&e->values, v);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create JSON value array: %m");
|
||||
|
||||
r = hashmap_put(h, json_variant_string(n), d);
|
||||
if (r < 0) {
|
||||
free(d);
|
||||
return log_error_errno(r, "Failed to insert JSON name into hashmap: %m");
|
||||
}
|
||||
r = hashmap_put(h, json_variant_string(e->name), e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to insert JSON data into hashmap: %m");
|
||||
|
||||
d->name = TAKE_PTR(n);
|
||||
TAKE_PTR(e);
|
||||
}
|
||||
|
||||
d->values[d->n_values++] = TAKE_PTR(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1156,28 +1151,20 @@ static int output_json(
|
||||
CLEANUP_ARRAY(array, n, json_variant_unref_many);
|
||||
|
||||
HASHMAP_FOREACH(d, h) {
|
||||
assert(d->n_values > 0);
|
||||
assert(json_variant_elements(d->values) > 0);
|
||||
|
||||
array[n++] = json_variant_ref(d->name);
|
||||
|
||||
if (d->n_values == 1)
|
||||
array[n++] = json_variant_ref(d->values[0]);
|
||||
else {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *q = NULL;
|
||||
|
||||
r = json_variant_new_array(&q, d->values, d->n_values);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create JSON array: %m");
|
||||
|
||||
array[n++] = TAKE_PTR(q);
|
||||
}
|
||||
if (json_variant_elements(d->values) == 1)
|
||||
array[n++] = json_variant_ref(json_variant_by_index(d->values, 0));
|
||||
else
|
||||
array[n++] = json_variant_ref(d->values);
|
||||
}
|
||||
|
||||
r = json_variant_new_object(&object, array, n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate JSON object: %m");
|
||||
|
||||
|
||||
return json_variant_dump(object,
|
||||
output_mode_to_json_format_flags(mode) |
|
||||
(FLAGS_SET(flags, OUTPUT_COLOR) ? JSON_FORMAT_COLOR : 0),
|
||||
|
||||
@@ -3838,34 +3838,30 @@ int tpm2_pcr_mask_from_string(const char *arg, uint32_t *ret_mask) {
|
||||
|
||||
int tpm2_make_pcr_json_array(uint32_t pcr_mask, JsonVariant **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *a = NULL;
|
||||
JsonVariant* pcr_array[TPM2_PCRS_MAX];
|
||||
unsigned n_pcrs = 0;
|
||||
int r;
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(pcr_array); i++) {
|
||||
assert(ret);
|
||||
|
||||
for (size_t i = 0; i < TPM2_PCRS_MAX; i++) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *e = NULL;
|
||||
|
||||
if ((pcr_mask & (UINT32_C(1) << i)) == 0)
|
||||
continue;
|
||||
|
||||
r = json_variant_new_integer(pcr_array + n_pcrs, i);
|
||||
r = json_variant_new_integer(&e, i);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return r;
|
||||
|
||||
n_pcrs++;
|
||||
r = json_variant_append_array(&a, e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = json_variant_new_array(&a, pcr_array, n_pcrs);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (!a)
|
||||
return json_variant_new_array(ret, NULL, 0);
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(a);
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
FOREACH_ARRAY(v, pcr_array, n_pcrs)
|
||||
json_variant_unref(*v);
|
||||
|
||||
return r;
|
||||
*ret = TAKE_PTR(a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tpm2_parse_pcr_json_array(JsonVariant *v, uint32_t *ret) {
|
||||
|
||||
@@ -963,6 +963,44 @@ TEST(string_strv_hashmap) {
|
||||
assert_se(strv_equal(s, STRV_MAKE("bar", "BAR")));
|
||||
}
|
||||
|
||||
TEST(hashmap_dump_sorted) {
|
||||
static void * const expected[] = { UINT_TO_PTR(123U), UINT_TO_PTR(12U), UINT_TO_PTR(345U), };
|
||||
_cleanup_hashmap_free_ Hashmap *m = NULL;
|
||||
_cleanup_free_ void **vals = NULL;
|
||||
size_t n;
|
||||
|
||||
assert_se(m = hashmap_new(&string_hash_ops));
|
||||
|
||||
assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
|
||||
assert_se(n == 0);
|
||||
assert_se(!vals);
|
||||
|
||||
assert_se(hashmap_put(m, "key 0", expected[0]) == 1);
|
||||
assert_se(hashmap_put(m, "key 1", expected[1]) == 1);
|
||||
assert_se(hashmap_put(m, "key 2", expected[2]) == 1);
|
||||
|
||||
assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
|
||||
assert_se(n == ELEMENTSOF(expected));
|
||||
assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0);
|
||||
|
||||
vals = mfree(vals);
|
||||
m = hashmap_free(m);
|
||||
|
||||
assert_se(m = hashmap_new(NULL));
|
||||
|
||||
assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
|
||||
assert_se(n == 0);
|
||||
assert_se(!vals);
|
||||
|
||||
assert_se(hashmap_put(m, UINT_TO_PTR(333U), expected[2]) == 1);
|
||||
assert_se(hashmap_put(m, UINT_TO_PTR(222U), expected[1]) == 1);
|
||||
assert_se(hashmap_put(m, UINT_TO_PTR(111U), expected[0]) == 1);
|
||||
|
||||
assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
|
||||
assert_se(n == ELEMENTSOF(expected));
|
||||
assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0);
|
||||
}
|
||||
|
||||
/* Signal to test-hashmap.c that tests from this compilation unit were run. */
|
||||
extern int n_extern_tests_run;
|
||||
TEST(ensure_extern_hashmap_tests) {
|
||||
|
||||
Reference in New Issue
Block a user