]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/install.c
path-util: introduce path_simplify()
[thirdparty/systemd.git] / src / shared / install.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6 ***/
7
8 #include <dirent.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <fnmatch.h>
12 #include <limits.h>
13 #include <stddef.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19
20 #include "alloc-util.h"
21 #include "conf-files.h"
22 #include "conf-parser.h"
23 #include "dirent-util.h"
24 #include "extract-word.h"
25 #include "fd-util.h"
26 #include "fileio.h"
27 #include "fs-util.h"
28 #include "hashmap.h"
29 #include "install-printf.h"
30 #include "install.h"
31 #include "locale-util.h"
32 #include "log.h"
33 #include "macro.h"
34 #include "mkdir.h"
35 #include "path-lookup.h"
36 #include "path-util.h"
37 #include "rm-rf.h"
38 #include "set.h"
39 #include "special.h"
40 #include "stat-util.h"
41 #include "string-table.h"
42 #include "string-util.h"
43 #include "strv.h"
44 #include "unit-name.h"
45
46 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
47
48 typedef enum SearchFlags {
49 SEARCH_LOAD = 1U << 0,
50 SEARCH_FOLLOW_CONFIG_SYMLINKS = 1U << 1,
51 SEARCH_DROPIN = 1U << 2,
52 } SearchFlags;
53
54 typedef struct {
55 OrderedHashmap *will_process;
56 OrderedHashmap *have_processed;
57 } InstallContext;
58
59 typedef enum {
60 PRESET_UNKNOWN,
61 PRESET_ENABLE,
62 PRESET_DISABLE,
63 } PresetAction;
64
65 typedef struct {
66 char *pattern;
67 PresetAction action;
68 } PresetRule;
69
70 typedef struct {
71 PresetRule *rules;
72 size_t n_rules;
73 } Presets;
74
75 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo *i) {
76 assert(i);
77
78 return !strv_isempty(i->aliases) ||
79 !strv_isempty(i->wanted_by) ||
80 !strv_isempty(i->required_by);
81 }
82
83 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo *i) {
84 assert(i);
85
86 return !strv_isempty(i->also);
87 }
88
89 static inline void presets_freep(Presets *p) {
90 size_t i;
91
92 if (!p)
93 return;
94
95 for (i = 0; i < p->n_rules; i++)
96 free(p->rules[i].pattern);
97
98 free(p->rules);
99 p->n_rules = 0;
100 }
101
102 bool unit_type_may_alias(UnitType type) {
103 return IN_SET(type,
104 UNIT_SERVICE,
105 UNIT_SOCKET,
106 UNIT_TARGET,
107 UNIT_DEVICE,
108 UNIT_TIMER,
109 UNIT_PATH);
110 }
111
112 bool unit_type_may_template(UnitType type) {
113 return IN_SET(type,
114 UNIT_SERVICE,
115 UNIT_SOCKET,
116 UNIT_TARGET,
117 UNIT_TIMER,
118 UNIT_PATH);
119 }
120
121 static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
122 [UNIT_FILE_TYPE_REGULAR] = "regular",
123 [UNIT_FILE_TYPE_SYMLINK] = "symlink",
124 [UNIT_FILE_TYPE_MASKED] = "masked",
125 };
126
127 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
128
129 static int in_search_path(const LookupPaths *p, const char *path) {
130 _cleanup_free_ char *parent = NULL;
131 char **i;
132
133 assert(path);
134
135 parent = dirname_malloc(path);
136 if (!parent)
137 return -ENOMEM;
138
139 STRV_FOREACH(i, p->search_path)
140 if (path_equal(parent, *i))
141 return true;
142
143 return false;
144 }
145
146 static const char* skip_root(const LookupPaths *p, const char *path) {
147 char *e;
148
149 assert(p);
150 assert(path);
151
152 if (!p->root_dir)
153 return path;
154
155 e = path_startswith(path, p->root_dir);
156 if (!e)
157 return NULL;
158
159 /* Make sure the returned path starts with a slash */
160 if (e[0] != '/') {
161 if (e == path || e[-1] != '/')
162 return NULL;
163
164 e--;
165 }
166
167 return e;
168 }
169
170 static int path_is_generator(const LookupPaths *p, const char *path) {
171 _cleanup_free_ char *parent = NULL;
172
173 assert(p);
174 assert(path);
175
176 parent = dirname_malloc(path);
177 if (!parent)
178 return -ENOMEM;
179
180 return path_equal_ptr(parent, p->generator) ||
181 path_equal_ptr(parent, p->generator_early) ||
182 path_equal_ptr(parent, p->generator_late);
183 }
184
185 static int path_is_transient(const LookupPaths *p, const char *path) {
186 _cleanup_free_ char *parent = NULL;
187
188 assert(p);
189 assert(path);
190
191 parent = dirname_malloc(path);
192 if (!parent)
193 return -ENOMEM;
194
195 return path_equal_ptr(parent, p->transient);
196 }
197
198 static int path_is_control(const LookupPaths *p, const char *path) {
199 _cleanup_free_ char *parent = NULL;
200
201 assert(p);
202 assert(path);
203
204 parent = dirname_malloc(path);
205 if (!parent)
206 return -ENOMEM;
207
208 return path_equal_ptr(parent, p->persistent_control) ||
209 path_equal_ptr(parent, p->runtime_control);
210 }
211
212 static int path_is_config(const LookupPaths *p, const char *path, bool check_parent) {
213 _cleanup_free_ char *parent = NULL;
214
215 assert(p);
216 assert(path);
217
218 /* Note that we do *not* have generic checks for /etc or /run in place, since with
219 * them we couldn't discern configuration from transient or generated units */
220
221 if (check_parent) {
222 parent = dirname_malloc(path);
223 if (!parent)
224 return -ENOMEM;
225
226 path = parent;
227 }
228
229 return path_equal_ptr(path, p->persistent_config) ||
230 path_equal_ptr(path, p->runtime_config);
231 }
232
233 static int path_is_runtime(const LookupPaths *p, const char *path, bool check_parent) {
234 _cleanup_free_ char *parent = NULL;
235 const char *rpath;
236
237 assert(p);
238 assert(path);
239
240 /* Everything in /run is considered runtime. On top of that we also add
241 * explicit checks for the various runtime directories, as safety net. */
242
243 rpath = skip_root(p, path);
244 if (rpath && path_startswith(rpath, "/run"))
245 return true;
246
247 if (check_parent) {
248 parent = dirname_malloc(path);
249 if (!parent)
250 return -ENOMEM;
251
252 path = parent;
253 }
254
255 return path_equal_ptr(path, p->runtime_config) ||
256 path_equal_ptr(path, p->generator) ||
257 path_equal_ptr(path, p->generator_early) ||
258 path_equal_ptr(path, p->generator_late) ||
259 path_equal_ptr(path, p->transient) ||
260 path_equal_ptr(path, p->runtime_control);
261 }
262
263 static int path_is_vendor(const LookupPaths *p, const char *path) {
264 const char *rpath;
265
266 assert(p);
267 assert(path);
268
269 rpath = skip_root(p, path);
270 if (!rpath)
271 return 0;
272
273 if (path_startswith(rpath, "/usr"))
274 return true;
275
276 #if HAVE_SPLIT_USR
277 if (path_startswith(rpath, "/lib"))
278 return true;
279 #endif
280
281 return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
282 }
283
284 int unit_file_changes_add(
285 UnitFileChange **changes,
286 size_t *n_changes,
287 UnitFileChangeType type,
288 const char *path,
289 const char *source) {
290
291 _cleanup_free_ char *p = NULL, *s = NULL;
292 UnitFileChange *c;
293
294 assert(path);
295 assert(!changes == !n_changes);
296
297 if (!changes)
298 return 0;
299
300 c = reallocarray(*changes, *n_changes + 1, sizeof(UnitFileChange));
301 if (!c)
302 return -ENOMEM;
303 *changes = c;
304
305 p = strdup(path);
306 if (source)
307 s = strdup(source);
308
309 if (!p || (source && !s))
310 return -ENOMEM;
311
312 path_simplify(p, false);
313 if (s)
314 path_simplify(s, false);
315
316 c[*n_changes] = (UnitFileChange) { type, p, s };
317 p = s = NULL;
318 (*n_changes) ++;
319 return 0;
320 }
321
322 void unit_file_changes_free(UnitFileChange *changes, size_t n_changes) {
323 size_t i;
324
325 assert(changes || n_changes == 0);
326
327 for (i = 0; i < n_changes; i++) {
328 free(changes[i].path);
329 free(changes[i].source);
330 }
331
332 free(changes);
333 }
334
335 void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, size_t n_changes, bool quiet) {
336 size_t i;
337 bool logged = false;
338
339 assert(changes || n_changes == 0);
340 /* If verb is not specified, errors are not allowed! */
341 assert(verb || r >= 0);
342
343 for (i = 0; i < n_changes; i++) {
344 assert(verb || changes[i].type >= 0);
345
346 switch(changes[i].type) {
347 case UNIT_FILE_SYMLINK:
348 if (!quiet)
349 log_info("Created symlink %s %s %s.",
350 changes[i].path,
351 special_glyph(ARROW),
352 changes[i].source);
353 break;
354 case UNIT_FILE_UNLINK:
355 if (!quiet)
356 log_info("Removed %s.", changes[i].path);
357 break;
358 case UNIT_FILE_IS_MASKED:
359 if (!quiet)
360 log_info("Unit %s is masked, ignoring.", changes[i].path);
361 break;
362 case UNIT_FILE_IS_DANGLING:
363 if (!quiet)
364 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
365 changes[i].path);
366 break;
367 case -EEXIST:
368 if (changes[i].source)
369 log_error_errno(changes[i].type,
370 "Failed to %s unit, file %s already exists and is a symlink to %s.",
371 verb, changes[i].path, changes[i].source);
372 else
373 log_error_errno(changes[i].type,
374 "Failed to %s unit, file %s already exists.",
375 verb, changes[i].path);
376 logged = true;
377 break;
378 case -ERFKILL:
379 log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
380 verb, changes[i].path);
381 logged = true;
382 break;
383 case -EADDRNOTAVAIL:
384 log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
385 verb, changes[i].path);
386 logged = true;
387 break;
388 case -ELOOP:
389 log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
390 verb, changes[i].path);
391 logged = true;
392 break;
393
394 case -ENOENT:
395 log_error_errno(changes[i].type, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path);
396 logged = true;
397 break;
398
399 default:
400 assert(changes[i].type < 0);
401 log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
402 verb, changes[i].path);
403 logged = true;
404 }
405 }
406
407 if (r < 0 && !logged)
408 log_error_errno(r, "Failed to %s: %m.", verb);
409 }
410
411 /**
412 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
413 * wc should be the full path in the host file system.
414 */
415 static bool chroot_symlinks_same(const char *root, const char *wd, const char *a, const char *b) {
416 assert(path_is_absolute(wd));
417
418 /* This will give incorrect results if the paths are relative and go outside
419 * of the chroot. False negatives are possible. */
420
421 if (!root)
422 root = "/";
423
424 a = strjoina(path_is_absolute(a) ? root : wd, "/", a);
425 b = strjoina(path_is_absolute(b) ? root : wd, "/", b);
426 return path_equal_or_files_same(a, b, 0);
427 }
428
429 static int create_symlink(
430 const LookupPaths *paths,
431 const char *old_path,
432 const char *new_path,
433 bool force,
434 UnitFileChange **changes,
435 size_t *n_changes) {
436
437 _cleanup_free_ char *dest = NULL, *dirname = NULL;
438 const char *rp;
439 int r;
440
441 assert(old_path);
442 assert(new_path);
443
444 rp = skip_root(paths, old_path);
445 if (rp)
446 old_path = rp;
447
448 /* Actually create a symlink, and remember that we did. Is
449 * smart enough to check if there's already a valid symlink in
450 * place.
451 *
452 * Returns 1 if a symlink was created or already exists and points to
453 * the right place, or negative on error.
454 */
455
456 mkdir_parents_label(new_path, 0755);
457
458 if (symlink(old_path, new_path) >= 0) {
459 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
460 return 1;
461 }
462
463 if (errno != EEXIST) {
464 unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
465 return -errno;
466 }
467
468 r = readlink_malloc(new_path, &dest);
469 if (r < 0) {
470 /* translate EINVAL (non-symlink exists) to EEXIST */
471 if (r == -EINVAL)
472 r = -EEXIST;
473
474 unit_file_changes_add(changes, n_changes, r, new_path, NULL);
475 return r;
476 }
477
478 dirname = dirname_malloc(new_path);
479 if (!dirname)
480 return -ENOMEM;
481
482 if (chroot_symlinks_same(paths->root_dir, dirname, dest, old_path))
483 return 1;
484
485 if (!force) {
486 unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
487 return -EEXIST;
488 }
489
490 r = symlink_atomic(old_path, new_path);
491 if (r < 0) {
492 unit_file_changes_add(changes, n_changes, r, new_path, NULL);
493 return r;
494 }
495
496 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
497 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
498
499 return 1;
500 }
501
502 static int mark_symlink_for_removal(
503 Set **remove_symlinks_to,
504 const char *p) {
505
506 char *n;
507 int r;
508
509 assert(p);
510
511 r = set_ensure_allocated(remove_symlinks_to, &path_hash_ops);
512 if (r < 0)
513 return r;
514
515 n = strdup(p);
516 if (!n)
517 return -ENOMEM;
518
519 path_simplify(n, false);
520
521 r = set_consume(*remove_symlinks_to, n);
522 if (r == -EEXIST)
523 return 0;
524 if (r < 0)
525 return r;
526
527 return 1;
528 }
529
530 static int remove_marked_symlinks_fd(
531 Set *remove_symlinks_to,
532 int fd,
533 const char *path,
534 const char *config_path,
535 const LookupPaths *lp,
536 bool dry_run,
537 bool *restart,
538 UnitFileChange **changes,
539 size_t *n_changes) {
540
541 _cleanup_closedir_ DIR *d = NULL;
542 struct dirent *de;
543 int r = 0;
544
545 assert(remove_symlinks_to);
546 assert(fd >= 0);
547 assert(path);
548 assert(config_path);
549 assert(lp);
550 assert(restart);
551
552 d = fdopendir(fd);
553 if (!d) {
554 safe_close(fd);
555 return -errno;
556 }
557
558 rewinddir(d);
559
560 FOREACH_DIRENT(de, d, return -errno) {
561
562 dirent_ensure_type(d, de);
563
564 if (de->d_type == DT_DIR) {
565 _cleanup_free_ char *p = NULL;
566 int nfd, q;
567
568 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
569 if (nfd < 0) {
570 if (errno == ENOENT)
571 continue;
572
573 if (r == 0)
574 r = -errno;
575 continue;
576 }
577
578 p = path_make_absolute(de->d_name, path);
579 if (!p) {
580 safe_close(nfd);
581 return -ENOMEM;
582 }
583
584 /* This will close nfd, regardless whether it succeeds or not */
585 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, dry_run, restart, changes, n_changes);
586 if (q < 0 && r == 0)
587 r = q;
588
589 } else if (de->d_type == DT_LNK) {
590 _cleanup_free_ char *p = NULL, *dest = NULL;
591 const char *rp;
592 bool found;
593 int q;
594
595 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
596 continue;
597
598 p = path_make_absolute(de->d_name, path);
599 if (!p)
600 return -ENOMEM;
601 path_simplify(p, false);
602
603 q = readlink_malloc(p, &dest);
604 if (q == -ENOENT)
605 continue;
606 if (q < 0) {
607 if (r == 0)
608 r = q;
609 continue;
610 }
611
612 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
613 * the same name as a file that is marked. */
614
615 found = set_contains(remove_symlinks_to, dest) ||
616 set_contains(remove_symlinks_to, basename(dest)) ||
617 set_contains(remove_symlinks_to, de->d_name);
618
619 if (!found)
620 continue;
621
622 if (!dry_run) {
623 if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
624 if (r == 0)
625 r = -errno;
626 unit_file_changes_add(changes, n_changes, -errno, p, NULL);
627 continue;
628 }
629
630 (void) rmdir_parents(p, config_path);
631 }
632
633 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
634
635 /* Now, remember the full path (but with the root prefix removed) of
636 * the symlink we just removed, and remove any symlinks to it, too. */
637
638 rp = skip_root(lp, p);
639 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
640 if (q < 0)
641 return q;
642 if (q > 0 && !dry_run)
643 *restart = true;
644 }
645 }
646
647 return r;
648 }
649
650 static int remove_marked_symlinks(
651 Set *remove_symlinks_to,
652 const char *config_path,
653 const LookupPaths *lp,
654 bool dry_run,
655 UnitFileChange **changes,
656 size_t *n_changes) {
657
658 _cleanup_close_ int fd = -1;
659 bool restart;
660 int r = 0;
661
662 assert(config_path);
663 assert(lp);
664
665 if (set_size(remove_symlinks_to) <= 0)
666 return 0;
667
668 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
669 if (fd < 0)
670 return errno == ENOENT ? 0 : -errno;
671
672 do {
673 int q, cfd;
674 restart = false;
675
676 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
677 if (cfd < 0)
678 return -errno;
679
680 /* This takes possession of cfd and closes it */
681 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, dry_run, &restart, changes, n_changes);
682 if (r == 0)
683 r = q;
684 } while (restart);
685
686 return r;
687 }
688
689 static bool is_symlink_with_known_name(const UnitFileInstallInfo *i, const char *name) {
690 int r;
691
692 if (streq(name, i->name))
693 return true;
694
695 if (strv_contains(i->aliases, name))
696 return true;
697
698 /* Look for template symlink matching DefaultInstance */
699 if (i->default_instance && unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
700 _cleanup_free_ char *s = NULL;
701
702 r = unit_name_replace_instance(i->name, i->default_instance, &s);
703 if (r < 0) {
704 if (r != -EINVAL)
705 return r;
706
707 } else if (streq(name, s))
708 return true;
709 }
710
711 return false;
712 }
713
714 static int find_symlinks_fd(
715 const char *root_dir,
716 UnitFileInstallInfo *i,
717 bool match_aliases,
718 int fd,
719 const char *path,
720 const char *config_path,
721 bool *same_name_link) {
722
723 _cleanup_closedir_ DIR *d = NULL;
724 struct dirent *de;
725 int r = 0;
726
727 assert(i);
728 assert(fd >= 0);
729 assert(path);
730 assert(config_path);
731 assert(same_name_link);
732
733 d = fdopendir(fd);
734 if (!d) {
735 safe_close(fd);
736 return -errno;
737 }
738
739 FOREACH_DIRENT(de, d, return -errno) {
740
741 dirent_ensure_type(d, de);
742
743 if (de->d_type == DT_DIR) {
744 _cleanup_free_ char *p = NULL;
745 int nfd, q;
746
747 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
748 if (nfd < 0) {
749 if (errno == ENOENT)
750 continue;
751
752 if (r == 0)
753 r = -errno;
754 continue;
755 }
756
757 p = path_make_absolute(de->d_name, path);
758 if (!p) {
759 safe_close(nfd);
760 return -ENOMEM;
761 }
762
763 /* This will close nfd, regardless whether it succeeds or not */
764 q = find_symlinks_fd(root_dir, i, match_aliases, nfd,
765 p, config_path, same_name_link);
766 if (q > 0)
767 return 1;
768 if (r == 0)
769 r = q;
770
771 } else if (de->d_type == DT_LNK) {
772 _cleanup_free_ char *p = NULL, *dest = NULL;
773 bool found_path, found_dest, b = false;
774 int q;
775
776 /* Acquire symlink name */
777 p = path_make_absolute(de->d_name, path);
778 if (!p)
779 return -ENOMEM;
780
781 /* Acquire symlink destination */
782 q = readlink_malloc(p, &dest);
783 if (q == -ENOENT)
784 continue;
785 if (q < 0) {
786 if (r == 0)
787 r = q;
788 continue;
789 }
790
791 /* Make absolute */
792 if (!path_is_absolute(dest)) {
793 char *x;
794
795 x = prefix_root(root_dir, dest);
796 if (!x)
797 return -ENOMEM;
798
799 free(dest);
800 dest = x;
801 }
802
803 /* Check if the symlink itself matches what we
804 * are looking for */
805 if (path_is_absolute(i->name))
806 found_path = path_equal(p, i->name);
807 else
808 found_path = streq(de->d_name, i->name);
809
810 /* Check if what the symlink points to
811 * matches what we are looking for */
812 if (path_is_absolute(i->name))
813 found_dest = path_equal(dest, i->name);
814 else
815 found_dest = streq(basename(dest), i->name);
816
817 if (found_path && found_dest) {
818 _cleanup_free_ char *t = NULL;
819
820 /* Filter out same name links in the main
821 * config path */
822 t = path_make_absolute(i->name, config_path);
823 if (!t)
824 return -ENOMEM;
825
826 b = path_equal(t, p);
827 }
828
829 if (b)
830 *same_name_link = true;
831 else if (found_path || found_dest) {
832 if (!match_aliases)
833 return 1;
834
835 /* Check if symlink name is in the set of names used by [Install] */
836 q = is_symlink_with_known_name(i, de->d_name);
837 if (q < 0)
838 return q;
839 if (q > 0)
840 return 1;
841 }
842 }
843 }
844
845 return r;
846 }
847
848 static int find_symlinks(
849 const char *root_dir,
850 UnitFileInstallInfo *i,
851 bool match_name,
852 const char *config_path,
853 bool *same_name_link) {
854
855 int fd;
856
857 assert(i);
858 assert(config_path);
859 assert(same_name_link);
860
861 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
862 if (fd < 0) {
863 if (IN_SET(errno, ENOENT, ENOTDIR, EACCES))
864 return 0;
865 return -errno;
866 }
867
868 /* This takes possession of fd and closes it */
869 return find_symlinks_fd(root_dir, i, match_name, fd,
870 config_path, config_path, same_name_link);
871 }
872
873 static int find_symlinks_in_scope(
874 UnitFileScope scope,
875 const LookupPaths *paths,
876 UnitFileInstallInfo *i,
877 bool match_name,
878 UnitFileState *state) {
879
880 bool same_name_link_runtime = false, same_name_link_config = false;
881 bool enabled_in_runtime = false, enabled_at_all = false;
882 char **p;
883 int r;
884
885 assert(paths);
886 assert(i);
887
888 STRV_FOREACH(p, paths->search_path) {
889 bool same_name_link = false;
890
891 r = find_symlinks(paths->root_dir, i, match_name, *p, &same_name_link);
892 if (r < 0)
893 return r;
894 if (r > 0) {
895 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
896
897 r = path_is_config(paths, *p, false);
898 if (r < 0)
899 return r;
900 if (r > 0) {
901 /* This is the best outcome, let's return it immediately. */
902 *state = UNIT_FILE_ENABLED;
903 return 1;
904 }
905
906 /* look for globally enablement of user units */
907 if (scope == UNIT_FILE_USER && path_is_user_config_dir(*p)) {
908 *state = UNIT_FILE_ENABLED;
909 return 1;
910 }
911
912 r = path_is_runtime(paths, *p, false);
913 if (r < 0)
914 return r;
915 if (r > 0)
916 enabled_in_runtime = true;
917 else
918 enabled_at_all = true;
919
920 } else if (same_name_link) {
921
922 r = path_is_config(paths, *p, false);
923 if (r < 0)
924 return r;
925 if (r > 0)
926 same_name_link_config = true;
927 else {
928 r = path_is_runtime(paths, *p, false);
929 if (r < 0)
930 return r;
931 if (r > 0)
932 same_name_link_runtime = true;
933 }
934 }
935 }
936
937 if (enabled_in_runtime) {
938 *state = UNIT_FILE_ENABLED_RUNTIME;
939 return 1;
940 }
941
942 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
943 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
944 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
945 * something, and hence are a much stronger concept. */
946 if (enabled_at_all && unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) {
947 *state = UNIT_FILE_STATIC;
948 return 1;
949 }
950
951 /* Hmm, we didn't find it, but maybe we found the same name
952 * link? */
953 if (same_name_link_config) {
954 *state = UNIT_FILE_LINKED;
955 return 1;
956 }
957 if (same_name_link_runtime) {
958 *state = UNIT_FILE_LINKED_RUNTIME;
959 return 1;
960 }
961
962 return 0;
963 }
964
965 static void install_info_free(UnitFileInstallInfo *i) {
966
967 if (!i)
968 return;
969
970 free(i->name);
971 free(i->path);
972 strv_free(i->aliases);
973 strv_free(i->wanted_by);
974 strv_free(i->required_by);
975 strv_free(i->also);
976 free(i->default_instance);
977 free(i->symlink_target);
978 free(i);
979 }
980
981 static void install_context_done(InstallContext *c) {
982 assert(c);
983
984 c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free);
985 c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free);
986 }
987
988 static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
989 UnitFileInstallInfo *i;
990
991 i = ordered_hashmap_get(c->have_processed, name);
992 if (i)
993 return i;
994
995 return ordered_hashmap_get(c->will_process, name);
996 }
997
998 static int install_info_may_process(
999 UnitFileInstallInfo *i,
1000 const LookupPaths *paths,
1001 UnitFileChange **changes,
1002 size_t *n_changes) {
1003 assert(i);
1004 assert(paths);
1005
1006 /* Checks whether the loaded unit file is one we should process, or is masked,
1007 * transient or generated and thus not subject to enable/disable operations. */
1008
1009 if (i->type == UNIT_FILE_TYPE_MASKED) {
1010 unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
1011 return -ERFKILL;
1012 }
1013 if (path_is_generator(paths, i->path) ||
1014 path_is_transient(paths, i->path)) {
1015 unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
1016 return -EADDRNOTAVAIL;
1017 }
1018
1019 return 0;
1020 }
1021
1022 /**
1023 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1024 * hashmap, or retrieves the existing one if already present.
1025 *
1026 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1027 */
1028 static int install_info_add(
1029 InstallContext *c,
1030 const char *name,
1031 const char *path,
1032 bool auxiliary,
1033 UnitFileInstallInfo **ret) {
1034
1035 UnitFileInstallInfo *i = NULL;
1036 int r;
1037
1038 assert(c);
1039 assert(name || path);
1040
1041 if (!name)
1042 name = basename(path);
1043
1044 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
1045 return -EINVAL;
1046
1047 i = install_info_find(c, name);
1048 if (i) {
1049 i->auxiliary = i->auxiliary && auxiliary;
1050
1051 if (ret)
1052 *ret = i;
1053 return 0;
1054 }
1055
1056 r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops);
1057 if (r < 0)
1058 return r;
1059
1060 i = new0(UnitFileInstallInfo, 1);
1061 if (!i)
1062 return -ENOMEM;
1063 i->type = _UNIT_FILE_TYPE_INVALID;
1064 i->auxiliary = auxiliary;
1065
1066 i->name = strdup(name);
1067 if (!i->name) {
1068 r = -ENOMEM;
1069 goto fail;
1070 }
1071
1072 if (path) {
1073 i->path = strdup(path);
1074 if (!i->path) {
1075 r = -ENOMEM;
1076 goto fail;
1077 }
1078 }
1079
1080 r = ordered_hashmap_put(c->will_process, i->name, i);
1081 if (r < 0)
1082 goto fail;
1083
1084 if (ret)
1085 *ret = i;
1086
1087 return 1;
1088
1089 fail:
1090 install_info_free(i);
1091 return r;
1092 }
1093
1094 static int config_parse_alias(
1095 const char *unit,
1096 const char *filename,
1097 unsigned line,
1098 const char *section,
1099 unsigned section_line,
1100 const char *lvalue,
1101 int ltype,
1102 const char *rvalue,
1103 void *data,
1104 void *userdata) {
1105
1106 UnitType type;
1107
1108 assert(unit);
1109 assert(filename);
1110 assert(lvalue);
1111 assert(rvalue);
1112
1113 type = unit_name_to_type(unit);
1114 if (!unit_type_may_alias(type))
1115 return log_syntax(unit, LOG_WARNING, filename, line, 0,
1116 "Alias= is not allowed for %s units, ignoring.",
1117 unit_type_to_string(type));
1118
1119 return config_parse_strv(unit, filename, line, section, section_line,
1120 lvalue, ltype, rvalue, data, userdata);
1121 }
1122
1123 static int config_parse_also(
1124 const char *unit,
1125 const char *filename,
1126 unsigned line,
1127 const char *section,
1128 unsigned section_line,
1129 const char *lvalue,
1130 int ltype,
1131 const char *rvalue,
1132 void *data,
1133 void *userdata) {
1134
1135 UnitFileInstallInfo *info = userdata, *alsoinfo = NULL;
1136 InstallContext *c = data;
1137 int r;
1138
1139 assert(unit);
1140 assert(filename);
1141 assert(lvalue);
1142 assert(rvalue);
1143
1144 for (;;) {
1145 _cleanup_free_ char *word = NULL, *printed = NULL;
1146
1147 r = extract_first_word(&rvalue, &word, NULL, 0);
1148 if (r < 0)
1149 return r;
1150 if (r == 0)
1151 break;
1152
1153 r = install_full_printf(info, word, &printed);
1154 if (r < 0)
1155 return r;
1156
1157 if (!unit_name_is_valid(printed, UNIT_NAME_ANY))
1158 return -EINVAL;
1159
1160 r = install_info_add(c, printed, NULL, true, &alsoinfo);
1161 if (r < 0)
1162 return r;
1163
1164 r = strv_push(&info->also, printed);
1165 if (r < 0)
1166 return r;
1167
1168 printed = NULL;
1169 }
1170
1171 return 0;
1172 }
1173
1174 static int config_parse_default_instance(
1175 const char *unit,
1176 const char *filename,
1177 unsigned line,
1178 const char *section,
1179 unsigned section_line,
1180 const char *lvalue,
1181 int ltype,
1182 const char *rvalue,
1183 void *data,
1184 void *userdata) {
1185
1186 UnitFileInstallInfo *i = data;
1187 _cleanup_free_ char *printed = NULL;
1188 int r;
1189
1190 assert(unit);
1191 assert(filename);
1192 assert(lvalue);
1193 assert(rvalue);
1194
1195 if (unit_name_is_valid(unit, UNIT_NAME_INSTANCE))
1196 /* When enabling an instance, we might be using a template unit file,
1197 * but we should ignore DefaultInstance silently. */
1198 return 0;
1199 if (!unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
1200 return log_syntax(unit, LOG_WARNING, filename, line, 0,
1201 "DefaultInstance= only makes sense for template units, ignoring.");
1202
1203 r = install_full_printf(i, rvalue, &printed);
1204 if (r < 0)
1205 return r;
1206
1207 if (!unit_instance_is_valid(printed))
1208 return -EINVAL;
1209
1210 return free_and_replace(i->default_instance, printed);
1211 }
1212
1213 static int unit_file_load(
1214 InstallContext *c,
1215 UnitFileInstallInfo *info,
1216 const char *path,
1217 const char *root_dir,
1218 SearchFlags flags) {
1219
1220 const ConfigTableItem items[] = {
1221 { "Install", "Alias", config_parse_alias, 0, &info->aliases },
1222 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1223 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1224 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
1225 { "Install", "Also", config_parse_also, 0, c },
1226 {}
1227 };
1228
1229 UnitType type;
1230 _cleanup_fclose_ FILE *f = NULL;
1231 _cleanup_close_ int fd = -1;
1232 struct stat st;
1233 int r;
1234
1235 assert(info);
1236 assert(path);
1237
1238 if (!(flags & SEARCH_DROPIN)) {
1239 /* Loading or checking for the main unit file… */
1240
1241 type = unit_name_to_type(info->name);
1242 if (type < 0)
1243 return -EINVAL;
1244 if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type)) {
1245 log_error("Unit type %s cannot be templated.", unit_type_to_string(type));
1246 return -EINVAL;
1247 }
1248
1249 if (!(flags & SEARCH_LOAD)) {
1250 r = lstat(path, &st);
1251 if (r < 0)
1252 return -errno;
1253
1254 if (null_or_empty(&st))
1255 info->type = UNIT_FILE_TYPE_MASKED;
1256 else if (S_ISREG(st.st_mode))
1257 info->type = UNIT_FILE_TYPE_REGULAR;
1258 else if (S_ISLNK(st.st_mode))
1259 return -ELOOP;
1260 else if (S_ISDIR(st.st_mode))
1261 return -EISDIR;
1262 else
1263 return -ENOTTY;
1264
1265 return 0;
1266 }
1267
1268 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
1269 if (fd < 0)
1270 return -errno;
1271 } else {
1272 /* Operating on a drop-in file. If we aren't supposed to load the unit file drop-ins don't matter, let's hence shortcut this. */
1273
1274 if (!(flags & SEARCH_LOAD))
1275 return 0;
1276
1277 fd = chase_symlinks_and_open(path, root_dir, 0, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
1278 if (fd < 0)
1279 return fd;
1280 }
1281
1282 if (fstat(fd, &st) < 0)
1283 return -errno;
1284
1285 if (null_or_empty(&st)) {
1286 if ((flags & SEARCH_DROPIN) == 0)
1287 info->type = UNIT_FILE_TYPE_MASKED;
1288
1289 return 0;
1290 }
1291
1292 r = stat_verify_regular(&st);
1293 if (r < 0)
1294 return r;
1295
1296 f = fdopen(fd, "re");
1297 if (!f)
1298 return -errno;
1299 fd = -1;
1300
1301 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1302 assert(c);
1303
1304 r = config_parse(info->name, path, f,
1305 NULL,
1306 config_item_table_lookup, items,
1307 CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
1308 if (r < 0)
1309 return log_debug_errno(r, "Failed to parse %s: %m", info->name);
1310
1311 if ((flags & SEARCH_DROPIN) == 0)
1312 info->type = UNIT_FILE_TYPE_REGULAR;
1313
1314 return
1315 (int) strv_length(info->aliases) +
1316 (int) strv_length(info->wanted_by) +
1317 (int) strv_length(info->required_by);
1318 }
1319
1320 static int unit_file_load_or_readlink(
1321 InstallContext *c,
1322 UnitFileInstallInfo *info,
1323 const char *path,
1324 const char *root_dir,
1325 SearchFlags flags) {
1326
1327 _cleanup_free_ char *target = NULL;
1328 int r;
1329
1330 r = unit_file_load(c, info, path, root_dir, flags);
1331 if (r != -ELOOP || (flags & SEARCH_DROPIN))
1332 return r;
1333
1334 /* This is a symlink, let's read it. */
1335
1336 r = readlink_malloc(path, &target);
1337 if (r < 0)
1338 return r;
1339
1340 if (path_equal(target, "/dev/null"))
1341 info->type = UNIT_FILE_TYPE_MASKED;
1342 else {
1343 const char *bn;
1344 UnitType a, b;
1345
1346 bn = basename(target);
1347
1348 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1349
1350 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1351 return -EINVAL;
1352
1353 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1354
1355 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1356 return -EINVAL;
1357
1358 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1359
1360 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1361 return -EINVAL;
1362 } else
1363 return -EINVAL;
1364
1365 /* Enforce that the symlink destination does not
1366 * change the unit file type. */
1367
1368 a = unit_name_to_type(info->name);
1369 b = unit_name_to_type(bn);
1370 if (a < 0 || b < 0 || a != b)
1371 return -EINVAL;
1372
1373 if (path_is_absolute(target))
1374 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1375 info->symlink_target = prefix_root(root_dir, target);
1376 else
1377 /* This is a relative path, take it relative to the dir the symlink is located in. */
1378 info->symlink_target = file_in_same_dir(path, target);
1379 if (!info->symlink_target)
1380 return -ENOMEM;
1381
1382 info->type = UNIT_FILE_TYPE_SYMLINK;
1383 }
1384
1385 return 0;
1386 }
1387
1388 static int unit_file_search(
1389 InstallContext *c,
1390 UnitFileInstallInfo *info,
1391 const LookupPaths *paths,
1392 SearchFlags flags) {
1393
1394 const char *dropin_dir_name = NULL, *dropin_template_dir_name = NULL;
1395 _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
1396 _cleanup_free_ char *template = NULL;
1397 bool found_unit = false;
1398 int r, result;
1399 char **p;
1400
1401 assert(info);
1402 assert(paths);
1403
1404 /* Was this unit already loaded? */
1405 if (info->type != _UNIT_FILE_TYPE_INVALID)
1406 return 0;
1407
1408 if (info->path)
1409 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
1410
1411 assert(info->name);
1412
1413 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1414 r = unit_name_template(info->name, &template);
1415 if (r < 0)
1416 return r;
1417 }
1418
1419 STRV_FOREACH(p, paths->search_path) {
1420 _cleanup_free_ char *path = NULL;
1421
1422 path = strjoin(*p, "/", info->name);
1423 if (!path)
1424 return -ENOMEM;
1425
1426 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1427 if (r >= 0) {
1428 info->path = TAKE_PTR(path);
1429 result = r;
1430 found_unit = true;
1431 break;
1432 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
1433 return r;
1434 }
1435
1436 if (!found_unit && template) {
1437
1438 /* Unit file doesn't exist, however instance
1439 * enablement was requested. We will check if it is
1440 * possible to load template unit file. */
1441
1442 STRV_FOREACH(p, paths->search_path) {
1443 _cleanup_free_ char *path = NULL;
1444
1445 path = strjoin(*p, "/", template);
1446 if (!path)
1447 return -ENOMEM;
1448
1449 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1450 if (r >= 0) {
1451 info->path = TAKE_PTR(path);
1452 result = r;
1453 found_unit = true;
1454 break;
1455 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
1456 return r;
1457 }
1458 }
1459
1460 if (!found_unit) {
1461 log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
1462 return -ENOENT;
1463 }
1464
1465 if (info->type == UNIT_FILE_TYPE_MASKED)
1466 return result;
1467
1468 /* Search for drop-in directories */
1469
1470 dropin_dir_name = strjoina(info->name, ".d");
1471 STRV_FOREACH(p, paths->search_path) {
1472 char *path;
1473
1474 path = path_join(NULL, *p, dropin_dir_name);
1475 if (!path)
1476 return -ENOMEM;
1477
1478 r = strv_consume(&dirs, path);
1479 if (r < 0)
1480 return r;
1481 }
1482
1483 if (template) {
1484 dropin_template_dir_name = strjoina(template, ".d");
1485 STRV_FOREACH(p, paths->search_path) {
1486 char *path;
1487
1488 path = path_join(NULL, *p, dropin_template_dir_name);
1489 if (!path)
1490 return -ENOMEM;
1491
1492 r = strv_consume(&dirs, path);
1493 if (r < 0)
1494 return r;
1495 }
1496 }
1497
1498 /* Load drop-in conf files */
1499
1500 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) dirs);
1501 if (r < 0)
1502 return log_debug_errno(r, "Failed to get list of conf files: %m");
1503
1504 STRV_FOREACH(p, files) {
1505 r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN);
1506 if (r < 0)
1507 return log_debug_errno(r, "Failed to load conf file %s: %m", *p);
1508 }
1509
1510 return result;
1511 }
1512
1513 static int install_info_follow(
1514 InstallContext *c,
1515 UnitFileInstallInfo *i,
1516 const char *root_dir,
1517 SearchFlags flags,
1518 bool ignore_different_name) {
1519
1520 assert(c);
1521 assert(i);
1522
1523 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1524 return -EINVAL;
1525 if (!i->symlink_target)
1526 return -EINVAL;
1527
1528 /* If the basename doesn't match, the caller should add a
1529 * complete new entry for this. */
1530
1531 if (!ignore_different_name && !streq(basename(i->symlink_target), i->name))
1532 return -EXDEV;
1533
1534 free_and_replace(i->path, i->symlink_target);
1535 i->type = _UNIT_FILE_TYPE_INVALID;
1536
1537 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1538 }
1539
1540 /**
1541 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1542 * target, maybe more than once. Propagate the instance name if present.
1543 */
1544 static int install_info_traverse(
1545 UnitFileScope scope,
1546 InstallContext *c,
1547 const LookupPaths *paths,
1548 UnitFileInstallInfo *start,
1549 SearchFlags flags,
1550 UnitFileInstallInfo **ret) {
1551
1552 UnitFileInstallInfo *i;
1553 unsigned k = 0;
1554 int r;
1555
1556 assert(paths);
1557 assert(start);
1558 assert(c);
1559
1560 r = unit_file_search(c, start, paths, flags);
1561 if (r < 0)
1562 return r;
1563
1564 i = start;
1565 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1566 /* Follow the symlink */
1567
1568 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
1569 return -ELOOP;
1570
1571 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
1572 r = path_is_config(paths, i->path, true);
1573 if (r < 0)
1574 return r;
1575 if (r > 0)
1576 return -ELOOP;
1577 }
1578
1579 r = install_info_follow(c, i, paths->root_dir, flags, false);
1580 if (r == -EXDEV) {
1581 _cleanup_free_ char *buffer = NULL;
1582 const char *bn;
1583
1584 /* Target has a different name, create a new
1585 * install info object for that, and continue
1586 * with that. */
1587
1588 bn = basename(i->symlink_target);
1589
1590 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1591 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
1592
1593 _cleanup_free_ char *instance = NULL;
1594
1595 r = unit_name_to_instance(i->name, &instance);
1596 if (r < 0)
1597 return r;
1598
1599 r = unit_name_replace_instance(bn, instance, &buffer);
1600 if (r < 0)
1601 return r;
1602
1603 if (streq(buffer, i->name)) {
1604
1605 /* We filled in the instance, and the target stayed the same? If so, then let's
1606 * honour the link as it is. */
1607
1608 r = install_info_follow(c, i, paths->root_dir, flags, true);
1609 if (r < 0)
1610 return r;
1611
1612 continue;
1613 }
1614
1615 bn = buffer;
1616 }
1617
1618 r = install_info_add(c, bn, NULL, false, &i);
1619 if (r < 0)
1620 return r;
1621
1622 /* Try again, with the new target we found. */
1623 r = unit_file_search(c, i, paths, flags);
1624 if (r == -ENOENT)
1625 /* Translate error code to highlight this specific case */
1626 return -ENOLINK;
1627 }
1628
1629 if (r < 0)
1630 return r;
1631 }
1632
1633 if (ret)
1634 *ret = i;
1635
1636 return 0;
1637 }
1638
1639 /**
1640 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1641 * or the name (otherwise). root_dir is prepended to the path.
1642 */
1643 static int install_info_add_auto(
1644 InstallContext *c,
1645 const LookupPaths *paths,
1646 const char *name_or_path,
1647 UnitFileInstallInfo **ret) {
1648
1649 assert(c);
1650 assert(name_or_path);
1651
1652 if (path_is_absolute(name_or_path)) {
1653 const char *pp;
1654
1655 pp = prefix_roota(paths->root_dir, name_or_path);
1656
1657 return install_info_add(c, NULL, pp, false, ret);
1658 } else
1659 return install_info_add(c, name_or_path, NULL, false, ret);
1660 }
1661
1662 static int install_info_discover(
1663 UnitFileScope scope,
1664 InstallContext *c,
1665 const LookupPaths *paths,
1666 const char *name,
1667 SearchFlags flags,
1668 UnitFileInstallInfo **ret,
1669 UnitFileChange **changes,
1670 size_t *n_changes) {
1671
1672 UnitFileInstallInfo *i;
1673 int r;
1674
1675 assert(c);
1676 assert(paths);
1677 assert(name);
1678
1679 r = install_info_add_auto(c, paths, name, &i);
1680 if (r >= 0)
1681 r = install_info_traverse(scope, c, paths, i, flags, ret);
1682
1683 if (r < 0)
1684 unit_file_changes_add(changes, n_changes, r, name, NULL);
1685 return r;
1686 }
1687
1688 static int install_info_symlink_alias(
1689 UnitFileInstallInfo *i,
1690 const LookupPaths *paths,
1691 const char *config_path,
1692 bool force,
1693 UnitFileChange **changes,
1694 size_t *n_changes) {
1695
1696 char **s;
1697 int r = 0, q;
1698
1699 assert(i);
1700 assert(paths);
1701 assert(config_path);
1702
1703 STRV_FOREACH(s, i->aliases) {
1704 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
1705
1706 q = install_full_printf(i, *s, &dst);
1707 if (q < 0)
1708 return q;
1709
1710 alias_path = path_make_absolute(dst, config_path);
1711 if (!alias_path)
1712 return -ENOMEM;
1713
1714 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
1715 if (r == 0)
1716 r = q;
1717 }
1718
1719 return r;
1720 }
1721
1722 static int install_info_symlink_wants(
1723 UnitFileInstallInfo *i,
1724 const LookupPaths *paths,
1725 const char *config_path,
1726 char **list,
1727 const char *suffix,
1728 UnitFileChange **changes,
1729 size_t *n_changes) {
1730
1731 _cleanup_free_ char *buf = NULL;
1732 const char *n;
1733 char **s;
1734 int r = 0, q;
1735
1736 assert(i);
1737 assert(paths);
1738 assert(config_path);
1739
1740 if (strv_isempty(list))
1741 return 0;
1742
1743 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance) {
1744 UnitFileInstallInfo instance = {
1745 .type = _UNIT_FILE_TYPE_INVALID,
1746 };
1747 _cleanup_free_ char *path = NULL;
1748
1749 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1750 if (r < 0)
1751 return r;
1752
1753 instance.name = buf;
1754 r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
1755 if (r < 0)
1756 return r;
1757
1758 path = TAKE_PTR(instance.path);
1759
1760 if (instance.type == UNIT_FILE_TYPE_MASKED) {
1761 unit_file_changes_add(changes, n_changes, -ERFKILL, path, NULL);
1762 return -ERFKILL;
1763 }
1764
1765 n = buf;
1766 } else
1767 n = i->name;
1768
1769 STRV_FOREACH(s, list) {
1770 _cleanup_free_ char *path = NULL, *dst = NULL;
1771
1772 q = install_full_printf(i, *s, &dst);
1773 if (q < 0)
1774 return q;
1775
1776 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
1777 r = -EINVAL;
1778 continue;
1779 }
1780
1781 path = strjoin(config_path, "/", dst, suffix, n);
1782 if (!path)
1783 return -ENOMEM;
1784
1785 q = create_symlink(paths, i->path, path, true, changes, n_changes);
1786 if (r == 0)
1787 r = q;
1788 }
1789
1790 return r;
1791 }
1792
1793 static int install_info_symlink_link(
1794 UnitFileInstallInfo *i,
1795 const LookupPaths *paths,
1796 const char *config_path,
1797 bool force,
1798 UnitFileChange **changes,
1799 size_t *n_changes) {
1800
1801 _cleanup_free_ char *path = NULL;
1802 int r;
1803
1804 assert(i);
1805 assert(paths);
1806 assert(config_path);
1807 assert(i->path);
1808
1809 r = in_search_path(paths, i->path);
1810 if (r < 0)
1811 return r;
1812 if (r > 0)
1813 return 0;
1814
1815 path = strjoin(config_path, "/", i->name);
1816 if (!path)
1817 return -ENOMEM;
1818
1819 return create_symlink(paths, i->path, path, force, changes, n_changes);
1820 }
1821
1822 static int install_info_apply(
1823 UnitFileInstallInfo *i,
1824 const LookupPaths *paths,
1825 const char *config_path,
1826 bool force,
1827 UnitFileChange **changes,
1828 size_t *n_changes) {
1829
1830 int r, q;
1831
1832 assert(i);
1833 assert(paths);
1834 assert(config_path);
1835
1836 if (i->type != UNIT_FILE_TYPE_REGULAR)
1837 return 0;
1838
1839 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
1840
1841 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
1842 if (r == 0)
1843 r = q;
1844
1845 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
1846 if (r == 0)
1847 r = q;
1848
1849 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1850 /* Do not count links to the unit file towards the "carries_install_info" count */
1851 if (r == 0 && q < 0)
1852 r = q;
1853
1854 return r;
1855 }
1856
1857 static int install_context_apply(
1858 UnitFileScope scope,
1859 InstallContext *c,
1860 const LookupPaths *paths,
1861 const char *config_path,
1862 bool force,
1863 SearchFlags flags,
1864 UnitFileChange **changes,
1865 size_t *n_changes) {
1866
1867 UnitFileInstallInfo *i;
1868 int r;
1869
1870 assert(c);
1871 assert(paths);
1872 assert(config_path);
1873
1874 if (ordered_hashmap_isempty(c->will_process))
1875 return 0;
1876
1877 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
1878 if (r < 0)
1879 return r;
1880
1881 r = 0;
1882 while ((i = ordered_hashmap_first(c->will_process))) {
1883 int q;
1884
1885 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1886 if (q < 0)
1887 return q;
1888
1889 r = install_info_traverse(scope, c, paths, i, flags, NULL);
1890 if (r < 0) {
1891 unit_file_changes_add(changes, n_changes, r, i->name, NULL);
1892 return r;
1893 }
1894
1895 /* We can attempt to process a masked unit when a different unit
1896 * that we were processing specifies it in Also=. */
1897 if (i->type == UNIT_FILE_TYPE_MASKED) {
1898 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL);
1899 if (r >= 0)
1900 /* Assume that something *could* have been enabled here,
1901 * avoid "empty [Install] section" warning. */
1902 r += 1;
1903 continue;
1904 }
1905
1906 if (i->type != UNIT_FILE_TYPE_REGULAR)
1907 continue;
1908
1909 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1910 if (r >= 0) {
1911 if (q < 0)
1912 r = q;
1913 else
1914 r += q;
1915 }
1916 }
1917
1918 return r;
1919 }
1920
1921 static int install_context_mark_for_removal(
1922 UnitFileScope scope,
1923 InstallContext *c,
1924 const LookupPaths *paths,
1925 Set **remove_symlinks_to,
1926 const char *config_path,
1927 UnitFileChange **changes,
1928 size_t *n_changes) {
1929
1930 UnitFileInstallInfo *i;
1931 int r;
1932
1933 assert(c);
1934 assert(paths);
1935 assert(config_path);
1936
1937 /* Marks all items for removal */
1938
1939 if (ordered_hashmap_isempty(c->will_process))
1940 return 0;
1941
1942 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
1943 if (r < 0)
1944 return r;
1945
1946 while ((i = ordered_hashmap_first(c->will_process))) {
1947
1948 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1949 if (r < 0)
1950 return r;
1951
1952 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
1953 if (r == -ENOLINK) {
1954 log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name);
1955 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL);
1956 } else if (r == -ENOENT) {
1957
1958 if (i->auxiliary) /* some unit specified in Also= or similar is missing */
1959 log_debug_errno(r, "Auxiliary unit of %s not found, removing name.", i->name);
1960 else {
1961 log_debug_errno(r, "Unit %s not found, removing name.", i->name);
1962 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
1963 }
1964
1965 } else if (r < 0) {
1966 log_debug_errno(r, "Failed to find unit %s, removing name: %m", i->name);
1967 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
1968 } else if (i->type == UNIT_FILE_TYPE_MASKED) {
1969 log_debug("Unit file %s is masked, ignoring.", i->name);
1970 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path ?: i->name, NULL);
1971 continue;
1972 } else if (i->type != UNIT_FILE_TYPE_REGULAR) {
1973 log_debug("Unit %s has type %s, ignoring.", i->name, unit_file_type_to_string(i->type) ?: "invalid");
1974 continue;
1975 }
1976
1977 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1978 if (r < 0)
1979 return r;
1980 }
1981
1982 return 0;
1983 }
1984
1985 int unit_file_mask(
1986 UnitFileScope scope,
1987 UnitFileFlags flags,
1988 const char *root_dir,
1989 char **files,
1990 UnitFileChange **changes,
1991 size_t *n_changes) {
1992
1993 _cleanup_(lookup_paths_free) LookupPaths paths = {};
1994 const char *config_path;
1995 char **i;
1996 int r;
1997
1998 assert(scope >= 0);
1999 assert(scope < _UNIT_FILE_SCOPE_MAX);
2000
2001 r = lookup_paths_init(&paths, scope, 0, root_dir);
2002 if (r < 0)
2003 return r;
2004
2005 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2006 if (!config_path)
2007 return -ENXIO;
2008
2009 STRV_FOREACH(i, files) {
2010 _cleanup_free_ char *path = NULL;
2011 int q;
2012
2013 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
2014 if (r == 0)
2015 r = -EINVAL;
2016 continue;
2017 }
2018
2019 path = path_make_absolute(*i, config_path);
2020 if (!path)
2021 return -ENOMEM;
2022
2023 q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
2024 if (q < 0 && r >= 0)
2025 r = q;
2026 }
2027
2028 return r;
2029 }
2030
2031 int unit_file_unmask(
2032 UnitFileScope scope,
2033 UnitFileFlags flags,
2034 const char *root_dir,
2035 char **files,
2036 UnitFileChange **changes,
2037 size_t *n_changes) {
2038
2039 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2040 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2041 _cleanup_strv_free_ char **todo = NULL;
2042 size_t n_todo = 0, n_allocated = 0;
2043 const char *config_path;
2044 char **i;
2045 bool dry_run;
2046 int r, q;
2047
2048 assert(scope >= 0);
2049 assert(scope < _UNIT_FILE_SCOPE_MAX);
2050
2051 r = lookup_paths_init(&paths, scope, 0, root_dir);
2052 if (r < 0)
2053 return r;
2054
2055 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2056 if (!config_path)
2057 return -ENXIO;
2058
2059 dry_run = !!(flags & UNIT_FILE_DRY_RUN);
2060
2061 STRV_FOREACH(i, files) {
2062 _cleanup_free_ char *path = NULL;
2063
2064 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2065 return -EINVAL;
2066
2067 path = path_make_absolute(*i, config_path);
2068 if (!path)
2069 return -ENOMEM;
2070
2071 r = null_or_empty_path(path);
2072 if (r == -ENOENT)
2073 continue;
2074 if (r < 0)
2075 return r;
2076 if (r == 0)
2077 continue;
2078
2079 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2080 return -ENOMEM;
2081
2082 todo[n_todo] = strdup(*i);
2083 if (!todo[n_todo])
2084 return -ENOMEM;
2085
2086 n_todo++;
2087 }
2088
2089 strv_uniq(todo);
2090
2091 r = 0;
2092 STRV_FOREACH(i, todo) {
2093 _cleanup_free_ char *path = NULL;
2094 const char *rp;
2095
2096 path = path_make_absolute(*i, config_path);
2097 if (!path)
2098 return -ENOMEM;
2099
2100 if (!dry_run && unlink(path) < 0) {
2101 if (errno != ENOENT) {
2102 if (r >= 0)
2103 r = -errno;
2104 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
2105 }
2106
2107 continue;
2108 }
2109
2110 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
2111
2112 rp = skip_root(&paths, path);
2113 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
2114 if (q < 0)
2115 return q;
2116 }
2117
2118 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
2119 if (r >= 0)
2120 r = q;
2121
2122 return r;
2123 }
2124
2125 int unit_file_link(
2126 UnitFileScope scope,
2127 UnitFileFlags flags,
2128 const char *root_dir,
2129 char **files,
2130 UnitFileChange **changes,
2131 size_t *n_changes) {
2132
2133 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2134 _cleanup_strv_free_ char **todo = NULL;
2135 size_t n_todo = 0, n_allocated = 0;
2136 const char *config_path;
2137 char **i;
2138 int r, q;
2139
2140 assert(scope >= 0);
2141 assert(scope < _UNIT_FILE_SCOPE_MAX);
2142
2143 r = lookup_paths_init(&paths, scope, 0, root_dir);
2144 if (r < 0)
2145 return r;
2146
2147 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2148 if (!config_path)
2149 return -ENXIO;
2150
2151 STRV_FOREACH(i, files) {
2152 _cleanup_free_ char *full = NULL;
2153 struct stat st;
2154 char *fn;
2155
2156 if (!path_is_absolute(*i))
2157 return -EINVAL;
2158
2159 fn = basename(*i);
2160 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
2161 return -EINVAL;
2162
2163 full = prefix_root(paths.root_dir, *i);
2164 if (!full)
2165 return -ENOMEM;
2166
2167 if (lstat(full, &st) < 0)
2168 return -errno;
2169 r = stat_verify_regular(&st);
2170 if (r < 0)
2171 return r;
2172
2173 q = in_search_path(&paths, *i);
2174 if (q < 0)
2175 return q;
2176 if (q > 0)
2177 continue;
2178
2179 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2180 return -ENOMEM;
2181
2182 todo[n_todo] = strdup(*i);
2183 if (!todo[n_todo])
2184 return -ENOMEM;
2185
2186 n_todo++;
2187 }
2188
2189 strv_uniq(todo);
2190
2191 r = 0;
2192 STRV_FOREACH(i, todo) {
2193 _cleanup_free_ char *new_path = NULL;
2194
2195 new_path = path_make_absolute(basename(*i), config_path);
2196 if (!new_path)
2197 return -ENOMEM;
2198
2199 q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
2200 if (q < 0 && r >= 0)
2201 r = q;
2202 }
2203
2204 return r;
2205 }
2206
2207 static int path_shall_revert(const LookupPaths *paths, const char *path) {
2208 int r;
2209
2210 assert(paths);
2211 assert(path);
2212
2213 /* Checks whether the path is one where the drop-in directories shall be removed. */
2214
2215 r = path_is_config(paths, path, true);
2216 if (r != 0)
2217 return r;
2218
2219 r = path_is_control(paths, path);
2220 if (r != 0)
2221 return r;
2222
2223 return path_is_transient(paths, path);
2224 }
2225
2226 int unit_file_revert(
2227 UnitFileScope scope,
2228 const char *root_dir,
2229 char **files,
2230 UnitFileChange **changes,
2231 size_t *n_changes) {
2232
2233 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2234 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2235 _cleanup_strv_free_ char **todo = NULL;
2236 size_t n_todo = 0, n_allocated = 0;
2237 char **i;
2238 int r, q;
2239
2240 /* Puts a unit file back into vendor state. This means:
2241 *
2242 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2243 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2244 *
2245 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2246 * "config", but not in "transient" or "control" or even "generated").
2247 *
2248 * We remove all that in both the runtime and the persistent directories, if that applies.
2249 */
2250
2251 r = lookup_paths_init(&paths, scope, 0, root_dir);
2252 if (r < 0)
2253 return r;
2254
2255 STRV_FOREACH(i, files) {
2256 bool has_vendor = false;
2257 char **p;
2258
2259 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2260 return -EINVAL;
2261
2262 STRV_FOREACH(p, paths.search_path) {
2263 _cleanup_free_ char *path = NULL, *dropin = NULL;
2264 struct stat st;
2265
2266 path = path_make_absolute(*i, *p);
2267 if (!path)
2268 return -ENOMEM;
2269
2270 r = lstat(path, &st);
2271 if (r < 0) {
2272 if (errno != ENOENT)
2273 return -errno;
2274 } else if (S_ISREG(st.st_mode)) {
2275 /* Check if there's a vendor version */
2276 r = path_is_vendor(&paths, path);
2277 if (r < 0)
2278 return r;
2279 if (r > 0)
2280 has_vendor = true;
2281 }
2282
2283 dropin = strappend(path, ".d");
2284 if (!dropin)
2285 return -ENOMEM;
2286
2287 r = lstat(dropin, &st);
2288 if (r < 0) {
2289 if (errno != ENOENT)
2290 return -errno;
2291 } else if (S_ISDIR(st.st_mode)) {
2292 /* Remove the drop-ins */
2293 r = path_shall_revert(&paths, dropin);
2294 if (r < 0)
2295 return r;
2296 if (r > 0) {
2297 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2298 return -ENOMEM;
2299
2300 todo[n_todo++] = TAKE_PTR(dropin);
2301 }
2302 }
2303 }
2304
2305 if (!has_vendor)
2306 continue;
2307
2308 /* OK, there's a vendor version, hence drop all configuration versions */
2309 STRV_FOREACH(p, paths.search_path) {
2310 _cleanup_free_ char *path = NULL;
2311 struct stat st;
2312
2313 path = path_make_absolute(*i, *p);
2314 if (!path)
2315 return -ENOMEM;
2316
2317 r = lstat(path, &st);
2318 if (r < 0) {
2319 if (errno != ENOENT)
2320 return -errno;
2321 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
2322 r = path_is_config(&paths, path, true);
2323 if (r < 0)
2324 return r;
2325 if (r > 0) {
2326 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2327 return -ENOMEM;
2328
2329 todo[n_todo++] = TAKE_PTR(path);
2330 }
2331 }
2332 }
2333 }
2334
2335 strv_uniq(todo);
2336
2337 r = 0;
2338 STRV_FOREACH(i, todo) {
2339 _cleanup_strv_free_ char **fs = NULL;
2340 const char *rp;
2341 char **j;
2342
2343 (void) get_files_in_directory(*i, &fs);
2344
2345 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2346 if (q < 0 && q != -ENOENT && r >= 0) {
2347 r = q;
2348 continue;
2349 }
2350
2351 STRV_FOREACH(j, fs) {
2352 _cleanup_free_ char *t = NULL;
2353
2354 t = strjoin(*i, "/", *j);
2355 if (!t)
2356 return -ENOMEM;
2357
2358 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
2359 }
2360
2361 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
2362
2363 rp = skip_root(&paths, *i);
2364 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2365 if (q < 0)
2366 return q;
2367 }
2368
2369 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes);
2370 if (r >= 0)
2371 r = q;
2372
2373 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes);
2374 if (r >= 0)
2375 r = q;
2376
2377 return r;
2378 }
2379
2380 int unit_file_add_dependency(
2381 UnitFileScope scope,
2382 UnitFileFlags flags,
2383 const char *root_dir,
2384 char **files,
2385 const char *target,
2386 UnitDependency dep,
2387 UnitFileChange **changes,
2388 size_t *n_changes) {
2389
2390 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2391 _cleanup_(install_context_done) InstallContext c = {};
2392 UnitFileInstallInfo *i, *target_info;
2393 const char *config_path;
2394 char **f;
2395 int r;
2396
2397 assert(scope >= 0);
2398 assert(scope < _UNIT_FILE_SCOPE_MAX);
2399 assert(target);
2400
2401 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
2402 return -EINVAL;
2403
2404 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2405 return -EINVAL;
2406
2407 r = lookup_paths_init(&paths, scope, 0, root_dir);
2408 if (r < 0)
2409 return r;
2410
2411 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2412 if (!config_path)
2413 return -ENXIO;
2414
2415 r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2416 &target_info, changes, n_changes);
2417 if (r < 0)
2418 return r;
2419 r = install_info_may_process(target_info, &paths, changes, n_changes);
2420 if (r < 0)
2421 return r;
2422
2423 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
2424
2425 STRV_FOREACH(f, files) {
2426 char ***l;
2427
2428 r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2429 &i, changes, n_changes);
2430 if (r < 0)
2431 return r;
2432 r = install_info_may_process(i, &paths, changes, n_changes);
2433 if (r < 0)
2434 return r;
2435
2436 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2437
2438 /* We didn't actually load anything from the unit
2439 * file, but instead just add in our new symlink to
2440 * create. */
2441
2442 if (dep == UNIT_WANTS)
2443 l = &i->wanted_by;
2444 else
2445 l = &i->required_by;
2446
2447 strv_free(*l);
2448 *l = strv_new(target_info->name, NULL);
2449 if (!*l)
2450 return -ENOMEM;
2451 }
2452
2453 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
2454 }
2455
2456 int unit_file_enable(
2457 UnitFileScope scope,
2458 UnitFileFlags flags,
2459 const char *root_dir,
2460 char **files,
2461 UnitFileChange **changes,
2462 size_t *n_changes) {
2463
2464 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2465 _cleanup_(install_context_done) InstallContext c = {};
2466 const char *config_path;
2467 UnitFileInstallInfo *i;
2468 char **f;
2469 int r;
2470
2471 assert(scope >= 0);
2472 assert(scope < _UNIT_FILE_SCOPE_MAX);
2473
2474 r = lookup_paths_init(&paths, scope, 0, root_dir);
2475 if (r < 0)
2476 return r;
2477
2478 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2479 if (!config_path)
2480 return -ENXIO;
2481
2482 STRV_FOREACH(f, files) {
2483 r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2484 &i, changes, n_changes);
2485 if (r < 0)
2486 return r;
2487 r = install_info_may_process(i, &paths, changes, n_changes);
2488 if (r < 0)
2489 return r;
2490
2491 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2492 }
2493
2494 /* This will return the number of symlink rules that were
2495 supposed to be created, not the ones actually created. This
2496 is useful to determine whether the passed files had any
2497 installation data at all. */
2498
2499 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
2500 }
2501
2502 int unit_file_disable(
2503 UnitFileScope scope,
2504 UnitFileFlags flags,
2505 const char *root_dir,
2506 char **files,
2507 UnitFileChange **changes,
2508 size_t *n_changes) {
2509
2510 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2511 _cleanup_(install_context_done) InstallContext c = {};
2512 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2513 const char *config_path;
2514 char **i;
2515 int r;
2516
2517 assert(scope >= 0);
2518 assert(scope < _UNIT_FILE_SCOPE_MAX);
2519
2520 r = lookup_paths_init(&paths, scope, 0, root_dir);
2521 if (r < 0)
2522 return r;
2523
2524 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2525 if (!config_path)
2526 return -ENXIO;
2527
2528 STRV_FOREACH(i, files) {
2529 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2530 return -EINVAL;
2531
2532 r = install_info_add(&c, *i, NULL, false, NULL);
2533 if (r < 0)
2534 return r;
2535 }
2536
2537 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
2538 if (r < 0)
2539 return r;
2540
2541 return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
2542 }
2543
2544 int unit_file_reenable(
2545 UnitFileScope scope,
2546 UnitFileFlags flags,
2547 const char *root_dir,
2548 char **files,
2549 UnitFileChange **changes,
2550 size_t *n_changes) {
2551
2552 char **n;
2553 int r;
2554 size_t l, i;
2555
2556 /* First, we invoke the disable command with only the basename... */
2557 l = strv_length(files);
2558 n = newa(char*, l+1);
2559 for (i = 0; i < l; i++)
2560 n[i] = basename(files[i]);
2561 n[i] = NULL;
2562
2563 r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
2564 if (r < 0)
2565 return r;
2566
2567 /* But the enable command with the full name */
2568 return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
2569 }
2570
2571 int unit_file_set_default(
2572 UnitFileScope scope,
2573 UnitFileFlags flags,
2574 const char *root_dir,
2575 const char *name,
2576 UnitFileChange **changes,
2577 size_t *n_changes) {
2578
2579 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2580 _cleanup_(install_context_done) InstallContext c = {};
2581 UnitFileInstallInfo *i;
2582 const char *new_path;
2583 int r;
2584
2585 assert(scope >= 0);
2586 assert(scope < _UNIT_FILE_SCOPE_MAX);
2587 assert(name);
2588
2589 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
2590 return -EINVAL;
2591 if (streq(name, SPECIAL_DEFAULT_TARGET))
2592 return -EINVAL;
2593
2594 r = lookup_paths_init(&paths, scope, 0, root_dir);
2595 if (r < 0)
2596 return r;
2597
2598 r = install_info_discover(scope, &c, &paths, name, 0, &i, changes, n_changes);
2599 if (r < 0)
2600 return r;
2601 r = install_info_may_process(i, &paths, changes, n_changes);
2602 if (r < 0)
2603 return r;
2604
2605 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
2606 return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
2607 }
2608
2609 int unit_file_get_default(
2610 UnitFileScope scope,
2611 const char *root_dir,
2612 char **name) {
2613
2614 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2615 _cleanup_(install_context_done) InstallContext c = {};
2616 UnitFileInstallInfo *i;
2617 char *n;
2618 int r;
2619
2620 assert(scope >= 0);
2621 assert(scope < _UNIT_FILE_SCOPE_MAX);
2622 assert(name);
2623
2624 r = lookup_paths_init(&paths, scope, 0, root_dir);
2625 if (r < 0)
2626 return r;
2627
2628 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2629 &i, NULL, NULL);
2630 if (r < 0)
2631 return r;
2632 r = install_info_may_process(i, &paths, NULL, 0);
2633 if (r < 0)
2634 return r;
2635
2636 n = strdup(i->name);
2637 if (!n)
2638 return -ENOMEM;
2639
2640 *name = n;
2641 return 0;
2642 }
2643
2644 int unit_file_lookup_state(
2645 UnitFileScope scope,
2646 const LookupPaths *paths,
2647 const char *name,
2648 UnitFileState *ret) {
2649
2650 _cleanup_(install_context_done) InstallContext c = {};
2651 UnitFileInstallInfo *i;
2652 UnitFileState state;
2653 int r;
2654
2655 assert(paths);
2656 assert(name);
2657
2658 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2659 return -EINVAL;
2660
2661 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2662 &i, NULL, NULL);
2663 if (r < 0)
2664 return r;
2665
2666 /* Shortcut things, if the caller just wants to know if this unit exists. */
2667 if (!ret)
2668 return 0;
2669
2670 switch (i->type) {
2671
2672 case UNIT_FILE_TYPE_MASKED:
2673 r = path_is_runtime(paths, i->path, true);
2674 if (r < 0)
2675 return r;
2676
2677 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
2678 break;
2679
2680 case UNIT_FILE_TYPE_REGULAR:
2681 r = path_is_generator(paths, i->path);
2682 if (r < 0)
2683 return r;
2684 if (r > 0) {
2685 state = UNIT_FILE_GENERATED;
2686 break;
2687 }
2688
2689 r = path_is_transient(paths, i->path);
2690 if (r < 0)
2691 return r;
2692 if (r > 0) {
2693 state = UNIT_FILE_TRANSIENT;
2694 break;
2695 }
2696
2697 /* Check if any of the Alias= symlinks have been created.
2698 * We ignore other aliases, and only check those that would
2699 * be created by systemctl enable for this unit. */
2700 r = find_symlinks_in_scope(scope, paths, i, true, &state);
2701 if (r < 0)
2702 return r;
2703 if (r > 0)
2704 break;
2705
2706 /* Check if the file is known under other names. If it is,
2707 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2708 r = find_symlinks_in_scope(scope, paths, i, false, &state);
2709 if (r < 0)
2710 return r;
2711 if (r > 0)
2712 state = UNIT_FILE_INDIRECT;
2713 else {
2714 if (unit_file_install_info_has_rules(i))
2715 state = UNIT_FILE_DISABLED;
2716 else if (unit_file_install_info_has_also(i))
2717 state = UNIT_FILE_INDIRECT;
2718 else
2719 state = UNIT_FILE_STATIC;
2720 }
2721
2722 break;
2723
2724 default:
2725 assert_not_reached("Unexpect unit file type.");
2726 }
2727
2728 *ret = state;
2729 return 0;
2730 }
2731
2732 int unit_file_get_state(
2733 UnitFileScope scope,
2734 const char *root_dir,
2735 const char *name,
2736 UnitFileState *ret) {
2737
2738 _cleanup_(lookup_paths_free) LookupPaths paths = {};
2739 int r;
2740
2741 assert(scope >= 0);
2742 assert(scope < _UNIT_FILE_SCOPE_MAX);
2743 assert(name);
2744
2745 r = lookup_paths_init(&paths, scope, 0, root_dir);
2746 if (r < 0)
2747 return r;
2748
2749 return unit_file_lookup_state(scope, &paths, name, ret);
2750 }
2751
2752 int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2753 _cleanup_(install_context_done) InstallContext c = {};
2754 int r;
2755
2756 assert(paths);
2757 assert(name);
2758
2759 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2760 return -EINVAL;
2761
2762 r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
2763 if (r == -ENOENT)
2764 return 0;
2765 if (r < 0)
2766 return r;
2767
2768 return 1;
2769 }
2770
2771 static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2772 _cleanup_(presets_freep) Presets ps = {};
2773 size_t n_allocated = 0;
2774 _cleanup_strv_free_ char **files = NULL;
2775 char **p;
2776 int r;
2777
2778 assert(scope >= 0);
2779 assert(scope < _UNIT_FILE_SCOPE_MAX);
2780 assert(presets);
2781
2782 switch (scope) {
2783 case UNIT_FILE_SYSTEM:
2784 r = conf_files_list(&files, ".preset", root_dir, 0,
2785 "/etc/systemd/system-preset",
2786 "/run/systemd/system-preset",
2787 "/usr/local/lib/systemd/system-preset",
2788 "/usr/lib/systemd/system-preset",
2789 #if HAVE_SPLIT_USR
2790 "/lib/systemd/system-preset",
2791 #endif
2792 NULL);
2793 break;
2794
2795 case UNIT_FILE_GLOBAL:
2796 case UNIT_FILE_USER:
2797 r = conf_files_list(&files, ".preset", root_dir, 0,
2798 "/etc/systemd/user-preset",
2799 "/run/systemd/user-preset",
2800 "/usr/local/lib/systemd/user-preset",
2801 "/usr/lib/systemd/user-preset",
2802 NULL);
2803 break;
2804
2805 default:
2806 assert_not_reached("Invalid unit file scope");
2807 }
2808
2809 if (r < 0)
2810 return r;
2811
2812 STRV_FOREACH(p, files) {
2813 _cleanup_fclose_ FILE *f;
2814 char line[LINE_MAX];
2815 int n = 0;
2816
2817 f = fopen(*p, "re");
2818 if (!f) {
2819 if (errno == ENOENT)
2820 continue;
2821
2822 return -errno;
2823 }
2824
2825 FOREACH_LINE(line, f, return -errno) {
2826 PresetRule rule = {};
2827 const char *parameter;
2828 char *l;
2829
2830 l = strstrip(line);
2831 n++;
2832
2833 if (isempty(l))
2834 continue;
2835 if (strchr(COMMENTS, *l))
2836 continue;
2837
2838 parameter = first_word(l, "enable");
2839 if (parameter) {
2840 char *pattern;
2841
2842 pattern = strdup(parameter);
2843 if (!pattern)
2844 return -ENOMEM;
2845
2846 rule = (PresetRule) {
2847 .pattern = pattern,
2848 .action = PRESET_ENABLE,
2849 };
2850 }
2851
2852 parameter = first_word(l, "disable");
2853 if (parameter) {
2854 char *pattern;
2855
2856 pattern = strdup(parameter);
2857 if (!pattern)
2858 return -ENOMEM;
2859
2860 rule = (PresetRule) {
2861 .pattern = pattern,
2862 .action = PRESET_DISABLE,
2863 };
2864 }
2865
2866 if (rule.action) {
2867 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
2868 return -ENOMEM;
2869
2870 ps.rules[ps.n_rules++] = rule;
2871 continue;
2872 }
2873
2874 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
2875 }
2876 }
2877
2878 *presets = ps;
2879 ps = (Presets){};
2880
2881 return 0;
2882 }
2883
2884 static int query_presets(const char *name, const Presets presets) {
2885 PresetAction action = PRESET_UNKNOWN;
2886 size_t i;
2887
2888 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2889 return -EINVAL;
2890
2891 for (i = 0; i < presets.n_rules; i++)
2892 if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
2893 action = presets.rules[i].action;
2894 break;
2895 }
2896
2897 switch (action) {
2898 case PRESET_UNKNOWN:
2899 log_debug("Preset files don't specify rule for %s. Enabling.", name);
2900 return 1;
2901 case PRESET_ENABLE:
2902 log_debug("Preset files say enable %s.", name);
2903 return 1;
2904 case PRESET_DISABLE:
2905 log_debug("Preset files say disable %s.", name);
2906 return 0;
2907 default:
2908 assert_not_reached("invalid preset action");
2909 }
2910 }
2911
2912 int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
2913 _cleanup_(presets_freep) Presets presets = {};
2914 int r;
2915
2916 r = read_presets(scope, root_dir, &presets);
2917 if (r < 0)
2918 return r;
2919
2920 return query_presets(name, presets);
2921 }
2922
2923 static int execute_preset(
2924 UnitFileScope scope,
2925 InstallContext *plus,
2926 InstallContext *minus,
2927 const LookupPaths *paths,
2928 const char *config_path,
2929 char **files,
2930 UnitFilePresetMode mode,
2931 bool force,
2932 UnitFileChange **changes,
2933 size_t *n_changes) {
2934
2935 int r;
2936
2937 assert(plus);
2938 assert(minus);
2939 assert(paths);
2940 assert(config_path);
2941
2942 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
2943 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2944
2945 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
2946 if (r < 0)
2947 return r;
2948
2949 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
2950 } else
2951 r = 0;
2952
2953 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
2954 int q;
2955
2956 /* Returns number of symlinks that where supposed to be installed. */
2957 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
2958 if (r >= 0) {
2959 if (q < 0)
2960 r = q;
2961 else
2962 r += q;
2963 }
2964 }
2965
2966 return r;
2967 }
2968
2969 static int preset_prepare_one(
2970 UnitFileScope scope,
2971 InstallContext *plus,
2972 InstallContext *minus,
2973 LookupPaths *paths,
2974 const char *name,
2975 Presets presets,
2976 UnitFileChange **changes,
2977 size_t *n_changes) {
2978
2979 _cleanup_(install_context_done) InstallContext tmp = {};
2980 UnitFileInstallInfo *i;
2981 int r;
2982
2983 if (install_info_find(plus, name) || install_info_find(minus, name))
2984 return 0;
2985
2986 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2987 &i, changes, n_changes);
2988 if (r < 0)
2989 return r;
2990 if (!streq(name, i->name)) {
2991 log_debug("Skipping %s because it is an alias for %s.", name, i->name);
2992 return 0;
2993 }
2994
2995 r = query_presets(name, presets);
2996 if (r < 0)
2997 return r;
2998
2999 if (r > 0) {
3000 r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
3001 &i, changes, n_changes);
3002 if (r < 0)
3003 return r;
3004
3005 r = install_info_may_process(i, paths, changes, n_changes);
3006 if (r < 0)
3007 return r;
3008 } else
3009 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
3010 &i, changes, n_changes);
3011
3012 return r;
3013 }
3014
3015 int unit_file_preset(
3016 UnitFileScope scope,
3017 UnitFileFlags flags,
3018 const char *root_dir,
3019 char **files,
3020 UnitFilePresetMode mode,
3021 UnitFileChange **changes,
3022 size_t *n_changes) {
3023
3024 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
3025 _cleanup_(lookup_paths_free) LookupPaths paths = {};
3026 _cleanup_(presets_freep) Presets presets = {};
3027 const char *config_path;
3028 char **i;
3029 int r;
3030
3031 assert(scope >= 0);
3032 assert(scope < _UNIT_FILE_SCOPE_MAX);
3033 assert(mode < _UNIT_FILE_PRESET_MAX);
3034
3035 r = lookup_paths_init(&paths, scope, 0, root_dir);
3036 if (r < 0)
3037 return r;
3038
3039 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
3040 if (!config_path)
3041 return -ENXIO;
3042
3043 r = read_presets(scope, root_dir, &presets);
3044 if (r < 0)
3045 return r;
3046
3047 STRV_FOREACH(i, files) {
3048 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
3049 if (r < 0)
3050 return r;
3051 }
3052
3053 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
3054 }
3055
3056 int unit_file_preset_all(
3057 UnitFileScope scope,
3058 UnitFileFlags flags,
3059 const char *root_dir,
3060 UnitFilePresetMode mode,
3061 UnitFileChange **changes,
3062 size_t *n_changes) {
3063
3064 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
3065 _cleanup_(lookup_paths_free) LookupPaths paths = {};
3066 _cleanup_(presets_freep) Presets presets = {};
3067 const char *config_path = NULL;
3068 char **i;
3069 int r;
3070
3071 assert(scope >= 0);
3072 assert(scope < _UNIT_FILE_SCOPE_MAX);
3073 assert(mode < _UNIT_FILE_PRESET_MAX);
3074
3075 r = lookup_paths_init(&paths, scope, 0, root_dir);
3076 if (r < 0)
3077 return r;
3078
3079 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
3080 if (!config_path)
3081 return -ENXIO;
3082
3083 r = read_presets(scope, root_dir, &presets);
3084 if (r < 0)
3085 return r;
3086
3087 STRV_FOREACH(i, paths.search_path) {
3088 _cleanup_closedir_ DIR *d = NULL;
3089 struct dirent *de;
3090
3091 d = opendir(*i);
3092 if (!d) {
3093 if (errno == ENOENT)
3094 continue;
3095
3096 return -errno;
3097 }
3098
3099 FOREACH_DIRENT(de, d, return -errno) {
3100
3101 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
3102 continue;
3103
3104 dirent_ensure_type(d, de);
3105
3106 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
3107 continue;
3108
3109 /* we don't pass changes[] in, because we want to handle errors on our own */
3110 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
3111 if (r == -ERFKILL)
3112 r = unit_file_changes_add(changes, n_changes,
3113 UNIT_FILE_IS_MASKED, de->d_name, NULL);
3114 else if (r == -ENOLINK)
3115 r = unit_file_changes_add(changes, n_changes,
3116 UNIT_FILE_IS_DANGLING, de->d_name, NULL);
3117 else if (r == -EADDRNOTAVAIL) /* Ignore generated/transient units when applying preset */
3118 continue;
3119 if (r < 0)
3120 return r;
3121 }
3122 }
3123
3124 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
3125 }
3126
3127 static void unit_file_list_free_one(UnitFileList *f) {
3128 if (!f)
3129 return;
3130
3131 free(f->path);
3132 free(f);
3133 }
3134
3135 Hashmap* unit_file_list_free(Hashmap *h) {
3136 return hashmap_free_with_destructor(h, unit_file_list_free_one);
3137 }
3138
3139 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
3140
3141 int unit_file_get_list(
3142 UnitFileScope scope,
3143 const char *root_dir,
3144 Hashmap *h,
3145 char **states,
3146 char **patterns) {
3147
3148 _cleanup_(lookup_paths_free) LookupPaths paths = {};
3149 char **i;
3150 int r;
3151
3152 assert(scope >= 0);
3153 assert(scope < _UNIT_FILE_SCOPE_MAX);
3154 assert(h);
3155
3156 r = lookup_paths_init(&paths, scope, 0, root_dir);
3157 if (r < 0)
3158 return r;
3159
3160 STRV_FOREACH(i, paths.search_path) {
3161 _cleanup_closedir_ DIR *d = NULL;
3162 struct dirent *de;
3163
3164 d = opendir(*i);
3165 if (!d) {
3166 if (errno == ENOENT)
3167 continue;
3168 if (IN_SET(errno, ENOTDIR, EACCES)) {
3169 log_debug_errno(errno, "Failed to open \"%s\": %m", *i);
3170 continue;
3171 }
3172
3173 return -errno;
3174 }
3175
3176 FOREACH_DIRENT(de, d, return -errno) {
3177 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
3178
3179 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
3180 continue;
3181
3182 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
3183 continue;
3184
3185 if (hashmap_get(h, de->d_name))
3186 continue;
3187
3188 dirent_ensure_type(d, de);
3189
3190 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
3191 continue;
3192
3193 f = new0(UnitFileList, 1);
3194 if (!f)
3195 return -ENOMEM;
3196
3197 f->path = path_make_absolute(de->d_name, *i);
3198 if (!f->path)
3199 return -ENOMEM;
3200
3201 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
3202 if (r < 0)
3203 f->state = UNIT_FILE_BAD;
3204
3205 if (!strv_isempty(states) &&
3206 !strv_contains(states, unit_file_state_to_string(f->state)))
3207 continue;
3208
3209 r = hashmap_put(h, basename(f->path), f);
3210 if (r < 0)
3211 return r;
3212
3213 f = NULL; /* prevent cleanup */
3214 }
3215 }
3216
3217 return 0;
3218 }
3219
3220 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
3221 [UNIT_FILE_ENABLED] = "enabled",
3222 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
3223 [UNIT_FILE_LINKED] = "linked",
3224 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
3225 [UNIT_FILE_MASKED] = "masked",
3226 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
3227 [UNIT_FILE_STATIC] = "static",
3228 [UNIT_FILE_DISABLED] = "disabled",
3229 [UNIT_FILE_INDIRECT] = "indirect",
3230 [UNIT_FILE_GENERATED] = "generated",
3231 [UNIT_FILE_TRANSIENT] = "transient",
3232 [UNIT_FILE_BAD] = "bad",
3233 };
3234
3235 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
3236
3237 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
3238 [UNIT_FILE_SYMLINK] = "symlink",
3239 [UNIT_FILE_UNLINK] = "unlink",
3240 [UNIT_FILE_IS_MASKED] = "masked",
3241 [UNIT_FILE_IS_DANGLING] = "dangling",
3242 };
3243
3244 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
3245
3246 static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
3247 [UNIT_FILE_PRESET_FULL] = "full",
3248 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
3249 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
3250 };
3251
3252 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);