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