Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2010 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include <string.h>
23 : #include <errno.h>
24 : #include <stdlib.h>
25 : #include <stdio.h>
26 : #include <dirent.h>
27 :
28 : #include "macro.h"
29 : #include "util.h"
30 : #include "missing.h"
31 : #include "log.h"
32 : #include "strv.h"
33 : #include "path-util.h"
34 : #include "hashmap.h"
35 : #include "conf-files.h"
36 :
37 24 : static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
38 48 : _cleanup_closedir_ DIR *dir = NULL;
39 : const char *dirpath;
40 : int r;
41 :
42 24 : assert(path);
43 24 : assert(suffix);
44 :
45 24 : dirpath = prefix_roota(root, path);
46 :
47 24 : dir = opendir(dirpath);
48 24 : if (!dir) {
49 15 : if (errno == ENOENT)
50 15 : return 0;
51 0 : return -errno;
52 : }
53 :
54 : for (;;) {
55 : struct dirent *de;
56 : char *p;
57 :
58 51 : errno = 0;
59 51 : de = readdir(dir);
60 51 : if (!de && errno != 0)
61 0 : return -errno;
62 :
63 51 : if (!de)
64 9 : break;
65 :
66 42 : if (!dirent_is_file_with_suffix(de, suffix))
67 24 : continue;
68 :
69 18 : p = strjoin(dirpath, "/", de->d_name, NULL);
70 18 : if (!p)
71 0 : return -ENOMEM;
72 :
73 18 : r = hashmap_put(h, basename(p), p);
74 18 : if (r == -EEXIST) {
75 2 : log_debug("Skipping overridden file: %s.", p);
76 2 : free(p);
77 16 : } else if (r < 0) {
78 0 : free(p);
79 0 : return r;
80 16 : } else if (r == 0) {
81 0 : log_debug("Duplicate file %s", p);
82 0 : free(p);
83 : }
84 42 : }
85 :
86 9 : return 0;
87 : }
88 :
89 19 : static int base_cmp(const void *a, const void *b) {
90 : const char *s1, *s2;
91 :
92 19 : s1 = *(char * const *)a;
93 19 : s2 = *(char * const *)b;
94 19 : return strcmp(basename(s1), basename(s2));
95 : }
96 :
97 10 : static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
98 20 : _cleanup_hashmap_free_ Hashmap *fh = NULL;
99 : char **files, **p;
100 : int r;
101 :
102 10 : assert(strv);
103 10 : assert(suffix);
104 :
105 : /* This alters the dirs string array */
106 10 : if (!path_strv_resolve_uniq(dirs, root))
107 0 : return -ENOMEM;
108 :
109 10 : fh = hashmap_new(&string_hash_ops);
110 10 : if (!fh)
111 0 : return -ENOMEM;
112 :
113 34 : STRV_FOREACH(p, dirs) {
114 24 : r = files_add(fh, root, *p, suffix);
115 24 : if (r == -ENOMEM) {
116 0 : return r;
117 24 : } else if (r < 0)
118 0 : log_debug_errno(r, "Failed to search for files in %s: %m",
119 : *p);
120 : }
121 :
122 10 : files = hashmap_get_strv(fh);
123 10 : if (files == NULL) {
124 0 : return -ENOMEM;
125 : }
126 :
127 10 : qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
128 10 : *strv = files;
129 :
130 10 : return 0;
131 : }
132 :
133 5 : int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) {
134 10 : _cleanup_strv_free_ char **copy = NULL;
135 :
136 5 : assert(strv);
137 5 : assert(suffix);
138 :
139 5 : copy = strv_copy((char**) dirs);
140 5 : if (!copy)
141 0 : return -ENOMEM;
142 :
143 5 : return conf_files_list_strv_internal(strv, suffix, root, copy);
144 : }
145 :
146 2 : int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
147 4 : _cleanup_strv_free_ char **dirs = NULL;
148 : va_list ap;
149 :
150 2 : assert(strv);
151 2 : assert(suffix);
152 :
153 2 : va_start(ap, dir);
154 2 : dirs = strv_new_ap(dir, ap);
155 2 : va_end(ap);
156 :
157 2 : if (!dirs)
158 0 : return -ENOMEM;
159 :
160 2 : return conf_files_list_strv_internal(strv, suffix, root, dirs);
161 : }
162 :
163 3 : int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
164 6 : _cleanup_strv_free_ char **dirs = NULL;
165 :
166 3 : assert(strv);
167 3 : assert(suffix);
168 :
169 3 : dirs = strv_split_nulstr(d);
170 3 : if (!dirs)
171 0 : return -ENOMEM;
172 :
173 3 : return conf_files_list_strv_internal(strv, suffix, root, dirs);
174 : }
|