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