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