199ca880aSopenharmony_ci/***
299ca880aSopenharmony_ci  This file is part of eudev, forked from systemd.
399ca880aSopenharmony_ci
499ca880aSopenharmony_ci  Copyright 2010 Lennart Poettering
599ca880aSopenharmony_ci
699ca880aSopenharmony_ci  systemd is free software; you can redistribute it and/or modify it
799ca880aSopenharmony_ci  under the terms of the GNU Lesser General Public License as published by
899ca880aSopenharmony_ci  the Free Software Foundation; either version 2.1 of the License, or
999ca880aSopenharmony_ci  (at your option) any later version.
1099ca880aSopenharmony_ci
1199ca880aSopenharmony_ci  systemd is distributed in the hope that it will be useful, but
1299ca880aSopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1399ca880aSopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1499ca880aSopenharmony_ci  Lesser General Public License for more details.
1599ca880aSopenharmony_ci
1699ca880aSopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1799ca880aSopenharmony_ci  along with systemd; If not, see <http://www.gnu.org/licenses/>.
1899ca880aSopenharmony_ci***/
1999ca880aSopenharmony_ci
2099ca880aSopenharmony_ci#include <assert.h>
2199ca880aSopenharmony_ci#include <string.h>
2299ca880aSopenharmony_ci#include <unistd.h>
2399ca880aSopenharmony_ci#include <errno.h>
2499ca880aSopenharmony_ci#include <stdlib.h>
2599ca880aSopenharmony_ci#include <stdio.h>
2699ca880aSopenharmony_ci#include <sys/stat.h>
2799ca880aSopenharmony_ci#include <dirent.h>
2899ca880aSopenharmony_ci
2999ca880aSopenharmony_ci#include "macro.h"
3099ca880aSopenharmony_ci#include "util.h"
3199ca880aSopenharmony_ci#include "missing.h"
3299ca880aSopenharmony_ci#include "log.h"
3399ca880aSopenharmony_ci#include "strv.h"
3499ca880aSopenharmony_ci#include "path-util.h"
3599ca880aSopenharmony_ci#include "hashmap.h"
3699ca880aSopenharmony_ci#include "conf-files.h"
3799ca880aSopenharmony_ci
3899ca880aSopenharmony_cistatic const char *basename_internal(const char *filename) {
3999ca880aSopenharmony_ci        const char *ret = filename, *p = filename;
4099ca880aSopenharmony_ci
4199ca880aSopenharmony_ci        p = strchr(filename, '/');
4299ca880aSopenharmony_ci        while (p) {
4399ca880aSopenharmony_ci                ret = &p[1];
4499ca880aSopenharmony_ci                p = strchr(ret, '/');
4599ca880aSopenharmony_ci        }
4699ca880aSopenharmony_ci        return ret;
4799ca880aSopenharmony_ci}
4899ca880aSopenharmony_ci
4999ca880aSopenharmony_cistatic int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
5099ca880aSopenharmony_ci        _cleanup_closedir_ DIR *dir = NULL;
5199ca880aSopenharmony_ci        char *dirpath;
5299ca880aSopenharmony_ci
5399ca880aSopenharmony_ci        assert(path);
5499ca880aSopenharmony_ci        assert(suffix);
5599ca880aSopenharmony_ci
5699ca880aSopenharmony_ci        dirpath = strjoina(root ? root : "", path);
5799ca880aSopenharmony_ci
5899ca880aSopenharmony_ci        dir = opendir(dirpath);
5999ca880aSopenharmony_ci        if (!dir) {
6099ca880aSopenharmony_ci                if (errno == ENOENT)
6199ca880aSopenharmony_ci                        return 0;
6299ca880aSopenharmony_ci                return -errno;
6399ca880aSopenharmony_ci        }
6499ca880aSopenharmony_ci
6599ca880aSopenharmony_ci        for (;;) {
6699ca880aSopenharmony_ci                struct dirent *de;
6799ca880aSopenharmony_ci                char *p;
6899ca880aSopenharmony_ci                int r;
6999ca880aSopenharmony_ci
7099ca880aSopenharmony_ci                errno = 0;
7199ca880aSopenharmony_ci                de = readdir(dir);
7299ca880aSopenharmony_ci                if (!de && errno != 0)
7399ca880aSopenharmony_ci                        return -errno;
7499ca880aSopenharmony_ci
7599ca880aSopenharmony_ci                if (!de)
7699ca880aSopenharmony_ci                        break;
7799ca880aSopenharmony_ci
7899ca880aSopenharmony_ci                if (!dirent_is_file_with_suffix(de, suffix))
7999ca880aSopenharmony_ci                        continue;
8099ca880aSopenharmony_ci
8199ca880aSopenharmony_ci                p = strjoin(dirpath, "/", de->d_name, NULL);
8299ca880aSopenharmony_ci                if (!p)
8399ca880aSopenharmony_ci                        return -ENOMEM;
8499ca880aSopenharmony_ci
8599ca880aSopenharmony_ci                r = hashmap_put(h, basename_internal(p), p);
8699ca880aSopenharmony_ci                if (r == -EEXIST) {
8799ca880aSopenharmony_ci                        log_debug("Skipping overridden file: %s.", p);
8899ca880aSopenharmony_ci                        free(p);
8999ca880aSopenharmony_ci                } else if (r < 0) {
9099ca880aSopenharmony_ci                        free(p);
9199ca880aSopenharmony_ci                        return r;
9299ca880aSopenharmony_ci                } else if (r == 0) {
9399ca880aSopenharmony_ci                        log_debug("Duplicate file %s", p);
9499ca880aSopenharmony_ci                        free(p);
9599ca880aSopenharmony_ci                }
9699ca880aSopenharmony_ci        }
9799ca880aSopenharmony_ci
9899ca880aSopenharmony_ci        return 0;
9999ca880aSopenharmony_ci}
10099ca880aSopenharmony_ci
10199ca880aSopenharmony_cistatic int base_cmp(const void *a, const void *b) {
10299ca880aSopenharmony_ci        const char *s1, *s2;
10399ca880aSopenharmony_ci
10499ca880aSopenharmony_ci        s1 = *(char * const *)a;
10599ca880aSopenharmony_ci        s2 = *(char * const *)b;
10699ca880aSopenharmony_ci        return strcmp(basename_internal(s1), basename_internal(s2));
10799ca880aSopenharmony_ci}
10899ca880aSopenharmony_ci
10999ca880aSopenharmony_cistatic int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
11099ca880aSopenharmony_ci        _cleanup_hashmap_free_ Hashmap *fh = NULL;
11199ca880aSopenharmony_ci        char **files, **p;
11299ca880aSopenharmony_ci        int r;
11399ca880aSopenharmony_ci
11499ca880aSopenharmony_ci        assert(strv);
11599ca880aSopenharmony_ci        assert(suffix);
11699ca880aSopenharmony_ci
11799ca880aSopenharmony_ci        /* This alters the dirs string array */
11899ca880aSopenharmony_ci        if (!path_strv_resolve_uniq(dirs, root))
11999ca880aSopenharmony_ci                return -ENOMEM;
12099ca880aSopenharmony_ci
12199ca880aSopenharmony_ci        fh = hashmap_new(&string_hash_ops);
12299ca880aSopenharmony_ci        if (!fh)
12399ca880aSopenharmony_ci                return -ENOMEM;
12499ca880aSopenharmony_ci
12599ca880aSopenharmony_ci        STRV_FOREACH(p, dirs) {
12699ca880aSopenharmony_ci                r = files_add(fh, root, *p, suffix);
12799ca880aSopenharmony_ci                if (r == -ENOMEM) {
12899ca880aSopenharmony_ci                        return r;
12999ca880aSopenharmony_ci                } else if (r < 0)
13099ca880aSopenharmony_ci                        log_debug("Failed to search for files in %s: %s",
13199ca880aSopenharmony_ci                                  *p, strerror(-r));
13299ca880aSopenharmony_ci        }
13399ca880aSopenharmony_ci
13499ca880aSopenharmony_ci        files = hashmap_get_strv(fh);
13599ca880aSopenharmony_ci        if (files == NULL) {
13699ca880aSopenharmony_ci                return -ENOMEM;
13799ca880aSopenharmony_ci        }
13899ca880aSopenharmony_ci
13999ca880aSopenharmony_ci        qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
14099ca880aSopenharmony_ci        *strv = files;
14199ca880aSopenharmony_ci
14299ca880aSopenharmony_ci        return 0;
14399ca880aSopenharmony_ci}
14499ca880aSopenharmony_ci
14599ca880aSopenharmony_ciint conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) {
14699ca880aSopenharmony_ci        _cleanup_strv_free_ char **copy = NULL;
14799ca880aSopenharmony_ci
14899ca880aSopenharmony_ci        assert(strv);
14999ca880aSopenharmony_ci        assert(suffix);
15099ca880aSopenharmony_ci
15199ca880aSopenharmony_ci        copy = strv_copy((char**) dirs);
15299ca880aSopenharmony_ci        if (!copy)
15399ca880aSopenharmony_ci                return -ENOMEM;
15499ca880aSopenharmony_ci
15599ca880aSopenharmony_ci        return conf_files_list_strv_internal(strv, suffix, root, copy);
15699ca880aSopenharmony_ci}
157