]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fileio: add new helper fdopen_independent()
authorLennart Poettering <lennart@poettering.net>
Thu, 23 Mar 2023 11:33:41 +0000 (12:33 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Thu, 23 Mar 2023 22:48:00 +0000 (22:48 +0000)
This is a combination of fdopen() and fd_reopen(). i.e. it first reopens
the fd, and then converts that into a FILE*.

We do this at various places already manually. let's move this into a
helper call of its own.

src/basic/env-file.c
src/basic/fileio.c
src/basic/fileio.h
src/locale/localed-util.c
src/portable/portable.c
src/test/test-fileio.c

index 16de727c09cd855e3a49adec4509e8e469dbbec9..34027ca2e51db183935ce57ee02f0f40e85304d5 100644 (file)
@@ -381,22 +381,15 @@ int parse_env_file_fd_sentinel(
                 const char *fname, /* only used for logging */
                 ...) {
 
-        _cleanup_close_ int fd_ro = -EBADF;
         _cleanup_fclose_ FILE *f = NULL;
         va_list ap;
         int r;
 
         assert(fd >= 0);
 
-        fd_ro = fd_reopen(fd, O_CLOEXEC | O_RDONLY);
-        if (fd_ro < 0)
-                return fd_ro;
-
-        f = fdopen(fd_ro, "re");
-        if (!f)
-                return -errno;
-
-        TAKE_FD(fd_ro);
+        r = fdopen_independent(fd, "re", &f);
+        if (r < 0)
+                return r;
 
         va_start(ap, fname);
         r = parse_env_filev(f, fname, ap);
index c802db749b369744b45cd09526c73140d690ce5b..c75981528eff3726479962ad5da9bf726b5dabfd 100644 (file)
@@ -1020,6 +1020,35 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r
         return 0;
 }
 
+int fdopen_independent(int fd, const char *mode, FILE **ret) {
+        _cleanup_close_ int copy_fd = -EBADF;
+        _cleanup_fclose_ FILE *f = NULL;
+        int mode_flags;
+
+        assert(fd >= 0);
+        assert(mode);
+        assert(ret);
+
+        /* A combination of fdopen() + fd_reopen(). i.e. reopens the inode the specified fd points to and
+         * returns a FILE* for it */
+
+        mode_flags = fopen_mode_to_flags(mode);
+        if (mode_flags < 0)
+                return mode_flags;
+
+        copy_fd = fd_reopen(fd, mode_flags);
+        if (copy_fd < 0)
+                return copy_fd;
+
+        f = fdopen(copy_fd, mode);
+        if (!f)
+                return -errno;
+
+        TAKE_FD(copy_fd);
+        *ret = TAKE_PTR(f);
+        return 0;
+}
+
 static int search_and_fopen_internal(
                 const char *path,
                 const char *mode,
index 7da3ee33e09e9568456b4f3d9013cd85bafa49f5..0a88a19146f947ceb3b223a059454e5472497f16 100644 (file)
@@ -106,6 +106,8 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
 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 fdopen_independent(int fd, const char *mode, FILE **ret);
+
 int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **ret, char **ret_path);
 int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **ret, char **ret_path);
 
