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