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