]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/conf-files.c
Merge pull request #6788 from zerkms/TIMER_TIMEZONE
[thirdparty/systemd.git] / src / basic / conf-files.c
CommitLineData
2c21044f
KS
1/***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
07630cea 20#include <dirent.h>
2c21044f 21#include <errno.h>
11c3a366 22#include <stdarg.h>
2c21044f 23#include <stdio.h>
07630cea
LP
24#include <stdlib.h>
25#include <string.h>
2c21044f 26
3ffd4af2 27#include "conf-files.h"
a0956174 28#include "dirent-util.h"
3ffd4af2 29#include "fd-util.h"
07630cea
LP
30#include "hashmap.h"
31#include "log.h"
2c21044f 32#include "macro.h"
2c21044f 33#include "missing.h"
9eb977db 34#include "path-util.h"
b5084605 35#include "stat-util.h"
07630cea
LP
36#include "string-util.h"
37#include "strv.h"
38#include "util.h"
2c21044f 39
b5084605 40static int files_add(Hashmap *h, const char *suffix, const char *root, unsigned flags, const char *path) {
fabe5c0e 41 _cleanup_closedir_ DIR *dir = NULL;
1d13f648 42 const char *dirpath;
31d5192d 43 struct dirent *de;
1d13f648 44 int r;
e02caf30 45
cba2ef02 46 assert(path);
cebed500 47
1d13f648 48 dirpath = prefix_roota(root, path);
cebed500 49
cba2ef02 50 dir = opendir(dirpath);
2c21044f
KS
51 if (!dir) {
52 if (errno == ENOENT)
53 return 0;
54 return -errno;
55 }
56
31d5192d 57 FOREACH_DIRENT(de, dir, return -errno) {
2c21044f
KS
58 char *p;
59
e34aa8ed
LP
60 if (!dirent_is_file_with_suffix(de, suffix)) {
61 log_debug("Ignoring %s/%s, because it's not a regular file with suffix %s.", dirpath, de->d_name, strna(suffix));
2c21044f 62 continue;
e34aa8ed 63 }
2c21044f 64
b5084605
LP
65 if (flags & CONF_FILES_EXECUTABLE) {
66 struct stat st;
67
68 /* As requested: check if the file is marked exectuable. Note that we don't check access(X_OK)
69 * here, as we care about whether the file is marked executable at all, and not whether it is
70 * executable for us, because if such errors are stuff we should log about. */
71
72 if (fstatat(dirfd(dir), de->d_name, &st, 0) < 0) {
73 log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", dirpath, de->d_name);
74 continue;
75 }
76
77 /* We only want executable regular files (or symlinks to them), or symlinks to /dev/null */
78 if (S_ISREG(st.st_mode)) {
79 if ((st.st_mode & 0111) == 0) { /* not executable */
80 log_debug("Ignoring %s/%s, as it is not marked executable.", dirpath, de->d_name);
81 continue;
82 }
83
84 } else if (!null_or_empty(&st)) { /* /dev/null? */
85 log_debug("Ignoring %s/%s, as it is not a regular file (or symlink to /dev/null).", dirpath, de->d_name);
86 continue;
87 }
88 }
89
605405c6 90 p = strjoin(dirpath, "/", de->d_name);
fabe5c0e 91 if (!p)
e02caf30 92 return -ENOMEM;
2c21044f 93
2b6bf07d 94 r = hashmap_put(h, basename(p), p);
fabe5c0e
LP
95 if (r == -EEXIST) {
96 log_debug("Skipping overridden file: %s.", p);
97 free(p);
98 } else if (r < 0) {
99 free(p);
100 return r;
101 } else if (r == 0) {
102 log_debug("Duplicate file %s", p);
2c21044f
KS
103 free(p);
104 }
105 }
106
e02caf30 107 return 0;
2c21044f
KS
108}
109
110static int base_cmp(const void *a, const void *b) {
111 const char *s1, *s2;
112
113 s1 = *(char * const *)a;
114 s2 = *(char * const *)b;
2b6bf07d 115 return strcmp(basename(s1), basename(s2));
2c21044f
KS
116}
117
b5084605 118static int conf_files_list_strv_internal(char ***strv, const char *suffix, const char *root, unsigned flags, char **dirs) {
e1d75803 119 _cleanup_hashmap_free_ Hashmap *fh = NULL;
fabe5c0e 120 char **files, **p;
578ac060 121 int r;
2c21044f 122
fabe5c0e 123 assert(strv);
fabe5c0e
LP
124
125 /* This alters the dirs string array */
7d8da2c9 126 if (!path_strv_resolve_uniq(dirs, root))
fabe5c0e 127 return -ENOMEM;
2c21044f 128
d5099efc 129 fh = hashmap_new(&string_hash_ops);
fabe5c0e
LP
130 if (!fh)
131 return -ENOMEM;
2c21044f
KS
132
133 STRV_FOREACH(p, dirs) {
b5084605 134 r = files_add(fh, suffix, root, flags, *p);
31d5192d 135 if (r == -ENOMEM)
fabe5c0e 136 return r;
31d5192d
LP
137 if (r < 0)
138 log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p);
2c21044f
KS
139 }
140
141 files = hashmap_get_strv(fh);
31d5192d 142 if (!files)
fabe5c0e 143 return -ENOMEM;
fabe5c0e 144
7ff7394d 145 qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
fabe5c0e 146 *strv = files;
2c21044f 147
fabe5c0e
LP
148 return 0;
149}
150
b5084605 151int conf_files_list_strv(char ***strv, const char *suffix, const char *root, unsigned flags, const char* const* dirs) {
fabe5c0e
LP
152 _cleanup_strv_free_ char **copy = NULL;
153
154 assert(strv);
fabe5c0e
LP
155
156 copy = strv_copy((char**) dirs);
157 if (!copy)
158 return -ENOMEM;
159
b5084605 160 return conf_files_list_strv_internal(strv, suffix, root, flags, copy);
2c21044f
KS
161}
162
b5084605 163int conf_files_list(char ***strv, const char *suffix, const char *root, unsigned flags, const char *dir, ...) {
8201ad81
LP
164 _cleanup_strv_free_ char **dirs = NULL;
165 va_list ap;
fabe5c0e
LP
166
167 assert(strv);
2c21044f 168
8201ad81
LP
169 va_start(ap, dir);
170 dirs = strv_new_ap(dir, ap);
171 va_end(ap);
172
173 if (!dirs)
174 return -ENOMEM;
fabe5c0e 175
b5084605 176 return conf_files_list_strv_internal(strv, suffix, root, flags, dirs);
fabe5c0e 177}
2c21044f 178
b5084605 179int conf_files_list_nulstr(char ***strv, const char *suffix, const char *root, unsigned flags, const char *d) {
fabe5c0e
LP
180 _cleanup_strv_free_ char **dirs = NULL;
181
182 assert(strv);
fabe5c0e
LP
183
184 dirs = strv_split_nulstr(d);
185 if (!dirs)
186 return -ENOMEM;
2c21044f 187
b5084605 188 return conf_files_list_strv_internal(strv, suffix, root, flags, dirs);
2c21044f 189}