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