index d6b6593bea607d9e4738d352033c8cd36f06955b..f9eb3e7e9f2def7fb8c7cd27dd209436c91858bd 100644 (file)
@@ -312,7 +312,7 @@ int vconsole_read_data(Context *c, sd_bus_message *m) {
 }
 
 int x11_read_data(Context *c, sd_bus_message *m) {
-        _cleanup_close_ int fd = -EBADF, fd_ro = -EBADF;
+        _cleanup_close_ int fd = -EBADF;
         _cleanup_fclose_ FILE *f = NULL;
         bool in_section = false;
         struct stat st;
@@ -348,15 +348,9 @@ int x11_read_data(Context *c, sd_bus_message *m) {
         c->x11_stat = st;
         x11_context_clear(&c->x11_from_xorg);
 
-        fd_ro = fd_reopen(fd, O_CLOEXEC | O_RDONLY);
-        if (fd_ro < 0)
-                return fd_ro;
-
-        f = fdopen(fd_ro, "re");
-        if (!f)
-                return -errno;
-
-        TAKE_FD(fd_ro);
+        r = fdopen_independent(fd, "re", &f);
+        if (r < 0)
+                return r;
 
         for (;;) {
                 _cleanup_free_ char *line = NULL;
index 23102e51ddff6b94fe305ca32e9cc9cb4b4262a7..664c873ca7b8d23bbcf8a25468235ada8437fe39 100644 (file)
@@ -594,7 +594,6 @@ static int extract_image_and_extensions(
                 _cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
                 _cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
                 _cleanup_strv_free_ char **extension_release = NULL;
-                _cleanup_close_ int extension_release_fd = -EBADF;
                 _cleanup_fclose_ FILE *f = NULL;
                 const char *e;
 
@@ -610,11 +609,7 @@ static int extract_image_and_extensions(
                         continue;
 
                 /* We need to keep the fd valid, to return the PortableMetadata to the caller. */
-                extension_release_fd = fd_reopen(extension_release_meta->fd, O_CLOEXEC|O_RDONLY);
-                if (extension_release_fd < 0)
-                        return extension_release_fd;
-
-                r = take_fdopen_unlocked(&extension_release_fd, "r", &f);
+                r = fdopen_independent(extension_release_meta->fd, "re", &f);
                 if (r < 0)
                         return r;
 
index 2e05992c18071fdff6e67039dbd8c855893ec6ba..1a9a8a5ddc9c320d32bc54d4c81a80a6f553d712 100644 (file)
@@ -14,6 +14,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "io-util.h"
+#include "memfd-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -1072,4 +1073,46 @@ TEST(test_read_virtual_file) {
         test_read_virtual_file_one(SIZE_MAX);
 }
 
+TEST(test_fdopen_independent) {
+#define TEST_TEXT "this is some random test text we are going to write to a memfd"
+        _cleanup_close_ int fd = -EBADF;
+        _cleanup_fclose_ FILE *f = NULL;
+        char buf[STRLEN(TEST_TEXT) + 1];
+
+        fd = memfd_new("fdopen_independent");
+        if (fd < 0) {
+                assert_se(ERRNO_IS_NOT_SUPPORTED(fd));
+                return;
+        }
+
+        assert_se(write(fd, TEST_TEXT, strlen(TEST_TEXT)) == strlen(TEST_TEXT));
+        /* we'll leave the read offset at the end of the memfd, the fdopen_independent() descriptors should
+         * start at the beginning anyway */
+
+        assert_se(fdopen_independent(fd, "re", &f) >= 0);
+        zero(buf);
+        assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
+        assert_se(streq(buf, TEST_TEXT));
+        assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE) == O_RDONLY);
+        assert_se(FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
+        f = safe_fclose(f);
+
+        assert_se(fdopen_independent(fd, "r", &f) >= 0);
+        zero(buf);
+        assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
+        assert_se(streq(buf, TEST_TEXT));
+        assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE) == O_RDONLY);
+        assert_se(!FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
+        f = safe_fclose(f);
+
+        assert_se(fdopen_independent(fd, "r+e", &f) >= 0);
+        zero(buf);
+        assert_se(fread(buf, 1, sizeof(buf), f) == strlen(TEST_TEXT));
+        assert_se(streq(buf, TEST_TEXT));
+        assert_se((fcntl(fileno(f), F_GETFL) & O_ACCMODE) == O_RDWR);
+        assert_se(FLAGS_SET(fcntl(fileno(f), F_GETFD), FD_CLOEXEC));
+        f = safe_fclose(f);
+}
+
+
 DEFINE_TEST_MAIN(LOG_DEBUG);