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