chiark / gitweb /
binfmt,tmpfiles,modules-load,sysctl: rework the various early-boot services that...
authorLennart Poettering <lennart@poettering.net>
Mon, 11 Feb 2013 22:48:36 +0000 (23:48 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 11 Feb 2013 22:54:30 +0000 (23:54 +0100)
This unifies much of the logic behind them:

- All four will now ofllow the rule that the earlier file and earlier
  assignment in the .d/ directories wins. Before, sysctl was the only
  outlier, where the later setting always won.

- All four now support getopt() and --help on the command line.

- All four can now handle specification of configuration file names on
  the command line to apply. The tools will automatically find them, and
  apply them. Previously only tmpfiles could do that. This is useful for
  %post scripts in RPMs and suchlike.

- This fixes various error path issues in conf_files_list()

15 files changed:
man/sysctl.d.xml
src/binfmt/binfmt.c
src/modules-load/modules-load.c
src/shared/conf-files.c
src/shared/conf-files.h
src/shared/hashmap.c
src/shared/hashmap.h
src/shared/path-util.c
src/shared/path-util.h
src/shared/strv.c
src/shared/strv.h
src/shared/util.c
src/shared/util.h
src/sysctl/sysctl.c
src/tmpfiles/tmpfiles.c

index 69aac8cab7a1530e371a2310d7da8176d853b125..0ef5545163bd49c3ec16ebd2482b101df7ebd00b 100644 (file)
@@ -92,7 +92,7 @@
                 alphabetical order, regardless in which of the
                 directories they reside, to guarantee that a specific
                 configuration file takes precedence over another file
                 alphabetical order, regardless in which of the
                 directories they reside, to guarantee that a specific
                 configuration file takes precedence over another file
-                with an alphabetically earlier name, if both files
+                with an alphabetically later name, if both files
                 contain the same variable setting.</para>
 
                 <para>If the administrator wants to disable a
                 contain the same variable setting.</para>
 
                 <para>If the administrator wants to disable a
index 296607d6a270f7e017a3ee8992d9e5a12a4f74b5..f8c97b5ca54869da0a170697b4e0631e0df53e50 100644 (file)
@@ -26,6 +26,7 @@
 #include <stdio.h>
 #include <limits.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <getopt.h>
 
 #include "log.h"
 #include "hashmap.h"
 
 #include "log.h"
 #include "hashmap.h"
 #include "util.h"
 #include "conf-files.h"
 
 #include "util.h"
 #include "conf-files.h"
 
+static const char conf_file_dirs[] =
+        "/etc/binfmt.d\0"
+        "/run/binfmt.d\0"
+        "/usr/local/lib/binfmt.d\0"
+        "/usr/lib/binfmt.d\0"
+#ifdef HAVE_SPLIT_USR
+        "/lib/binfmt.d\0"
+#endif
+        ;
+
 static int delete_rule(const char *rule) {
 static int delete_rule(const char *rule) {
-        char *x, *fn = NULL, *e;
-        int r;
+        _cleanup_free_ char *x = NULL, *fn = NULL;
+        char *e;
 
         assert(rule[0]);
 
 
         assert(rule[0]);
 
-        if (!(x = strdup(rule)))
+        x = strdup(rule);
+        if (!x)
                 return log_oom();
 
         e = strchrnul(x+1, x[0]);
         *e = 0;
 
                 return log_oom();
 
         e = strchrnul(x+1, x[0]);
         *e = 0;
 
-        asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1);
-        free(x);
-
+        fn = strappend("/proc/sys/fs/binfmt_misc/", x+1);
         if (!fn)
                 return log_oom();
 
         if (!fn)
                 return log_oom();
 
-        r = write_one_line_file(fn, "-1");
-        free(fn);
-
-        return r;
+        return write_one_line_file(fn, "-1");
 }
 
 static int apply_rule(const char *rule) {
 }
 
 static int apply_rule(const char *rule) {
@@ -62,7 +69,8 @@ static int apply_rule(const char *rule) {
 
         delete_rule(rule);
 
 
         delete_rule(rule);
 
-        if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) {
+        r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule);
+        if (r < 0) {
                 log_error("Failed to add binary format: %s", strerror(-r));
                 return r;
         }
                 log_error("Failed to add binary format: %s", strerror(-r));
                 return r;
         }
@@ -71,21 +79,22 @@ static int apply_rule(const char *rule) {
 }
 
 static int apply_file(const char *path, bool ignore_enoent) {
 }
 
 static int apply_file(const char *path, bool ignore_enoent) {
-        FILE *f;
-        int r = 0;
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
 
         assert(path);
 
 
         assert(path);
 
-        if (!(f = fopen(path, "re"))) {
-                if (ignore_enoent && errno == ENOENT)
+        r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
+        if (r < 0) {
+                if (ignore_enoent && r == -ENOENT)
                         return 0;
 
                         return 0;
 
-                log_error("Failed to open file '%s', ignoring: %m", path);
-                return -errno;
+                log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
+                return r;
         }
 
         log_debug("apply: %s\n", path);
         }
 
         log_debug("apply: %s\n", path);
-        while (!feof(f)) {
+        for (;;) {
                 char l[LINE_MAX], *p;
                 int k;
 
                 char l[LINE_MAX], *p;
                 int k;
 
@@ -94,30 +103,71 @@ static int apply_file(const char *path, bool ignore_enoent) {
                                 break;
 
                         log_error("Failed to read file '%s', ignoring: %m", path);
                                 break;
 
                         log_error("Failed to read file '%s', ignoring: %m", path);
-                        r = -errno;
-                        goto finish;
+                        return -errno;
                 }
 
                 p = strstrip(l);
                 }
 
                 p = strstrip(l);
-
                 if (!*p)
                         continue;
                 if (!*p)
                         continue;
-
                 if (strchr(COMMENTS, *p))
                         continue;
 
                 if (strchr(COMMENTS, *p))
                         continue;
 
-                if ((k = apply_rule(p)) < 0 && r == 0)
+                k = apply_rule(p);
+                if (k < 0 && r == 0)
                         r = k;
         }
 
                         r = k;
         }
 
-finish:
-        fclose(f);
-
         return r;
 }
 
         return r;
 }
 
