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