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