Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <stdio.h>
5 : : #include <stdlib.h>
6 : : #include <string.h>
7 : :
8 : : #include "alloc-util.h"
9 : : #include "fs-util.h"
10 : : #include "install.h"
11 : : #include "log.h"
12 : : #include "macro.h"
13 : : #include "mkdir.h"
14 : : #include "path-lookup.h"
15 : : #include "path-util.h"
16 : : #include "rm-rf.h"
17 : : #include "stat-util.h"
18 : : #include "string-util.h"
19 : : #include "strv.h"
20 : : #include "tmpfile-util.h"
21 : : #include "user-util.h"
22 : : #include "util.h"
23 : :
24 : 300 : int xdg_user_runtime_dir(char **ret, const char *suffix) {
25 : : const char *e;
26 : : char *j;
27 : :
28 [ - + ]: 300 : assert(ret);
29 [ - + ]: 300 : assert(suffix);
30 : :
31 : 300 : e = getenv("XDG_RUNTIME_DIR");
32 [ + + ]: 300 : if (!e)
33 : 4 : return -ENXIO;
34 : :
35 : 296 : j = strjoin(e, suffix);
36 [ - + ]: 296 : if (!j)
37 : 0 : return -ENOMEM;
38 : :
39 : 296 : *ret = j;
40 : 296 : return 0;
41 : : }
42 : :
43 : 288 : int xdg_user_config_dir(char **ret, const char *suffix) {
44 : : const char *e;
45 : : char *j;
46 : : int r;
47 : :
48 [ - + ]: 288 : assert(ret);
49 : :
50 : 288 : e = getenv("XDG_CONFIG_HOME");
51 [ - + ]: 288 : if (e)
52 : 0 : j = strjoin(e, suffix);
53 : : else {
54 [ + - ]: 288 : _cleanup_free_ char *home = NULL;
55 : :
56 : 288 : r = get_home_dir(&home);
57 [ - + ]: 288 : if (r < 0)
58 : 0 : return r;
59 : :
60 : 288 : j = strjoin(home, "/.config", suffix);
61 : : }
62 : :
63 [ - + ]: 288 : if (!j)
64 : 0 : return -ENOMEM;
65 : :
66 : 288 : *ret = j;
67 : 288 : return 0;
68 : : }
69 : :
70 : 176 : int xdg_user_data_dir(char **ret, const char *suffix) {
71 : : const char *e;
72 : : char *j;
73 : : int r;
74 : :
75 [ - + ]: 176 : assert(ret);
76 [ - + ]: 176 : assert(suffix);
77 : :
78 : : /* We don't treat /etc/xdg/systemd here as the spec
79 : : * suggests because we assume that is a link to
80 : : * /etc/systemd/ anyway. */
81 : :
82 : 176 : e = getenv("XDG_DATA_HOME");
83 [ - + ]: 176 : if (e)
84 : 0 : j = strjoin(e, suffix);
85 : : else {
86 [ + - ]: 176 : _cleanup_free_ char *home = NULL;
87 : :
88 : 176 : r = get_home_dir(&home);
89 [ - + ]: 176 : if (r < 0)
90 : 0 : return r;
91 : :
92 : 176 : j = strjoin(home, "/.local/share", suffix);
93 : : }
94 [ - + ]: 176 : if (!j)
95 : 0 : return -ENOMEM;
96 : :
97 : 176 : *ret = j;
98 : 176 : return 1;
99 : : }
100 : :
101 : : static const char* const user_data_unit_paths[] = {
102 : : "/usr/local/lib/systemd/user",
103 : : "/usr/local/share/systemd/user",
104 : : USER_DATA_UNIT_PATH,
105 : : "/usr/lib/systemd/user",
106 : : "/usr/share/systemd/user",
107 : : NULL
108 : : };
109 : :
110 : : static const char* const user_config_unit_paths[] = {
111 : : USER_CONFIG_UNIT_PATH,
112 : : "/etc/systemd/user",
113 : : NULL
114 : : };
115 : :
116 : 176 : int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
117 : : /* Implement the mechanisms defined in
118 : : *
119 : : * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
120 : : *
121 : : * We look in both the config and the data dirs because we
122 : : * want to encourage that distributors ship their unit files
123 : : * as data, and allow overriding as configuration.
124 : : */
125 : : const char *e;
126 : 176 : _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
127 : :
128 : 176 : e = getenv("XDG_CONFIG_DIRS");
129 [ - + ]: 176 : if (e) {
130 : 0 : config_dirs = strv_split(e, ":");
131 [ # # ]: 0 : if (!config_dirs)
132 : 0 : return -ENOMEM;
133 : : }
134 : :
135 : 176 : e = getenv("XDG_DATA_DIRS");
136 [ + + ]: 176 : if (e)
137 : 168 : data_dirs = strv_split(e, ":");
138 : : else
139 : 8 : data_dirs = strv_new("/usr/local/share",
140 : : "/usr/share");
141 [ - + ]: 176 : if (!data_dirs)
142 : 0 : return -ENOMEM;
143 : :
144 : 176 : *ret_config_dirs = TAKE_PTR(config_dirs);
145 : 176 : *ret_data_dirs = TAKE_PTR(data_dirs);
146 : :
147 : 176 : return 0;
148 : : }
149 : :
150 : 16 : static char** user_dirs(
151 : : const char *persistent_config,
152 : : const char *runtime_config,
153 : : const char *global_persistent_config,
154 : : const char *global_runtime_config,
155 : : const char *generator,
156 : : const char *generator_early,
157 : : const char *generator_late,
158 : : const char *transient,
159 : : const char *persistent_control,
160 : : const char *runtime_control) {
161 : :
162 : 16 : _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
163 : 16 : _cleanup_free_ char *data_home = NULL;
164 : 16 : _cleanup_strv_free_ char **res = NULL;
165 : : int r;
166 : :
167 : 16 : r = xdg_user_dirs(&config_dirs, &data_dirs);
168 [ - + ]: 16 : if (r < 0)
169 : 0 : return NULL;
170 : :
171 : 16 : r = xdg_user_data_dir(&data_home, "/systemd/user");
172 [ - + # # ]: 16 : if (r < 0 && r != -ENXIO)
173 : 0 : return NULL;
174 : :
175 : : /* Now merge everything we found. */
176 [ - + ]: 16 : if (strv_extend(&res, persistent_control) < 0)
177 : 0 : return NULL;
178 : :
179 [ - + ]: 16 : if (strv_extend(&res, runtime_control) < 0)
180 : 0 : return NULL;
181 : :
182 [ - + ]: 16 : if (strv_extend(&res, transient) < 0)
183 : 0 : return NULL;
184 : :
185 [ - + ]: 16 : if (strv_extend(&res, generator_early) < 0)
186 : 0 : return NULL;
187 : :
188 [ - + ]: 16 : if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
189 : 0 : return NULL;
190 : :
191 [ - + ]: 16 : if (strv_extend(&res, persistent_config) < 0)
192 : 0 : return NULL;
193 : :
194 : : /* global config has lower priority than the user config of the same type */
195 [ - + ]: 16 : if (strv_extend(&res, global_persistent_config) < 0)
196 : 0 : return NULL;
197 : :
198 [ - + ]: 16 : if (strv_extend_strv(&res, (char**) user_config_unit_paths, false) < 0)
199 : 0 : return NULL;
200 : :
201 [ - + ]: 16 : if (strv_extend(&res, runtime_config) < 0)
202 : 0 : return NULL;
203 : :
204 [ - + ]: 16 : if (strv_extend(&res, global_runtime_config) < 0)
205 : 0 : return NULL;
206 : :
207 [ - + ]: 16 : if (strv_extend(&res, generator) < 0)
208 : 0 : return NULL;
209 : :
210 [ - + ]: 16 : if (strv_extend(&res, data_home) < 0)
211 : 0 : return NULL;
212 : :
213 [ - + ]: 16 : if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
214 : 0 : return NULL;
215 : :
216 [ - + ]: 16 : if (strv_extend_strv(&res, (char**) user_data_unit_paths, false) < 0)
217 : 0 : return NULL;
218 : :
219 [ - + ]: 16 : if (strv_extend(&res, generator_late) < 0)
220 : 0 : return NULL;
221 : :
222 [ - + ]: 16 : if (path_strv_make_absolute_cwd(res) < 0)
223 : 0 : return NULL;
224 : :
225 : 16 : return TAKE_PTR(res);
226 : : }
227 : :
228 : 0 : bool path_is_user_data_dir(const char *path) {
229 [ # # ]: 0 : assert(path);
230 : :
231 : 0 : return strv_contains((char**) user_data_unit_paths, path);
232 : : }
233 : :
234 : 0 : bool path_is_user_config_dir(const char *path) {
235 [ # # ]: 0 : assert(path);
236 : :
237 : 0 : return strv_contains((char**) user_config_unit_paths, path);
238 : : }
239 : :
240 : 1020 : static int acquire_generator_dirs(
241 : : UnitFileScope scope,
242 : : const char *tempdir,
243 : : char **generator,
244 : : char **generator_early,
245 : : char **generator_late) {
246 : :
247 : 1020 : _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
248 : : const char *prefix;
249 : :
250 [ - + ]: 1020 : assert(generator);
251 [ - + ]: 1020 : assert(generator_early);
252 [ - + ]: 1020 : assert(generator_late);
253 [ + - - + ]: 1020 : assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
254 : :
255 [ + + ]: 1020 : if (scope == UNIT_FILE_GLOBAL)
256 : 12 : return -EOPNOTSUPP;
257 : :
258 [ + + ]: 1008 : if (tempdir)
259 : 52 : prefix = tempdir;
260 [ + + ]: 956 : else if (scope == UNIT_FILE_SYSTEM)
261 : 944 : prefix = "/run/systemd";
262 : : else {
263 : : /* UNIT_FILE_USER */
264 : : const char *e;
265 : :
266 : 12 : e = getenv("XDG_RUNTIME_DIR");
267 [ - + ]: 12 : if (!e)
268 : 0 : return -ENXIO;
269 : :
270 [ + + + - : 60 : prefix = strjoina(e, "/systemd");
- + - + +
+ + - ]
271 : : }
272 : :
273 : 1008 : x = path_join(prefix, "generator");
274 [ - + ]: 1008 : if (!x)
275 : 0 : return -ENOMEM;
276 : :
277 : 1008 : y = path_join(prefix, "generator.early");
278 [ - + ]: 1008 : if (!y)
279 : 0 : return -ENOMEM;
280 : :
281 : 1008 : z = path_join(prefix, "generator.late");
282 [ - + ]: 1008 : if (!z)
283 : 0 : return -ENOMEM;
284 : :
285 : 1008 : *generator = TAKE_PTR(x);
286 : 1008 : *generator_early = TAKE_PTR(y);
287 : 1008 : *generator_late = TAKE_PTR(z);
288 : :
289 : 1008 : return 0;
290 : : }
291 : :
292 : 1096 : static int acquire_transient_dir(
293 : : UnitFileScope scope,
294 : : const char *tempdir,
295 : : char **ret) {
296 : :
297 : : char *transient;
298 : :
299 [ - + ]: 1096 : assert(ret);
300 [ + - - + ]: 1096 : assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER, UNIT_FILE_GLOBAL));
301 : :
302 [ + + ]: 1096 : if (scope == UNIT_FILE_GLOBAL)
303 : 12 : return -EOPNOTSUPP;
304 : :
305 [ + + ]: 1084 : if (tempdir)
306 : 52 : transient = path_join(tempdir, "transient");
307 [ + + ]: 1032 : else if (scope == UNIT_FILE_SYSTEM)
308 : 1020 : transient = strdup("/run/systemd/transient");
309 : : else
310 : 12 : return xdg_user_runtime_dir(ret, "/systemd/transient");
311 : :
312 [ - + ]: 1072 : if (!transient)
313 : 0 : return -ENOMEM;
314 : 1072 : *ret = transient;
315 : 1072 : return 0;
316 : : }
317 : :
318 : 1160 : static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
319 : 1160 : _cleanup_free_ char *a = NULL, *b = NULL;
320 : : int r;
321 : :
322 [ - + ]: 1160 : assert(persistent);
323 [ - + ]: 1160 : assert(runtime);
324 : :
325 [ + + + - ]: 1160 : switch (scope) {
326 : :
327 : 1020 : case UNIT_FILE_SYSTEM:
328 : 1020 : a = strdup(SYSTEM_CONFIG_UNIT_PATH);
329 : 1020 : b = strdup("/run/systemd/system");
330 : 1020 : break;
331 : :
332 : 76 : case UNIT_FILE_GLOBAL:
333 : 76 : a = strdup(USER_CONFIG_UNIT_PATH);
334 : 76 : b = strdup("/run/systemd/user");
335 : 76 : break;
336 : :
337 : 64 : case UNIT_FILE_USER:
338 : 64 : r = xdg_user_config_dir(&a, "/systemd/user");
339 [ - + # # ]: 64 : if (r < 0 && r != -ENXIO)
340 : 0 : return r;
341 : :
342 : 64 : r = xdg_user_runtime_dir(runtime, "/systemd/user");
343 [ - + ]: 64 : if (r < 0) {
344 [ # # ]: 0 : if (r != -ENXIO)
345 : 0 : return r;
346 : :
347 : : /* If XDG_RUNTIME_DIR is not set, don't consider that fatal, simply initialize the runtime
348 : : * directory to NULL */
349 : 0 : *runtime = NULL;
350 : : }
351 : :
352 : 64 : *persistent = TAKE_PTR(a);
353 : :
354 : 64 : return 0;
355 : :
356 : 0 : default:
357 : 0 : assert_not_reached("Hmm, unexpected scope value.");
358 : : }
359 : :
360 [ + - - + ]: 1096 : if (!a || !b)
361 : 0 : return -ENOMEM;
362 : :
363 : 1096 : *persistent = TAKE_PTR(a);
364 : 1096 : *runtime = TAKE_PTR(b);
365 : :
366 : 1096 : return 0;
367 : : }
368 : :
369 : 1096 : static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
370 : 1096 : _cleanup_free_ char *a = NULL;
371 : : int r;
372 : :
373 [ - + ]: 1096 : assert(persistent);
374 [ - + ]: 1096 : assert(runtime);
375 : :
376 [ + + + - ]: 1096 : switch (scope) {
377 : :
378 : 1020 : case UNIT_FILE_SYSTEM: {
379 [ - + ]: 1020 : _cleanup_free_ char *b = NULL;
380 : :
381 : 1020 : a = strdup("/etc/systemd/system.control");
382 [ - + ]: 1020 : if (!a)
383 : 0 : return -ENOMEM;
384 : :
385 : 1020 : b = strdup("/run/systemd/system.control");
386 [ - + ]: 1020 : if (!b)
387 : 0 : return -ENOMEM;
388 : :
389 : 1020 : *runtime = TAKE_PTR(b);
390 : :
391 : 1020 : break;
392 : : }
393 : :
394 : 64 : case UNIT_FILE_USER:
395 : 64 : r = xdg_user_config_dir(&a, "/systemd/user.control");
396 [ - + # # ]: 64 : if (r < 0 && r != -ENXIO)
397 : 0 : return r;
398 : :
399 : 64 : r = xdg_user_runtime_dir(runtime, "/systemd/user.control");
400 [ - + ]: 64 : if (r < 0) {
401 [ # # ]: 0 : if (r != -ENXIO)
402 : 0 : return r;
403 : :
404 : : /* If XDG_RUNTIME_DIR is not set, don't consider this fatal, simply initialize the directory to
405 : : * NULL */
406 : 0 : *runtime = NULL;
407 : : }
408 : :
409 : 64 : break;
410 : :
411 : 12 : case UNIT_FILE_GLOBAL:
412 : 12 : return -EOPNOTSUPP;
413 : :
414 : 0 : default:
415 : 0 : assert_not_reached("Hmm, unexpected scope value.");
416 : : }
417 : :
418 : 1084 : *persistent = TAKE_PTR(a);
419 : :
420 : 1084 : return 0;
421 : : }
422 : :
423 : 1096 : static int acquire_attached_dirs(
424 : : UnitFileScope scope,
425 : : char **ret_persistent,
426 : : char **ret_runtime) {
427 : :
428 : 1096 : _cleanup_free_ char *a = NULL, *b = NULL;
429 : :
430 [ - + ]: 1096 : assert(ret_persistent);
431 [ - + ]: 1096 : assert(ret_runtime);
432 : :
433 : : /* Portable services are not available to regular users for now. */
434 [ + + ]: 1096 : if (scope != UNIT_FILE_SYSTEM)
435 : 76 : return -EOPNOTSUPP;
436 : :
437 : 1020 : a = strdup("/etc/systemd/system.attached");
438 [ - + ]: 1020 : if (!a)
439 : 0 : return -ENOMEM;
440 : :
441 : 1020 : b = strdup("/run/systemd/system.attached");
442 [ - + ]: 1020 : if (!b)
443 : 0 : return -ENOMEM;
444 : :
445 : 1020 : *ret_persistent = TAKE_PTR(a);
446 : 1020 : *ret_runtime = TAKE_PTR(b);
447 : :
448 : 1020 : return 0;
449 : : }
450 : :
451 : 25808 : static int patch_root_prefix(char **p, const char *root_dir) {
452 : : char *c;
453 : :
454 [ - + ]: 25808 : assert(p);
455 : :
456 [ + + ]: 25808 : if (!*p)
457 : 452 : return 0;
458 : :
459 : 25356 : c = path_join(root_dir, *p);
460 [ - + ]: 25356 : if (!c)
461 : 0 : return -ENOMEM;
462 : :
463 : 25356 : free_and_replace(*p, c);
464 : 25356 : return 0;
465 : : }
466 : :
467 : 1096 : static int patch_root_prefix_strv(char **l, const char *root_dir) {
468 : : char **i;
469 : : int r;
470 : :
471 [ + + ]: 1096 : if (!root_dir)
472 : 168 : return 0;
473 : :
474 [ + - + + ]: 15776 : STRV_FOREACH(i, l) {
475 : 14848 : r = patch_root_prefix(i, root_dir);
476 [ - + ]: 14848 : if (r < 0)
477 : 0 : return r;
478 : : }
479 : :
480 : 928 : return 0;
481 : : }
482 : :
483 : 1096 : int lookup_paths_init(
484 : : LookupPaths *p,
485 : : UnitFileScope scope,
486 : : LookupPathsFlags flags,
487 : : const char *root_dir) {
488 : :
489 : 1096 : _cleanup_(rmdir_and_freep) char *tempdir = NULL;
490 : : _cleanup_free_ char
491 : 1096 : *root = NULL,
492 : 1096 : *persistent_config = NULL, *runtime_config = NULL,
493 : 1096 : *global_persistent_config = NULL, *global_runtime_config = NULL,
494 : 1096 : *generator = NULL, *generator_early = NULL, *generator_late = NULL,
495 : 1096 : *transient = NULL,
496 : 1096 : *persistent_control = NULL, *runtime_control = NULL,
497 : 1096 : *persistent_attached = NULL, *runtime_attached = NULL;
498 : 1096 : bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
499 : 1096 : _cleanup_strv_free_ char **paths = NULL;
500 : : const char *e;
501 : : int r;
502 : :
503 [ - + ]: 1096 : assert(p);
504 [ - + ]: 1096 : assert(scope >= 0);
505 [ - + ]: 1096 : assert(scope < _UNIT_FILE_SCOPE_MAX);
506 : :
507 : : #if HAVE_SPLIT_USR
508 : : flags |= LOOKUP_PATHS_SPLIT_USR;
509 : : #endif
510 : :
511 [ + + ]: 1096 : if (!empty_or_root(root_dir)) {
512 [ - + ]: 928 : if (scope == UNIT_FILE_USER)
513 : 0 : return -EINVAL;
514 : :
515 : 928 : r = is_dir(root_dir, true);
516 [ - + ]: 928 : if (r < 0)
517 : 0 : return r;
518 [ - + ]: 928 : if (r == 0)
519 : 0 : return -ENOTDIR;
520 : :
521 : 928 : root = strdup(root_dir);
522 [ - + ]: 928 : if (!root)
523 : 0 : return -ENOMEM;
524 : : }
525 : :
526 [ + + ]: 1096 : if (flags & LOOKUP_PATHS_TEMPORARY_GENERATED) {
527 : 52 : r = mkdtemp_malloc("/tmp/systemd-temporary-XXXXXX", &tempdir);
528 [ - + ]: 52 : if (r < 0)
529 [ # # ]: 0 : return log_debug_errno(r, "Failed to create temporary directory: %m");
530 : : }
531 : :
532 : : /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_config to NULL */
533 : 1096 : r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
534 [ - + ]: 1096 : if (r < 0)
535 : 0 : return r;
536 : :
537 [ + + ]: 1096 : if (scope == UNIT_FILE_USER) {
538 : 64 : r = acquire_config_dirs(UNIT_FILE_GLOBAL, &global_persistent_config, &global_runtime_config);
539 [ - + ]: 64 : if (r < 0)
540 : 0 : return r;
541 : : }
542 : :
543 [ + + ]: 1096 : if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
544 : : /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
545 : 1020 : r = acquire_generator_dirs(scope, tempdir,
546 : : &generator, &generator_early, &generator_late);
547 [ + + + - : 1020 : if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
- + ]
548 : 0 : return r;
549 : : }
550 : :
551 : : /* Note: if XDG_RUNTIME_DIR is not set, this will fail completely with ENXIO */
552 : 1096 : r = acquire_transient_dir(scope, tempdir, &transient);
553 [ + + + - : 1096 : if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENXIO))
- + ]
554 : 0 : return r;
555 : :
556 : : /* Note: when XDG_RUNTIME_DIR is not set this will not return -ENXIO, but simply set runtime_control to NULL */
557 : 1096 : r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
558 [ + + - + ]: 1096 : if (r < 0 && r != -EOPNOTSUPP)
559 : 0 : return r;
560 : :
561 : 1096 : r = acquire_attached_dirs(scope, &persistent_attached, &runtime_attached);
562 [ + + - + ]: 1096 : if (r < 0 && r != -EOPNOTSUPP)
563 : 0 : return r;
564 : :
565 : : /* First priority is whatever has been passed to us via env vars */
566 : 1096 : e = getenv("SYSTEMD_UNIT_PATH");
567 [ + + ]: 1096 : if (e) {
568 : : const char *k;
569 : :
570 : 132 : k = endswith(e, ":");
571 [ - + ]: 132 : if (k) {
572 : 0 : e = strndupa(e, k - e);
573 : 0 : append = true;
574 : : }
575 : :
576 : : /* FIXME: empty components in other places should be rejected. */
577 : :
578 : 132 : r = path_split_and_make_absolute(e, &paths);
579 [ - + ]: 132 : if (r < 0)
580 : 0 : return r;
581 : : }
582 : :
583 [ + + - + ]: 1096 : if (!paths || append) {
584 : : /* Let's figure something out. */
585 : :
586 [ + - ]: 964 : _cleanup_strv_free_ char **add = NULL;
587 : :
588 : : /* For the user units we include share/ in the search
589 : : * path in order to comply with the XDG basedir spec.
590 : : * For the system stuff we avoid such nonsense. OTOH
591 : : * we include /lib in the search path for the system
592 : : * stuff but avoid it for user stuff. */
593 : :
594 [ + + + - ]: 964 : switch (scope) {
595 : :
596 : 940 : case UNIT_FILE_SYSTEM:
597 [ - + ]: 940 : add = strv_new(
598 : : /* If you modify this you also want to modify
599 : : * systemdsystemunitpath= in systemd.pc.in! */
600 : : STRV_IFNOTNULL(persistent_control),
601 : : STRV_IFNOTNULL(runtime_control),
602 : : STRV_IFNOTNULL(transient),
603 : : STRV_IFNOTNULL(generator_early),
604 : : persistent_config,
605 : : SYSTEM_CONFIG_UNIT_PATH,
606 : : "/etc/systemd/system",
607 : : STRV_IFNOTNULL(persistent_attached),
608 : : runtime_config,
609 : : "/run/systemd/system",
610 : : STRV_IFNOTNULL(runtime_attached),
611 : : STRV_IFNOTNULL(generator),
612 : : "/usr/local/lib/systemd/system",
613 : : SYSTEM_DATA_UNIT_PATH,
614 : : "/usr/lib/systemd/system",
615 : : STRV_IFNOTNULL(flags & LOOKUP_PATHS_SPLIT_USR ? "/lib/systemd/system" : NULL),
616 : : STRV_IFNOTNULL(generator_late));
617 : 940 : break;
618 : :
619 : 8 : case UNIT_FILE_GLOBAL:
620 : 8 : add = strv_new(
621 : : /* If you modify this you also want to modify
622 : : * systemduserunitpath= in systemd.pc.in, and
623 : : * the arrays in user_dirs() above! */
624 : : STRV_IFNOTNULL(persistent_control),
625 : : STRV_IFNOTNULL(runtime_control),
626 : : STRV_IFNOTNULL(transient),
627 : : STRV_IFNOTNULL(generator_early),
628 : : persistent_config,
629 : : USER_CONFIG_UNIT_PATH,
630 : : "/etc/systemd/user",
631 : : runtime_config,
632 : : "/run/systemd/user",
633 : : STRV_IFNOTNULL(generator),
634 : : "/usr/local/share/systemd/user",
635 : : "/usr/share/systemd/user",
636 : : "/usr/local/lib/systemd/user",
637 : : USER_DATA_UNIT_PATH,
638 : : "/usr/lib/systemd/user",
639 : : STRV_IFNOTNULL(generator_late));
640 : 8 : break;
641 : :
642 : 16 : case UNIT_FILE_USER:
643 : 16 : add = user_dirs(persistent_config, runtime_config,
644 : : global_persistent_config, global_runtime_config,
645 : : generator, generator_early, generator_late,
646 : : transient,
647 : : persistent_control, runtime_control);
648 : 16 : break;
649 : :
650 : 0 : default:
651 : 0 : assert_not_reached("Hmm, unexpected scope?");
652 : : }
653 : :
654 [ - + ]: 964 : if (!add)
655 : 0 : return -ENOMEM;
656 : :
657 [ - + ]: 964 : if (paths) {
658 : 0 : r = strv_extend_strv(&paths, add, true);
659 [ # # ]: 0 : if (r < 0)
660 : 0 : return r;
661 : : } else
662 : : /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
663 : : * and don't have to copy anything */
664 : 964 : paths = TAKE_PTR(add);
665 : : }
666 : :
667 : 1096 : r = patch_root_prefix(&persistent_config, root);
668 [ - + ]: 1096 : if (r < 0)
669 : 0 : return r;
670 : 1096 : r = patch_root_prefix(&runtime_config, root);
671 [ - + ]: 1096 : if (r < 0)
672 : 0 : return r;
673 : :
674 : 1096 : r = patch_root_prefix(&generator, root);
675 [ - + ]: 1096 : if (r < 0)
676 : 0 : return r;
677 : 1096 : r = patch_root_prefix(&generator_early, root);
678 [ - + ]: 1096 : if (r < 0)
679 : 0 : return r;
680 : 1096 : r = patch_root_prefix(&generator_late, root);
681 [ - + ]: 1096 : if (r < 0)
682 : 0 : return r;
683 : :
684 : 1096 : r = patch_root_prefix(&transient, root);
685 [ - + ]: 1096 : if (r < 0)
686 : 0 : return r;
687 : :
688 : 1096 : r = patch_root_prefix(&persistent_control, root);
689 [ - + ]: 1096 : if (r < 0)
690 : 0 : return r;
691 : 1096 : r = patch_root_prefix(&runtime_control, root);
692 [ - + ]: 1096 : if (r < 0)
693 : 0 : return r;
694 : :
695 : 1096 : r = patch_root_prefix(&persistent_attached, root);
696 [ - + ]: 1096 : if (r < 0)
697 : 0 : return r;
698 : 1096 : r = patch_root_prefix(&runtime_attached, root);
699 [ - + ]: 1096 : if (r < 0)
700 : 0 : return r;
701 : :
702 : 1096 : r = patch_root_prefix_strv(paths, root);
703 [ - + ]: 1096 : if (r < 0)
704 : 0 : return -ENOMEM;
705 : :
706 : 1096 : *p = (LookupPaths) {
707 : 1096 : .search_path = strv_uniq(paths),
708 : :
709 : 1096 : .persistent_config = TAKE_PTR(persistent_config),
710 : 1096 : .runtime_config = TAKE_PTR(runtime_config),
711 : :
712 : 1096 : .generator = TAKE_PTR(generator),
713 : 1096 : .generator_early = TAKE_PTR(generator_early),
714 : 1096 : .generator_late = TAKE_PTR(generator_late),
715 : :
716 : 1096 : .transient = TAKE_PTR(transient),
717 : :
718 : 1096 : .persistent_control = TAKE_PTR(persistent_control),
719 : 1096 : .runtime_control = TAKE_PTR(runtime_control),
720 : :
721 : 1096 : .persistent_attached = TAKE_PTR(persistent_attached),
722 : 1096 : .runtime_attached = TAKE_PTR(runtime_attached),
723 : :
724 : 1096 : .root_dir = TAKE_PTR(root),
725 : 1096 : .temporary_dir = TAKE_PTR(tempdir),
726 : : };
727 : :
728 : 1096 : paths = NULL;
729 : 1096 : return 0;
730 : : }
731 : :
732 : 1100 : void lookup_paths_free(LookupPaths *p) {
733 [ - + ]: 1100 : if (!p)
734 : 0 : return;
735 : :
736 : 1100 : p->search_path = strv_free(p->search_path);
737 : :
738 : 1100 : p->persistent_config = mfree(p->persistent_config);
739 : 1100 : p->runtime_config = mfree(p->runtime_config);
740 : :
741 : 1100 : p->persistent_attached = mfree(p->persistent_attached);
742 : 1100 : p->runtime_attached = mfree(p->runtime_attached);
743 : :
744 : 1100 : p->generator = mfree(p->generator);
745 : 1100 : p->generator_early = mfree(p->generator_early);
746 : 1100 : p->generator_late = mfree(p->generator_late);
747 : :
748 : 1100 : p->transient = mfree(p->transient);
749 : :
750 : 1100 : p->persistent_control = mfree(p->persistent_control);
751 : 1100 : p->runtime_control = mfree(p->runtime_control);
752 : :
753 : 1100 : p->root_dir = mfree(p->root_dir);
754 : 1100 : p->temporary_dir = mfree(p->temporary_dir);
755 : : }
756 : :
757 : 76 : int lookup_paths_reduce(LookupPaths *p) {
758 : 76 : _cleanup_free_ struct stat *stats = NULL;
759 : 76 : size_t n_stats = 0, allocated = 0;
760 : 76 : size_t c = 0;
761 : : int r;
762 : :
763 [ - + ]: 76 : assert(p);
764 : :
765 : : /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
766 : : * the same by comparing their device and inode numbers. */
767 : :
768 [ - + ]: 76 : if (!p->search_path)
769 : 0 : return 0;
770 : :
771 [ + + ]: 408 : while (p->search_path[c]) {
772 : : struct stat st;
773 : : size_t k;
774 : :
775 : : /* Never strip the transient and control directories from the path */
776 [ + + + + ]: 648 : if (path_equal_ptr(p->search_path[c], p->transient) ||
777 [ + + ]: 616 : path_equal_ptr(p->search_path[c], p->persistent_control) ||
778 : 300 : path_equal_ptr(p->search_path[c], p->runtime_control)) {
779 : 48 : c++;
780 : 144 : continue;
781 : : }
782 : :
783 : 284 : r = chase_symlinks_and_stat(p->search_path[c], p->root_dir, 0, NULL, &st);
784 [ + + ]: 284 : if (r == -ENOENT)
785 : 188 : goto remove_item;
786 [ - + ]: 96 : if (r < 0) {
787 : : /* If something we don't grok happened, let's better leave it in. */
788 [ # # ]: 0 : log_debug_errno(r, "Failed to chase and stat %s: %m", p->search_path[c]);
789 : 0 : c++;
790 : 0 : continue;
791 : : }
792 : :
793 [ + + ]: 152 : for (k = 0; k < n_stats; k++)
794 [ + + ]: 56 : if (stats[k].st_dev == st.st_dev &&
795 [ - + ]: 32 : stats[k].st_ino == st.st_ino)
796 : 0 : break;
797 : :
798 [ - + ]: 96 : if (k < n_stats) /* Is there already an entry with the same device/inode? */
799 : 0 : goto remove_item;
800 : :
801 [ - + ]: 96 : if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
802 : 0 : return -ENOMEM;
803 : :
804 : 96 : stats[n_stats++] = st;
805 : 96 : c++;
806 : 96 : continue;
807 : :
808 : 188 : remove_item:
809 : 188 : free(p->search_path[c]);
810 : 564 : memmove(p->search_path + c,
811 : 376 : p->search_path + c + 1,
812 : 188 : (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
813 : : }
814 : :
815 [ + + ]: 76 : if (strv_isempty(p->search_path)) {
816 [ + - ]: 12 : log_debug("Ignoring unit files.");
817 : 12 : p->search_path = strv_free(p->search_path);
818 : : } else {
819 [ + - ]: 64 : _cleanup_free_ char *t;
820 : :
821 : 64 : t = strv_join(p->search_path, "\n\t");
822 [ - + ]: 64 : if (!t)
823 : 0 : return -ENOMEM;
824 : :
825 [ + + ]: 64 : log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
826 : : }
827 : :
828 : 76 : return 0;
829 : : }
830 : :
831 : 0 : int lookup_paths_mkdir_generator(LookupPaths *p) {
832 : : int r, q;
833 : :
834 [ # # ]: 0 : assert(p);
835 : :
836 [ # # # # : 0 : if (!p->generator || !p->generator_early || !p->generator_late)
# # ]
837 : 0 : return -EINVAL;
838 : :
839 : 0 : r = mkdir_p_label(p->generator, 0755);
840 : :
841 : 0 : q = mkdir_p_label(p->generator_early, 0755);
842 [ # # # # ]: 0 : if (q < 0 && r >= 0)
843 : 0 : r = q;
844 : :
845 : 0 : q = mkdir_p_label(p->generator_late, 0755);
846 [ # # # # ]: 0 : if (q < 0 && r >= 0)
847 : 0 : r = q;
848 : :
849 : 0 : return r;
850 : : }
851 : :
852 : 0 : void lookup_paths_trim_generator(LookupPaths *p) {
853 [ # # ]: 0 : assert(p);
854 : :
855 : : /* Trim empty dirs */
856 : :
857 [ # # ]: 0 : if (p->generator)
858 : 0 : (void) rmdir(p->generator);
859 [ # # ]: 0 : if (p->generator_early)
860 : 0 : (void) rmdir(p->generator_early);
861 [ # # ]: 0 : if (p->generator_late)
862 : 0 : (void) rmdir(p->generator_late);
863 : 0 : }
864 : :
865 : 56 : void lookup_paths_flush_generator(LookupPaths *p) {
866 [ - + ]: 56 : assert(p);
867 : :
868 : : /* Flush the generated unit files in full */
869 : :
870 [ + + ]: 56 : if (p->generator)
871 : 52 : (void) rm_rf(p->generator, REMOVE_ROOT|REMOVE_PHYSICAL);
872 [ + + ]: 56 : if (p->generator_early)
873 : 52 : (void) rm_rf(p->generator_early, REMOVE_ROOT|REMOVE_PHYSICAL);
874 [ + + ]: 56 : if (p->generator_late)
875 : 52 : (void) rm_rf(p->generator_late, REMOVE_ROOT|REMOVE_PHYSICAL);
876 : :
877 [ + + ]: 56 : if (p->temporary_dir)
878 : 52 : (void) rm_rf(p->temporary_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
879 : 56 : }
880 : :
881 : 8 : char **generator_binary_paths(UnitFileScope scope) {
882 : :
883 [ + + - ]: 8 : switch (scope) {
884 : :
885 : 4 : case UNIT_FILE_SYSTEM:
886 : 4 : return strv_new("/run/systemd/system-generators",
887 : : "/etc/systemd/system-generators",
888 : : "/usr/local/lib/systemd/system-generators",
889 : : SYSTEM_GENERATOR_PATH);
890 : :
891 : 4 : case UNIT_FILE_GLOBAL:
892 : : case UNIT_FILE_USER:
893 : 4 : return strv_new("/run/systemd/user-generators",
894 : : "/etc/systemd/user-generators",
895 : : "/usr/local/lib/systemd/user-generators",
896 : : USER_GENERATOR_PATH);
897 : :
898 : 0 : default:
899 : 0 : assert_not_reached("Hmm, unexpected scope.");
900 : : }
901 : : }
|