+static int help(void) {
+
+        printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
+               "Registers binary formats.\n\n"
+               "  -h --help             Show this help\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, 'h'           },
+                { NULL,        0,                 NULL, 0             }
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        help();
+                        return 0;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
+
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
-        int r = 0;
+        int r, k;
+
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
@@ -125,28 +175,21 @@ int main(int argc, char *argv[]) {
 
         umask(0022);
 
 
         umask(0022);
 
-        if (argc > 1) {
-                int i;
+        r = 0;
 
 
-                for (i = 1; i < argc; i++) {
-                        int k;
+        if (argc > optind) {
+                int i;
 
 
+                for (i = optind; i < argc; i++) {
                         k = apply_file(argv[i], false);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
         } else {
                         k = apply_file(argv[i], false);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
         } else {
-                char **files, **f;
+                _cleanup_strv_free_ char **files = NULL;
+                char **f;
 
 
-                r = conf_files_list(&files, ".conf", NULL,
-                                    "/etc/binfmt.d",
-                                    "/run/binfmt.d",
-                                    "/usr/local/lib/binfmt.d",
-                                    "/usr/lib/binfmt.d",
-#ifdef HAVE_SPLIT_USR
-                                    "/lib/binfmt.d",
-#endif
-                                    NULL);
+                r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
                 if (r < 0) {
                         log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
                         goto finish;
                 if (r < 0) {
                         log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
                         goto finish;
@@ -156,15 +199,12 @@ int main(int argc, char *argv[]) {
                 write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1");
 
                 STRV_FOREACH(f, files) {
                 write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1");
 
                 STRV_FOREACH(f, files) {
-                        int k;
-
                         k = apply_file(*f, true);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
                         k = apply_file(*f, true);
                         if (k < 0 && r == 0)
                                 r = k;
                 }
-
-                strv_free(files);
         }
         }
+
 finish:
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
 finish:
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
index 936aaed8e46cc8cebf2e834c377c3f66aaf96534..88b1261494182e072b27b4bc5993aebc3591442b 100644 (file)
@@ -26,6 +26,7 @@
 #include <sys/stat.h>
 #include <limits.h>
 #include <dirent.h>
 #include <sys/stat.h>
 #include <limits.h>
 #include <dirent.h>
+#include <getopt.h>
 #include <libkmod.h>
 
 #include "log.h"
 #include <libkmod.h>
 
 #include "log.h"
 
 static char **arg_proc_cmdline_modules = NULL;
 
 
 static char **arg_proc_cmdline_modules = NULL;
 
+static const char conf_file_dirs[] =
+        "/etc/modules-load.d\0"
+        "/run/modules-load.d\0"
+        "/usr/local/lib/modules-load.d\0"
+        "/usr/lib/modules-load.d\0"
+#ifdef HAVE_SPLIT_USR
+        "/lib/modules-load.d\0"
+#endif
+        ;
+
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
@@ -46,14 +57,14 @@ static void systemd_kmod_log(void *data, int priority, const char *file, int lin
 #pragma GCC diagnostic pop
 
 static int add_modules(const char *p) {
 #pragma GCC diagnostic pop
 
 static int add_modules(const char *p) {
-        char **t, **k;
+        char **t;
+        _cleanup_strv_free_ char **k = NULL;
 
         k = strv_split(p, ",");
         if (!k)
                 return log_oom();
 
         t = strv_merge(arg_proc_cmdline_modules, k);
 
         k = strv_split(p, ",");
         if (!k)
                 return log_oom();
 
         t = strv_merge(arg_proc_cmdline_modules, k);
-        strv_free(k);
         if (!t)
                 return log_oom();
 
         if (!t)
                 return log_oom();
 
@@ -162,15 +173,98 @@ static int load_module(struct kmod_ctx *ctx, const char *m) {
         return r;
 }
 
         return r;
 }
 
+static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        assert(ctx);
+        assert(path);
+
+        r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
+        if (r < 0) {
+                if (ignore_enoent && r == -ENOENT)
+                        return 0;
+
+                log_error("Failed to open %s, ignoring: %s", path, strerror(-r));
+                return r;
+        }
+
+        log_debug("apply: %s\n", path);
+        for (;;) {
+                char line[LINE_MAX], *l;
+                int k;
+
+                if (!fgets(line, sizeof(line), f)) {
+                        if (feof(f))
+                                break;
+
+                        log_error("Failed to read file '%s', ignoring: %m", path);
+                        return -errno;
+                }
+
+                l = strstrip(line);
+                if (!*l)
+                        continue;
+                if (strchr(COMMENTS, *l))
+                        continue;
+
+                k = load_module(ctx, l);
+                if (k < 0 && r == 0)
+                        r = k;
+        }
+
+        return r;
+}
+
+static int help(void) {
+
+        printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
+               "Loads statically configured kernel modules.\n\n"
+               "  -h --help             Show this help\n",
+               program_invocation_short_name);
+
+        return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+        static const struct option options[] = {
+                { "help",      no_argument,       NULL, 'h'           },
+                { NULL,        0,                 NULL, 0             }
+        };
+
+        int c;
+
+        assert(argc >= 0);
+        assert(argv);
+
+        while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
+
+                switch (c) {
+
+                case 'h':
+                        help();
+                        return 0;
+
+                case '?':
+                        return -EINVAL;
+
+                default:
+                        log_error("Unknown option code %c", c);
+                        return -EINVAL;
+                }
+        }
+
+        return 1;
+}
+
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
-        int r = EXIT_FAILURE, k;
-        char **files = NULL, **fn, **i;
+        int r, k;
         struct kmod_ctx *ctx;
 
         struct kmod_ctx *ctx;
 
-        if (argc > 1) {
-                log_error("This program takes no argument.");
-                return EXIT_FAILURE;
-        }
+        r = parse_argv(argc, argv);
+        if (r <= 0)
+                return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
 
         log_set_target(LOG_TARGET_AUTO);
         log_parse_environment();
@@ -190,70 +284,43 @@ int main(int argc, char *argv[]) {
         kmod_load_resources(ctx);
         kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
 
         kmod_load_resources(ctx);
         kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
 
-        r = EXIT_SUCCESS;
+        r = 0;
 
 
-        STRV_FOREACH(i, arg_proc_cmdline_modules) {
-                k = load_module(ctx, *i);
-                if (k < 0)
-                        r = EXIT_FAILURE;
-        }
-
-        k = conf_files_list(&files, ".conf", NULL,
-                            "/etc/modules-load.d",
-                            "/run/modules-load.d",
-                            "/usr/local/lib/modules-load.d",
-                            "/usr/lib/modules-load.d",
-#ifdef HAVE_SPLIT_USR
-                            "/lib/modules-load.d",
-#endif
-                            NULL);
-        if (k < 0) {
-                log_error("Failed to enumerate modules-load.d files: %s", strerror(-k));
-                r = EXIT_FAILURE;
-                goto finish;
-        }
-
-        STRV_FOREACH(fn, files) {
-                FILE *f;
+        if (argc > optind) {
+                int i;
 
 
-                f = fopen(*fn, "re");
-                if (!f) {
-                        if (errno == ENOENT)
-                                continue;
-
-                        log_error("Failed to open %s: %m", *fn);
-                        r = EXIT_FAILURE;
-                        continue;
+                for (i = optind; i < argc; i++) {
+                        k = apply_file(ctx, argv[i], false);
+                        if (k < 0 && r == 0)
+                                r = k;
                 }
 
                 }
 
-                log_debug("apply: %s\n", *fn);
-                for (;;) {
-                        char line[LINE_MAX], *l;
-
-                        if (!fgets(line, sizeof(line), f))
-                                break;
+        } else {
+                _cleanup_free_ char **files = NULL;
+                char **fn, **i;
 
 
-                        l = strstrip(line);
-                        if (*l == '#' || *l == 0)
-                                continue;
-
-                        k = load_module(ctx, l);
+                STRV_FOREACH(i, arg_proc_cmdline_modules) {
+                        k = load_module(ctx, *i);
                         if (k < 0)
                                 r = EXIT_FAILURE;
                 }
 
                         if (k < 0)
                                 r = EXIT_FAILURE;
                 }
 
-                if (ferror(f)) {
-                        log_error("Failed to read from file: %m");
-                        r = EXIT_FAILURE;
+                r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
+                if (r < 0) {
+                        log_error("Failed to enumerate modules-load.d files: %s", strerror(-r));
+                        goto finish;
                 }
 
                 }
 
-                fclose(f);
+                STRV_FOREACH(fn, files) {
+                        k = apply_file(ctx, *fn, true);
+                        if (k < 0 && r == 0)
+                                r = k;
+                }
         }
 
 finish:
         }
 
 finish:
-        strv_free(files);
         kmod_unref(ctx);
         strv_free(arg_proc_cmdline_modules);
 
         kmod_unref(ctx);
         strv_free(arg_proc_cmdline_modules);
 
-        return r;
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
 }
index 5bbd2388d3d03084663b118becac7d7d77094958..296e605761c79236b034a09f3aab8b5d0d5947d1 100644 (file)
@@ -38,7 +38,7 @@
 #include "conf-files.h"
 
 static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
 #include "conf-files.h"
 
 static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
-        _cleanup_closedir_ DIR *dir;
+        _cleanup_closedir_ DIR *dir = NULL;
         _cleanup_free_ char *dirpath = NULL;
 
         if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0)
         _cleanup_free_ char *dirpath = NULL;
 
         if (asprintf(&dirpath, "%s%s", root ? root : "", path) < 0)
@@ -55,11 +55,11 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
                 struct dirent *de;
                 union dirent_storage buf;
                 char *p;
                 struct dirent *de;
                 union dirent_storage buf;
                 char *p;
-                int err;
+                int r;
 
 
-                err = readdir_r(dir, &buf.de, &de);
-                if (err != 0)
-                        return err;
+                r = readdir_r(dir, &buf.de, &de);
+                if (r != 0)
+                        return -r;
 
                 if (!de)
                         break;
 
                 if (!de)
                         break;
@@ -67,11 +67,19 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
                 if (!dirent_is_file_with_suffix(de, suffix))
                         continue;
 
                 if (!dirent_is_file_with_suffix(de, suffix))
                         continue;
 
-                if (asprintf(&p, "%s/%s", dirpath, de->d_name) < 0)
+                p = strjoin(dirpath, "/", de->d_name, NULL);
+                if (!p)
                         return -ENOMEM;
 
                         return -ENOMEM;
 
-                if (hashmap_put(h, path_get_file_name(p), p) <= 0) {
-                        log_debug("Skip overridden file: %s.", p);
+                r = hashmap_put(h, path_get_file_name(p), p);
+                if (r == -EEXIST) {
+                        log_debug("Skipping overridden file: %s.", p);
+                        free(p);
+                } else if (r < 0) {
+                        free(p);
+                        return r;
+                } else if (r == 0) {
+                        log_debug("Duplicate file %s", p);
                         free(p);
                 }
         }
                         free(p);
                 }
         }
@@ -87,64 +95,84 @@ static int base_cmp(const void *a, const void *b) {
         return strcmp(path_get_file_name(s1), path_get_file_name(s2));
 }
 
         return strcmp(path_get_file_name(s1), path_get_file_name(s2));
 }
 
-int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs) {
-        Hashmap *fh = NULL;
-        char **files = NULL;
-        const char **p;
+static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
+        Hashmap *fh;
+        char **files, **p;
         int r;
 
         int r;
 
-        assert(dirs);
+        assert(strv);
+        assert(suffix);
+
+        /* This alters the dirs string array */
+        if (!path_strv_canonicalize_uniq(dirs))
+                return -ENOMEM;
 
         fh = hashmap_new(string_hash_func, string_compare_func);
 
         fh = hashmap_new(string_hash_func, string_compare_func);
-        if (!fh) {
-                r = -ENOMEM;
-                goto finish;
-        }
+        if (!fh)
+                return -ENOMEM;
 
         STRV_FOREACH(p, dirs) {
                 r = files_add(fh, root, *p, suffix);
 
         STRV_FOREACH(p, dirs) {
                 r = files_add(fh, root, *p, suffix);
-                if (r < 0)
-                        log_warning("Failed to search for files in %s: %s",
-                                    *p, strerror(-r));
+                if (r == -ENOMEM) {
+                        hashmap_free_free(fh);
+                        return r;
+                } else if (r < 0)
+                        log_debug("Failed to search for files in %s: %s",
+                                  *p, strerror(-r));
         }
 
         files = hashmap_get_strv(fh);
         if (files == NULL) {
         }
 
         files = hashmap_get_strv(fh);
         if (files == NULL) {
-                log_error("Failed to compose list of files.");
-                r = -ENOMEM;
-                goto finish;
+                hashmap_free_free(fh);
+                return -ENOMEM;
         }
         }
+
         qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
         qsort(files, hashmap_size(fh), sizeof(char *), base_cmp);
-        r = 0;
+        *strv = files;
 
 
-finish:
         hashmap_free(fh);
         hashmap_free(fh);
-        *strv = files;
-        return r;
+        return 0;
+}
+
+int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs) {
+        _cleanup_strv_free_ char **copy = NULL;
+
+        assert(strv);
+        assert(suffix);
+
+        copy = strv_copy((char**) dirs);
+        if (!copy)
+                return -ENOMEM;
+
+        return conf_files_list_strv_internal(strv, suffix, root, copy);
 }
 
 int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
 }
 
 int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
