]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dropin.c
man: Fix typo in name of sd_id128_to_uuid_string
[thirdparty/systemd.git] / src / shared / dropin.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
29686440 2
a8fbdf54 3#include <stdio.h>
a8fbdf54 4
b5efdb8a 5#include "alloc-util.h"
f461a28d 6#include "chase.h"
1a7f1b38 7#include "conf-files.h"
3ffd4af2 8#include "dropin.h"
4f5dd394 9#include "escape.h"
8eeb8709 10#include "fileio.h"
a8fbdf54 11#include "log.h"
bb15fafe 12#include "path-util.h"
a8fbdf54 13#include "set.h"
69a283c5 14#include "stdio-util.h"
07630cea 15#include "string-util.h"
4f5dd394 16#include "strv.h"
69a283c5 17#include "unit-def.h"
a8fbdf54 18#include "unit-name.h"
29686440 19
f9ef2aad
MY
20int drop_in_file(
21 const char *dir,
22 const char *unit,
23 unsigned level,
24 const char *name,
25 char **ret_unit_dir,
26 char **ret_path) {
29686440 27
db21bf5a 28 _cleanup_free_ char *n = NULL, *unit_dir = NULL;
29686440 29
f9ef2aad 30 assert(dir);
29686440
ZJS
31 assert(unit);
32 assert(name);
29686440 33
f9ef2aad
MY
34 n = xescape(name, "/.");
35 if (!n)
29686440 36 return -ENOMEM;
f9ef2aad 37 if (!filename_is_valid(n))
29686440
ZJS
38 return -EINVAL;
39
db21bf5a
LP
40 if (ret_unit_dir || ret_path) {
41 unit_dir = path_join(dir, strjoina(unit, ".d"));
42 if (!unit_dir)
43 return -ENOMEM;
44 }
f9ef2aad 45
db21bf5a
LP
46 if (ret_path) {
47 char prefix[DECIMAL_STR_MAX(unsigned) + 1] = {};
48
49 if (level != UINT_MAX)
50 xsprintf(prefix, "%u-", level);
51
52 _cleanup_free_ char *path = strjoin(unit_dir, "/", prefix, n, ".conf");
53 if (!path)
54 return -ENOMEM;
55
56 *ret_path = TAKE_PTR(path);
57 }
58
59 if (ret_unit_dir)
60 *ret_unit_dir = TAKE_PTR(unit_dir);
29686440 61
29686440
ZJS
62 return 0;
63}
64
f9ef2aad
MY
65int write_drop_in(
66 const char *dir,
67 const char *unit,
68 unsigned level,
69 const char *name,
70 const char *data) {
29686440 71
5048a6bd 72 _cleanup_free_ char *p = NULL;
29686440
ZJS
73 int r;
74
75 assert(dir);
76 assert(unit);
77 assert(name);
78 assert(data);
79
5048a6bd 80 r = drop_in_file(dir, unit, level, name, /* ret_unit_dir= */ NULL, &p);
29686440
ZJS
81 if (r < 0)
82 return r;
83
8eeb8709 84 return write_string_file(p, data, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_MKDIR_0755|WRITE_STRING_FILE_LABEL);
29686440
ZJS
85}
86
f9ef2aad
MY
87int write_drop_in_format(
88 const char *dir,
89 const char *unit,
90 unsigned level,
91 const char *name,
92 const char *format, ...) {
93
94 _cleanup_free_ char *content = NULL;
29686440
ZJS
95 va_list ap;
96 int r;
97
98 assert(dir);
99 assert(unit);
100 assert(name);
101 assert(format);
102
103 va_start(ap, format);
f9ef2aad 104 r = vasprintf(&content, format, ap);
29686440
ZJS
105 va_end(ap);
106
107 if (r < 0)
108 return -ENOMEM;
109
f9ef2aad 110 return write_drop_in(dir, unit, level, name, content);
29686440 111}
1a7f1b38 112
47a00111 113static int unit_file_add_dir(
17e78d18 114 const char *original_root,
dcc4f30e
ZJS
115 const char *path,
116 char ***dirs) {
1a7f1b38 117
17e78d18 118 _cleanup_free_ char *chased = NULL;
1a7f1b38
ZJS
119 int r;
120
121 assert(path);
122
47a00111
ZJS
123 /* This adds [original_root]/path to dirs, if it exists. */
124
f461a28d 125 r = chase(path, original_root, 0, &chased, NULL);
952713b0 126 if (r == -ENOENT) /* Ignore -ENOENT, after all most units won't have a drop-in dir. */
09c62487 127 return 0;
952713b0
LP
128 if (r == -ENAMETOOLONG) {
129 /* Also, ignore -ENAMETOOLONG but log about it. After all, users are not even able to create the
130 * drop-in dir in such case. This mostly happens for device units with an overly long /sys path. */
131 log_debug_errno(r, "Path '%s' too long, couldn't canonicalize, ignoring.", path);
132 return 0;
133 }
17e78d18 134 if (r < 0)
952713b0 135 return log_warning_errno(r, "Failed to canonicalize path '%s': %m", path);
17e78d18 136
f1b4b94c 137 if (strv_consume(dirs, TAKE_PTR(chased)) < 0)
dcc4f30e 138 return log_oom();
1a7f1b38
ZJS
139
140 return 0;
141}
142
dcc4f30e 143static int unit_file_find_dirs(
17e78d18 144 const char *original_root,
7410616c 145 Set *unit_path_cache,
1a7f1b38
ZJS
146 const char *unit_path,
147 const char *name,
148 const char *suffix,
dcc4f30e 149 char ***dirs) {
1a7f1b38 150
53966245
LP
151 _cleanup_free_ char *prefix = NULL, *instance = NULL, *built = NULL;
152 bool is_instance, chopped;
153 const char *dash;
154 UnitType type;
96bb2fd8 155 char *path;
53966245 156 size_t n;
7410616c 157 int r;
1a7f1b38
ZJS
158
159 assert(unit_path);
160 assert(name);
161 assert(suffix);
162
96bb2fd8 163 path = strjoina(unit_path, "/", name, suffix);
dcc4f30e 164 if (!unit_path_cache || set_get(unit_path_cache, path)) {
47a00111 165 r = unit_file_add_dir(original_root, path, dirs);
dcc4f30e
ZJS
166 if (r < 0)
167 return r;
168 }
1a7f1b38 169
53966245
LP
170 is_instance = unit_name_is_valid(name, UNIT_NAME_INSTANCE);
171 if (is_instance) { /* Also try the template dir */
a09d3eaf
LP
172 _cleanup_free_ char *template = NULL;
173
7410616c
LP
174 r = unit_name_template(name, &template);
175 if (r < 0)
176 return log_error_errno(r, "Failed to generate template from unit name: %m");
1a7f1b38 177
53966245
LP
178 r = unit_file_find_dirs(original_root, unit_path_cache, unit_path, template, suffix, dirs);
179 if (r < 0)
180 return r;
1a7f1b38
ZJS
181 }
182
3e1db806
AZ
183 /* Return early for top level drop-ins. */
184 if (unit_type_from_string(name) >= 0)
185 return 0;
186
53966245
LP
187 /* Let's see if there's a "-" prefix for this unit name. If so, let's invoke ourselves for it. This will then
188 * recursively do the same for all our prefixes. i.e. this means given "foo-bar-waldo.service" we'll also
189 * search "foo-bar-.service" and "foo-.service".
190 *
191 * Note the order in which we do it: we traverse up adding drop-ins on each step. This means the more specific
192 * drop-ins may override the more generic drop-ins, which is the intended behaviour. */
193
194 r = unit_name_to_prefix(name, &prefix);
195 if (r < 0)
196 return log_error_errno(r, "Failed to derive unit name prefix from unit name: %m");
197
198 chopped = false;
199 for (;;) {
200 dash = strrchr(prefix, '-');
201 if (!dash) /* No dash? if so we are done */
202 return 0;
203
204 n = (size_t) (dash - prefix);
205 if (n == 0) /* Leading dash? If so, we are done */
206 return 0;
207
208 if (prefix[n+1] != 0 || chopped) {
209 prefix[n+1] = 0;
210 break;
211 }
212
213 /* Trailing dash? If so, chop it off and try again, but not more than once. */
214 prefix[n] = 0;
215 chopped = true;
216 }
217
218 if (!unit_prefix_is_valid(prefix))
219 return 0;
220
221 type = unit_name_to_type(name);
baaa35ad
ZJS
222 if (type < 0)
223 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
cd990847 224 "Failed to derive unit type from unit name: %s",
baaa35ad 225 name);
53966245
LP
226
227 if (is_instance) {
228 r = unit_name_to_instance(name, &instance);
229 if (r < 0)
230 return log_error_errno(r, "Failed to derive unit name instance from unit name: %m");
231 }
232
233 r = unit_name_build_from_type(prefix, instance, type, &built);
234 if (r < 0)
235 return log_error_errno(r, "Failed to build prefix unit name: %m");
236
237 return unit_file_find_dirs(original_root, unit_path_cache, unit_path, built, suffix, dirs);
1a7f1b38
ZJS
238}
239
240int unit_file_find_dropin_paths(
17e78d18 241 const char *original_root,
1a7f1b38
ZJS
242 char **lookup_path,
243 Set *unit_path_cache,
95778782
ZJS
244 const char *dir_suffix,
245 const char *file_suffix,
4562c355
ZJS
246 const char *name,
247 const Set *aliases,
058db925 248 char ***ret) {
1a7f1b38 249
3f6de63b 250 _cleanup_strv_free_ char **dirs = NULL;
4562c355 251 const char *n;
1a7f1b38
ZJS
252 int r;
253
058db925 254 assert(ret);
1a7f1b38 255
4562c355 256 if (name)
e6627f23
GGM
257 STRV_FOREACH(p, lookup_path)
258 (void) unit_file_find_dirs(original_root, unit_path_cache, *p, name, dir_suffix, &dirs);
259
90e74a66 260 SET_FOREACH(n, aliases)
4562c355
ZJS
261 STRV_FOREACH(p, lookup_path)
262 (void) unit_file_find_dirs(original_root, unit_path_cache, *p, n, dir_suffix, &dirs);
263
d2724678 264 /* All the names in the unit are of the same type so just grab one. */
4562c355
ZJS
265 n = name ?: (const char*) set_first(aliases);
266 if (n) {
7a670b1d
TM
267 UnitType type = _UNIT_TYPE_INVALID;
268
4562c355 269 type = unit_name_to_type(n);
d2724678
AZ
270 if (type < 0)
271 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
cd990847 272 "Failed to derive unit type from unit name: %s", n);
d2724678 273
e6627f23 274 /* Special top level drop in for "<unit type>.<suffix>". Add this last as it's the most generic
7a670b1d
TM
275 * and should be able to be overridden by more specific drop-ins. */
276 STRV_FOREACH(p, lookup_path)
277 (void) unit_file_find_dirs(original_root,
278 unit_path_cache,
279 *p,
280 unit_type_to_string(type),
281 dir_suffix,
282 &dirs);
283 }
d2724678 284
058db925
LP
285 if (strv_isempty(dirs)) {
286 *ret = NULL;
1a7f1b38 287 return 0;
058db925 288 }
1a7f1b38 289
b5084605 290 r = conf_files_list_strv(ret, file_suffix, NULL, 0, (const char**) dirs);
1a7f1b38 291 if (r < 0)
3f6de63b 292 return log_warning_errno(r, "Failed to create the list of configuration files: %m");
058db925 293
1a7f1b38
ZJS
294 return 1;
295}