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