-        char **dirs = NULL;
+        _cleanup_strv_free_ char **dirs = NULL;
         va_list ap;
         va_list ap;
-        int r;
+
+        assert(strv);
+        assert(suffix);
 
         va_start(ap, dir);
         dirs = strv_new_ap(dir, ap);
         va_end(ap);
 
         va_start(ap, dir);
         dirs = strv_new_ap(dir, ap);
         va_end(ap);
-        if (!dirs) {
-                r = -ENOMEM;
-                goto finish;
-        }
 
 
-        if (!path_strv_canonicalize(dirs)) {
-                r = -ENOMEM;
-                goto finish;
-        }
-        strv_uniq(dirs);
+        if (!dirs)
+                return -ENOMEM;
+
+        return conf_files_list_strv_internal(strv, suffix, root, dirs);
+}
 
 
-        r = conf_files_list_strv(strv, suffix, root, (const char **)dirs);
+int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
+        _cleanup_strv_free_ char **dirs = NULL;
+
+        assert(strv);
+        assert(suffix);
+
+        dirs = strv_split_nulstr(d);
+        if (!dirs)
+                return -ENOMEM;
 
 
-finish:
-        strv_free(dirs);
-        return r;
+        return conf_files_list_strv_internal(strv, suffix, root, dirs);
 }
 }
