chiark / gitweb /
5854caeb518d1a2ec49b07520c73a0ebd757688d
[elogind.git] / src / basic / conf-files.c
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 <dirent.h>
23 #include <errno.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "conf-files.h"
30 #include "dirent-util.h"
31 #include "fd-util.h"
32 #include "hashmap.h"
33 #include "log.h"
34 #include "macro.h"
35 #include "missing.h"
36 #include "path-util.h"
37 #include "string-util.h"
38 #include "strv.h"
39 #include "util.h"
40
41 static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
42         _cleanup_closedir_ DIR *dir = NULL;
43         const char *dirpath;
44         struct dirent *de;
45         int r;
46
47         assert(path);
48         assert(suffix);
49
50         dirpath = prefix_roota(root, path);
51
52         dir = opendir(dirpath);
53         if (!dir) {
54                 if (errno == ENOENT)
55                         return 0;
56                 return -errno;
57         }
58
59         FOREACH_DIRENT(de, dir, return -errno) {
60                 char *p;
61
62                 if (!dirent_is_file_with_suffix(de, suffix))
63                         continue;
64
65                 p = strjoin(dirpath, "/", de->d_name, NULL);
66                 if (!p)
67                         return -ENOMEM;
68
69                 r = hashmap_put(h, basename(p), p);
70                 if (r == -EEXIST) {
71                         log_debug("Skipping overridden file: %s.", p);
72                         free(p);
73                 } else if (r < 0) {
74                         free(p);
75                         return r;
76                 } else if (r == 0) {
77                         log_debug("Duplicate file %s", p);
78                         free(p);
79                 }
80         }
81
82         return 0;
83 }
84
85 static int base_cmp(const void *a, const void *b) {
86         const char *s1, *s2;
87
88         s1 = *(char * const *)a;
89         s2 = *(char * const *)b;
90         return strcmp(basename(s1), basename(s2));
91 }
92
93 static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, char **dirs) {
94         _cleanup_hashmap_free_ Hashmap *fh = NULL;
95         char **files, **p;
96         int r;
97
98         assert(strv);
99         assert(suffix);
100
101         /* This alters the dirs string array */
102         if (!path_strv_resolve_uniq(dirs, root))
103                 return -ENOMEM;
104
105         fh = hashmap_new(&string_hash_ops);
106         if (!fh)
107                 return -ENOMEM;
108
109         STRV_FOREACH(p, dirs) {
110                 r = files_add(fh, root, *p, suffix);
111                 if (r == -ENOMEM)
112                         return r;
113                 if (r < 0)
114                         log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p);
115         }
116
117         files = hashmap_get_strv(fh);
118         if (!files)
119                 return -ENOMEM;
120
121         qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
122         *strv = files;
123
124         return 0;
125 }
126
127 int conf_files_list_strv(char ***strv, const char *suffix, const char *root, const char* const* dirs) {
128         _cleanup_strv_free_ char **copy = NULL;
129
130         assert(strv);
131         assert(suffix);
132
133         copy = strv_copy((char**) dirs);
134         if (!copy)
135                 return -ENOMEM;
136
137         return conf_files_list_strv_internal(strv, suffix, root, copy);
138 }
139
140 int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) {
141         _cleanup_strv_free_ char **dirs = NULL;
142         va_list ap;
143
144         assert(strv);
145         assert(suffix);
146
147         va_start(ap, dir);
148         dirs = strv_new_ap(dir, ap);
149         va_end(ap);
150
151         if (!dirs)
152                 return -ENOMEM;
153
154         return conf_files_list_strv_internal(strv, suffix, root, dirs);
155 }
156
157 int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, const char *d) {
158         _cleanup_strv_free_ char **dirs = NULL;
159
160         assert(strv);
161         assert(suffix);
162
163         dirs = strv_split_nulstr(d);
164         if (!dirs)
165                 return -ENOMEM;
166
167         return conf_files_list_strv_internal(strv, suffix, root, dirs);
168 }