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