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