mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
Merge pull request #14208 from poettering/json-homed-prepare
json bits from homed PR
This commit is contained in:
commit
3267cb45e9
@ -136,16 +136,21 @@ static int write_string_file_atomic(
|
||||
assert(fn);
|
||||
assert(line);
|
||||
|
||||
/* Note that we'd really like to use O_TMPFILE here, but can't really, since we want replacement
|
||||
* semantics here, and O_TMPFILE can't offer that. i.e. rename() replaces but linkat() doesn't. */
|
||||
|
||||
r = fopen_temporary(fn, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) fchmod_umask(fileno(f), 0644);
|
||||
|
||||
r = write_string_stream_ts(f, line, flags, ts);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = fchmod_umask(fileno(f), FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0644);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (rename(p, fn) < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
@ -165,7 +170,7 @@ int write_string_file_ts(
|
||||
struct timespec *ts) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int q, r;
|
||||
int q, r, fd;
|
||||
|
||||
assert(fn);
|
||||
assert(line);
|
||||
@ -190,26 +195,20 @@ int write_string_file_ts(
|
||||
} else
|
||||
assert(!ts);
|
||||
|
||||
if (flags & WRITE_STRING_FILE_CREATE) {
|
||||
r = fopen_unlocked(fn, "we", &f);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
} else {
|
||||
int fd;
|
||||
/* We manually build our own version of fopen(..., "we") that works without O_CREAT and with O_NOFOLLOW if needed. */
|
||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0),
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* We manually build our own version of fopen(..., "we") that
|
||||
* works without O_CREAT */
|
||||
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY | ((flags & WRITE_STRING_FILE_NOFOLLOW) ? O_NOFOLLOW : 0));
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = fdopen_unlocked(fd, "w", &f);
|
||||
if (r < 0) {
|
||||
safe_close(fd);
|
||||
goto fail;
|
||||
}
|
||||
r = fdopen_unlocked(fd, "w", &f);
|
||||
if (r < 0) {
|
||||
safe_close(fd);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (flags & WRITE_STRING_FILE_DISABLE_BUFFER)
|
||||
@ -543,17 +542,19 @@ finalize:
|
||||
return r;
|
||||
}
|
||||
|
||||
int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
|
||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(contents);
|
||||
|
||||
r = fopen_unlocked(filename, "re", &f);
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
|
||||
return read_full_stream_full(f, filename, flags, contents, size);
|
||||
}
|
||||
|
||||
@ -680,6 +681,81 @@ DIR *xopendirat(int fd, const char *name, int flags) {
|
||||
return d;
|
||||
}
|
||||
|
||||
static int mode_to_flags(const char *mode) {
|
||||
const char *p;
|
||||
int flags;
|
||||
|
||||
if ((p = startswith(mode, "r+")))
|
||||
flags = O_RDWR;
|
||||
else if ((p = startswith(mode, "r")))
|
||||
flags = O_RDONLY;
|
||||
else if ((p = startswith(mode, "w+")))
|
||||
flags = O_RDWR|O_CREAT|O_TRUNC;
|
||||
else if ((p = startswith(mode, "w")))
|
||||
flags = O_WRONLY|O_CREAT|O_TRUNC;
|
||||
else if ((p = startswith(mode, "a+")))
|
||||
flags = O_RDWR|O_CREAT|O_APPEND;
|
||||
else if ((p = startswith(mode, "a")))
|
||||
flags = O_WRONLY|O_CREAT|O_APPEND;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
for (; *p != 0; p++) {
|
||||
|
||||
switch (*p) {
|
||||
|
||||
case 'e':
|
||||
flags |= O_CLOEXEC;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
flags |= O_EXCL;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
/* ignore this here, fdopen() might care later though */
|
||||
break;
|
||||
|
||||
case 'c': /* not sure what to do about this one */
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret) {
|
||||
FILE *f;
|
||||
|
||||
/* A combination of fopen() with openat() */
|
||||
|
||||
if (dir_fd == AT_FDCWD && flags == 0) {
|
||||
f = fopen(path, mode);
|
||||
if (!f)
|
||||
return -errno;
|
||||
} else {
|
||||
int fd, mode_flags;
|
||||
|
||||
mode_flags = mode_to_flags(mode);
|
||||
if (mode_flags < 0)
|
||||
return mode_flags;
|
||||
|
||||
fd = openat(dir_fd, path, mode_flags | flags);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
f = fdopen(fd, mode);
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
|
||||
char **i;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
@ -22,6 +23,7 @@ typedef enum {
|
||||
WRITE_STRING_FILE_DISABLE_BUFFER = 1 << 5,
|
||||
WRITE_STRING_FILE_NOFOLLOW = 1 << 6,
|
||||
WRITE_STRING_FILE_MKDIR_0755 = 1 << 7,
|
||||
WRITE_STRING_FILE_MODE_0600 = 1 << 8,
|
||||
|
||||
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
|
||||
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
|
||||
@ -52,9 +54,9 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
|
||||
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
|
||||
|
||||
int read_one_line_file(const char *filename, char **line);
|
||||
int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
static inline int read_full_file(const char *filename, char **contents, size_t *size) {
|
||||
return read_full_file_full(filename, 0, contents, size);
|
||||
return read_full_file_full(AT_FDCWD, filename, 0, contents, size);
|
||||
}
|
||||
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
|
||||
int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
@ -69,6 +71,7 @@ int executable_is_script(const char *path, char **interpreter);
|
||||
int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
|
||||
|
||||
DIR *xopendirat(int dirfd, const char *name, int flags);
|
||||
int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **ret);
|
||||
|
||||
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f);
|
||||
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f);
|
||||
|
@ -18,7 +18,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
f = fmemopen_unlocked((char*) data, size, "re");
|
||||
assert_se(f);
|
||||
|
||||
if (json_parse_file(f, NULL, &v, NULL, NULL) < 0)
|
||||
if (json_parse_file(f, NULL, 0, &v, NULL, NULL) < 0)
|
||||
return 0;
|
||||
|
||||
g = open_memstream_unlocked(&out, &out_size);
|
||||
|
@ -981,7 +981,7 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
|
||||
|
||||
(void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0);
|
||||
|
||||
r = read_full_file_full(sa->key_file, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX, (char **) &key, &key_len);
|
||||
r = read_full_file_full(AT_FDCWD, sa->key_file, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX, (char **) &key, &key_len);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r,
|
||||
"Failed to read key from '%s', ignoring: %m",
|
||||
|
@ -902,7 +902,7 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_
|
||||
|
||||
(void) warn_file_is_world_accessible(filename, NULL, NULL, 0);
|
||||
|
||||
r = read_full_file_full(filename, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64, &key, &key_len);
|
||||
r = read_full_file_full(AT_FDCWD, filename, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64, &key, &key_len);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -172,24 +172,13 @@ static int oci_env(const char *name, JsonVariant *v, JsonDispatchFlags flags, vo
|
||||
static int oci_args(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
char ***value = userdata;
|
||||
JsonVariant *e;
|
||||
int r;
|
||||
|
||||
assert(value);
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(e, v) {
|
||||
const char *n;
|
||||
|
||||
if (!json_variant_is_string(e))
|
||||
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Argument is not a string.");
|
||||
|
||||
assert_se(n = json_variant_string(e));
|
||||
|
||||
r = strv_extend(&l, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
r = json_variant_strv(v, &l);
|
||||
if (r < 0)
|
||||
return json_log(v, flags, r, "Cannot parse arguments as list of strings: %m");
|
||||
|
||||
if (strv_isempty(l))
|
||||
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
@ -2214,7 +2203,7 @@ int oci_load(FILE *f, const char *bundle, Settings **ret) {
|
||||
|
||||
path = strjoina(bundle, "/config.json");
|
||||
|
||||
r = json_parse_file(f, path, &oci, &line, &column);
|
||||
r = json_parse_file(f, path, 0, &oci, &line, &column);
|
||||
if (r < 0) {
|
||||
if (line != 0 && column != 0)
|
||||
return log_error_errno(r, "Failed to parse '%s' at %u:%u: %m", path, line, column);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#pragma once
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@ -54,6 +55,7 @@ typedef enum JsonVariantType {
|
||||
} JsonVariantType;
|
||||
|
||||
int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n);
|
||||
int json_variant_new_base64(JsonVariant **ret, const void *p, size_t n);
|
||||
int json_variant_new_integer(JsonVariant **ret, intmax_t i);
|
||||
int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u);
|
||||
int json_variant_new_real(JsonVariant **ret, long double d);
|
||||
@ -120,6 +122,10 @@ static inline bool json_variant_is_null(JsonVariant *v) {
|
||||
}
|
||||
|
||||
bool json_variant_is_negative(JsonVariant *v);
|
||||
bool json_variant_is_blank_object(JsonVariant *v);
|
||||
bool json_variant_is_blank_array(JsonVariant *v);
|
||||
bool json_variant_is_normalized(JsonVariant *v);
|
||||
bool json_variant_is_sorted(JsonVariant *v);
|
||||
|
||||
size_t json_variant_elements(JsonVariant *v);
|
||||
JsonVariant *json_variant_by_index(JsonVariant *v, size_t index);
|
||||
@ -128,6 +134,8 @@ JsonVariant *json_variant_by_key_full(JsonVariant *v, const char *key, JsonVaria
|
||||
|
||||
bool json_variant_equal(JsonVariant *a, JsonVariant *b);
|
||||
|
||||
void json_variant_sensitive(JsonVariant *v);
|
||||
|
||||
struct json_variant_foreach_state {
|
||||
JsonVariant *variant;
|
||||
size_t idx;
|
||||
@ -153,21 +161,48 @@ struct json_variant_foreach_state {
|
||||
int json_variant_get_source(JsonVariant *v, const char **ret_source, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
typedef enum JsonFormatFlags {
|
||||
JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
|
||||
JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
|
||||
JSON_FORMAT_COLOR = 1 << 2, /* insert ANSI color sequences */
|
||||
JSON_FORMAT_COLOR_AUTO = 1 << 3, /* insert ANSI color sequences if colors_enabled() says so */
|
||||
JSON_FORMAT_SOURCE = 1 << 4, /* prefix with source filename/line/column */
|
||||
JSON_FORMAT_SSE = 1 << 5, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 6, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
JSON_FORMAT_NEWLINE = 1 << 0, /* suffix with newline */
|
||||
JSON_FORMAT_PRETTY = 1 << 1, /* add internal whitespace to appeal to human readers */
|
||||
JSON_FORMAT_PRETTY_AUTO = 1 << 2, /* same, but only if connected to a tty (and JSON_FORMAT_NEWLINE otherwise) */
|
||||
JSON_FORMAT_COLOR = 1 << 3, /* insert ANSI color sequences */
|
||||
JSON_FORMAT_COLOR_AUTO = 1 << 4, /* insert ANSI color sequences if colors_enabled() says so */
|
||||
JSON_FORMAT_SOURCE = 1 << 5, /* prefix with source filename/line/column */
|
||||
JSON_FORMAT_SSE = 1 << 6, /* prefix/suffix with W3C server-sent events */
|
||||
JSON_FORMAT_SEQ = 1 << 7, /* prefix/suffix with RFC 7464 application/json-seq */
|
||||
JSON_FORMAT_FLUSH = 1 << 8, /* call fflush() after dumping JSON */
|
||||
} JsonFormatFlags;
|
||||
|
||||
int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret);
|
||||
void json_variant_dump(JsonVariant *v, JsonFormatFlags flags, FILE *f, const char *prefix);
|
||||
|
||||
int json_parse(const char *string, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_continue(const char **p, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_file(FILE *f, const char *path, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
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_field_string(JsonVariant **v, const char *field, const char *value);
|
||||
int json_variant_set_field_integer(JsonVariant **v, const char *field, intmax_t value);
|
||||
int json_variant_set_field_unsigned(JsonVariant **v, const char *field, uintmax_t value);
|
||||
int json_variant_set_field_boolean(JsonVariant **v, const char *field, bool b);
|
||||
|
||||
int json_variant_append_array(JsonVariant **v, JsonVariant *element);
|
||||
|
||||
int json_variant_merge(JsonVariant **v, JsonVariant *m);
|
||||
|
||||
int json_variant_strv(JsonVariant *v, char ***ret);
|
||||
|
||||
int json_variant_sort(JsonVariant **v);
|
||||
int json_variant_normalize(JsonVariant **v);
|
||||
|
||||
typedef enum JsonParseFlags {
|
||||
JSON_PARSE_SENSITIVE = 1 << 0, /* mark variant as "sensitive", i.e. something containing secret key material or such */
|
||||
} JsonParseFlags;
|
||||
|
||||
int json_parse(const char *string, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_continue(const char **p, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column);
|
||||
|
||||
static inline int json_parse_file(FILE *f, const char *path, JsonParseFlags flags, JsonVariant **ret, unsigned *ret_line, unsigned *ret_column) {
|
||||
return json_parse_file_at(f, AT_FDCWD, path, flags, ret, ret_line, ret_column);
|
||||
}
|
||||
|
||||
enum {
|
||||
_JSON_BUILD_STRING,
|
||||
@ -183,8 +218,10 @@ enum {
|
||||
_JSON_BUILD_PAIR_CONDITION,
|
||||
_JSON_BUILD_NULL,
|
||||
_JSON_BUILD_VARIANT,
|
||||
_JSON_BUILD_VARIANT_ARRAY,
|
||||
_JSON_BUILD_LITERAL,
|
||||
_JSON_BUILD_STRV,
|
||||
_JSON_BUILD_BASE64,
|
||||
_JSON_BUILD_MAX,
|
||||
};
|
||||
|
||||
@ -194,13 +231,17 @@ enum {
|
||||
#define JSON_BUILD_REAL(d) _JSON_BUILD_REAL, ({ long double _x = d; _x; })
|
||||
#define JSON_BUILD_BOOLEAN(b) _JSON_BUILD_BOOLEAN, ({ bool _x = b; _x; })
|
||||
#define JSON_BUILD_ARRAY(...) _JSON_BUILD_ARRAY_BEGIN, __VA_ARGS__, _JSON_BUILD_ARRAY_END
|
||||
#define JSON_BUILD_EMPTY_ARRAY _JSON_BUILD_ARRAY_BEGIN, _JSON_BUILD_ARRAY_END
|
||||
#define JSON_BUILD_OBJECT(...) _JSON_BUILD_OBJECT_BEGIN, __VA_ARGS__, _JSON_BUILD_OBJECT_END
|
||||
#define JSON_BUILD_EMPTY_OBJECT _JSON_BUILD_OBJECT_BEGIN, _JSON_BUILD_OBJECT_END
|
||||
#define JSON_BUILD_PAIR(n, ...) _JSON_BUILD_PAIR, ({ const char *_x = n; _x; }), __VA_ARGS__
|
||||
#define JSON_BUILD_PAIR_CONDITION(c, n, ...) _JSON_BUILD_PAIR_CONDITION, ({ bool _x = c; _x; }), ({ const char *_x = n; _x; }), __VA_ARGS__
|
||||
#define JSON_BUILD_NULL _JSON_BUILD_NULL
|
||||
#define JSON_BUILD_VARIANT(v) _JSON_BUILD_VARIANT, ({ JsonVariant *_x = v; _x; })
|
||||
#define JSON_BUILD_VARIANT_ARRAY(v, n) _JSON_BUILD_VARIANT_ARRAY, ({ JsonVariant **_x = v; _x; }), ({ size_t _y = n; _y; })
|
||||
#define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; })
|
||||
#define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; })
|
||||
#define JSON_BUILD_BASE64(p, n) _JSON_BUILD_BASE64, ({ const void *_x = p; _x; }), ({ size_t _y = n; _y; })
|
||||
|
||||
int json_build(JsonVariant **ret, ...);
|
||||
int json_buildv(JsonVariant **ret, va_list ap);
|
||||
@ -213,10 +254,11 @@ typedef enum JsonDispatchFlags {
|
||||
JSON_PERMISSIVE = 1 << 0, /* Shall parsing errors be considered fatal for this property? */
|
||||
JSON_MANDATORY = 1 << 1, /* Should existence of this property be mandatory? */
|
||||
JSON_LOG = 1 << 2, /* Should the parser log about errors? */
|
||||
JSON_SAFE = 1 << 3, /* Don't accept "unsafe" strings in json_dispatch_string() + json_dispatch_string() */
|
||||
|
||||
/* The following two may be passed into log_json() in addition to the three above */
|
||||
JSON_DEBUG = 1 << 3, /* Indicates that this log message is a debug message */
|
||||
JSON_WARNING = 1 << 4, /* Indicates that this log message is a warning message */
|
||||
JSON_DEBUG = 1 << 4, /* Indicates that this log message is a debug message */
|
||||
JSON_WARNING = 1 << 5, /* Indicates that this log message is a warning message */
|
||||
} JsonDispatchFlags;
|
||||
|
||||
typedef int (*JsonDispatchCallback)(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
@ -232,6 +274,7 @@ typedef struct JsonDispatch {
|
||||
int json_dispatch(JsonVariant *v, const JsonDispatch table[], JsonDispatchCallback bad, JsonDispatchFlags flags, void *userdata);
|
||||
|
||||
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);
|
||||
int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
@ -240,6 +283,10 @@ int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFl
|
||||
int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
int json_dispatch_unsupported(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata);
|
||||
|
||||
assert_cc(sizeof(uintmax_t) == sizeof(uint64_t));
|
||||
#define json_dispatch_uint64 json_dispatch_unsigned
|
||||
@ -275,6 +322,9 @@ int json_log_internal(JsonVariant *variant, int level, int error, const char *fi
|
||||
: -ERRNO_VALUE(_e); \
|
||||
})
|
||||
|
||||
#define json_log_oom(variant, flags) \
|
||||
json_log(variant, flags, SYNTHETIC_ERRNO(ENOMEM), "Out of memory.")
|
||||
|
||||
#define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
|
||||
|
||||
#define _JSON_VARIANT_STRING_CONST(xq, x) \
|
||||
@ -284,5 +334,7 @@ int json_log_internal(JsonVariant *variant, int level, int error, const char *fi
|
||||
(JsonVariant*) ((uintptr_t) UNIQ_T(json_string_const, xq) + 1); \
|
||||
})
|
||||
|
||||
int json_variant_unbase64(JsonVariant *v, void **ret, size_t *ret_size);
|
||||
|
||||
const char *json_variant_type_to_string(JsonVariantType t);
|
||||
JsonVariantType json_variant_type_from_string(const char *s);
|
||||
|
@ -577,7 +577,7 @@ static int varlink_parse_message(Varlink *v) {
|
||||
|
||||
varlink_log(v, "New incoming message: %s", begin);
|
||||
|
||||
r = json_parse(begin, &v->current, NULL, NULL);
|
||||
r = json_parse(begin, 0, &v->current, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -82,7 +82,7 @@ static void test_variant(const char *data, Test test) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
r = json_parse(data, &v, NULL, NULL);
|
||||
r = json_parse(data, 0, &v, NULL, NULL);
|
||||
assert_se(r == 0);
|
||||
assert_se(v);
|
||||
|
||||
@ -93,7 +93,7 @@ static void test_variant(const char *data, Test test) {
|
||||
|
||||
log_info("formatted normally: %s\n", s);
|
||||
|
||||
r = json_parse(data, &w, NULL, NULL);
|
||||
r = json_parse(data, JSON_PARSE_SENSITIVE, &w, NULL, NULL);
|
||||
assert_se(r == 0);
|
||||
assert_se(w);
|
||||
assert_se(json_variant_has_type(v, json_variant_type(w)));
|
||||
@ -110,7 +110,7 @@ static void test_variant(const char *data, Test test) {
|
||||
|
||||
log_info("formatted prettily:\n%s", s);
|
||||
|
||||
r = json_parse(data, &w, NULL, NULL);
|
||||
r = json_parse(data, 0, &w, NULL, NULL);
|
||||
assert_se(r == 0);
|
||||
assert_se(w);
|
||||
|
||||
@ -302,7 +302,7 @@ static void test_build(void) {
|
||||
|
||||
assert_se(json_variant_format(a, 0, &s) >= 0);
|
||||
log_info("GOT: %s\n", s);
|
||||
assert_se(json_parse(s, &b, NULL, NULL) >= 0);
|
||||
assert_se(json_parse(s, 0, &b, NULL, NULL) >= 0);
|
||||
assert_se(json_variant_equal(a, b));
|
||||
|
||||
a = json_variant_unref(a);
|
||||
@ -313,7 +313,7 @@ static void test_build(void) {
|
||||
s = mfree(s);
|
||||
assert_se(json_variant_format(a, 0, &s) >= 0);
|
||||
log_info("GOT: %s\n", s);
|
||||
assert_se(json_parse(s, &b, NULL, NULL) >= 0);
|
||||
assert_se(json_parse(s, 0, &b, NULL, NULL) >= 0);
|
||||
assert_se(json_variant_format(b, 0, &t) >= 0);
|
||||
log_info("GOT: %s\n", t);
|
||||
|
||||
@ -365,7 +365,7 @@ static void test_source(void) {
|
||||
|
||||
assert_se(f = fmemopen_unlocked((void*) data, strlen(data), "r"));
|
||||
|
||||
assert_se(json_parse_file(f, "waldo", &v, NULL, NULL) >= 0);
|
||||
assert_se(json_parse_file(f, "waldo", 0, &v, NULL, NULL) >= 0);
|
||||
|
||||
printf("--- non-pretty begin ---\n");
|
||||
json_variant_dump(v, 0, stdout, NULL);
|
||||
@ -415,6 +415,93 @@ static void test_depth(void) {
|
||||
fputs("\n", stdout);
|
||||
}
|
||||
|
||||
static void test_normalize(void) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
|
||||
_cleanup_free_ char *t = NULL;
|
||||
|
||||
assert_se(json_build(&v, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("b", JSON_BUILD_STRING("x")),
|
||||
JSON_BUILD_PAIR("c", JSON_BUILD_STRING("y")),
|
||||
JSON_BUILD_PAIR("a", JSON_BUILD_STRING("z")))) >= 0);
|
||||
|
||||
assert_se(!json_variant_is_sorted(v));
|
||||
assert_se(!json_variant_is_normalized(v));
|
||||
|
||||
assert_se(json_variant_format(v, 0, &t) >= 0);
|
||||
assert_se(streq(t, "{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}"));
|
||||
t = mfree(t);
|
||||
|
||||
assert_se(json_build(&w, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR("bar", JSON_BUILD_STRING("zzz")),
|
||||
JSON_BUILD_PAIR("foo", JSON_BUILD_VARIANT(v)))) >= 0);
|
||||
|
||||
assert_se(json_variant_is_sorted(w));
|
||||
assert_se(!json_variant_is_normalized(w));
|
||||
|
||||
assert_se(json_variant_format(w, 0, &t) >= 0);
|
||||
assert_se(streq(t, "{\"bar\":\"zzz\",\"foo\":{\"b\":\"x\",\"c\":\"y\",\"a\":\"z\"}}"));
|
||||
t = mfree(t);
|
||||
|
||||
assert_se(json_variant_sort(&v) >= 0);
|
||||
assert_se(json_variant_is_sorted(v));
|
||||
assert_se(json_variant_is_normalized(v));
|
||||
|
||||
assert_se(json_variant_format(v, 0, &t) >= 0);
|
||||
assert_se(streq(t, "{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}"));
|
||||
t = mfree(t);
|
||||
|
||||
assert_se(json_variant_normalize(&w) >= 0);
|
||||
assert_se(json_variant_is_sorted(w));
|
||||
assert_se(json_variant_is_normalized(w));
|
||||
|
||||
assert_se(json_variant_format(w, 0, &t) >= 0);
|
||||
assert_se(streq(t, "{\"bar\":\"zzz\",\"foo\":{\"a\":\"z\",\"b\":\"x\",\"c\":\"y\"}}"));
|
||||
t = mfree(t);
|
||||
}
|
||||
|
||||
static void test_bisect(void) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
char c;
|
||||
|
||||
/* Tests the bisection logic in json_variant_by_key() */
|
||||
|
||||
for (c = 'z'; c >= 'a'; c--) {
|
||||
|
||||
if ((c % 3) == 0)
|
||||
continue;
|
||||
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||
assert_se(json_variant_new_stringn(&w, (char[4]) { '<', c, c, '>' }, 4) >= 0);
|
||||
assert_se(json_variant_set_field(&v, (char[2]) { c, 0 }, w) >= 0);
|
||||
}
|
||||
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
assert_se(!json_variant_is_sorted(v));
|
||||
assert_se(!json_variant_is_normalized(v));
|
||||
assert_se(json_variant_normalize(&v) >= 0);
|
||||
assert_se(json_variant_is_sorted(v));
|
||||
assert_se(json_variant_is_normalized(v));
|
||||
|
||||
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
|
||||
|
||||
for (c = 'a'; c <= 'z'; c++) {
|
||||
JsonVariant *k;
|
||||
const char *z;
|
||||
|
||||
k = json_variant_by_key(v, (char[2]) { c, 0 });
|
||||
assert_se(!k == ((c % 3) == 0));
|
||||
|
||||
if (!k)
|
||||
continue;
|
||||
|
||||
assert_se(json_variant_is_string(k));
|
||||
|
||||
z = (char[5]){ '<', c, c, '>', 0};
|
||||
assert_se(streq(json_variant_string(k), z));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@ -462,10 +549,11 @@ int main(int argc, char *argv[]) {
|
||||
test_variant("[ 0, -0, 0.0, -0.0, 0.000, -0.000, 0e0, -0e0, 0e+0, -0e-0, 0e-0, -0e000, 0e+000 ]", test_zeroes);
|
||||
|
||||
test_build();
|
||||
|
||||
test_source();
|
||||
|
||||
test_depth();
|
||||
|
||||
test_normalize();
|
||||
test_bisect();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user