diff options
-rw-r--r-- | src/shared/json.c | 318 | ||||
-rw-r--r-- | src/shared/json.h | 58 |
2 files changed, 371 insertions, 5 deletions
diff --git a/src/shared/json.c b/src/shared/json.c index 58d6117ac9..8d9a90203a 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -3242,7 +3242,7 @@ int json_buildv(JsonVariant **ret, va_list ap) { }; for (;;) { - _cleanup_(json_variant_unrefp) JsonVariant *add = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *add = NULL, *add_more = NULL; size_t n_subtract = 0; /* how much to subtract from current->n_suppress, i.e. how many elements would * have been added to the current variant */ JsonStack *current; @@ -3707,6 +3707,34 @@ int json_buildv(JsonVariant **ret, va_list ap) { break; } + case _JSON_BUILD_HW_ADDR: { + const struct hw_addr_data *hw_addr; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + assert_se(hw_addr = va_arg(ap, struct hw_addr_data*)); + + if (current->n_suppress == 0) { + r = json_variant_new_array_bytes(&add, hw_addr->bytes, hw_addr->length); + if (r < 0) + goto finish; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _JSON_BUILD_OBJECT_BEGIN: if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { @@ -3806,16 +3834,298 @@ int json_buildv(JsonVariant **ret, va_list ap) { current->expect = EXPECT_OBJECT_VALUE; break; - }} + } + + case _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO: { + const char *n; + uint64_t u; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + u = va_arg(ap, uint64_t); + + if (u != 0 && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_unsigned(&add_more, u); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_FINITE_USEC: { + const char *n; + usec_t u; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + u = va_arg(ap, usec_t); + + if (u != USEC_INFINITY && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; - /* If a variant was generated, add it to our current variant, but only if we are not supposed to suppress additions */ + r = json_variant_new_unsigned(&add_more, u); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_STRING_NON_EMPTY: { + const char *n, *s; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + s = va_arg(ap, const char *); + + if (!isempty(s) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_string(&add_more, s); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_STRV_NON_EMPTY: { + const char *n; + char **l; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + l = va_arg(ap, char **); + + if (!strv_isempty(l) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_strv(&add_more, l); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_VARIANT_NON_NULL: { + JsonVariant *v; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + v = va_arg(ap, JsonVariant *); + + if (v && !json_variant_is_null(v) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + add_more = json_variant_ref(v); + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL: { + const struct in_addr *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct in_addr *); + + if (in4_addr_is_set(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a, sizeof(struct in_addr)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL: { + const struct in6_addr *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct in6_addr *); + + if (in6_addr_is_set(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a, sizeof(struct in6_addr)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_IN_ADDR_NON_NULL: { + const union in_addr_union *a; + const char *n; + int f; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const union in_addr_union *); + f = va_arg(ap, int); + + if (in_addr_is_set(f, a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a->bytes, FAMILY_ADDRESS_SIZE(f)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL: { + const struct ether_addr *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct ether_addr *); + + if (!ether_addr_is_null(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a->ether_addr_octet, sizeof(struct ether_addr)); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + + case _JSON_BUILD_PAIR_HW_ADDR_NON_NULL: { + const struct hw_addr_data *a; + const char *n; + + if (current->expect != EXPECT_OBJECT_KEY) { + r = -EINVAL; + goto finish; + } + + n = va_arg(ap, const char *); + a = va_arg(ap, const struct hw_addr_data *); + + if (!hw_addr_is_null(a) && current->n_suppress == 0) { + r = json_variant_new_string(&add, n); + if (r < 0) + goto finish; + + r = json_variant_new_array_bytes(&add_more, a->bytes, a->length); + if (r < 0) + goto finish; + } + + n_subtract = 2; /* we generated two item */ + + current->expect = EXPECT_OBJECT_KEY; + break; + } + } + + /* If variants were generated, add them to our current variant, but only if we are not supposed to suppress additions */ if (add && current->n_suppress == 0) { - if (!GREEDY_REALLOC(current->elements, current->n_elements + 1)) { + if (!GREEDY_REALLOC(current->elements, current->n_elements + 1 + !!add_more)) { r = -ENOMEM; goto finish; } current->elements[current->n_elements++] = TAKE_PTR(add); + if (add_more) + current->elements[current->n_elements++] = TAKE_PTR(add_more); } /* If we are supposed to suppress items, let's subtract how many items where generated from that diff --git a/src/shared/json.h b/src/shared/json.h index 2248515ef7..8760354b66 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -9,9 +9,13 @@ #include "sd-id128.h" +#include "ether-addr-util.h" +#include "in-addr-util.h" +#include "log.h" #include "macro.h" #include "string-util.h" -#include "log.h" +#include "strv.h" +#include "time-util.h" /* In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has @@ -236,6 +240,18 @@ enum { _JSON_BUILD_HEX, _JSON_BUILD_ID128, _JSON_BUILD_BYTE_ARRAY, + _JSON_BUILD_HW_ADDR, + _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, + _JSON_BUILD_PAIR_FINITE_USEC, + _JSON_BUILD_PAIR_STRING_NON_EMPTY, + _JSON_BUILD_PAIR_STRV_NON_EMPTY, + _JSON_BUILD_PAIR_VARIANT_NON_NULL, + _JSON_BUILD_PAIR_VARIANT_ARRAY_NON_EMPTY, + _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, + _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, + _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, + _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, + _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, _JSON_BUILD_MAX, }; @@ -260,6 +276,46 @@ enum { #define JSON_BUILD_ID128(id) _JSON_BUILD_ID128, (const sd_id128_t*) { &(id) } #define JSON_BUILD_BYTE_ARRAY(v, n) _JSON_BUILD_BYTE_ARRAY, (const void*) { v }, (size_t) { n } #define JSON_BUILD_CONST_STRING(s) _JSON_BUILD_VARIANT, JSON_VARIANT_STRING_CONST(s) +#define JSON_BUILD_IN4_ADDR(v) JSON_BUILD_BYTE_ARRAY((const struct in_addr*) { v }, sizeof(struct in_addr)) +#define JSON_BUILD_IN6_ADDR(v) JSON_BUILD_BYTE_ARRAY((const struct in6_addr*) { v }, sizeof(struct in6_addr)) +#define JSON_BUILD_IN_ADDR(v, f) JSON_BUILD_BYTE_ARRAY(((const union in_addr_union*) { v })->bytes, FAMILY_ADDRESS_SIZE_SAFE(f)) +#define JSON_BUILD_ETHER_ADDR(v) JSON_BUILD_BYTE_ARRAY(((const struct ether_addr*) { v })->ether_addr_octet, sizeof(struct ether_addr)) +#define JSON_BUILD_HW_ADDR(v) _JSON_BUILD_HW_ADDR, (const struct hw_addr_data*) { v } + +#define JSON_BUILD_PAIR_STRING(name, s) JSON_BUILD_PAIR(name, JSON_BUILD_STRING(s)) +#define JSON_BUILD_PAIR_INTEGER(name, i) JSON_BUILD_PAIR(name, JSON_BUILD_INTEGER(i)) +#define JSON_BUILD_PAIR_UNSIGNED(name, u) JSON_BUILD_PAIR(name, JSON_BUILD_UNSIGNED(u)) +#define JSON_BUILD_PAIR_REAL(name, d) JSON_BUILD_PAIR(name, JSON_BUILD_REAL(d)) +#define JSON_BUILD_PAIR_BOOLEAN(name, b) JSON_BUILD_PAIR(name, JSON_BUILD_BOOLEAN(b)) +#define JSON_BUILD_PAIR_ARRAY(name, ...) JSON_BUILD_PAIR(name, JSON_BUILD_ARRAY(__VA_ARGS__)) +#define JSON_BUILD_PAIR_EMPTY_ARRAY(name) JSON_BUILD_PAIR(name, JSON_BUILD_EMPTY_ARRAY) +#define JSON_BUILD_PAIR_OBJECT(name, ...) JSON_BUILD_PAIR(name, JSON_BUILD_OBJECT(__VA_ARGS__)) +#define JSON_BUILD_PAIR_EMPTY_OBJECT(name) JSON_BUILD_PAIR(name, JSON_BUILD_EMPTY_OBJECT) +#define JSON_BUILD_PAIR_NULL(name) JSON_BUILD_PAIR(name, JSON_BUILD_NULL) +#define JSON_BUILD_PAIR_VARIANT(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_VARIANT(v)) +#define JSON_BUILD_PAIR_VARIANT_ARRAY(name, v, n) JSON_BUILD_PAIR(name, JSON_BUILD_VARIANT_ARRAY(v, n)) +#define JSON_BUILD_PAIR_LITERAL(name, l) JSON_BUILD_PAIR(name, JSON_BUILD_LITERAL(l)) +#define JSON_BUILD_PAIR_STRV(name, l) JSON_BUILD_PAIR(name, JSON_BUILD_STRV(l)) +#define JSON_BUILD_PAIR_BASE64(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_BASE64(p, n)) +#define JSON_BUILD_PAIR_HEX(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_HEX(p, n)) +#define JSON_BUILD_PAIR_ID128(name, id) JSON_BUILD_PAIR(name, JSON_BUILD_ID128(id)) +#define JSON_BUILD_PAIR_BYTE_ARRAY(name, v, n) JSON_BUILD_PAIR(name, JSON_BUILD_BYTE_ARRAY(v, n)) +#define JSON_BUILD_PAIR_IN4_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_IN4_ADDR(v)) +#define JSON_BUILD_PAIR_IN6_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_IN6_ADDR(v)) +#define JSON_BUILD_PAIR_IN_ADDR(name, v, f) JSON_BUILD_PAIR(name, JSON_BUILD_IN_ADDR(v, f)) +#define JSON_BUILD_PAIR_ETHER_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_ETHER_ADDR(v)) +#define JSON_BUILD_PAIR_HW_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_HW_ADDR(v)) + +#define JSON_BUILD_PAIR_UNSIGNED_NON_ZERO(name, u) _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO, (const char*) { name }, (uint64_t) { u } +#define JSON_BUILD_PAIR_FINITE_USEC(name, u) _JSON_BUILD_PAIR_FINITE_USEC, (const char*) { name }, (usec_t) { u } +#define JSON_BUILD_PAIR_STRING_NON_EMPTY(name, s) _JSON_BUILD_PAIR_STRING_NON_EMPTY, (const char*) { name }, (const char*) { s } +#define JSON_BUILD_PAIR_STRV_NON_EMPTY(name, l) _JSON_BUILD_PAIR_STRV_NON_EMPTY, (const char*) { name }, (char**) { l } +#define JSON_BUILD_PAIR_VARIANT_NON_NULL(name, v) _JSON_BUILD_PAIR_VARIANT_NON_NULL, (const char*) { name }, (JsonVariant*) { v } +#define JSON_BUILD_PAIR_IN4_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN4_ADDR_NON_NULL, (const char*) { name }, (const struct in_addr*) { v } +#define JSON_BUILD_PAIR_IN6_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_IN6_ADDR_NON_NULL, (const char*) { name }, (const struct in6_addr*) { v } +#define JSON_BUILD_PAIR_IN_ADDR_NON_NULL(name, v, f) _JSON_BUILD_PAIR_IN_ADDR_NON_NULL, (const char*) { name }, (const union in_addr_union*) { v }, (int) { f } +#define JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL, (const char*) { name }, (const struct ether_addr*) { v } +#define JSON_BUILD_PAIR_HW_ADDR_NON_NULL(name, v) _JSON_BUILD_PAIR_HW_ADDR_NON_NULL, (const char*) { name }, (const struct hw_addr_data*) { v } int json_build(JsonVariant **ret, ...); int json_buildv(JsonVariant **ret, va_list ap); |