index 4d7941f4cb5265265382c7d11bbd4b1b03471bf3..28588e6f0377bd805d466da30f079718331fbb75 100644 (file)
@@ -27,5 +27,6 @@
 
 int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
 int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs);
 
 int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...);
 int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char **dirs);
+int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *dirs);
 
 #endif
 
 #endif
index a2c728d642540bab342e1c989924bb0e4d0ae721..9f7db3439728b7e89ed409ef7acfa2861f5d8e36 100644 (file)
@@ -309,6 +309,17 @@ void hashmap_free_free(Hashmap *h) {
         hashmap_free(h);
 }
 
         hashmap_free(h);
 }
 
+void hashmap_free_free_free(Hashmap *h) {
+
+        /* Free the hashmap and all data and key objects in it */
+
+        if (!h)
+                return;
+
+        hashmap_clear_free_free(h);
+        hashmap_free(h);
+}
+
 void hashmap_clear(Hashmap *h) {
         if (!h)
                 return;
 void hashmap_clear(Hashmap *h) {
         if (!h)
                 return;
@@ -327,6 +338,22 @@ void hashmap_clear_free(Hashmap *h) {
                 free(p);
 }
 
                 free(p);
 }
 
+void hashmap_clear_free_free(Hashmap *h) {
+        if (!h)
+                return;
+
+        while (h->iterate_list_head) {
+                void *a, *b;
+
+                a = h->iterate_list_head->value;
+                b = (void*) h->iterate_list_head->key;
+                remove_entry(h, h->iterate_list_head);
+                free(a);
+                free(b);
+        }
+}
+
+
 static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
         struct hashmap_entry *e;
         assert(h);
 static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) {
         struct hashmap_entry *e;
         assert(h);
index 6fd71cf519fa2fcd4895a3eb43592ed71615bda4..26bd03096d51d1b24479ff996638936764f6590d 100644 (file)
@@ -50,6 +50,7 @@ int uint64_compare_func(const void *a, const void *b);
 Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
 void hashmap_free(Hashmap *h);
 void hashmap_free_free(Hashmap *h);
 Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func);
 void hashmap_free(Hashmap *h);
 void hashmap_free_free(Hashmap *h);
