diff --git a/man/rules/meson.build b/man/rules/meson.build index c42a8d47f8..e0a99b1a21 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -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', diff --git a/man/sd_json_parse.xml b/man/sd_json_parse.xml index c5234734da..73089853a2 100644 --- a/man/sd_json_parse.xml +++ b/man/sd_json_parse.xml @@ -22,9 +22,13 @@ sd_json_parse_with_source_continue sd_json_parse_file sd_json_parse_file_at + sd_json_parse_fd SD_JSON_PARSE_SENSITIVE SD_JSON_PARSE_MUST_BE_OBJECT SD_JSON_PARSE_MUST_BE_ARRAY + SD_JSON_PARSE_SEEK0 + SD_JSON_PARSE_DONATE_FD + SD_JSON_PARSE_REOPEN_FD Parse JSON strings and files into JSON variant objects @@ -91,6 +95,16 @@ 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 + @@ -146,6 +160,16 @@ against the current working directory, which is the default behaviour of sd_json_parse_file(). + sd_json_parse_fd() reads and parses a JSON value from the file referenced by + the file descriptor fd. 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 SD_JSON_PARSE_SEEK0, + SD_JSON_PARSE_DONATE_FD and SD_JSON_PARSE_REOPEN_FD flags, see + below. The path 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 + NULL. + The flags argument is a bitmask of zero or more of the following flags: @@ -179,6 +203,44 @@ + + + SD_JSON_PARSE_SEEK0 + + 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 + SD_JSON_PARSE_REOPEN_FD in sd_json_parse_fd() it is + redundant, since a freshly reopened file descriptor starts at offset 0 anyway. + + + + + + SD_JSON_PARSE_DONATE_FD + + Only has an effect on sd_json_parse_fd(). If set, ownership of + the file descriptor passed in fd 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 fd and the function operates on an + internally duplicated descriptor instead. This flag may not be combined with + SD_JSON_PARSE_REOPEN_FD. + + + + + + SD_JSON_PARSE_REOPEN_FD + + Only has an effect on sd_json_parse_fd(). If set, the file + descriptor passed in fd 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 O_PATH). The caller retains ownership of the + original descriptor, which is left untouched. This flag may not be combined with + SD_JSON_PARSE_DONATE_FD. + + + If both SD_JSON_PARSE_MUST_BE_OBJECT and @@ -232,6 +294,11 @@ sd_json_parse_with_source_continue(), sd_json_parse_file(), and sd_json_parse_file_at() were added in version 257. + + sd_json_parse_fd() and the SD_JSON_PARSE_MUST_BE_OBJECT, + SD_JSON_PARSE_MUST_BE_ARRAY, SD_JSON_PARSE_SEEK0, + SD_JSON_PARSE_DONATE_FD and SD_JSON_PARSE_REOPEN_FD flags were + added in version 261. diff --git a/src/core/luo.c b/src/core/luo.c index 9dc892d5d6..929a0e3f49 100644 --- a/src/core/luo.c +++ b/src/core/luo.c @@ -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"); diff --git a/src/core/main.c b/src/core/main.c index f98d0edb2d..0b88afae62 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -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; diff --git a/src/home/homed-home.c b/src/home/homed-home.c index f467ef7015..33d3916559 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -4,6 +4,7 @@ #include #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); diff --git a/src/home/homework.c b/src/home/homework.c index d63d481447..eecb91511c 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -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); diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 38ab92dea1..6afc11d91b 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -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; diff --git a/src/libsystemd/sd-json/sd-json.c b/src/libsystemd/sd-json/sd-json.c index a7ff526bc8..1ba07da6f9 100644 --- a/src/libsystemd/sd-json/sd-json.c +++ b/src/libsystemd/sd-json/sd-json.c @@ -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; diff --git a/src/libsystemd/sd-json/test-json.c b/src/libsystemd/sd-json/test-json.c index 3be4b09660..c9aa5d2f90 100644 --- a/src/libsystemd/sd-json/test-json.c +++ b/src/libsystemd/sd-json/test-json.c @@ -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; diff --git a/src/network/networkd-serialize.c b/src/network/networkd-serialize.c index 31f885d87a..394f03ced6 100644 --- a/src/network/networkd-serialize.c +++ b/src/network/networkd-serialize.c @@ -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); diff --git a/src/resolve/resolved-static-records.c b/src/resolve/resolved-static-records.c index efcd91c090..348422e244 100644 --- a/src/resolve/resolved-static-records.c +++ b/src/resolve/resolved-static-records.c @@ -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"); diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c index 02035404a6..75e1285c2f 100644 --- a/src/shared/elf-util.c +++ b/src/shared/elf-util.c @@ -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"); } diff --git a/src/shared/luo-util.c b/src/shared/luo-util.c index 898e51efa5..ab4a4a3235 100644 --- a/src/shared/luo-util.c +++ b/src/shared/luo-util.c @@ -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"); diff --git a/src/systemd/sd-json.h b/src/systemd/sd-json.h index 6a19775490..5ad825f3c1 100644 --- a/src/systemd/sd-json.h +++ b/src/systemd/sd-json.h @@ -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 */ diff --git a/src/sysupdate/sysupdated.c b/src/sysupdate/sysupdated.c index 4c7a759a4d..3d696baa75 100644 --- a/src/sysupdate/sysupdated.c +++ b/src/sysupdate/sysupdated.c @@ -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");