]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/json.h
json: add new flag for forcing a flush after dumping json data to file
[thirdparty/systemd.git] / src / shared / json.h
CommitLineData
cd0b6c53 1/* SPDX-License-Identifier: LGPL-2.1+ */
cd0b6c53
LP
2#pragma once
3
f325aaf3 4#include <fcntl.h>
cd0b6c53
LP
5#include <stdbool.h>
6#include <stddef.h>
7#include <stdint.h>
ca78ad1d 8#include <stdio.h>
cd0b6c53
LP
9
10#include "macro.h"
11#include "string-util.h"
ca78ad1d 12#include "log.h"
cd0b6c53
LP
13
14/*
15 In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has
5238e957 16 benefits over various other implementations:
cd0b6c53
LP
17
18 - We need support for 64bit signed and unsigned integers, i.e. the full 64,5bit range of -9223372036854775808…18446744073709551615
19 - All our variants are immutable after creation
20 - Special values such as true, false, zero, null, empty strings, empty array, empty objects require zero dynamic memory
21 - Progressive parsing
22 - Our integer/real type implicitly converts, but only if that's safe and loss-lessly possible
23 - There's a "builder" for putting together objects easily in varargs function calls
24 - There's a "dispatcher" for mapping objects to C data structures
25 - Every variant optionally carries parsing location information, which simplifies debugging and parse log error generation
26 - Formatter has color, line, column support
27
28 Limitations:
29 - Doesn't allow embedded NUL in strings
30 - Can't store integers outside of the -9223372036854775808…18446744073709551615 range (it will use 'long double' for
31 values outside this range, which is lossy)
32 - Can't store negative zero (will be treated identical to positive zero, and not retained across serialization)
33 - Can't store non-integer numbers that can't be stored in "long double" losslessly
34 - Allows creation and parsing of objects with duplicate keys. The "dispatcher" will refuse them however. This means
35 we can parse and pass around such objects, but will carefully refuse them when we convert them into our own data.
36
37 (These limitations should be pretty much in line with those of other JSON implementations, in fact might be less
38 limiting in most cases even.)
39*/
40
41typedef struct JsonVariant JsonVariant;
42
43typedef enum JsonVariantType {
44 JSON_VARIANT_STRING,
45 JSON_VARIANT_INTEGER,
46 JSON_VARIANT_UNSIGNED,
47 JSON_VARIANT_REAL,
48 JSON_VARIANT_NUMBER, /* This a pseudo-type: we can never create variants of this type, but we use it as wildcard check for the above three types */
49 JSON_VARIANT_BOOLEAN,
50 JSON_VARIANT_ARRAY,
51 JSON_VARIANT_OBJECT,
52 JSON_VARIANT_NULL,
53 _JSON_VARIANT_TYPE_MAX,
54 _JSON_VARIANT_TYPE_INVALID = -1
55} JsonVariantType;
56
57int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n);
cc164891 58int json_variant_new_base64(JsonVariant **ret, const void *p, size_t n);
cd0b6c53
LP
59int json_variant_new_integer(JsonVariant **ret, intmax_t i);
60int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u);
61int json_variant_new_real(JsonVariant **ret, long double d);
62int json_variant_new_boolean(JsonVariant **ret, bool b);
63int json_variant_new_array(JsonVariant **ret, JsonVariant **array, size_t n);
64int json_variant_new_array_bytes(JsonVariant **ret, const void *p, size_t n);
65int json_variant_new_array_strv(JsonVariant **ret, char **l);
66int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n);
67int json_variant_new_null(JsonVariant **ret);
68
69static inline int json_variant_new_string(JsonVariant **ret, const char *s) {
cbb3092c 70 return json_variant_new_stringn(ret, s, (size_t) -1);
cd0b6c53
LP
71}
72
73JsonVariant *json_variant_ref(JsonVariant *v);
74JsonVariant *json_variant_unref(JsonVariant *v);
75void json_variant_unref_many(JsonVariant **array, size_t n);
76
77DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref);
78
79const char *json_variant_string(JsonVariant *v);
80intmax_t json_variant_integer(JsonVariant *v);
81uintmax_t json_variant_unsigned(JsonVariant *v);
82long double json_variant_real(JsonVariant *v);
83bool json_variant_boolean(JsonVariant *v);
84
85JsonVariantType json_variant_type(JsonVariant *v);
86bool json_variant_has_type(JsonVariant *v, JsonVariantType type);
87
88static inline bool json_variant_is_string(JsonVariant *v) {
89 return json_variant_has_type(v, JSON_VARIANT_STRING);
90}
91
92static inline bool json_variant_is_integer(JsonVariant *v) {
93 return json_variant_has_type(v, JSON_VARIANT_INTEGER);
94}
95
96static inline bool json_variant_is_unsigned(JsonVariant *v) {
97 return json_variant_has_type(v, JSON_VARIANT_UNSIGNED);
98}
99
100static inline bool json_variant_is_real(JsonVariant *v) {
101 return json_variant_has_type(v, JSON_VARIANT_REAL);
102}
103
104static inline bool json_variant_is_number(JsonVariant *v) {
105 return json_variant_has_type(v, JSON_VARIANT_NUMBER);
106}
107
108static inline bool json_variant_is_boolean(JsonVariant *v) {
109 return json_variant_has_type(v, JSON_VARIANT_BOOLEAN);
110}
111
112static inline bool json_variant_is_array(JsonVariant *v) {
113 return json_variant_has_type(v, JSON_VARIANT_ARRAY);
114}
115
116static inline bool json_variant_is_object(JsonVariant *v) {
117 return json_variant_has_type(v, JSON_VARIANT_OBJECT);
118}
119
120static inline bool json_variant_is_null(JsonVariant *v) {
121 return json_variant_has_type(v, JSON_VARIANT_NULL);
122}
123
124bool json_variant_is_negative(JsonVariant *v);
e787b211
LP
125bool json_variant_is_blank_object(JsonVariant *v);
126bool json_variant_is_blank_array(JsonVariant *v);
b7fc90a2
LP
127bool json_variant_is_normalized(JsonVariant *v);
128bool json_variant_is_sorted(JsonVariant *v);
cd0b6c53
LP
129
130size_t json_variant_elements(JsonVariant *v);
131JsonVariant *json_variant_by_index(JsonVariant *v, size_t index);
132JsonVariant *json_variant_by_key(JsonVariant *v, const char *key);
133JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVariant **ret_key);
134
135bool json_variant_equal(JsonVariant *a, JsonVariant *b);
136
83bc6cb7
LP
137void json_variant_sensitive(JsonVariant *v);
138
cd0b6c53
LP
139struct json_variant_foreach_state {
140 JsonVariant *variant;
141 size_t idx;
142};
143
144#define JSON_VARIANT_ARRAY_FOREACH(i, v) \
145 for (struct json_variant_foreach_state _state = { (v), 0 }; \
1b266e3c
LP
146 json_variant_is_array(_state.variant) && \
147 _state.idx < json_variant_elements(_state.variant) && \
cd0b6c53
LP
148 ({ i = json_variant_by_index(_state.variant, _state.idx); \
149 true; }); \
150 _state.idx++)
151
152#define JSON_VARIANT_OBJECT_FOREACH(k, e, v) \
153 for (struct json_variant_foreach_state _state = { (v), 0 }; \
1b266e3c
LP
154 json_variant_is_object(_state.variant) && \
155 _state.idx < json_variant_elements(_state.variant) && \
33d60b8d 156 ({ k = json_variant_string(json_variant_by_index(_state.variant, _state.idx)); \
cd0b6c53
LP
157 e = json_variant_by_index(_state.variant, _state.idx + 1); \
158 true; }); \
159 _state.idx += 2)
160
161int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
162
897f099b 163typedef enum JsonFormatFlags {
ab91733c
LP
164 JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
165 JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
166 JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */
6af022fe 167 JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insert ANSI color sequences if colors_enabled() says so */
ab91733c
LP
168 JSON_FORMAT_SOURCE = 1 << 4, /* prefix with source filename/line/column */
169 JSON_FORMAT_SSE = 1 << 5, /* prefix/suffix with W3C server-sent events */
170 JSON_FORMAT_SEQ = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
0b1f2e8a 171 JSON_FORMAT_FLUSH = 1 << 7, /* call fflush() after dumping JSON */
897f099b 172} JsonFormatFlags;
cd0b6c53 173
897f099b
LP
174int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
175void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
cd0b6c53 176
f2ff34ff
LP
177int json_variant_filter(JsonVariant **v, char **to_remove);
178
78a41236 179int json_variant_set_field(JsonVariant **v, const char *field, JsonVariant *value);
15f1fb3e
LP
180int json_variant_set_field_string(JsonVariant **v, const char *field, const char *value);
181int json_variant_set_field_unsigned(JsonVariant **v, const char *field, uintmax_t value);
78a41236 182
21e21511
LP
183int json_variant_append_array(JsonVariant **v, JsonVariant *element);
184
ca409a59
LP
185int json_variant_merge(JsonVariant **v, JsonVariant *m);
186
22f14d6b
LP
187int json_variant_strv(JsonVariant *v, char ***ret);
188
b7fc90a2
LP
189int json_variant_sort(JsonVariant **v);
190int json_variant_normalize(JsonVariant **v);
191
d642f640
LP
192typedef enum JsonParseFlags {
193 JSON_PARSE_SENSITIVE = 1 << 0, /* mark variant as "sensitive", i.e. something containing secret key material or such */
194} JsonParseFlags;
f325aaf3 195
d642f640
LP
196int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
197int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
198int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
199
200static inline int json_parse_file(FILE *f, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
201 return json_parse_file_at(f, AT_FDCWD, path, flags, ret, ret_line, ret_column);
f325aaf3 202}
cd0b6c53
LP
203
204enum {
205 _JSON_BUILD_STRING,
206 _JSON_BUILD_INTEGER,
207 _JSON_BUILD_UNSIGNED,
208 _JSON_BUILD_REAL,
209 _JSON_BUILD_BOOLEAN,
210 _JSON_BUILD_ARRAY_BEGIN,
211 _JSON_BUILD_ARRAY_END,
212 _JSON_BUILD_OBJECT_BEGIN,
213 _JSON_BUILD_OBJECT_END,
214 _JSON_BUILD_PAIR,
319a4f27 215 _JSON_BUILD_PAIR_CONDITION,
cd0b6c53
LP
216 _JSON_BUILD_NULL,
217 _JSON_BUILD_VARIANT,
218 _JSON_BUILD_LITERAL,
219 _JSON_BUILD_STRV,
886b0c93 220 _JSON_BUILD_BASE64,
cd0b6c53
LP
221 _JSON_BUILD_MAX,
222};
223
224#define JSON_BUILD_STRING(s) _JSON_BUILD_STRING, ({ const char *_x = s; _x; })
225#define JSON_BUILD_INTEGER(i) _JSON_BUILD_INTEGER, ({ intmax_t _x = i; _x; })
226#define JSON_BUILD_UNSIGNED(u) _JSON_BUILD_UNSIGNED, ({ uintmax_t _x = u; _x; })
227#define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, ({ long double _x = d; _x; })
228#define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, ({ bool _x = b; _x; })
229#define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
aafa52ab 230#define JSON_BUILD_EMPTY_ARRAY _JSON_BUILD_ARRAY_BEGIN, _JSON_BUILD_ARRAY_END
cd0b6c53 231#define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END
aafa52ab 232#define JSON_BUILD_EMPTY_OBJECT _JSON_BUILD_OBJECT_BEGIN, _JSON_BUILD_OBJECT_END
cd0b6c53 233#define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__
319a4f27 234#define JSON_BUILD_PAIR_CONDITION(c, n, ...) _JSON_BUILD_PAIR_CONDITION, ({ bool _x = c; _x; }), ({ const char *_x = n; _x; }), __VA_ARGS__
cd0b6c53
LP
235#define JSON_BUILD_NULL _JSON_BUILD_NULL
236#define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; })
237#define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; })
238#define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; })
886b0c93 239#define JSON_BUILD_BASE64(p, n) _JSON_BUILD_BASE64, ({ const void *_x = p; _x; }), ({ size_t _y = n; _y; })
cd0b6c53
LP
240
241int json_build(JsonVariant **ret, ...);
242int json_buildv(JsonVariant **ret, va_list ap);
243
244/* A bitmask of flags used by the dispatch logic. Note that this is a combined bit mask, that is generated from the bit
245 * mask originally passed into json_dispatch(), the individual bitmask associated with the static JsonDispatch callout
246 * entry, as well the bitmask specified for json_log() calls */
247typedef enum JsonDispatchFlags {
248 /* The following three may be set in JsonDispatch's .flags field or the json_dispatch() flags parameter */
249 JSON_PERMISSIVE = 1 << 0, /* Shall parsing errors be considered fatal for this property? */
5238e957 250 JSON_MANDATORY = 1 << 1, /* Should existence of this property be mandatory? */
cd0b6c53 251 JSON_LOG = 1 << 2, /* Should the parser log about errors? */
ba23dbf1 252 JSON_SAFE = 1 << 3, /* Don't accept "unsafe" strings in json_dispatch_string() + json_dispatch_string() */
cd0b6c53
LP
253
254 /* The following two may be passed into log_json() in addition to the three above */
ba23dbf1
LP
255 JSON_DEBUG = 1 << 4, /* Indicates that this log message is a debug message */
256 JSON_WARNING = 1 << 5, /* Indicates that this log message is a warning message */
cd0b6c53
LP
257} JsonDispatchFlags;
258
259typedef int (*JsonDispatchCallback)(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
260
261typedef struct JsonDispatch {
262 const char *name;
263 JsonVariantType type;
264 JsonDispatchCallback callback;
265 size_t offset;
266 JsonDispatchFlags flags;
267} JsonDispatch;
268
269int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
270
271int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
272int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
273int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
274int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
275int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
276int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
277int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
278int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
279int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
280
ab1a1ba5 281assert_cc(sizeof(uintmax_t) == sizeof(uint64_t));
cd0b6c53
LP
282#define json_dispatch_uint64 json_dispatch_unsigned
283
ab1a1ba5 284assert_cc(sizeof(intmax_t) == sizeof(int64_t));
cd0b6c53
LP
285#define json_dispatch_int64 json_dispatch_integer
286
287static inline int json_dispatch_level(JsonDispatchFlags flags) {
288
289 /* Did the user request no logging? If so, then never log higher than LOG_DEBUG. Also, if this is marked as
290 * debug message, then also log at debug level. */
291
292 if (!(flags & JSON_LOG) ||
293 (flags & JSON_DEBUG))
294 return LOG_DEBUG;
295
296 /* Are we invoked in permissive mode, or is this explicitly marked as warning message? Then this should be
297 * printed at LOG_WARNING */
298 if (flags & (JSON_PERMISSIVE|JSON_WARNING))
299 return LOG_WARNING;
300
301 /* Otherwise it's an error. */
302 return LOG_ERR;
303}
304
305int json_log_internal(JsonVariant *variant, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
306
19130626 307#define json_log(variant, flags, error, ...) \
cd0b6c53 308 ({ \
19130626 309 int _level = json_dispatch_level(flags), _e = (error); \
cd0b6c53 310 (log_get_max_level() >= LOG_PRI(_level)) \
62c6bbbc 311 ? json_log_internal(variant, _level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \
19130626 312 : -ERRNO_VALUE(_e); \
cd0b6c53
LP
313 })
314
0ac0787e
LP
315#define json_log_oom(variant, flags) \
316 json_log(variant, flags, SYNTHETIC_ERRNO(ENOMEM), "Out of memory.")
317
d520d519
LP
318#define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
319
90b365ce 320#define _JSON_VARIANT_STRING_CONST(xq, x) \
d520d519 321 ({ \
90b365ce 322 _align_(2) static const char UNIQ_T(json_string_const, xq)[] = (x); \
d520d519
LP
323 assert((((uintptr_t) UNIQ_T(json_string_const, xq)) & 1) == 0); \
324 (JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \
325 })
326
cd0b6c53
LP
327const char *json_variant_type_to_string(JsonVariantType t);
328JsonVariantType json_variant_type_from_string(const char *s);