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