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