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