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