]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/dropin.c
systemctl: also use chase_symlinks for dropins
[thirdparty/systemd.git] / src / shared / dropin.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Zbigniew Jędrzejewski-Szmek
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
20 #include <errno.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "alloc-util.h"
26 #include "conf-files.h"
27 #include "dirent-util.h"
28 #include "dropin.h"
29 #include "escape.h"
30 #include "fd-util.h"
31 #include "fileio-label.h"
32 #include "fs-util.h"
33 #include "hashmap.h"
34 #include "log.h"
35 #include "macro.h"
36 #include "mkdir.h"
37 #include "path-util.h"
38 #include "set.h"
39 #include "string-util.h"
40 #include "strv.h"
41 #include "unit-name.h"
42
43 int drop_in_file(const char *dir, const char *unit, unsigned level,
44 const char *name, char **_p, char **_q) {
45
46 _cleanup_free_ char *b = NULL;
47 char *p, *q;
48
49 char prefix[DECIMAL_STR_MAX(unsigned)];
50
51 assert(unit);
52 assert(name);
53 assert(_p);
54 assert(_q);
55
56 sprintf(prefix, "%u", level);
57
58 b = xescape(name, "/.");
59 if (!b)
60 return -ENOMEM;
61
62 if (!filename_is_valid(b))
63 return -EINVAL;
64
65 p = strjoin(dir, "/", unit, ".d");
66 if (!p)
67 return -ENOMEM;
68
69 q = strjoin(p, "/", prefix, "-", b, ".conf");
70 if (!q) {
71 free(p);
72 return -ENOMEM;
73 }
74
75 *_p = p;
76 *_q = q;
77 return 0;
78 }
79
80 int write_drop_in(const char *dir, const char *unit, unsigned level,
81 const char *name, const char *data) {
82
83 _cleanup_free_ char *p = NULL, *q = NULL;
84 int r;
85
86 assert(dir);
87 assert(unit);
88 assert(name);
89 assert(data);
90
91 r = drop_in_file(dir, unit, level, name, &p, &q);
92 if (r < 0)
93 return r;
94
95 (void) mkdir_p(p, 0755);
96 return write_string_file_atomic_label(q, data);
97 }
98
99 int write_drop_in_format(const char *dir, const char *unit, unsigned level,
100 const char *name, const char *format, ...) {
101 _cleanup_free_ char *p = NULL;
102 va_list ap;
103 int r;
104
105 assert(dir);
106 assert(unit);
107 assert(name);
108 assert(format);
109
110 va_start(ap, format);
111 r = vasprintf(&p, format, ap);
112 va_end(ap);
113
114 if (r < 0)
115 return -ENOMEM;
116
117 return write_drop_in(dir, unit, level, name, p);
118 }
119
120 static int iterate_dir(
121 const char *path,
122 const char *original_root,
123 UnitDependency dependency,
124 dependency_consumer_t consumer,
125 void *arg,
126 char ***strv) {
127
128 _cleanup_free_ char *chased = NULL;
129 _cleanup_closedir_ DIR *d = NULL;
130 struct dirent *de;
131 int r;
132
133 assert(path);
134
135 r = chase_symlinks(path, original_root, 0, &chased);
136 if (r < 0)
137 return log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING,
138 r, "Failed to canonicalize path %s: %m", path);
139
140 /* The config directories are special, since the order of the
141 * drop-ins matters */
142 if (dependency < 0) {
143 r = strv_push(strv, chased);
144 if (r < 0)
145 return log_oom();
146
147 chased = NULL;
148 return 0;
149 }
150
151 assert(consumer);
152
153 d = opendir(chased);
154 if (!d) {
155 if (errno == ENOENT)
156 return 0;
157
158 return log_warning_errno(errno, "Failed to open directory %s: %m", path);
159 }
160
161 FOREACH_DIRENT(de, d, return log_warning_errno(errno, "Failed to read directory %s: %m", path)) {
162 _cleanup_free_ char *f = NULL;
163
164 f = strjoin(path, "/", de->d_name);
165 if (!f)
166 return log_oom();
167
168 r = consumer(dependency, de->d_name, f, arg);
169 if (r < 0)
170 return r;
171 }
172
173 return 0;
174 }
175
176 int unit_file_process_dir(
177 const char *original_root,
178 Set *unit_path_cache,
179 const char *unit_path,
180 const char *name,
181 const char *suffix,
182 UnitDependency dependency,
183 dependency_consumer_t consumer,
184 void *arg,
185 char ***strv) {
186
187 _cleanup_free_ char *path = NULL;
188 int r;
189
190 assert(unit_path);
191 assert(name);
192 assert(suffix);
193
194 path = strjoin(unit_path, "/", name, suffix);
195 if (!path)
196 return log_oom();
197
198 if (!unit_path_cache || set_get(unit_path_cache, path))
199 (void) iterate_dir(path, original_root, dependency, consumer, arg, strv);
200
201 if (unit_name_is_valid(name, UNIT_NAME_INSTANCE)) {
202 _cleanup_free_ char *template = NULL, *p = NULL;
203 /* Also try the template dir */
204
205 r = unit_name_template(name, &template);
206 if (r < 0)
207 return log_error_errno(r, "Failed to generate template from unit name: %m");
208
209 p = strjoin(unit_path, "/", template, suffix);
210 if (!p)
211 return log_oom();
212
213 if (!unit_path_cache || set_get(unit_path_cache, p))
214 (void) iterate_dir(p, original_root, dependency, consumer, arg, strv);
215 }
216
217 return 0;
218 }
219
220 int unit_file_find_dropin_paths(
221 const char *original_root,
222 char **lookup_path,
223 Set *unit_path_cache,
224 Set *names,
225 char ***paths) {
226
227 _cleanup_strv_free_ char **strv = NULL, **ans = NULL;
228 Iterator i;
229 char *t;
230 int r;
231
232 assert(paths);
233
234 SET_FOREACH(t, names, i) {
235 char **p;
236
237 STRV_FOREACH(p, lookup_path)
238 unit_file_process_dir(original_root, unit_path_cache, *p, t, ".d",
239 _UNIT_DEPENDENCY_INVALID, NULL, NULL, &strv);
240 }
241
242 if (strv_isempty(strv))
243 return 0;
244
245 r = conf_files_list_strv(&ans, ".conf", NULL, (const char**) strv);
246 if (r < 0)
247 return log_warning_errno(r, "Failed to get list of configuration files: %m");
248
249 *paths = ans;
250 ans = NULL;
251 return 1;
252 }