sd-json: add sd_json_parse_fd() + flags (#42136)
In particular in the recent LUO work we started to read JSON a lot from fds, let's add some helpers to make that simpler. No change in behaviour, just helpers to shorten code.
This commit is contained in:
@@ -869,10 +869,14 @@ manpages = [
|
||||
''],
|
||||
['sd_json_parse',
|
||||
'3',
|
||||
['SD_JSON_PARSE_MUST_BE_ARRAY',
|
||||
['SD_JSON_PARSE_DONATE_FD',
|
||||
'SD_JSON_PARSE_MUST_BE_ARRAY',
|
||||
'SD_JSON_PARSE_MUST_BE_OBJECT',
|
||||
'SD_JSON_PARSE_REOPEN_FD',
|
||||
'SD_JSON_PARSE_SEEK0',
|
||||
'SD_JSON_PARSE_SENSITIVE',
|
||||
'sd_json_parse_continue',
|
||||
'sd_json_parse_fd',
|
||||
'sd_json_parse_file',
|
||||
'sd_json_parse_file_at',
|
||||
'sd_json_parse_with_source',
|
||||
|
||||
@@ -22,9 +22,13 @@
|
||||
<refname>sd_json_parse_with_source_continue</refname>
|
||||
<refname>sd_json_parse_file</refname>
|
||||
<refname>sd_json_parse_file_at</refname>
|
||||
<refname>sd_json_parse_fd</refname>
|
||||
<refname>SD_JSON_PARSE_SENSITIVE</refname>
|
||||
<refname>SD_JSON_PARSE_MUST_BE_OBJECT</refname>
|
||||
<refname>SD_JSON_PARSE_MUST_BE_ARRAY</refname>
|
||||
<refname>SD_JSON_PARSE_SEEK0</refname>
|
||||
<refname>SD_JSON_PARSE_DONATE_FD</refname>
|
||||
<refname>SD_JSON_PARSE_REOPEN_FD</refname>
|
||||
|
||||
<refpurpose>Parse JSON strings and files into JSON variant objects</refpurpose>
|
||||
</refnamediv>
|
||||
@@ -91,6 +95,16 @@
|
||||
<paramdef>unsigned *<parameter>reterr_line</parameter></paramdef>
|
||||
<paramdef>unsigned *<parameter>reterr_column</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_json_parse_fd</function></funcdef>
|
||||
<paramdef>const char *<parameter>path</parameter></paramdef>
|
||||
<paramdef>int <parameter>fd</parameter></paramdef>
|
||||
<paramdef>sd_json_parse_flags_t <parameter>flags</parameter></paramdef>
|
||||
<paramdef>sd_json_variant **<parameter>ret</parameter></paramdef>
|
||||
<paramdef>unsigned *<parameter>reterr_line</parameter></paramdef>
|
||||
<paramdef>unsigned *<parameter>reterr_column</parameter></paramdef>
|
||||
</funcprototype>
|
||||
</funcsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@@ -146,6 +160,16 @@
|
||||
against the current working directory, which is the default behaviour of
|
||||
<function>sd_json_parse_file()</function>.</para>
|
||||
|
||||
<para><function>sd_json_parse_fd()</function> reads and parses a JSON value from the file referenced by
|
||||
the file descriptor <parameter>fd</parameter>. By default the file descriptor is internally duplicated
|
||||
and the caller's descriptor is left untouched (the current file offset will be shared with the original
|
||||
file descriptor however); the JSON text is read starting at the descriptor's current file offset. This
|
||||
behaviour may be modified via the <constant>SD_JSON_PARSE_SEEK0</constant>,
|
||||
<constant>SD_JSON_PARSE_DONATE_FD</constant> and <constant>SD_JSON_PARSE_REOPEN_FD</constant> flags, see
|
||||
below. The <parameter>path</parameter> argument is not used to open anything in this case; it is only
|
||||
recorded as source information in the resulting JSON variant (see above) and may be passed as
|
||||
<constant>NULL</constant>.</para>
|
||||
|
||||
<para>The <parameter>flags</parameter> argument is a bitmask of zero or more of the following
|
||||
flags:</para>
|
||||
|
||||
@@ -179,6 +203,44 @@
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SD_JSON_PARSE_SEEK0</constant></term>
|
||||
|
||||
<listitem><para>Before reading, seek the input to its beginning (i.e. file offset 0). This flag has
|
||||
no effect when parsing from a string. When used together with
|
||||
<constant>SD_JSON_PARSE_REOPEN_FD</constant> in <function>sd_json_parse_fd()</function> it is
|
||||
redundant, since a freshly reopened file descriptor starts at offset 0 anyway.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SD_JSON_PARSE_DONATE_FD</constant></term>
|
||||
|
||||
<listitem><para>Only has an effect on <function>sd_json_parse_fd()</function>. If set, ownership of
|
||||
the file descriptor passed in <parameter>fd</parameter> is transferred into the call: the descriptor
|
||||
is consumed and closed before the function returns, including in the error path. If not set (the
|
||||
default), the caller retains ownership of <parameter>fd</parameter> and the function operates on an
|
||||
internally duplicated descriptor instead. This flag may not be combined with
|
||||
<constant>SD_JSON_PARSE_REOPEN_FD</constant>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>SD_JSON_PARSE_REOPEN_FD</constant></term>
|
||||
|
||||
<listitem><para>Only has an effect on <function>sd_json_parse_fd()</function>. If set, the file
|
||||
descriptor passed in <parameter>fd</parameter> is reopened (read-only) before reading, instead of
|
||||
being duplicated. This is primarily useful to obtain an independent file offset (positioned at the
|
||||
beginning of the file) and a clean, read-only access mode, even if the original descriptor was opened
|
||||
differently (for example with <constant>O_PATH</constant>). The caller retains ownership of the
|
||||
original descriptor, which is left untouched. This flag may not be combined with
|
||||
<constant>SD_JSON_PARSE_DONATE_FD</constant>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v261"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>If both <constant>SD_JSON_PARSE_MUST_BE_OBJECT</constant> and
|
||||
@@ -232,6 +294,11 @@
|
||||
<function>sd_json_parse_with_source_continue()</function>,
|
||||
<function>sd_json_parse_file()</function>, and
|
||||
<function>sd_json_parse_file_at()</function> were added in version 257.</para>
|
||||
|
||||
<para><function>sd_json_parse_fd()</function> and the <constant>SD_JSON_PARSE_MUST_BE_OBJECT</constant>,
|
||||
<constant>SD_JSON_PARSE_MUST_BE_ARRAY</constant>, <constant>SD_JSON_PARSE_SEEK0</constant>,
|
||||
<constant>SD_JSON_PARSE_DONATE_FD</constant> and <constant>SD_JSON_PARSE_REOPEN_FD</constant> flags were
|
||||
added in version 261.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
||||
+9
-10
@@ -5,7 +5,6 @@
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fdset.h"
|
||||
#include "fileio.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "luo.h"
|
||||
@@ -17,23 +16,23 @@
|
||||
#include "unit-name.h"
|
||||
|
||||
static int luo_read_mapping(int session_fd, sd_json_variant **ret) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
_cleanup_close_ int mapping_fd = -EBADF;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(session_fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
mapping_fd = luo_session_retrieve_fd(session_fd, LUO_MAPPING_INDEX);
|
||||
_cleanup_close_ int mapping_fd = luo_session_retrieve_fd(session_fd, LUO_MAPPING_INDEX);
|
||||
if (mapping_fd < 0)
|
||||
return log_warning_errno(mapping_fd, "Failed to retrieve LUO mapping fd (fd_index 0): %m");
|
||||
|
||||
r = fdopen_independent(mapping_fd, "r", &f);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to open LUO mapping fd for reading: %m");
|
||||
|
||||
r = sd_json_parse_file(f, "luo-mapping", SD_JSON_PARSE_MUST_BE_OBJECT, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL);
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
r = sd_json_parse_fd(
|
||||
"luo-mapping",
|
||||
mapping_fd,
|
||||
SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_REOPEN_FD,
|
||||
&v,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse LUO mapping JSON: %m");
|
||||
|
||||
|
||||
+11
-11
@@ -3161,10 +3161,6 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
ListenFDsTag, listen_fds_tag_free);
|
||||
|
||||
static int parse_listen_fds_mapping(int mapping_fd, Hashmap **ret_index_to_tag) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *root = NULL;
|
||||
_cleanup_hashmap_free_ Hashmap *index_to_tag = NULL;
|
||||
const char *unit_id;
|
||||
sd_json_variant *fds_json;
|
||||
int r;
|
||||
|
||||
assert(mapping_fd >= 0);
|
||||
@@ -3175,16 +3171,20 @@ static int parse_listen_fds_mapping(int mapping_fd, Hashmap **ret_index_to_tag)
|
||||
* Returns a hashmap keyed by stringified index ("1", "2", ...) with ListenFDsTag* values
|
||||
* carrying the resolved (unit_id, original fdname, upstream index). */
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
r = fdopen_independent(mapping_fd, "r", &f);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to open fdstore-mapping memfd: %m");
|
||||
|
||||
r = sd_json_parse_file(f, "fdstore-mapping", SD_JSON_PARSE_MUST_BE_OBJECT, &root,
|
||||
/* reterr_line= */ NULL, /* reterr_column= */ NULL);
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *root = NULL;
|
||||
r = sd_json_parse_fd(
|
||||
"fdstore-mapping",
|
||||
mapping_fd,
|
||||
SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_REOPEN_FD,
|
||||
&root,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse fdstore-mapping JSON: %m");
|
||||
|
||||
_cleanup_hashmap_free_ Hashmap *index_to_tag = NULL;
|
||||
sd_json_variant *fds_json;
|
||||
const char *unit_id;
|
||||
JSON_VARIANT_OBJECT_FOREACH(unit_id, fds_json, root) {
|
||||
sd_json_variant *entry;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "blockdev-util.h"
|
||||
#include "btrfs-util.h"
|
||||
@@ -570,26 +571,24 @@ static int home_parse_worker_stdout(int _fd, UserRecord **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||
return log_error_errno(errno, "Failed to seek to beginning of memfd: %m");
|
||||
|
||||
f = take_fdopen(&fd, "r");
|
||||
if (!f)
|
||||
return log_error_errno(errno, "Failed to reopen memfd: %m");
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *text = NULL;
|
||||
if (fseek(f, 0, SEEK_SET) < 0)
|
||||
return log_error_errno(errno, "Failed to seek to beginning of memfd: %m");
|
||||
|
||||
_cleanup_free_ char *text = NULL;
|
||||
r = read_full_stream(f, &text, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read from client: %m");
|
||||
|
||||
log_debug("Got from worker: %s", text);
|
||||
rewind(f);
|
||||
}
|
||||
|
||||
unsigned line = 0, column = 0;
|
||||
r = sd_json_parse_file(f, "stdout", SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_SENSITIVE, &v, &line, &column);
|
||||
r = sd_json_parse_file(f, "stdout", SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_SENSITIVE|SD_JSON_PARSE_SEEK0, &v, &line, &column);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse identity at %u:%u: %m", line, column);
|
||||
|
||||
|
||||
+10
-13
@@ -19,6 +19,7 @@
|
||||
#include "fileio.h"
|
||||
#include "filesystems.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "home-util.h"
|
||||
#include "homework-fido2.h"
|
||||
@@ -551,27 +552,23 @@ int home_sync_and_statfs(int root_fd, struct statfs *ret) {
|
||||
}
|
||||
|
||||
static int read_identity_file(int root_fd, sd_json_variant **ret) {
|
||||
_cleanup_fclose_ FILE *identity_file = NULL;
|
||||
_cleanup_close_ int identity_fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(root_fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
identity_fd = openat(root_fd, ".identity", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK);
|
||||
_cleanup_close_ int identity_fd = xopenat_full(root_fd, ".identity", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW|O_NONBLOCK, XO_REGULAR, MODE_INVALID);
|
||||
if (identity_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open .identity file in home directory: %m");
|
||||
|
||||
r = fd_verify_regular(identity_fd);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Embedded identity file is not a regular file, refusing: %m");
|
||||
|
||||
identity_file = take_fdopen(&identity_fd, "r");
|
||||
if (!identity_file)
|
||||
return log_oom();
|
||||
return log_error_errno(identity_fd, "Failed to open .identity file in home directory: %m");
|
||||
|
||||
unsigned line = 0, column = 0;
|
||||
r = sd_json_parse_file(identity_file, ".identity", SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_SENSITIVE, ret, &line, &column);
|
||||
r = sd_json_parse_fd(
|
||||
".identity",
|
||||
TAKE_FD(identity_fd),
|
||||
SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_SENSITIVE|SD_JSON_PARSE_DONATE_FD,
|
||||
ret,
|
||||
&line,
|
||||
&column);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "[.identity:%u:%u] Failed to parse JSON data: %m", line, column);
|
||||
|
||||
|
||||
@@ -1093,13 +1093,14 @@ global:
|
||||
|
||||
LIBSYSTEMD_261 {
|
||||
global:
|
||||
sd_event_add_cpu_pressure;
|
||||
sd_event_add_io_pressure;
|
||||
sd_event_source_set_cpu_pressure_period;
|
||||
sd_event_source_set_cpu_pressure_type;
|
||||
sd_event_source_set_io_pressure_period;
|
||||
sd_event_source_set_io_pressure_type;
|
||||
sd_json_parse_fd;
|
||||
sd_varlink_call_and_upgrade;
|
||||
sd_varlink_reply_and_upgrade;
|
||||
sd_varlink_set_sentinel;
|
||||
sd_event_add_cpu_pressure;
|
||||
sd_event_source_set_cpu_pressure_type;
|
||||
sd_event_source_set_cpu_pressure_period;
|
||||
sd_event_add_io_pressure;
|
||||
sd_event_source_set_io_pressure_type;
|
||||
sd_event_source_set_io_pressure_period;
|
||||
} LIBSYSTEMD_260;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "float.h"
|
||||
#include "hexdecoct.h"
|
||||
@@ -3502,9 +3503,12 @@ _public_ int sd_json_parse_file_at(
|
||||
_cleanup_free_ char *text = NULL;
|
||||
int r;
|
||||
|
||||
if (f)
|
||||
if (f) {
|
||||
if (FLAGS_SET(flags, SD_JSON_PARSE_SEEK0) && fseek(f, /* offset= */ 0, SEEK_SET) < 0)
|
||||
return -errno;
|
||||
|
||||
r = read_full_stream(f, &text, NULL);
|
||||
else
|
||||
} else
|
||||
r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -3523,6 +3527,44 @@ _public_ int sd_json_parse_file(
|
||||
return sd_json_parse_file_at(f, AT_FDCWD, path, flags, ret, reterr_line, reterr_column);
|
||||
}
|
||||
|
||||
_public_ int sd_json_parse_fd(
|
||||
const char *path,
|
||||
int fd,
|
||||
sd_json_parse_flags_t flags,
|
||||
sd_json_variant **ret,
|
||||
unsigned *reterr_line,
|
||||
unsigned *reterr_column) {
|
||||
|
||||
int r;
|
||||
|
||||
assert_return(fd >= 0, -EBADF);
|
||||
|
||||
_cleanup_close_ int our_fd = -EBADF;
|
||||
if (FLAGS_SET(flags, SD_JSON_PARSE_REOPEN_FD)) {
|
||||
assert_return(!FLAGS_SET(flags, SD_JSON_PARSE_DONATE_FD), -EINVAL);
|
||||
|
||||
our_fd = fd_reopen(fd, O_RDONLY|O_CLOEXEC);
|
||||
if (our_fd < 0)
|
||||
return our_fd;
|
||||
|
||||
/* If we reopened the thing the file offset will be at the beginning anyway */
|
||||
flags &= ~SD_JSON_PARSE_SEEK0;
|
||||
} else if (FLAGS_SET(flags, SD_JSON_PARSE_DONATE_FD))
|
||||
our_fd = fd;
|
||||
else {
|
||||
our_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
if (our_fd < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
r = take_fdopen_unlocked(&our_fd, "r", &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_json_parse_file(f, path, flags, ret, reterr_line, reterr_column);
|
||||
}
|
||||
|
||||
char *json_underscorify(char *p) {
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fileio.h"
|
||||
#include "io-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "json-internal.h"
|
||||
#include "json-util.h"
|
||||
@@ -518,6 +519,68 @@ TEST(source) {
|
||||
printf("--- pretty end ---\n");
|
||||
}
|
||||
|
||||
TEST(parse_fd) {
|
||||
static const char data[] = "{ \"foo\" : \"bar\", \"baz\" : 4711 }";
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
ASSERT_OK(fd = open_tmpfile_unlinkable(NULL, O_RDWR));
|
||||
ASSERT_OK(loop_write(fd, data, strlen(data)));
|
||||
|
||||
/* By default the fd is internally duplicated, the caller's fd stays open and the JSON text is
|
||||
* read starting at the current file offset. */
|
||||
ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_SET));
|
||||
ASSERT_OK(sd_json_parse_fd("tmpfile", fd, /* flags= */ 0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL));
|
||||
ASSERT_OK(fd_validate(fd)); /* still open, we only got a duplicate */
|
||||
ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar");
|
||||
ASSERT_EQ(sd_json_variant_unsigned(sd_json_variant_by_key(v, "baz")), UINT64_C(4711));
|
||||
v = sd_json_variant_unref(v);
|
||||
|
||||
/* Without SD_JSON_PARSE_SEEK0 and with the offset left at EOF there is nothing to read. */
|
||||
ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_END));
|
||||
ASSERT_ERROR(sd_json_parse_fd("tmpfile", fd, /* flags= */ 0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL), ENODATA);
|
||||
ASSERT_NULL(v);
|
||||
ASSERT_OK(fd_validate(fd));
|
||||
|
||||
/* SD_JSON_PARSE_SEEK0 rewinds to the beginning first, so the stale offset no longer matters. */
|
||||
ASSERT_OK(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_SEEK0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL));
|
||||
ASSERT_OK(fd_validate(fd));
|
||||
ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar");
|
||||
v = sd_json_variant_unref(v);
|
||||
|
||||
/* SD_JSON_PARSE_REOPEN_FD reopens the fd internally (starting at offset 0), the caller's fd and
|
||||
* its offset are left untouched. */
|
||||
ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_END));
|
||||
ASSERT_OK(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_REOPEN_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL));
|
||||
ASSERT_OK(fd_validate(fd));
|
||||
ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar");
|
||||
v = sd_json_variant_unref(v);
|
||||
|
||||
/* SD_JSON_PARSE_REOPEN_FD and SD_JSON_PARSE_DONATE_FD are mutually exclusive. */
|
||||
ASSERT_RETURN_EXPECTED_SE(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_REOPEN_FD|SD_JSON_PARSE_DONATE_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL) == -EINVAL);
|
||||
ASSERT_OK(fd_validate(fd)); /* not consumed on the -EINVAL path */
|
||||
|
||||
/* SD_JSON_PARSE_DONATE_FD passes ownership into the call: the fd is consumed and closed even on
|
||||
* success. */
|
||||
ASSERT_OK_ERRNO(lseek(fd, 0, SEEK_SET));
|
||||
ASSERT_OK(sd_json_parse_fd("tmpfile", fd, SD_JSON_PARSE_DONATE_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL));
|
||||
ASSERT_ERROR(fd_validate(fd), EBADF);
|
||||
TAKE_FD(fd); /* already closed by the call, don't double-close */
|
||||
ASSERT_STREQ(sd_json_variant_string(sd_json_variant_by_key(v, "foo")), "bar");
|
||||
v = sd_json_variant_unref(v);
|
||||
|
||||
/* SD_JSON_PARSE_DONATE_FD also consumes the fd when parsing fails. */
|
||||
_cleanup_close_ int fd2 = -EBADF;
|
||||
ASSERT_OK(fd2 = open_tmpfile_unlinkable(NULL, O_RDWR));
|
||||
ASSERT_OK(loop_write(fd2, "kookoo", strlen("kookoo")));
|
||||
ASSERT_OK_ERRNO(lseek(fd2, 0, SEEK_SET));
|
||||
ASSERT_ERROR(sd_json_parse_fd("tmpfile", fd2, SD_JSON_PARSE_DONATE_FD, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL), EINVAL);
|
||||
ASSERT_ERROR(fd_validate(fd2), EBADF);
|
||||
TAKE_FD(fd2);
|
||||
ASSERT_NULL(v);
|
||||
}
|
||||
|
||||
TEST(depth) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
int r;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "daemon-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
#include "iovec-util.h"
|
||||
#include "json-util.h"
|
||||
@@ -442,16 +441,12 @@ int manager_deserialize(Manager *manager) {
|
||||
|
||||
log_debug("Deserializing...");
|
||||
|
||||
_cleanup_fclose_ FILE *f = take_fdopen(&fd, "r");
|
||||
if (!f)
|
||||
return log_debug_errno(errno, "Failed to fdopen() serialization file descriptor: %m");
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
unsigned err_line = 0, err_column = 0;
|
||||
r = sd_json_parse_file(
|
||||
f,
|
||||
r = sd_json_parse_fd(
|
||||
/* path= */ NULL,
|
||||
/* flags= */ 0,
|
||||
TAKE_FD(fd),
|
||||
SD_JSON_PARSE_DONATE_FD,
|
||||
&v,
|
||||
&err_line,
|
||||
&err_column);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include "dns-question.h"
|
||||
#include "dns-rr.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "hashmap.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
@@ -96,16 +94,9 @@ static int load_static_record_file(const ConfFile *cf, Hashmap **records, Set **
|
||||
if (set_ensure_consume(stats, &inode_unmodified_hash_ops, TAKE_PTR(st_copy)) < 0)
|
||||
return log_oom();
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
r = xfopenat(cf->fd, /* path= */ NULL, "re", /* open_flags= */ 0, &f);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to open '%s', skipping: %m", cf->result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
|
||||
unsigned line = 0, column = 0;
|
||||
r = sd_json_parse_file(f, cf->result, /* flags= */ 0, &j, &line, &column);
|
||||
r = sd_json_parse_fd(cf->result, cf->fd, SD_JSON_PARSE_REOPEN_FD, &j, &line, &column);
|
||||
if (r < 0) {
|
||||
if (line > 0)
|
||||
log_syntax(/* unit= */ NULL, LOG_WARNING, cf->result, line, r, "Failed to parse JSON, skipping: %m");
|
||||
|
||||
+14
-14
@@ -994,25 +994,25 @@ int parse_elf_object(
|
||||
}
|
||||
|
||||
if (ret_package_metadata) {
|
||||
_cleanup_fclose_ FILE *json_in = NULL;
|
||||
|
||||
json_in = take_fdopen(&package_metadata_pipe[0], "r");
|
||||
if (!json_in)
|
||||
return -errno;
|
||||
|
||||
r = sd_json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
|
||||
r = sd_json_parse_fd(
|
||||
/* path= */ NULL,
|
||||
TAKE_FD(package_metadata_pipe[0]),
|
||||
SD_JSON_PARSE_DONATE_FD,
|
||||
&package_metadata,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
|
||||
log_warning_errno(r, "Failed to read or parse package metadata, ignoring: %m");
|
||||
}
|
||||
|
||||
if (ret_dlopen_metadata) {
|
||||
_cleanup_fclose_ FILE *json_in = NULL;
|
||||
|
||||
json_in = take_fdopen(&dlopen_metadata_pipe[0], "r");
|
||||
if (!json_in)
|
||||
return -errno;
|
||||
|
||||
r = sd_json_parse_file(json_in, NULL, 0, &dlopen_metadata, NULL, NULL);
|
||||
r = sd_json_parse_fd(
|
||||
/* path= */ NULL,
|
||||
TAKE_FD(dlopen_metadata_pipe[0]),
|
||||
SD_JSON_PARSE_DONATE_FD,
|
||||
&dlopen_metadata,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
|
||||
log_warning_errno(r, "Failed to read or parse dlopen metadata, ignoring: %m");
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "luo-util.h"
|
||||
@@ -118,7 +117,6 @@ int luo_session_finish(int session_fd) {
|
||||
int luo_parse_serialization(sd_json_variant **ret, int **ret_fds, size_t *ret_n_fds) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *root = NULL;
|
||||
_cleanup_free_ int *fd_list = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
size_t n_fds = 0;
|
||||
int serialize_fd = -EBADF, r;
|
||||
|
||||
@@ -139,11 +137,13 @@ int luo_parse_serialization(sd_json_variant **ret, int **ret_fds, size_t *ret_n_
|
||||
return log_warning_errno(serialize_fd,
|
||||
"Failed to parse SYSTEMD_LUO_SERIALIZE_FD='%s': %m", luo_fd_str);
|
||||
|
||||
r = fdopen_independent(serialize_fd, "r", &f);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to open LUO serialization fd %d: %m", serialize_fd);
|
||||
|
||||
r = sd_json_parse_file(f, /* path= */ NULL, SD_JSON_PARSE_MUST_BE_OBJECT, &root, /* reterr_line= */ NULL, /* reterr_column= */ NULL);
|
||||
r = sd_json_parse_fd(
|
||||
/* path= */ NULL,
|
||||
serialize_fd,
|
||||
SD_JSON_PARSE_MUST_BE_OBJECT|SD_JSON_PARSE_REOPEN_FD,
|
||||
&root,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse LUO serialization JSON: %m");
|
||||
|
||||
|
||||
@@ -184,6 +184,9 @@ __extension__ typedef enum _SD_ENUM_TYPE_S64(sd_json_parse_flags_t) {
|
||||
SD_JSON_PARSE_SENSITIVE = 1 << 0, /* mark variant as "sensitive", i.e. something containing secret key material or such */
|
||||
SD_JSON_PARSE_MUST_BE_OBJECT = 1 << 1, /* refuse parsing if top-level is not an object */
|
||||
SD_JSON_PARSE_MUST_BE_ARRAY = 1 << 2, /* refuse parsing if top-level is not an array */
|
||||
SD_JSON_PARSE_SEEK0 = 1 << 3, /* seek to offset 0 before reading */
|
||||
SD_JSON_PARSE_DONATE_FD = 1 << 4, /* pass ownership of fd to call, incl. on failure */
|
||||
SD_JSON_PARSE_REOPEN_FD = 1 << 5, /* reopen the specified file descriptor */
|
||||
_SD_ENUM_FORCE_S64(JSON_PARSE_FLAGS)
|
||||
} sd_json_parse_flags_t;
|
||||
|
||||
@@ -193,6 +196,7 @@ int sd_json_parse(const char *string, sd_json_parse_flags_t flags, sd_json_varia
|
||||
int sd_json_parse_continue(const char **p, sd_json_parse_flags_t flags, sd_json_variant **ret, unsigned *reterr_line, unsigned *reterr_column);
|
||||
int sd_json_parse_file_at(FILE *f, int dir_fd, const char *path, sd_json_parse_flags_t flags, sd_json_variant **ret, unsigned *reterr_line, unsigned *reterr_column);
|
||||
int sd_json_parse_file(FILE *f, const char *path, sd_json_parse_flags_t flags, sd_json_variant **ret, unsigned *reterr_line, unsigned *reterr_column);
|
||||
int sd_json_parse_fd(const char *path, int fd, sd_json_parse_flags_t flags, sd_json_variant **ret, unsigned *reterr_line, unsigned *reterr_column);
|
||||
|
||||
enum {
|
||||
/* Do not use these directly, use the SD_JSON_BUILD_*() macros below */
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "escape.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "log.h"
|
||||
@@ -246,8 +245,13 @@ static int job_parse_child_output(int _fd, sd_json_variant **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_parse_file_at(/* f= */ NULL, fd, /* path= */ NULL, /* flags= */ 0,
|
||||
&v, /* reterr_line= */ NULL, /* reterr_column= */ NULL);
|
||||
r = sd_json_parse_fd(
|
||||
/* path= */ "stdout",
|
||||
TAKE_FD(fd),
|
||||
SD_JSON_PARSE_DONATE_FD|SD_JSON_PARSE_SEEK0,
|
||||
&v,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse child output as JSON: %m");
|
||||
|
||||
@@ -771,7 +775,6 @@ static int target_new(Manager *m, TargetClass class, const char *name, const cha
|
||||
static int sysupdate_run_simple(sd_json_variant **ret, Target *t, ...) {
|
||||
_cleanup_close_pair_ int pipe[2] = EBADF_PAIR;
|
||||
_cleanup_(pidref_done_sigkill_wait) PidRef pid = PIDREF_NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
_cleanup_free_ char *target_arg = NULL;
|
||||
int r;
|
||||
@@ -845,11 +848,14 @@ static int sysupdate_run_simple(sd_json_variant **ret, Target *t, ...) {
|
||||
}
|
||||
|
||||
pipe[1] = safe_close(pipe[1]);
|
||||
f = take_fdopen(&pipe[0], "r");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
r = sd_json_parse_file(f, "stdout", 0, &v, NULL, NULL);
|
||||
r = sd_json_parse_fd(
|
||||
"stdout",
|
||||
TAKE_FD(pipe[0]),
|
||||
SD_JSON_PARSE_DONATE_FD,
|
||||
&v,
|
||||
/* reterr_line= */ NULL,
|
||||
/* reterr_column= */ NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse JSON: %m");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user