]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fileio: optionally, return discovered path of file in search_and_fopen()
authorLennart Poettering <lennart@poettering.net>
Mon, 3 May 2021 16:18:09 +0000 (18:18 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 May 2021 14:43:26 +0000 (16:43 +0200)
src/basic/fileio.c
src/basic/fileio.h
src/binfmt/binfmt.c
src/home/homed-manager.c
src/modules-load/modules-load.c
src/sysctl/sysctl.c
src/sysusers/sysusers.c
src/test/test-fileio.c
src/tmpfiles/tmpfiles.c

index 414fd15d567c6296de5d6b9aaac81f39713cf82c..16cd2408f050d917c148f8ae98fdba09d76c8771 100644 (file)
@@ -914,12 +914,19 @@ int xfopenat(int dir_fd, const char *path, const char *mode, int flags, FILE **r
         return 0;
 }
 
-static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
+static int search_and_fopen_internal(
+                const char *path,
+                const char *mode,
+                const char *root,
+                char **search,
+                FILE **ret,
+                char **ret_path) {
+
         char **i;
 
         assert(path);
         assert(mode);
-        assert(_f);
+        assert(ret);
 
         if (!path_strv_resolve_uniq(search, root))
                 return -ENOMEM;
@@ -934,7 +941,10 @@ static int search_and_fopen_internal(const char *path, const char *mode, const c
 
                 f = fopen(p, mode);
                 if (f) {
-                        *_f = f;
+                        if (ret_path)
+                                *ret_path = path_simplify(TAKE_PTR(p), true);
+
+                        *ret = f;
                         return 0;
                 }
 
@@ -945,52 +955,84 @@ static int search_and_fopen_internal(const char *path, const char *mode, const c
         return -ENOENT;
 }
 
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) {
+int search_and_fopen(
+                const char *filename,
+                const char *mode,
+                const char *root,
+                const char **search,
+                FILE **ret,
+                char **ret_path) {
+
         _cleanup_strv_free_ char **copy = NULL;
 
-        assert(path);
+        assert(filename);
         assert(mode);
-        assert(_f);
+        assert(ret);
 
-        if (path_is_absolute(path)) {
-                FILE *f;
+        if (path_is_absolute(filename)) {
+                _cleanup_fclose_ FILE *f = NULL;
 
-                f = fopen(path, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
+                f = fopen(filename, mode);
+                if (!f)
+                        return -errno;
+
+                if (ret_path) {
+                        char *p;
+
+                        p = strdup(filename);
+                        if (!p)
+                                return -ENOMEM;
+
+                        *ret_path = path_simplify(p, true);
                 }
 
-                return -errno;
+                *ret = TAKE_PTR(f);
+                return 0;
         }
 
         copy = strv_copy((char**) search);
         if (!copy)
                 return -ENOMEM;
 
-        return search_and_fopen_internal(path, mode, root, copy, _f);
+        return search_and_fopen_internal(filename, mode, root, copy, ret, ret_path);
 }
 
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
+int search_and_fopen_nulstr(
+                const char *filename,
+                const char *mode,
+                const char *root,
+                const char *search,
+                FILE **ret,
+                char **ret_path) {
+
         _cleanup_strv_free_ char **s = NULL;
 
-        if (path_is_absolute(path)) {
-                FILE *f;
+        if (path_is_absolute(filename)) {
+                _cleanup_fclose_ FILE *f = NULL;
 
-                f = fopen(path, mode);
-                if (f) {
-                        *_f = f;
-                        return 0;
+                f = fopen(filename, mode);
+                if (!f)
+                        return -errno;
+
+                if (ret_path) {
+                        char *p;
+
+                        p = strdup(filename);
+                        if (!p)
+                                return -ENOMEM;
+
+                        *ret_path = path_simplify(p, true);
                 }
 
-                return -errno;
+                *ret = TAKE_PTR(f);
+                return 0;
         }
 
         s = strv_split_nulstr(search);
         if (!s)
                 return -ENOMEM;
 
-        return search_and_fopen_internal(path, mode, root, s, _f);
+        return search_and_fopen_internal(filename, mode, root, s, ret, ret_path);
 }
 
 int chase_symlinks_and_fopen_unlocked(
index 752995c2a3d7dfb67c385a388e18d19cf2ee6bf0..d772b0a50d2ac1b1d5e9027805181b17df198f05 100644 (file)
@@ -80,8 +80,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 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);
+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);
 
 int chase_symlinks_and_fopen_unlocked(
                 const char *path,
index f6b72e0bae865f3402716938f4298583aa4545e0..29530bb691c6c22c398a3067836ea6c4c7a0a0ed 100644 (file)
@@ -65,11 +65,12 @@ static int apply_rule(const char *rule) {
 
 static int apply_file(const char *path, bool ignore_enoent) {
         _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *pp = NULL;
         int r;
 
         assert(path);
 
-        r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("binfmt.d"), &f);
+        r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("binfmt.d"), &f, &pp);
         if (r < 0) {
                 if (ignore_enoent && r == -ENOENT)
                         return 0;
@@ -77,7 +78,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
                 return log_error_errno(r, "Failed to open file '%s': %m", path);
         }
 
-        log_debug("apply: %s", path);
+        log_debug("apply: %s", pp);
         for (;;) {
                 _cleanup_free_ char *line = NULL;
                 char *p;
@@ -85,7 +86,7 @@ static int apply_file(const char *path, bool ignore_enoent) {
 
                 k = read_line(f, LONG_LINE_MAX, &line);
                 if (k < 0)
-                        return log_error_errno(k, "Failed to read file '%s': %m", path);
+                        return log_error_errno(k, "Failed to read file '%s': %m", pp);
                 if (k == 0)
                         break;
 
index bd104f68112b127cd3bcb605e0ca6c1d58917c33..f8dfa272b93101099d202fc6dff6cca43afa5469 100644 (file)
@@ -1327,7 +1327,7 @@ static int manager_load_key_pair(Manager *m) {
                 m->private_key = NULL;
         }
 
-        r = search_and_fopen_nulstr("local.private", "re", NULL, KEY_PATHS_NULSTR, &f);
+        r = search_and_fopen_nulstr("local.private", "re", NULL, KEY_PATHS_NULSTR, &f, NULL);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
index 9cfd292011602d00427d83b5308b3b8e6a415a3a..b57d806fab289472681a73a15729858b53ca4932 100644 (file)
@@ -62,12 +62,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
 
 static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
         _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *pp = NULL;
         int r;
 
         assert(ctx);
         assert(path);
 
-        r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
+        r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f, &pp);
         if (r < 0) {
                 if (ignore_enoent && r == -ENOENT)
                         return 0;
@@ -75,7 +76,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
                 return log_error_errno(r, "Failed to open %s: %m", path);
         }
 
-        log_debug("apply: %s", path);
+        log_debug("apply: %s", pp);
         for (;;) {
                 _cleanup_free_ char *line = NULL;
                 char *l;
@@ -83,7 +84,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent
 
                 k = read_line(f, LONG_LINE_MAX, &line);
                 if (k < 0)
-                        return log_error_errno(k, "Failed to read file '%s': %m", path);
+                        return log_error_errno(k, "Failed to read file '%s': %m", pp);
                 if (k == 0)
                         break;
 
index 15b68b7d2ef9c72d54b547d636a354d87ccd947e..458a91be29c8e21c901c068dd4e0ff0a08c30544 100644 (file)
@@ -182,12 +182,13 @@ static int apply_all(OrderedHashmap *sysctl_options) {
 
 static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ignore_enoent) {
         _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *pp = NULL;
         unsigned c = 0;
         int r;
 
         assert(path);
 
-        r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("sysctl.d"), &f);
+        r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("sysctl.d"), &f, &pp);
         if (r < 0) {
                 if (ignore_enoent && r == -ENOENT)
                         return 0;
@@ -195,7 +196,7 @@ static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ig
                 return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
         }
 
-        log_debug("Parsing %s", path);
+        log_debug("Parsing %s", pp);
         for (;;) {
                 _cleanup_(option_freep) Option *new_option = NULL;
                 _cleanup_free_ char *l = NULL;
@@ -208,7 +209,7 @@ static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ig
                 if (k == 0)
                         break;
                 if (k < 0)
-                        return log_error_errno(k, "Failed to read file '%s', ignoring: %m", path);
+                        return log_error_errno(k, "Failed to read file '%s', ignoring: %m", pp);
 
                 c++;
 
@@ -235,7 +236,7 @@ static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ig
                                 /* We have a "negative match" option. Let's continue with value==NULL. */
                                 p++;
                         else {
-                                log_syntax(NULL, LOG_WARNING, path, c, 0,
+                                log_syntax(NULL, LOG_WARNING, pp, c, 0,
                                            "Line is not an assignment, ignoring: %s", p);
                                 if (r == 0)
                                         r = -EINVAL;
@@ -261,7 +262,7 @@ static int parse_file(OrderedHashmap **sysctl_options, const char *path, bool ig
                                 continue;
                         }
 
-                        log_debug("Overwriting earlier assignment of %s at '%s:%u'.", p, path, c);
+                        log_debug("Overwriting earlier assignment of %s at '%s:%u'.", p, pp, c);
                         option_free(ordered_hashmap_remove(*sysctl_options, p));
                 }
 
index 35ae3ae4af2c5100fc62d5420de8140fc62c45f5..848e5e867c7017d428a693ee60e338cff9e97735 100644 (file)
@@ -1728,6 +1728,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
 static int read_config_file(const char *fn, bool ignore_enoent) {
         _cleanup_fclose_ FILE *rf = NULL;
+        _cleanup_free_ char *pp = NULL;
         FILE *f = NULL;
         unsigned v = 0;
         int r = 0;
@@ -1737,7 +1738,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
         if (streq(fn, "-"))
                 f = stdin;
         else {
-                r = search_and_fopen(fn, "re", arg_root, (const char**) CONF_PATHS_STRV("sysusers.d"), &rf);
+                r = search_and_fopen(fn, "re", arg_root, (const char**) CONF_PATHS_STRV("sysusers.d"), &rf, &pp);
                 if (r < 0) {
                         if (ignore_enoent && r == -ENOENT)
                                 return 0;
@@ -1746,6 +1747,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
                 }
 
                 f = rf;
+                fn = pp;
         }
 
         for (;;) {
index c5c8116e96d3db831925d85b1ff8b3896d66ebfb..4d2895c84771ed61a7fb7913740b4fd78e550f4f 100644 (file)
@@ -15,6 +15,7 @@
 #include "fs-util.h"
 #include "io-util.h"
 #include "parse-util.h"
+#include "path-util.h"
 #include "process-util.h"
 #include "random-util.h"
 #include "rm-rf.h"
@@ -525,69 +526,93 @@ static void test_load_env_file_pairs(void) {
 }
 
 static void test_search_and_fopen(void) {
-        const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
-
+        static const char* const dirs[] = {
+                "/tmp/foo/bar",
+                "/tmp",
+                NULL
+        };
         char name[] = "/tmp/test-search_and_fopen.XXXXXX";
-        int fd, r;
-        FILE *f;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
+        _cleanup_close_ int fd = -1;
+        const char *e;
+        int r;
 
         fd = mkostemp_safe(name);
         assert_se(fd >= 0);
-        close(fd);
+        fd = safe_close(fd);
 
-        r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
+        r = search_and_fopen(basename(name), "re", NULL, (const char**) dirs, &f, &p);
         assert_se(r >= 0);
-        fclose(f);
+        assert_se(e = path_startswith(p, "/tmp/"));
+        assert_se(streq(basename(name), e));
+        f = safe_fclose(f);
+        p = mfree(p);
 
-        r = search_and_fopen(name, "r", NULL, dirs, &f);
+        r = search_and_fopen(name, "re", NULL, (const char**) dirs, &f, &p);
         assert_se(r >= 0);
-        fclose(f);
+        assert_se(path_equal(name, p));
+        f = safe_fclose(f);
+        p = mfree(p);
 
-        r = search_and_fopen(basename(name), "r", "/", dirs, &f);
+        r = search_and_fopen(basename(name), "re", "/", (const char**) dirs, &f, &p);
         assert_se(r >= 0);
-        fclose(f);
+        assert_se(e = path_startswith(p, "/tmp/"));
+        assert_se(streq(basename(name), e));
+        f = safe_fclose(f);
+        p = mfree(p);
 
-        r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
-        assert_se(r < 0);
-        r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
-        assert_se(r < 0);
+        r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, (const char**) dirs, &f, &p);
+        assert_se(r == -ENOENT);
+        r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, (const char**) dirs, &f, &p);
+        assert_se(r == -ENOENT);
 
         r = unlink(name);
         assert_se(r == 0);
 
-        r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
-        assert_se(r < 0);
+        r = search_and_fopen(basename(name), "r", NULL, (const char**) dirs, &f, &p);
+        assert_se(r == -ENOENT);
 }
 
 static void test_search_and_fopen_nulstr(void) {
-        const char dirs[] = "/tmp/foo/bar\0/tmp\0";
+        static const char dirs[] =
+                "/tmp/foo/bar\0"
+                "/tmp\0";
 
         _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-search_and_fopen.XXXXXX";
-        int fd, r;
-        FILE *f;
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *p = NULL;
+        _cleanup_close_ int fd = -1;
+        const char *e;
+        int r;
 
         fd = mkostemp_safe(name);
         assert_se(fd >= 0);
-        close(fd);
+        fd = safe_close(fd);
 
-        r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
+        r = search_and_fopen_nulstr(basename(name), "re", NULL, dirs, &f, &p);
         assert_se(r >= 0);
-        fclose(f);
+        assert_se(e = path_startswith(p, "/tmp/"));
+        assert_se(streq(basename(name), e));
+        f = safe_fclose(f);
+        p = mfree(p);
 
-        r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
+        r = search_and_fopen_nulstr(name, "re", NULL, dirs, &f, &p);
         assert_se(r >= 0);
-        fclose(f);
+        assert_se(path_equal(name, p));
+        f = safe_fclose(f);
+        p = mfree(p);
 
-        r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
-        assert_se(r < 0);
-        r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
-        assert_se(r < 0);
+        r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f, &p);
+        assert_se(r == -ENOENT);
+        r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f, &p);
+        assert_se(r == -ENOENT);
 
         r = unlink(name);
         assert_se(r == 0);
 
-        r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
-        assert_se(r < 0);
+        r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f, &p);
+        assert_se(r == -ENOENT);
 }
 
 static void test_writing_tmpfile(void) {
index 98f14bbbe7293dab97652118e95ed3ff6f9f0e8f..9529b09b3f3ef56a5275d423889203c103c77dab 100644 (file)
@@ -3185,6 +3185,7 @@ static int parse_argv(int argc, char *argv[]) {
 static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
         _cleanup_(hashmap_freep) Hashmap *uid_cache = NULL, *gid_cache = NULL;
         _cleanup_fclose_ FILE *_f = NULL;
+        _cleanup_free_ char *pp = NULL;
         unsigned v = 0;
         FILE *f;
         ItemArray *ia;
@@ -3197,7 +3198,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
                 fn = "<stdin>";
                 f = stdin;
         } else {
-                r = search_and_fopen(fn, "re", arg_root, (const char**) config_dirs, &_f);
+                r = search_and_fopen(fn, "re", arg_root, (const char**) config_dirs, &_f, &pp);
                 if (r < 0) {
                         if (ignore_enoent && r == -ENOENT) {
                                 log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
@@ -3206,7 +3207,9 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
 
                         return log_error_errno(r, "Failed to open '%s': %m", fn);
                 }
-                log_debug("Reading config file \"%s\"…", fn);
+
+                log_debug("Reading config file \"%s\"…", pp);
+                fn = pp;
                 f = _f;
         }