+void hashmap_free_free_free(Hashmap *h);
 Hashmap *hashmap_copy(Hashmap *h);
 int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
 
 Hashmap *hashmap_copy(Hashmap *h);
 int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func);
 
@@ -77,6 +78,7 @@ void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i);
 
 void hashmap_clear(Hashmap *h);
 void hashmap_clear_free(Hashmap *h);
 
 void hashmap_clear(Hashmap *h);
 void hashmap_clear_free(Hashmap *h);
+void hashmap_clear_free_free(Hashmap *h);
 
 void *hashmap_steal_first(Hashmap *h);
 void *hashmap_steal_first_key(Hashmap *h);
 
 void *hashmap_steal_first(Hashmap *h);
 void *hashmap_steal_first_key(Hashmap *h);
index 52ce65de6d9a8b8e65f6a533ab896c317129c628..0b50ea646aa984a3a1a64b15946f438ac17527e1 100644 (file)
@@ -215,6 +215,16 @@ char **path_strv_canonicalize(char **l) {
         return l;
 }
 
         return l;
 }
 
+char **path_strv_canonicalize_uniq(char **l) {
+        if (strv_isempty(l))
+                return l;
+
+        if (!path_strv_canonicalize(l))
+                return NULL;
+
+        return strv_uniq(l);
+}
+
 char *path_kill_slashes(char *path) {
         char *f, *t;
         bool slash = false;
 char *path_kill_slashes(char *path) {
         char *f, *t;
         bool slash = false;
index e37ab9350b28951a8020ed1af9bcf67f9b49ba50..ff523943dce2ae463721856cebd18ef407c9f2f7 100644 (file)
@@ -37,6 +37,7 @@ bool path_equal(const char *a, const char *b);
 
 char **path_strv_make_absolute_cwd(char **l);
 char **path_strv_canonicalize(char **l);
 
 char **path_strv_make_absolute_cwd(char **l);
 char **path_strv_canonicalize(char **l);
+char **path_strv_canonicalize_uniq(char **l);
 
 int path_is_mount_point(const char *path, bool allow_symlink);
 int path_is_read_only_fs(const char *path);
 
 int path_is_mount_point(const char *path, bool allow_symlink);
 int path_is_read_only_fs(const char *path);
index ee0b71ece048bf3a4aa59823ccd654912d38038b..ec25755289a2c5a8e9aecc689693e5e0269ec0a4 100644 (file)
@@ -504,6 +504,22 @@ char **strv_parse_nulstr(const char *s, size_t l) {
         return v;
 }
 
         return v;
 }
 
+char **strv_split_nulstr(const char *s) {
+        const char *i;
+        char **r = NULL;
+
+        NULSTR_FOREACH(i, s)
+                if (strv_extend(&r, i) < 0) {
+                        strv_free(r);
+                        return NULL;
+                }
+
+        if (!r)
+                return strv_new(NULL, NULL);
+
+        return r;
+}
+
 bool strv_overlap(char **a, char **b) {
         char **i, **j;
 
 bool strv_overlap(char **a, char **b) {
         char **i, **j;
 
index d28625bd2f6ec9747fb843c151d538d2ef38ba1a..b3802a7a3ff6b6fcf93c3554843e6d315f66fd81 100644 (file)
@@ -62,6 +62,7 @@ char **strv_split_quoted(const char *s) _malloc_;
 char *strv_join(char **l, const char *separator) _malloc_;
 
 char **strv_parse_nulstr(const char *s, size_t l);
 char *strv_join(char **l, const char *separator) _malloc_;
 
 char **strv_parse_nulstr(const char *s, size_t l);
+char **strv_split_nulstr(const char *s);
 
 bool strv_overlap(char **a, char **b);
 
 
 bool strv_overlap(char **a, char **b);
 
index 29cb9f1e8df05782302322fe5d76a22ba6636aee..24f9e7ee58338c4ad293012e7811671e3a1dad9e 100644 (file)
@@ -5909,3 +5909,82 @@ int on_ac_power(void) {
 
         return found_online || !found_offline;
 }
 
         return found_online || !found_offline;
 }
+
+static int search_and_fopen_internal(const char *path, const char *mode, char **search, FILE **_f) {
+        char **i;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (!path_strv_canonicalize_uniq(search))
+                return -ENOMEM;
+
+        STRV_FOREACH(i, search) {
+                _cleanup_free_ char *p = NULL;
+                FILE *f;
+
+                p = strjoin(*i, "/", path, NULL);
+                if (!p)
+                        return -ENOMEM;
+
+                f = fopen(p, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                if (errno != ENOENT)
+                        return -errno;
+        }
+
+        return -ENOENT;
+}
+
+int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f) {
+        _cleanup_strv_free_ char **copy = NULL;
+
+        assert(path);
+        assert(mode);
+        assert(_f);
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        copy = strv_copy((char**) search);
+        if (!copy)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, copy, _f);
+}
+
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f) {
+        _cleanup_strv_free_ char **s = NULL;
+
+        if (path_is_absolute(path)) {
+                FILE *f;
+
+                f = fopen(path, mode);
+                if (f) {
+                        *_f = f;
+                        return 0;
+                }
+
+                return -errno;
+        }
+
+        s = strv_split_nulstr(search);
+        if (!s)
+                return -ENOMEM;
+
+        return search_and_fopen_internal(path, mode, s, _f);
+}
index d926b01919ec0436c6fe1ca72016e0f7dfa6999e..cd13457528c14d2727483b1497e673adc404c9db 100644 (file)
@@ -568,6 +568,9 @@ char *strip_tab_ansi(char **p, size_t *l);
 
 int on_ac_power(void);
 
 
 int on_ac_power(void);
 
