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