+int search_and_fopen(const char *path, const char *mode, const char **search, FILE **_f);
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *search, FILE **_f);
+
 #define FOREACH_LINE(f, line, on_error)                         \
         for (char line[LINE_MAX]; !feof(f); )                   \
                 if (!fgets(line, sizeof(line), f)) {            \
 #define FOREACH_LINE(f, line, on_error)                         \
         for (char line[LINE_MAX]; !feof(f); )                   \
                 if (!fgets(line, sizeof(line), f)) {            \
index f5ef89b38579be8bb0870f723a677af37b96602a..f59a85832366f6439d29afb3942fe5b8877f5cd5 100644 (file)
 #include "path-util.h"
 #include "conf-files.h"
 
 #include "path-util.h"
 #include "conf-files.h"
 
-#define PROC_SYS_PREFIX "/proc/sys/"
+static char **arg_prefixes = NULL;
 
 
-static char **arg_prefixes;
-static Hashmap *sysctl_options;
+static const char conf_file_dirs[] =
+        "/etc/sysctl.d\0"
+        "/run/sysctl.d\0"
+        "/usr/local/lib/sysctl.d\0"
+        "/usr/lib/sysctl.d\0"
+#ifdef HAVE_SPLIT_USR
+        "/lib/sysctl.d\0"
+#endif
+        ;
+
+static char *normalize_sysctl(char *s) {
+        char *n;
+
+        for (n = s; *n; n++)
+                if (*n == '.')
+                        *n = '/';
+
+        return s;
+}
 
 static int apply_sysctl(const char *property, const char *value) {
 
 static int apply_sysctl(const char *property, const char *value) {
-        char *p, *n;
+        _cleanup_free_ char *p = NULL;
+        char *n;
         int r = 0, k;
 
         log_debug("Setting '%s' to '%s'", property, value);
 
         int r = 0, k;
 
         log_debug("Setting '%s' to '%s'", property, value);
 
-        p = new(char, sizeof(PROC_SYS_PREFIX) + strlen(property));
+        p = new(char, sizeof("/proc/sys/") + strlen(property));
         if (!p)
                 return log_oom();
 
         if (!p)
                 return log_oom();
 
-        n = stpcpy(p, PROC_SYS_PREFIX);
+        n = stpcpy(p, "/proc/sys/");
         strcpy(n, property);
 
         strcpy(n, property);
 
-        for (; *n; n++)
-                if (*n == '.')
-                        *n = '/';
-
         if (!strv_isempty(arg_prefixes)) {
                 char **i;
                 bool good = false;
         if (!strv_isempty(arg_prefixes)) {
                 char **i;
                 bool good = false;
@@ -69,14 +83,12 @@ static int apply_sysctl(const char *property, const char *value) {
 
                 if (!good) {
                         log_debug("Skipping %s", p);
 
                 if (!good) {
                         log_debug("Skipping %s", p);
-                        free(p);
                         return 0;
                 }
         }
 
         k = write_one_line_file(p, value);
         if (k < 0) {
                         return 0;
                 }
         }
 
         k = write_one_line_file(p, value);
         if (k < 0) {
-
                 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
                          "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
 
                 log_full(k == -ENOENT ? LOG_DEBUG : LOG_WARNING,
                          "Failed to write '%s' to '%s': %s", value, p, strerror(-k));
 
@@ -84,16 +96,16 @@ static int apply_sysctl(const char *property, const char *value) {
                         r = k;
         }
 
                         r = k;
         }
 
-        free(p);
-
         return r;
 }
 
         return r;
 }
 
-static int apply_all(void) {
+static int apply_all(Hashmap *sysctl_options) {
         int r = 0;
         char *property, *value;
         Iterator i;
 
         int r = 0;
         char *property, *value;
         Iterator i;
 
+        assert(sysctl_options);
+
         HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
                 int k;
 
         HASHMAP_FOREACH_KEY(value, property, sysctl_options, i) {
                 int k;
 
@@ -104,36 +116,35 @@ static int apply_all(void) {
         return r;
 }
 
         return r;
 }
 
-static int parse_file(const char *path, bool ignore_enoent) {
-        FILE *f;
-        int r = 0;
+static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_enoent) {
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
 
         assert(path);
 
 
         assert(path);
 
-        f = fopen(path, "re");
-        if (!f) {
-                if (ignore_enoent && errno == ENOENT)
+        r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
+        if (r < 0) {
+                if (ignore_enoent && errno == -ENOENT)
                         return 0;
 
                         return 0;
 
-                log_error("Failed to open file '%s', ignoring: %m", path);
-                return -errno;
+                log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
+                return r;
         }
 
         log_debug("parse: %s\n", path);
         while (!feof(f)) {
         }
 
         log_debug("parse: %s\n", path);
         while (!feof(f)) {
-                char l[LINE_MAX], *p, *value, *new_value, *property;
+                char l[LINE_MAX], *p, *value, *new_value, *property, *existing;
+                int k;
 
                 if (!fgets(l, sizeof(l), f)) {
                         if (feof(f))
                                 break;
 
                         log_error("Failed to read file '%s', ignoring: %m", path);
 
                 if (!fgets(l, sizeof(l), f)) {
                         if (feof(f))
                                 break;
 
                         log_error("Failed to read file '%s', ignoring: %m", path);
-                        r = -errno;
-                        goto finish;
+                        return -errno;
                 }
 
                 p = strstrip(l);
                 }
 
                 p = strstrip(l);
-
                 if (!*p)
                         continue;
 
                 if (!*p)
                         continue;
 
@@ -152,40 +163,36 @@ static int parse_file(const char *path, bool ignore_enoent) {
                 *value = 0;
                 value++;
 
                 *value = 0;
                 value++;
 
-                property = strdup(strstrip(p));
-                if (!property) {
-                        r = log_oom();
-                        goto finish;
+                p = normalize_sysctl(strstrip(p));
+                value = strstrip(value);
+
+                existing = hashmap_get(sysctl_options, p);
+                if (existing) {
+                        if (!streq(value, existing))
+                                log_warning("Two ore more conflicting assignments of %s, ignoring.", property);
+
+                        continue;
                 }
 
                 }
 
-                new_value = strdup(strstrip(value));
+                property = strdup(p);
+                if (!property)
+                        return log_oom();
+
+                new_value = strdup(value);
                 if (!new_value) {
                         free(property);
                 if (!new_value) {
                         free(property);
-                        r = log_oom();
-                        goto finish;
+                        return log_oom();
                 }
 
                 }
 
-                r = hashmap_put(sysctl_options, property, new_value);
-                if (r < 0) {
-                        if (r == -EEXIST) {
-                                /* ignore this "error" to avoid returning it
-                                 * for the function when this is the last key
-                                 * in the file being parsed. */
-                                r = 0;
-                                log_debug("Skipping previously assigned sysctl variable %s", property);
-                        } else
-                                log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-r));
-
+                k = hashmap_put(sysctl_options, property, new_value);
+                if (k < 0) {
+                        log_error("Failed to add sysctl variable %s to hashmap: %s", property, strerror(-r));
                         free(property);
                         free(new_value);
                         free(property);
                         free(new_value);
-                        if (r != 0)
-                                goto finish;
+                        return k;
                 }
         }
 
                 }
         }
 
-finish:
-        fclose(f);
-
         return r;
 }
 
         return r;
 }
 
@@ -257,8 +264,7 @@ static int parse_argv(int argc, char *argv[]) {
 
 int main(int argc, char *argv[]) {
         int r = 0, k;
 
 int main(int argc, char *argv[]) {
         int r = 0, k;
-        char *property, *value;
-        Iterator it;
+        Hashmap *sysctl_options;
 
         r = parse_argv(argc, argv);
         if (r <= 0)
 
         r = parse_argv(argc, argv);
         if (r <= 0)
@@ -282,54 +288,35 @@ int main(int argc, char *argv[]) {
                 int i;
 
                 for (i = optind; i < argc; i++) {
                 int i;
 
                 for (i = optind; i < argc; i++) {
-                        k = parse_file(argv[i], false);
-                        if (k < 0)
+                        k = parse_file(sysctl_options, argv[i], false);
+                        if (k < 0 && r == 0)
                                 r = k;
                 }
         } else {
                                 r = k;
                 }
         } else {
-                char **files, **f;
+                _cleanup_strv_free_ char **files = NULL;
+                char **f;
 
 
-                r = conf_files_list(&files, ".conf", NULL,
-                                    "/etc/sysctl.d",
-                                    "/run/sysctl.d",
-                                    "/usr/local/lib/sysctl.d",
-                                    "/usr/lib/sysctl.d",
-#ifdef HAVE_SPLIT_USR
-                                    "/lib/sysctl.d",
-#endif
-                                    NULL);
+                r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
                 if (r < 0) {
                         log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
                         goto finish;
                 }
 
                 if (r < 0) {
                         log_error("Failed to enumerate sysctl.d files: %s", strerror(-r));
                         goto finish;
                 }
 
-                /* We parse the files in decreasing order of precedence.
-                 * parse_file() will skip keys that were already assigned. */
+                r = parse_file(sysctl_options, "/etc/sysctl.conf", true);
 
 
-                r = parse_file("/etc/sysctl.conf", true);
-
-                f = files + strv_length(files) - 1;
-                STRV_FOREACH_BACKWARDS(f, files) {
-                        k = parse_file(*f, true);
-                        if (k < 0)
+                STRV_FOREACH(f, files) {
+                        k = parse_file(sysctl_options, *f, true);
+                        if (k < 0 && r == 0)
                                 r = k;
                 }
                                 r = k;
                 }
-
-                strv_free(files);
         }
 
         }
 
-        k = apply_all();
-        if (k < 0)
+        k = apply_all(sysctl_options);
+        if (k < 0 && r == 0)
                 r = k;
 
 finish:
                 r = k;
 
 finish:
-        HASHMAP_FOREACH_KEY(value, property, sysctl_options, it) {
-                hashmap_remove(sysctl_options, property);
-                free(property);
-                free(value);
-        }
-        hashmap_free(sysctl_options);
-
+        hashmap_free_free_free(sysctl_options);
         strv_free(arg_prefixes);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
         strv_free(arg_prefixes);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
index 96adbff42e9dcab8613e1a957add1074cef6c199..6b3f70e071e17a10f9cc91a4da8688e1681e5a37 100644 (file)
@@ -106,16 +106,15 @@ static bool arg_remove = false;
 
 static const char *arg_prefix = NULL;
 
 
 static const char *arg_prefix = NULL;
 
-static const char * const conf_file_dirs[] = {
-        "/etc/tmpfiles.d",
-        "/run/tmpfiles.d",
-        "/usr/local/lib/tmpfiles.d",
-        "/usr/lib/tmpfiles.d",
+static const char conf_file_dirs[] =
+        "/etc/tmpfiles.d\0"
+        "/run/tmpfiles.d\0"
+        "/usr/local/lib/tmpfiles.d\0"
+        "/usr/lib/tmpfiles.d\0"
 #ifdef HAVE_SPLIT_USR
 #ifdef HAVE_SPLIT_USR
-        "/lib/tmpfiles.d",
+        "/lib/tmpfiles.d\0"
 #endif
 #endif
-        NULL
-};
+        ;
 
 #define MAX_DEPTH 256
 
 
 #define MAX_DEPTH 256
 
@@ -1289,20 +1288,19 @@ static int parse_argv(int argc, char *argv[]) {
 static int read_config_file(const char *fn, bool ignore_enoent) {
         FILE *f;
         unsigned v = 0;
 static int read_config_file(const char *fn, bool ignore_enoent) {
         FILE *f;
         unsigned v = 0;
-        int r = 0;
+        int r;
         Iterator iterator;
         Item *i;
 
         assert(fn);
 
         Iterator iterator;
         Item *i;
 
         assert(fn);
 
-        f = fopen(fn, "re");
-        if (!f) {
-
-                if (ignore_enoent && errno == ENOENT)
+        r = search_and_fopen_nulstr(fn, "re", conf_file_dirs, &f);
+        if (r < 0) {
+                if (ignore_enoent && r == -ENOENT)
                         return 0;
 
                         return 0;
 
-                log_error("Failed to open %s: %m", fn);
-                return -errno;
+                log_error("Failed to open '%s', ignoring: %s", fn, strerror(-r));
+                return r;
         }
 
         log_debug("apply: %s\n", fn);
         }
 
         log_debug("apply: %s\n", fn);
@@ -1363,32 +1361,8 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
         return r;
 }
 
         return r;
 }
 
-static char *resolve_fragment(const char *fragment, const char **search_paths) {
-        const char **p;
-        char *resolved_path;
-
-        if (is_path(fragment))
-                return strdup(fragment);
-
-        STRV_FOREACH(p, search_paths) {
-                resolved_path = strjoin(*p, "/", fragment, NULL);
-                if (resolved_path == NULL) {
-                        log_oom();
-                        return NULL;
-                }
-
-                if (access(resolved_path, F_OK) == 0)
-                        return resolved_path;
-
-                free(resolved_path);
-        }
-
-        errno = ENOENT;
-        return NULL;
-}
-
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
-        int r;
+        int r, k;
         Item *i;
         Iterator iterator;
 
         Item *i;
         Iterator iterator;
 
@@ -1408,46 +1382,36 @@ int main(int argc, char *argv[]) {
         globs = hashmap_new(string_hash_func, string_compare_func);
 
         if (!items || !globs) {
         globs = hashmap_new(string_hash_func, string_compare_func);
 
         if (!items || !globs) {
-                log_oom();
-                r = EXIT_FAILURE;
+                r = log_oom();
                 goto finish;
         }
 
                 goto finish;
         }
 
-        r = EXIT_SUCCESS;
+        r = 0;
 
         if (optind < argc) {
                 int j;
 
                 for (j = optind; j < argc; j++) {
 
         if (optind < argc) {
                 int j;
 
                 for (j = optind; j < argc; j++) {
-                        char *fragment;
-
-                        fragment = resolve_fragment(argv[j], (const char **)conf_file_dirs);
-                        if (!fragment) {
-                                log_error("Failed to find a %s file: %m", argv[j]);
-                                r = EXIT_FAILURE;
-                                goto finish;
-                        }
-                        if (read_config_file(fragment, false) < 0)
-                                r = EXIT_FAILURE;
-                        free(fragment);
+                        k = read_config_file(argv[j], false);
+                        if (k < 0 && r == 0)
+                                r = k;
                 }
 
         } else {
                 }
 
         } else {
-                char **files, **f;
+                _cleanup_strv_free_ char **files = NULL;
+                char **f;
 
 
-                r = conf_files_list_strv(&files, ".conf", NULL, (const char **)conf_file_dirs);
+                r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
                 if (r < 0) {
                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
                 if (r < 0) {
                         log_error("Failed to enumerate tmpfiles.d files: %s", strerror(-r));
-                        r = EXIT_FAILURE;
                         goto finish;
                 }
 
                 STRV_FOREACH(f, files) {
                         goto finish;
                 }
 
                 STRV_FOREACH(f, files) {
-                        if (read_config_file(*f, true) < 0)
-                                r = EXIT_FAILURE;
+                        k = read_config_file(*f, true);
+                        if (k < 0 && r == 0)
+                                r = k;
                 }
                 }
-
-                strv_free(files);
         }
 
         HASHMAP_FOREACH(i, globs, iterator)
         }
 
         HASHMAP_FOREACH(i, globs, iterator)
@@ -1470,5 +1434,5 @@ finish:
 
         label_finish();
 
 
         label_finish();
 
-        return r;
+        return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }
 }