]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/install.c
Various formatting and style fixes
[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 "log.h"
44 #include "macro.h"
45 #include "mkdir.h"
46 #include "path-lookup.h"
47 #include "path-util.h"
48 #include "rm-rf.h"
49 #include "set.h"
50 #include "special.h"
51 #include "stat-util.h"
52 #include "string-table.h"
53 #include "string-util.h"
54 #include "strv.h"
55 #include "unit-name.h"
56
57 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
58
59 typedef enum SearchFlags {
60 SEARCH_LOAD = 1,
61 SEARCH_FOLLOW_CONFIG_SYMLINKS = 2,
62 } SearchFlags;
63
64 typedef struct {
65 OrderedHashmap *will_process;
66 OrderedHashmap *have_processed;
67 } InstallContext;
68
69 static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret);
70
71 static int in_search_path(const LookupPaths *p, const char *path) {
72 _cleanup_free_ char *parent = NULL;
73 char **i;
74
75 assert(path);
76
77 parent = dirname_malloc(path);
78 if (!parent)
79 return -ENOMEM;
80
81 STRV_FOREACH(i, p->search_path)
82 if (path_equal(parent, *i))
83 return true;
84
85 return false;
86 }
87
88 static const char* skip_root(const LookupPaths *p, const char *path) {
89 char *e;
90
91 assert(p);
92 assert(path);
93
94 if (!p->root_dir)
95 return path;
96
97 e = path_startswith(path, p->root_dir);
98 if (!e)
99 return NULL;
100
101 /* Make sure the returned path starts with a slash */
102 if (e[0] != '/') {
103 if (e == path || e[-1] != '/')
104 return NULL;
105
106 e--;
107 }
108
109 return e;
110 }
111
112 static int path_is_generator(const LookupPaths *p, const char *path) {
113 _cleanup_free_ char *parent = NULL;
114
115 assert(p);
116 assert(path);
117
118 parent = dirname_malloc(path);
119 if (!parent)
120 return -ENOMEM;
121
122 return path_equal_ptr(parent, p->generator) ||
123 path_equal_ptr(parent, p->generator_early) ||
124 path_equal_ptr(parent, p->generator_late);
125 }
126
127 static int path_is_transient(const LookupPaths *p, const char *path) {
128 _cleanup_free_ char *parent = NULL;
129
130 assert(p);
131 assert(path);
132
133 parent = dirname_malloc(path);
134 if (!parent)
135 return -ENOMEM;
136
137 return path_equal_ptr(parent, p->transient);
138 }
139
140 static int path_is_control(const LookupPaths *p, const char *path) {
141 _cleanup_free_ char *parent = NULL;
142
143 assert(p);
144 assert(path);
145
146 parent = dirname_malloc(path);
147 if (!parent)
148 return -ENOMEM;
149
150 return path_equal_ptr(parent, p->persistent_control) ||
151 path_equal_ptr(parent, p->runtime_control);
152 }
153
154 static int path_is_config(const LookupPaths *p, const char *path) {
155 _cleanup_free_ char *parent = NULL;
156
157 assert(p);
158 assert(path);
159
160 /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern
161 * configuration from transient or generated units */
162
163 parent = dirname_malloc(path);
164 if (!parent)
165 return -ENOMEM;
166
167 return path_equal_ptr(parent, p->persistent_config) ||
168 path_equal_ptr(parent, p->runtime_config);
169 }
170
171 static int path_is_runtime(const LookupPaths *p, const char *path) {
172 _cleanup_free_ char *parent = NULL;
173 const char *rpath;
174
175 assert(p);
176 assert(path);
177
178 /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime
179 * directories, as safety net. */
180
181 rpath = skip_root(p, path);
182 if (rpath && path_startswith(rpath, "/run"))
183 return true;
184
185 parent = dirname_malloc(path);
186 if (!parent)
187 return -ENOMEM;
188
189 return path_equal_ptr(parent, p->runtime_config) ||
190 path_equal_ptr(parent, p->generator) ||
191 path_equal_ptr(parent, p->generator_early) ||
192 path_equal_ptr(parent, p->generator_late) ||
193 path_equal_ptr(parent, p->transient) ||
194 path_equal_ptr(parent, p->runtime_control);
195 }
196
197 static int path_is_vendor(const LookupPaths *p, const char *path) {
198 const char *rpath;
199
200 assert(p);
201 assert(path);
202
203 rpath = skip_root(p, path);
204 if (!rpath)
205 return 0;
206
207 if (path_startswith(rpath, "/usr"))
208 return true;
209
210 #ifdef HAVE_SPLIT_USR
211 if (path_startswith(rpath, "/lib"))
212 return true;
213 #endif
214
215 return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
216 }
217
218 int unit_file_changes_add(
219 UnitFileChange **changes,
220 unsigned *n_changes,
221 UnitFileChangeType type,
222 const char *path,
223 const char *source) {
224
225 UnitFileChange *c;
226 unsigned i;
227
228 assert(path);
229 assert(!changes == !n_changes);
230
231 if (!changes)
232 return 0;
233
234 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
235 if (!c)
236 return -ENOMEM;
237
238 *changes = c;
239 i = *n_changes;
240
241 c[i].type = type;
242 c[i].path = strdup(path);
243 if (!c[i].path)
244 return -ENOMEM;
245
246 path_kill_slashes(c[i].path);
247
248 if (source) {
249 c[i].source = strdup(source);
250 if (!c[i].source) {
251 free(c[i].path);
252 return -ENOMEM;
253 }
254
255 path_kill_slashes(c[i].path);
256 } else
257 c[i].source = NULL;
258
259 *n_changes = i+1;
260 return 0;
261 }
262
263 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
264 unsigned i;
265
266 assert(changes || n_changes == 0);
267
268 if (!changes)
269 return;
270
271 for (i = 0; i < n_changes; i++) {
272 free(changes[i].path);
273 free(changes[i].source);
274 }
275
276 free(changes);
277 }
278
279 static int create_symlink(
280 const char *old_path,
281 const char *new_path,
282 bool force,
283 UnitFileChange **changes,
284 unsigned *n_changes) {
285
286 _cleanup_free_ char *dest = NULL;
287 int r;
288
289 assert(old_path);
290 assert(new_path);
291
292 /* Actually create a symlink, and remember that we did. Is
293 * smart enough to check if there's already a valid symlink in
294 * place. */
295
296 mkdir_parents_label(new_path, 0755);
297
298 if (symlink(old_path, new_path) >= 0) {
299 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
300 return 1;
301 }
302
303 if (errno != EEXIST)
304 return -errno;
305
306 r = readlink_malloc(new_path, &dest);
307 if (r < 0)
308 return r;
309
310 if (path_equal(dest, old_path))
311 return 0;
312
313 if (!force)
314 return -EEXIST;
315
316 r = symlink_atomic(old_path, new_path);
317 if (r < 0)
318 return r;
319
320 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
321 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
322
323 return 1;
324 }
325
326 static int mark_symlink_for_removal(
327 Set **remove_symlinks_to,
328 const char *p) {
329
330 char *n;
331 int r;
332
333 assert(p);
334
335 r = set_ensure_allocated(remove_symlinks_to, &string_hash_ops);
336 if (r < 0)
337 return r;
338
339 n = strdup(p);
340 if (!n)
341 return -ENOMEM;
342
343 path_kill_slashes(n);
344
345 r = set_consume(*remove_symlinks_to, n);
346 if (r == -EEXIST)
347 return 0;
348 if (r < 0)
349 return r;
350
351 return 1;
352 }
353
354 static int remove_marked_symlinks_fd(
355 Set *remove_symlinks_to,
356 int fd,
357 const char *path,
358 const char *config_path,
359 const LookupPaths *lp,
360 bool *restart,
361 UnitFileChange **changes,
362 unsigned *n_changes) {
363
364 _cleanup_closedir_ DIR *d = NULL;
365 struct dirent *de;
366 int r = 0;
367
368 assert(remove_symlinks_to);
369 assert(fd >= 0);
370 assert(path);
371 assert(config_path);
372 assert(lp);
373 assert(restart);
374
375 d = fdopendir(fd);
376 if (!d) {
377 safe_close(fd);
378 return -errno;
379 }
380
381 rewinddir(d);
382
383 FOREACH_DIRENT(de, d, return -errno) {
384
385 dirent_ensure_type(d, de);
386
387 if (de->d_type == DT_DIR) {
388 _cleanup_free_ char *p = NULL;
389 int nfd, q;
390
391 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
392 if (nfd < 0) {
393 if (errno == ENOENT)
394 continue;
395
396 if (r == 0)
397 r = -errno;
398 continue;
399 }
400
401 p = path_make_absolute(de->d_name, path);
402 if (!p) {
403 safe_close(nfd);
404 return -ENOMEM;
405 }
406
407 /* This will close nfd, regardless whether it succeeds or not */
408 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes);
409 if (q < 0 && r == 0)
410 r = q;
411
412 } else if (de->d_type == DT_LNK) {
413 _cleanup_free_ char *p = NULL, *dest = NULL;
414 const char *rp;
415 bool found;
416 int q;
417
418 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
419 continue;
420
421 p = path_make_absolute(de->d_name, path);
422 if (!p)
423 return -ENOMEM;
424
425 q = readlink_malloc(p, &dest);
426 if (q == -ENOENT)
427 continue;
428 if (q < 0) {
429 if (r == 0)
430 r = q;
431 continue;
432 }
433
434 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
435 * the same name as a file that is marked. */
436
437 found = set_contains(remove_symlinks_to, dest) ||
438 set_contains(remove_symlinks_to, basename(dest)) ||
439 set_contains(remove_symlinks_to, de->d_name);
440
441 if (!found)
442 continue;
443
444 if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
445 if (r == 0)
446 r = -errno;
447 continue;
448 }
449
450 path_kill_slashes(p);
451 (void) rmdir_parents(p, config_path);
452
453 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
454
455 /* Now, remember the full path (but with the root prefix removed) of the symlink we just
456 * removed, and remove any symlinks to it, too */
457
458 rp = skip_root(lp, p);
459 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
460 if (q < 0)
461 return q;
462 if (q > 0)
463 *restart = true;
464 }
465 }
466
467 return r;
468 }
469
470 static int remove_marked_symlinks(
471 Set *remove_symlinks_to,
472 const char *config_path,
473 const LookupPaths *lp,
474 UnitFileChange **changes,
475 unsigned *n_changes) {
476
477 _cleanup_close_ int fd = -1;
478 bool restart;
479 int r = 0;
480
481 assert(config_path);
482 assert(lp);
483
484 if (set_size(remove_symlinks_to) <= 0)
485 return 0;
486
487 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
488 if (fd < 0)
489 return -errno;
490
491 do {
492 int q, cfd;
493 restart = false;
494
495 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
496 if (cfd < 0)
497 return -errno;
498
499 /* This takes possession of cfd and closes it */
500 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes);
501 if (r == 0)
502 r = q;
503 } while (restart);
504
505 return r;
506 }
507
508 static int find_symlinks_fd(
509 const char *root_dir,
510 const char *name,
511 int fd,
512 const char *path,
513 const char *config_path,
514 const LookupPaths *lp,
515 bool *same_name_link) {
516
517 _cleanup_closedir_ DIR *d = NULL;
518 struct dirent *de;
519 int r = 0;
520
521 assert(name);
522 assert(fd >= 0);
523 assert(path);
524 assert(config_path);
525 assert(lp);
526 assert(same_name_link);
527
528 d = fdopendir(fd);
529 if (!d) {
530 safe_close(fd);
531 return -errno;
532 }
533
534 FOREACH_DIRENT(de, d, return -errno) {
535
536 dirent_ensure_type(d, de);
537
538 if (de->d_type == DT_DIR) {
539 _cleanup_free_ char *p = NULL;
540 int nfd, q;
541
542 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
543 if (nfd < 0) {
544 if (errno == ENOENT)
545 continue;
546
547 if (r == 0)
548 r = -errno;
549 continue;
550 }
551
552 p = path_make_absolute(de->d_name, path);
553 if (!p) {
554 safe_close(nfd);
555 return -ENOMEM;
556 }
557
558 /* This will close nfd, regardless whether it succeeds or not */
559 q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link);
560 if (q > 0)
561 return 1;
562 if (r == 0)
563 r = q;
564
565 } else if (de->d_type == DT_LNK) {
566 _cleanup_free_ char *p = NULL, *dest = NULL;
567 bool found_path, found_dest, b = false;
568 int q;
569
570 /* Acquire symlink name */
571 p = path_make_absolute(de->d_name, path);
572 if (!p)
573 return -ENOMEM;
574
575 /* Acquire symlink destination */
576 q = readlink_malloc(p, &dest);
577 if (q == -ENOENT)
578 continue;
579 if (q < 0) {
580 if (r == 0)
581 r = q;
582 continue;
583 }
584
585 /* Make absolute */
586 if (!path_is_absolute(dest)) {
587 char *x;
588
589 x = prefix_root(root_dir, dest);
590 if (!x)
591 return -ENOMEM;
592
593 free(dest);
594 dest = x;
595 }
596
597 /* Check if the symlink itself matches what we
598 * are looking for */
599 if (path_is_absolute(name))
600 found_path = path_equal(p, name);
601 else
602 found_path = streq(de->d_name, name);
603
604 /* Check if what the symlink points to
605 * matches what we are looking for */
606 if (path_is_absolute(name))
607 found_dest = path_equal(dest, name);
608 else
609 found_dest = streq(basename(dest), name);
610
611 if (found_path && found_dest) {
612 _cleanup_free_ char *t = NULL;
613
614 /* Filter out same name links in the main
615 * config path */
616 t = path_make_absolute(name, config_path);
617 if (!t)
618 return -ENOMEM;
619
620 b = path_equal(t, p);
621 }
622
623 if (b)
624 *same_name_link = true;
625 else if (found_path || found_dest)
626 return 1;
627 }
628 }
629
630 return r;
631 }
632
633 static int find_symlinks(
634 const char *root_dir,
635 const char *name,
636 const char *config_path,
637 const LookupPaths *lp,
638 bool *same_name_link) {
639
640 int fd;
641
642 assert(name);
643 assert(config_path);
644 assert(same_name_link);
645
646 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
647 if (fd < 0) {
648 if (errno == ENOENT)
649 return 0;
650 return -errno;
651 }
652
653 /* This takes possession of fd and closes it */
654 return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link);
655 }
656
657 static int find_symlinks_in_scope(
658 UnitFileScope scope,
659 const LookupPaths *paths,
660 const char *name,
661 UnitFileState *state) {
662
663 bool same_name_link_runtime = false, same_name_link = false;
664 int r;
665
666 assert(scope >= 0);
667 assert(scope < _UNIT_FILE_SCOPE_MAX);
668 assert(paths);
669 assert(name);
670
671 /* First look in the persistent config path */
672 r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link);
673 if (r < 0)
674 return r;
675 if (r > 0) {
676 *state = UNIT_FILE_ENABLED;
677 return r;
678 }
679
680 /* Then look in runtime config path */
681 r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime);
682 if (r < 0)
683 return r;
684 if (r > 0) {
685 *state = UNIT_FILE_ENABLED_RUNTIME;
686 return r;
687 }
688
689 /* Hmm, we didn't find it, but maybe we found the same name
690 * link? */
691 if (same_name_link) {
692 *state = UNIT_FILE_LINKED;
693 return 1;
694 }
695 if (same_name_link_runtime) {
696 *state = UNIT_FILE_LINKED_RUNTIME;
697 return 1;
698 }
699
700 return 0;
701 }
702
703 static void install_info_free(UnitFileInstallInfo *i) {
704
705 if (!i)
706 return;
707
708 free(i->name);
709 free(i->path);
710 strv_free(i->aliases);
711 strv_free(i->wanted_by);
712 strv_free(i->required_by);
713 strv_free(i->also);
714 free(i->default_instance);
715 free(i->symlink_target);
716 free(i);
717 }
718
719 static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) {
720 UnitFileInstallInfo *i;
721
722 if (!m)
723 return NULL;
724
725 while ((i = ordered_hashmap_steal_first(m)))
726 install_info_free(i);
727
728 return ordered_hashmap_free(m);
729 }
730
731 static void install_context_done(InstallContext *c) {
732 assert(c);
733
734 c->will_process = install_info_hashmap_free(c->will_process);
735 c->have_processed = install_info_hashmap_free(c->have_processed);
736 }
737
738 static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
739 UnitFileInstallInfo *i;
740
741 i = ordered_hashmap_get(c->have_processed, name);
742 if (i)
743 return i;
744
745 return ordered_hashmap_get(c->will_process, name);
746 }
747
748 static int install_info_may_process(UnitFileInstallInfo *i, const LookupPaths *paths) {
749 assert(i);
750 assert(paths);
751
752 /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
753 * not subject to enable/disable operations. */
754
755 if (i->type == UNIT_FILE_TYPE_MASKED)
756 return -ERFKILL;
757 if (path_is_generator(paths, i->path))
758 return -EADDRNOTAVAIL;
759 if (path_is_transient(paths, i->path))
760 return -EADDRNOTAVAIL;
761
762 return 0;
763 }
764
765 static int install_info_add(
766 InstallContext *c,
767 const char *name,
768 const char *path,
769 UnitFileInstallInfo **ret) {
770
771 UnitFileInstallInfo *i = NULL;
772 int r;
773
774 assert(c);
775 assert(name || path);
776
777 if (!name)
778 name = basename(path);
779
780 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
781 return -EINVAL;
782
783 i = install_info_find(c, name);
784 if (i) {
785 if (ret)
786 *ret = i;
787 return 0;
788 }
789
790 r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops);
791 if (r < 0)
792 return r;
793
794 i = new0(UnitFileInstallInfo, 1);
795 if (!i)
796 return -ENOMEM;
797 i->type = _UNIT_FILE_TYPE_INVALID;
798
799 i->name = strdup(name);
800 if (!i->name) {
801 r = -ENOMEM;
802 goto fail;
803 }
804
805 if (path) {
806 i->path = strdup(path);
807 if (!i->path) {
808 r = -ENOMEM;
809 goto fail;
810 }
811 }
812
813 r = ordered_hashmap_put(c->will_process, i->name, i);
814 if (r < 0)
815 goto fail;
816
817 if (ret)
818 *ret = i;
819
820 return 0;
821
822 fail:
823 install_info_free(i);
824 return r;
825 }
826
827 static int config_parse_also(
828 const char *unit,
829 const char *filename,
830 unsigned line,
831 const char *section,
832 unsigned section_line,
833 const char *lvalue,
834 int ltype,
835 const char *rvalue,
836 void *data,
837 void *userdata) {
838
839 UnitFileInstallInfo *i = userdata;
840 InstallContext *c = data;
841 int r;
842
843 assert(filename);
844 assert(lvalue);
845 assert(rvalue);
846
847 for (;;) {
848 _cleanup_free_ char *word = NULL;
849
850 r = extract_first_word(&rvalue, &word, NULL, 0);
851 if (r < 0)
852 return r;
853 if (r == 0)
854 break;
855
856 r = install_info_add(c, word, NULL, NULL);
857 if (r < 0)
858 return r;
859
860 r = strv_push(&i->also, word);
861 if (r < 0)
862 return r;
863
864 word = NULL;
865 }
866
867 return 0;
868 }
869
870 static int config_parse_default_instance(
871 const char *unit,
872 const char *filename,
873 unsigned line,
874 const char *section,
875 unsigned section_line,
876 const char *lvalue,
877 int ltype,
878 const char *rvalue,
879 void *data,
880 void *userdata) {
881
882 UnitFileInstallInfo *i = data;
883 char *printed;
884 int r;
885
886 assert(filename);
887 assert(lvalue);
888 assert(rvalue);
889
890 r = install_full_printf(i, rvalue, &printed);
891 if (r < 0)
892 return r;
893
894 if (!unit_instance_is_valid(printed)) {
895 free(printed);
896 return -EINVAL;
897 }
898
899 free(i->default_instance);
900 i->default_instance = printed;
901
902 return 0;
903 }
904
905 static int unit_file_load(
906 InstallContext *c,
907 UnitFileInstallInfo *info,
908 const char *path,
909 SearchFlags flags) {
910
911 const ConfigTableItem items[] = {
912 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
913 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
914 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
915 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
916 { "Install", "Also", config_parse_also, 0, c },
917 {}
918 };
919
920 _cleanup_fclose_ FILE *f = NULL;
921 _cleanup_close_ int fd = -1;
922 struct stat st;
923 int r;
924
925 assert(c);
926 assert(info);
927 assert(path);
928
929 if (!(flags & SEARCH_LOAD)) {
930 r = lstat(path, &st);
931 if (r < 0)
932 return -errno;
933
934 if (null_or_empty(&st))
935 info->type = UNIT_FILE_TYPE_MASKED;
936 else if (S_ISREG(st.st_mode))
937 info->type = UNIT_FILE_TYPE_REGULAR;
938 else if (S_ISLNK(st.st_mode))
939 return -ELOOP;
940 else if (S_ISDIR(st.st_mode))
941 return -EISDIR;
942 else
943 return -ENOTTY;
944
945 return 0;
946 }
947
948 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
949 if (fd < 0)
950 return -errno;
951 if (fstat(fd, &st) < 0)
952 return -errno;
953 if (null_or_empty(&st)) {
954 info->type = UNIT_FILE_TYPE_MASKED;
955 return 0;
956 }
957 if (S_ISDIR(st.st_mode))
958 return -EISDIR;
959 if (!S_ISREG(st.st_mode))
960 return -ENOTTY;
961
962 f = fdopen(fd, "re");
963 if (!f)
964 return -errno;
965 fd = -1;
966
967 r = config_parse(NULL, path, f,
968 NULL,
969 config_item_table_lookup, items,
970 true, true, false, info);
971 if (r < 0)
972 return r;
973
974 info->type = UNIT_FILE_TYPE_REGULAR;
975
976 return
977 (int) strv_length(info->aliases) +
978 (int) strv_length(info->wanted_by) +
979 (int) strv_length(info->required_by);
980 }
981
982 static int unit_file_load_or_readlink(
983 InstallContext *c,
984 UnitFileInstallInfo *info,
985 const char *path,
986 const char *root_dir,
987 SearchFlags flags) {
988
989 _cleanup_free_ char *target = NULL;
990 int r;
991
992 r = unit_file_load(c, info, path, flags);
993 if (r != -ELOOP)
994 return r;
995
996 /* This is a symlink, let's read it. */
997
998 r = readlink_malloc(path, &target);
999 if (r < 0)
1000 return r;
1001
1002 if (path_equal(target, "/dev/null"))
1003 info->type = UNIT_FILE_TYPE_MASKED;
1004 else {
1005 const char *bn;
1006 UnitType a, b;
1007
1008 bn = basename(target);
1009
1010 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1011
1012 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1013 return -EINVAL;
1014
1015 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1016
1017 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1018 return -EINVAL;
1019
1020 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1021
1022 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1023 return -EINVAL;
1024 } else
1025 return -EINVAL;
1026
1027 /* Enforce that the symlink destination does not
1028 * change the unit file type. */
1029
1030 a = unit_name_to_type(info->name);
1031 b = unit_name_to_type(bn);
1032 if (a < 0 || b < 0 || a != b)
1033 return -EINVAL;
1034
1035 if (path_is_absolute(target))
1036 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1037 info->symlink_target = prefix_root(root_dir, target);
1038 else
1039 /* This is a relative path, take it relative to the dir the symlink is located in. */
1040 info->symlink_target = file_in_same_dir(path, target);
1041 if (!info->symlink_target)
1042 return -ENOMEM;
1043
1044 info->type = UNIT_FILE_TYPE_SYMLINK;
1045 }
1046
1047 return 0;
1048 }
1049
1050 static int unit_file_search(
1051 InstallContext *c,
1052 UnitFileInstallInfo *info,
1053 const LookupPaths *paths,
1054 SearchFlags flags) {
1055
1056 char **p;
1057 int r;
1058
1059 assert(c);
1060 assert(info);
1061 assert(paths);
1062
1063 /* Was this unit already loaded? */
1064 if (info->type != _UNIT_FILE_TYPE_INVALID)
1065 return 0;
1066
1067 if (info->path)
1068 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
1069
1070 assert(info->name);
1071
1072 STRV_FOREACH(p, paths->search_path) {
1073 _cleanup_free_ char *path = NULL;
1074
1075 path = strjoin(*p, "/", info->name, NULL);
1076 if (!path)
1077 return -ENOMEM;
1078
1079 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1080 if (r < 0) {
1081 if (r != -ENOENT)
1082 return r;
1083 } else {
1084 info->path = path;
1085 path = NULL;
1086 return r;
1087 }
1088 }
1089
1090 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1091
1092 /* Unit file doesn't exist, however instance
1093 * enablement was requested. We will check if it is
1094 * possible to load template unit file. */
1095
1096 _cleanup_free_ char *template = NULL;
1097
1098 r = unit_name_template(info->name, &template);
1099 if (r < 0)
1100 return r;
1101
1102 STRV_FOREACH(p, paths->search_path) {
1103 _cleanup_free_ char *path = NULL;
1104
1105 path = strjoin(*p, "/", template, NULL);
1106 if (!path)
1107 return -ENOMEM;
1108
1109 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1110 if (r < 0) {
1111 if (r != -ENOENT)
1112 return r;
1113 } else {
1114 info->path = path;
1115 path = NULL;
1116 return r;
1117 }
1118 }
1119 }
1120
1121 return -ENOENT;
1122 }
1123
1124 static int install_info_follow(
1125 InstallContext *c,
1126 UnitFileInstallInfo *i,
1127 const char *root_dir,
1128 SearchFlags flags) {
1129
1130 assert(c);
1131 assert(i);
1132
1133 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1134 return -EINVAL;
1135 if (!i->symlink_target)
1136 return -EINVAL;
1137
1138 /* If the basename doesn't match, the caller should add a
1139 * complete new entry for this. */
1140
1141 if (!streq(basename(i->symlink_target), i->name))
1142 return -EXDEV;
1143
1144 free(i->path);
1145 i->path = i->symlink_target;
1146 i->symlink_target = NULL;
1147 i->type = _UNIT_FILE_TYPE_INVALID;
1148
1149 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1150 }
1151
1152 static int install_info_traverse(
1153 UnitFileScope scope,
1154 InstallContext *c,
1155 const LookupPaths *paths,
1156 UnitFileInstallInfo *start,
1157 SearchFlags flags,
1158 UnitFileInstallInfo **ret) {
1159
1160 UnitFileInstallInfo *i;
1161 unsigned k = 0;
1162 int r;
1163
1164 assert(paths);
1165 assert(start);
1166 assert(c);
1167
1168 r = unit_file_search(c, start, paths, flags);
1169 if (r < 0)
1170 return r;
1171
1172 i = start;
1173 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1174 /* Follow the symlink */
1175
1176 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
1177 return -ELOOP;
1178
1179 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
1180 r = path_is_config(paths, i->path);
1181 if (r < 0)
1182 return r;
1183 if (r > 0)
1184 return -ELOOP;
1185 }
1186
1187 r = install_info_follow(c, i, paths->root_dir, flags);
1188 if (r < 0) {
1189 _cleanup_free_ char *buffer = NULL;
1190 const char *bn;
1191
1192 if (r != -EXDEV)
1193 return r;
1194
1195 /* Target has a different name, create a new
1196 * install info object for that, and continue
1197 * with that. */
1198
1199 bn = basename(i->symlink_target);
1200
1201 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1202 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
1203
1204 _cleanup_free_ char *instance = NULL;
1205
1206 r = unit_name_to_instance(i->name, &instance);
1207 if (r < 0)
1208 return r;
1209
1210 r = unit_name_replace_instance(bn, instance, &buffer);
1211 if (r < 0)
1212 return r;
1213
1214 bn = buffer;
1215 }
1216
1217 r = install_info_add(c, bn, NULL, &i);
1218 if (r < 0)
1219 return r;
1220
1221 r = unit_file_search(c, i, paths, flags);
1222 if (r < 0)
1223 return r;
1224 }
1225
1226 /* Try again, with the new target we found. */
1227 }
1228
1229 if (ret)
1230 *ret = i;
1231
1232 return 0;
1233 }
1234
1235 static int install_info_add_auto(
1236 InstallContext *c,
1237 const LookupPaths *paths,
1238 const char *name_or_path,
1239 UnitFileInstallInfo **ret) {
1240
1241 assert(c);
1242 assert(name_or_path);
1243
1244 if (path_is_absolute(name_or_path)) {
1245 const char *pp;
1246
1247 pp = prefix_roota(paths->root_dir, name_or_path);
1248
1249 return install_info_add(c, NULL, pp, ret);
1250 } else
1251 return install_info_add(c, name_or_path, NULL, ret);
1252 }
1253
1254 static int install_info_discover(
1255 UnitFileScope scope,
1256 InstallContext *c,
1257 const LookupPaths *paths,
1258 const char *name,
1259 SearchFlags flags,
1260 UnitFileInstallInfo **ret) {
1261
1262 UnitFileInstallInfo *i;
1263 int r;
1264
1265 assert(c);
1266 assert(paths);
1267 assert(name);
1268
1269 r = install_info_add_auto(c, paths, name, &i);
1270 if (r < 0)
1271 return r;
1272
1273 return install_info_traverse(scope, c, paths, i, flags, ret);
1274 }
1275
1276 static int install_info_symlink_alias(
1277 UnitFileInstallInfo *i,
1278 const LookupPaths *paths,
1279 const char *config_path,
1280 bool force,
1281 UnitFileChange **changes,
1282 unsigned *n_changes) {
1283
1284 char **s;
1285 int r = 0, q;
1286
1287 assert(i);
1288 assert(paths);
1289 assert(config_path);
1290
1291 STRV_FOREACH(s, i->aliases) {
1292 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
1293 const char *rp;
1294
1295 q = install_full_printf(i, *s, &dst);
1296 if (q < 0)
1297 return q;
1298
1299 alias_path = path_make_absolute(dst, config_path);
1300 if (!alias_path)
1301 return -ENOMEM;
1302
1303 rp = skip_root(paths, i->path);
1304
1305 q = create_symlink(rp ?: i->path, alias_path, force, changes, n_changes);
1306 if (r == 0)
1307 r = q;
1308 }
1309
1310 return r;
1311 }
1312
1313 static int install_info_symlink_wants(
1314 UnitFileInstallInfo *i,
1315 const LookupPaths *paths,
1316 const char *config_path,
1317 char **list,
1318 const char *suffix,
1319 bool force,
1320 UnitFileChange **changes,
1321 unsigned *n_changes) {
1322
1323 _cleanup_free_ char *buf = NULL;
1324 const char *n;
1325 char **s;
1326 int r = 0, q;
1327
1328 assert(i);
1329 assert(paths);
1330 assert(config_path);
1331
1332 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
1333
1334 /* Don't install any symlink if there's no default
1335 * instance configured */
1336
1337 if (!i->default_instance)
1338 return 0;
1339
1340 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1341 if (r < 0)
1342 return r;
1343
1344 n = buf;
1345 } else
1346 n = i->name;
1347
1348 STRV_FOREACH(s, list) {
1349 _cleanup_free_ char *path = NULL, *dst = NULL;
1350 const char *rp;
1351
1352 q = install_full_printf(i, *s, &dst);
1353 if (q < 0)
1354 return q;
1355
1356 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
1357 r = -EINVAL;
1358 continue;
1359 }
1360
1361 path = strjoin(config_path, "/", dst, suffix, n, NULL);
1362 if (!path)
1363 return -ENOMEM;
1364
1365 rp = skip_root(paths, i->path);
1366
1367 q = create_symlink(rp ?: i->path, path, force, changes, n_changes);
1368 if (r == 0)
1369 r = q;
1370 }
1371
1372 return r;
1373 }
1374
1375 static int install_info_symlink_link(
1376 UnitFileInstallInfo *i,
1377 const LookupPaths *paths,
1378 const char *config_path,
1379 bool force,
1380 UnitFileChange **changes,
1381 unsigned *n_changes) {
1382
1383 _cleanup_free_ char *path = NULL;
1384 const char *rp;
1385 int r;
1386
1387 assert(i);
1388 assert(paths);
1389 assert(config_path);
1390 assert(i->path);
1391
1392 r = in_search_path(paths, i->path);
1393 if (r != 0)
1394 return r;
1395
1396 path = strjoin(config_path, "/", i->name, NULL);
1397 if (!path)
1398 return -ENOMEM;
1399
1400 rp = skip_root(paths, i->path);
1401
1402 return create_symlink(rp ?: i->path, path, force, changes, n_changes);
1403 }
1404
1405 static int install_info_apply(
1406 UnitFileInstallInfo *i,
1407 const LookupPaths *paths,
1408 const char *config_path,
1409 bool force,
1410 UnitFileChange **changes,
1411 unsigned *n_changes) {
1412
1413 int r, q;
1414
1415 assert(i);
1416 assert(paths);
1417 assert(config_path);
1418
1419 if (i->type != UNIT_FILE_TYPE_REGULAR)
1420 return 0;
1421
1422 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
1423
1424 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
1425 if (r == 0)
1426 r = q;
1427
1428 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", force, changes, n_changes);
1429 if (r == 0)
1430 r = q;
1431
1432 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1433 if (r == 0)
1434 r = q;
1435
1436 return r;
1437 }
1438
1439 static int install_context_apply(
1440 UnitFileScope scope,
1441 InstallContext *c,
1442 const LookupPaths *paths,
1443 const char *config_path,
1444 bool force,
1445 SearchFlags flags,
1446 UnitFileChange **changes,
1447 unsigned *n_changes) {
1448
1449 UnitFileInstallInfo *i;
1450 int r;
1451
1452 assert(c);
1453 assert(paths);
1454 assert(config_path);
1455
1456 if (ordered_hashmap_isempty(c->will_process))
1457 return 0;
1458
1459 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
1460 if (r < 0)
1461 return r;
1462
1463 r = 0;
1464 while ((i = ordered_hashmap_first(c->will_process))) {
1465 int q;
1466
1467 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1468 if (q < 0)
1469 return q;
1470
1471 r = install_info_traverse(scope, c, paths, i, flags, NULL);
1472 if (r < 0)
1473 return r;
1474
1475 if (i->type != UNIT_FILE_TYPE_REGULAR)
1476 continue;
1477
1478 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1479 if (r >= 0) {
1480 if (q < 0)
1481 r = q;
1482 else
1483 r += q;
1484 }
1485 }
1486
1487 return r;
1488 }
1489
1490 static int install_context_mark_for_removal(
1491 UnitFileScope scope,
1492 InstallContext *c,
1493 const LookupPaths *paths,
1494 Set **remove_symlinks_to,
1495 const char *config_path) {
1496
1497 UnitFileInstallInfo *i;
1498 int r;
1499
1500 assert(c);
1501 assert(paths);
1502 assert(config_path);
1503
1504 /* Marks all items for removal */
1505
1506 if (ordered_hashmap_isempty(c->will_process))
1507 return 0;
1508
1509 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
1510 if (r < 0)
1511 return r;
1512
1513 while ((i = ordered_hashmap_first(c->will_process))) {
1514
1515 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1516 if (r < 0)
1517 return r;
1518
1519 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
1520 if (r < 0)
1521 return r;
1522
1523 if (i->type != UNIT_FILE_TYPE_REGULAR)
1524 continue;
1525
1526 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1527 if (r < 0)
1528 return r;
1529 }
1530
1531 return 0;
1532 }
1533
1534 int unit_file_mask(
1535 UnitFileScope scope,
1536 bool runtime,
1537 const char *root_dir,
1538 char **files,
1539 bool force,
1540 UnitFileChange **changes,
1541 unsigned *n_changes) {
1542
1543 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1544 const char *config_path;
1545 char **i;
1546 int r;
1547
1548 assert(scope >= 0);
1549 assert(scope < _UNIT_FILE_SCOPE_MAX);
1550
1551 r = lookup_paths_init(&paths, scope, 0, root_dir);
1552 if (r < 0)
1553 return r;
1554
1555 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1556
1557 STRV_FOREACH(i, files) {
1558 _cleanup_free_ char *path = NULL;
1559 int q;
1560
1561 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
1562 if (r == 0)
1563 r = -EINVAL;
1564 continue;
1565 }
1566
1567 path = path_make_absolute(*i, config_path);
1568 if (!path)
1569 return -ENOMEM;
1570
1571 q = create_symlink("/dev/null", path, force, changes, n_changes);
1572 if (q < 0 && r >= 0)
1573 r = q;
1574 }
1575
1576 return r;
1577 }
1578
1579 int unit_file_unmask(
1580 UnitFileScope scope,
1581 bool runtime,
1582 const char *root_dir,
1583 char **files,
1584 UnitFileChange **changes,
1585 unsigned *n_changes) {
1586
1587 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1588 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1589 _cleanup_free_ char **todo = NULL;
1590 size_t n_todo = 0, n_allocated = 0;
1591 const char *config_path;
1592 char **i;
1593 int r, q;
1594
1595 assert(scope >= 0);
1596 assert(scope < _UNIT_FILE_SCOPE_MAX);
1597
1598 r = lookup_paths_init(&paths, scope, 0, root_dir);
1599 if (r < 0)
1600 return r;
1601
1602 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1603
1604 STRV_FOREACH(i, files) {
1605 _cleanup_free_ char *path = NULL;
1606
1607 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
1608 return -EINVAL;
1609
1610 path = path_make_absolute(*i, config_path);
1611 if (!path)
1612 return -ENOMEM;
1613
1614 r = null_or_empty_path(path);
1615 if (r == -ENOENT)
1616 continue;
1617 if (r < 0)
1618 return r;
1619 if (r == 0)
1620 continue;
1621
1622 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1623 return -ENOMEM;
1624
1625 todo[n_todo++] = *i;
1626 }
1627
1628 strv_uniq(todo);
1629
1630 r = 0;
1631 STRV_FOREACH(i, todo) {
1632 _cleanup_free_ char *path = NULL;
1633 const char *rp;
1634
1635 path = path_make_absolute(*i, config_path);
1636 if (!path)
1637 return -ENOMEM;
1638
1639 if (unlink(path) < 0) {
1640 if (errno != ENOENT && r >= 0)
1641 r = -errno;
1642
1643 continue;
1644 }
1645
1646 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
1647
1648 rp = skip_root(&paths, path);
1649 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
1650 if (q < 0)
1651 return q;
1652 }
1653
1654 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
1655 if (r >= 0)
1656 r = q;
1657
1658 return r;
1659 }
1660
1661 int unit_file_link(
1662 UnitFileScope scope,
1663 bool runtime,
1664 const char *root_dir,
1665 char **files,
1666 bool force,
1667 UnitFileChange **changes,
1668 unsigned *n_changes) {
1669
1670 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1671 _cleanup_free_ char **todo = NULL;
1672 size_t n_todo = 0, n_allocated = 0;
1673 const char *config_path;
1674 char **i;
1675 int r, q;
1676
1677 assert(scope >= 0);
1678 assert(scope < _UNIT_FILE_SCOPE_MAX);
1679
1680 r = lookup_paths_init(&paths, scope, 0, root_dir);
1681 if (r < 0)
1682 return r;
1683
1684 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1685
1686 STRV_FOREACH(i, files) {
1687 _cleanup_free_ char *full = NULL;
1688 struct stat st;
1689 char *fn;
1690
1691 if (!path_is_absolute(*i))
1692 return -EINVAL;
1693
1694 fn = basename(*i);
1695 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
1696 return -EINVAL;
1697
1698 full = prefix_root(paths.root_dir, *i);
1699 if (!full)
1700 return -ENOMEM;
1701
1702 if (lstat(full, &st) < 0)
1703 return -errno;
1704 if (S_ISLNK(st.st_mode))
1705 return -ELOOP;
1706 if (S_ISDIR(st.st_mode))
1707 return -EISDIR;
1708 if (!S_ISREG(st.st_mode))
1709 return -ENOTTY;
1710
1711 q = in_search_path(&paths, *i);
1712 if (q < 0)
1713 return q;
1714 if (q > 0)
1715 continue;
1716
1717 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1718 return -ENOMEM;
1719
1720 todo[n_todo++] = *i;
1721 }
1722
1723 strv_uniq(todo);
1724
1725 r = 0;
1726 STRV_FOREACH(i, todo) {
1727 _cleanup_free_ char *new_path = NULL;
1728 const char *old_path;
1729
1730 old_path = skip_root(&paths, *i);
1731 new_path = path_make_absolute(basename(*i), config_path);
1732 if (!new_path)
1733 return -ENOMEM;
1734
1735 q = create_symlink(old_path ?: *i, new_path, force, changes, n_changes);
1736 if (q < 0 && r >= 0)
1737 r = q;
1738 }
1739
1740 return r;
1741 }
1742
1743 static int path_shall_revert(const LookupPaths *paths, const char *path) {
1744 int r;
1745
1746 assert(paths);
1747 assert(path);
1748
1749 /* Checks whether the path is one where the drop-in directories shall be removed. */
1750
1751 r = path_is_config(paths, path);
1752 if (r != 0)
1753 return r;
1754
1755 r = path_is_control(paths, path);
1756 if (r != 0)
1757 return r;
1758
1759 return path_is_transient(paths, path);
1760 }
1761
1762 int unit_file_revert(
1763 UnitFileScope scope,
1764 const char *root_dir,
1765 char **files,
1766 UnitFileChange **changes,
1767 unsigned *n_changes) {
1768
1769 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1770 /* _cleanup_(install_context_done) InstallContext c = {}; */
1771 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1772 _cleanup_strv_free_ char **todo = NULL;
1773 size_t n_todo = 0, n_allocated = 0;
1774 char **i;
1775 int r, q;
1776
1777 /* Puts a unit file back into vendor state. This means:
1778 *
1779 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
1780 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
1781 *
1782 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
1783 * "config", but not in "transient" or "control" or even "generated").
1784 *
1785 * We remove all that in both the runtime and the persistant directories, if that applies.
1786 */
1787
1788 r = lookup_paths_init(&paths, scope, 0, root_dir);
1789 if (r < 0)
1790 return r;
1791
1792 STRV_FOREACH(i, files) {
1793 bool has_vendor = false;
1794 char **p;
1795
1796 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
1797 return -EINVAL;
1798
1799 STRV_FOREACH(p, paths.search_path) {
1800 _cleanup_free_ char *path = NULL, *dropin = NULL;
1801 struct stat st;
1802
1803 path = path_make_absolute(*i, *p);
1804 if (!path)
1805 return -ENOMEM;
1806
1807 r = lstat(path, &st);
1808 if (r < 0) {
1809 if (errno != ENOENT)
1810 return -errno;
1811 } else if (S_ISREG(st.st_mode)) {
1812 /* Check if there's a vendor version */
1813 r = path_is_vendor(&paths, path);
1814 if (r < 0)
1815 return r;
1816 if (r > 0)
1817 has_vendor = true;
1818 }
1819
1820 dropin = strappend(path, ".d");
1821 if (!dropin)
1822 return -ENOMEM;
1823
1824 r = lstat(dropin, &st);
1825 if (r < 0) {
1826 if (errno != ENOENT)
1827 return -errno;
1828 } else if (S_ISDIR(st.st_mode)) {
1829 /* Remove the drop-ins */
1830 r = path_shall_revert(&paths, dropin);
1831 if (r < 0)
1832 return r;
1833 if (r > 0) {
1834 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1835 return -ENOMEM;
1836
1837 todo[n_todo++] = dropin;
1838 dropin = NULL;
1839 }
1840 }
1841 }
1842
1843 if (!has_vendor)
1844 continue;
1845
1846 /* OK, there's a vendor version, hence drop all configuration versions */
1847 STRV_FOREACH(p, paths.search_path) {
1848 _cleanup_free_ char *path = NULL;
1849 struct stat st;
1850
1851 path = path_make_absolute(*i, *p);
1852 if (!path)
1853 return -ENOMEM;
1854
1855 r = lstat(path, &st);
1856 if (r < 0) {
1857 if (errno != ENOENT)
1858 return -errno;
1859 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
1860 r = path_is_config(&paths, path);
1861 if (r < 0)
1862 return r;
1863 if (r > 0) {
1864 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1865 return -ENOMEM;
1866
1867 todo[n_todo++] = path;
1868 path = NULL;
1869 }
1870 }
1871 }
1872 }
1873
1874 strv_uniq(todo);
1875
1876 r = 0;
1877 STRV_FOREACH(i, todo) {
1878 _cleanup_strv_free_ char **fs = NULL;
1879 const char *rp;
1880 char **j;
1881
1882 (void) get_files_in_directory(*i, &fs);
1883
1884 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
1885 if (q < 0 && q != -ENOENT && r >= 0) {
1886 r = q;
1887 continue;
1888 }
1889
1890 STRV_FOREACH(j, fs) {
1891 _cleanup_free_ char *t = NULL;
1892
1893 t = strjoin(*i, "/", *j, NULL);
1894 if (!t)
1895 return -ENOMEM;
1896
1897 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
1898 }
1899
1900 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
1901
1902 rp = skip_root(&paths, *i);
1903 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
1904 if (q < 0)
1905 return q;
1906 }
1907
1908 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes);
1909 if (r >= 0)
1910 r = q;
1911
1912 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes);
1913 if (r >= 0)
1914 r = q;
1915
1916 return r;
1917 }
1918
1919 int unit_file_add_dependency(
1920 UnitFileScope scope,
1921 bool runtime,
1922 const char *root_dir,
1923 char **files,
1924 const char *target,
1925 UnitDependency dep,
1926 bool force,
1927 UnitFileChange **changes,
1928 unsigned *n_changes) {
1929
1930 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1931 _cleanup_(install_context_done) InstallContext c = {};
1932 UnitFileInstallInfo *i, *target_info;
1933 const char *config_path;
1934 char **f;
1935 int r;
1936
1937 assert(scope >= 0);
1938 assert(scope < _UNIT_FILE_SCOPE_MAX);
1939 assert(target);
1940
1941 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
1942 return -EINVAL;
1943
1944 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
1945 return -EINVAL;
1946
1947 r = lookup_paths_init(&paths, scope, 0, root_dir);
1948 if (r < 0)
1949 return r;
1950
1951 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1952
1953 r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
1954 if (r < 0)
1955 return r;
1956 r = install_info_may_process(target_info, &paths);
1957 if (r < 0)
1958 return r;
1959
1960 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
1961
1962 STRV_FOREACH(f, files) {
1963 char ***l;
1964
1965 r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
1966 if (r < 0)
1967 return r;
1968 r = install_info_may_process(i, &paths);
1969 if (r < 0)
1970 return r;
1971
1972 assert(i->type == UNIT_FILE_TYPE_REGULAR);
1973
1974 /* We didn't actually load anything from the unit
1975 * file, but instead just add in our new symlink to
1976 * create. */
1977
1978 if (dep == UNIT_WANTS)
1979 l = &i->wanted_by;
1980 else
1981 l = &i->required_by;
1982
1983 strv_free(*l);
1984 *l = strv_new(target_info->name, NULL);
1985 if (!*l)
1986 return -ENOMEM;
1987 }
1988
1989 return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
1990 }
1991
1992 int unit_file_enable(
1993 UnitFileScope scope,
1994 bool runtime,
1995 const char *root_dir,
1996 char **files,
1997 bool force,
1998 UnitFileChange **changes,
1999 unsigned *n_changes) {
2000
2001 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2002 _cleanup_(install_context_done) InstallContext c = {};
2003 const char *config_path;
2004 UnitFileInstallInfo *i;
2005 char **f;
2006 int r;
2007
2008 assert(scope >= 0);
2009 assert(scope < _UNIT_FILE_SCOPE_MAX);
2010
2011 r = lookup_paths_init(&paths, scope, 0, root_dir);
2012 if (r < 0)
2013 return r;
2014
2015 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2016
2017 STRV_FOREACH(f, files) {
2018 r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i);
2019 if (r < 0)
2020 return r;
2021 r = install_info_may_process(i, &paths);
2022 if (r < 0)
2023 return r;
2024
2025 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2026 }
2027
2028 /* This will return the number of symlink rules that were
2029 supposed to be created, not the ones actually created. This
2030 is useful to determine whether the passed files had any
2031 installation data at all. */
2032
2033 return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes);
2034 }
2035
2036 int unit_file_disable(
2037 UnitFileScope scope,
2038 bool runtime,
2039 const char *root_dir,
2040 char **files,
2041 UnitFileChange **changes,
2042 unsigned *n_changes) {
2043
2044 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2045 _cleanup_(install_context_done) InstallContext c = {};
2046 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2047 const char *config_path;
2048 char **i;
2049 int r;
2050
2051 assert(scope >= 0);
2052 assert(scope < _UNIT_FILE_SCOPE_MAX);
2053
2054 r = lookup_paths_init(&paths, scope, 0, root_dir);
2055 if (r < 0)
2056 return r;
2057
2058 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2059
2060 STRV_FOREACH(i, files) {
2061 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2062 return -EINVAL;
2063
2064 r = install_info_add(&c, *i, NULL, NULL);
2065 if (r < 0)
2066 return r;
2067 }
2068
2069 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path);
2070 if (r < 0)
2071 return r;
2072
2073 return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
2074 }
2075
2076 int unit_file_reenable(
2077 UnitFileScope scope,
2078 bool runtime,
2079 const char *root_dir,
2080 char **files,
2081 bool force,
2082 UnitFileChange **changes,
2083 unsigned *n_changes) {
2084
2085 char **n;
2086 int r;
2087 size_t l, i;
2088
2089 /* First, we invoke the disable command with only the basename... */
2090 l = strv_length(files);
2091 n = newa(char*, l+1);
2092 for (i = 0; i < l; i++)
2093 n[i] = basename(files[i]);
2094 n[i] = NULL;
2095
2096 r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes);
2097 if (r < 0)
2098 return r;
2099
2100 /* But the enable command with the full name */
2101 return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes);
2102 }
2103
2104 int unit_file_set_default(
2105 UnitFileScope scope,
2106 const char *root_dir,
2107 const char *name,
2108 bool force,
2109 UnitFileChange **changes,
2110 unsigned *n_changes) {
2111
2112 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2113 _cleanup_(install_context_done) InstallContext c = {};
2114 UnitFileInstallInfo *i;
2115 const char *new_path, *old_path;
2116 int r;
2117
2118 assert(scope >= 0);
2119 assert(scope < _UNIT_FILE_SCOPE_MAX);
2120 assert(name);
2121
2122 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
2123 return -EINVAL;
2124 if (streq(name, SPECIAL_DEFAULT_TARGET))
2125 return -EINVAL;
2126
2127 r = lookup_paths_init(&paths, scope, 0, root_dir);
2128 if (r < 0)
2129 return r;
2130
2131 r = install_info_discover(scope, &c, &paths, name, 0, &i);
2132 if (r < 0)
2133 return r;
2134 r = install_info_may_process(i, &paths);
2135 if (r < 0)
2136 return r;
2137
2138 old_path = skip_root(&paths, i->path);
2139 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
2140
2141 return create_symlink(old_path ?: i->path, new_path, force, changes, n_changes);
2142 }
2143
2144 int unit_file_get_default(
2145 UnitFileScope scope,
2146 const char *root_dir,
2147 char **name) {
2148
2149 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2150 _cleanup_(install_context_done) InstallContext c = {};
2151 UnitFileInstallInfo *i;
2152 char *n;
2153 int r;
2154
2155 assert(scope >= 0);
2156 assert(scope < _UNIT_FILE_SCOPE_MAX);
2157 assert(name);
2158
2159 r = lookup_paths_init(&paths, scope, 0, root_dir);
2160 if (r < 0)
2161 return r;
2162
2163 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2164 if (r < 0)
2165 return r;
2166 r = install_info_may_process(i, &paths);
2167 if (r < 0)
2168 return r;
2169
2170 n = strdup(i->name);
2171 if (!n)
2172 return -ENOMEM;
2173
2174 *name = n;
2175 return 0;
2176 }
2177
2178 static int unit_file_lookup_state(
2179 UnitFileScope scope,
2180 const LookupPaths *paths,
2181 const char *name,
2182 UnitFileState *ret) {
2183
2184 _cleanup_(install_context_done) InstallContext c = {};
2185 UnitFileInstallInfo *i;
2186 UnitFileState state;
2187 int r;
2188
2189 assert(paths);
2190 assert(name);
2191
2192 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2193 return -EINVAL;
2194
2195 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2196 if (r < 0)
2197 return r;
2198
2199 /* Shortcut things, if the caller just wants to know if this unit exists. */
2200 if (!ret)
2201 return 0;
2202
2203 switch (i->type) {
2204
2205 case UNIT_FILE_TYPE_MASKED:
2206 r = path_is_runtime(paths, i->path);
2207 if (r < 0)
2208 return r;
2209
2210 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
2211 break;
2212
2213 case UNIT_FILE_TYPE_REGULAR:
2214 r = path_is_generator(paths, i->path);
2215 if (r < 0)
2216 return r;
2217 if (r > 0) {
2218 state = UNIT_FILE_GENERATED;
2219 break;
2220 }
2221
2222 r = path_is_transient(paths, i->path);
2223 if (r < 0)
2224 return r;
2225 if (r > 0) {
2226 state = UNIT_FILE_TRANSIENT;
2227 break;
2228 }
2229
2230 r = find_symlinks_in_scope(scope, paths, i->name, &state);
2231 if (r < 0)
2232 return r;
2233 if (r == 0) {
2234 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i))
2235 state = UNIT_FILE_DISABLED;
2236 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i))
2237 state = UNIT_FILE_INDIRECT;
2238 else
2239 state = UNIT_FILE_STATIC;
2240 }
2241
2242 break;
2243
2244 default:
2245 assert_not_reached("Unexpect unit file type.");
2246 }
2247
2248 *ret = state;
2249 return 0;
2250 }
2251
2252 int unit_file_get_state(
2253 UnitFileScope scope,
2254 const char *root_dir,
2255 const char *name,
2256 UnitFileState *ret) {
2257
2258 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2259 int r;
2260
2261 assert(scope >= 0);
2262 assert(scope < _UNIT_FILE_SCOPE_MAX);
2263 assert(name);
2264
2265 r = lookup_paths_init(&paths, scope, 0, root_dir);
2266 if (r < 0)
2267 return r;
2268
2269 return unit_file_lookup_state(scope, &paths, name, ret);
2270 }
2271
2272 int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2273 _cleanup_(install_context_done) InstallContext c = {};
2274 int r;
2275
2276 assert(paths);
2277 assert(name);
2278
2279 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2280 return -EINVAL;
2281
2282 r = install_info_discover(scope, &c, paths, name, 0, NULL);
2283 if (r == -ENOENT)
2284 return 0;
2285 if (r < 0)
2286 return r;
2287
2288 return 1;
2289 }
2290
2291 int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
2292 _cleanup_strv_free_ char **files = NULL;
2293 char **p;
2294 int r;
2295
2296 assert(scope >= 0);
2297 assert(scope < _UNIT_FILE_SCOPE_MAX);
2298 assert(name);
2299
2300 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2301 return -EINVAL;
2302
2303 if (scope == UNIT_FILE_SYSTEM)
2304 r = conf_files_list(&files, ".preset", root_dir,
2305 "/etc/systemd/system-preset",
2306 "/usr/local/lib/systemd/system-preset",
2307 "/usr/lib/systemd/system-preset",
2308 #ifdef HAVE_SPLIT_USR
2309 "/lib/systemd/system-preset",
2310 #endif
2311 NULL);
2312 else if (scope == UNIT_FILE_GLOBAL)
2313 r = conf_files_list(&files, ".preset", root_dir,
2314 "/etc/systemd/user-preset",
2315 "/usr/local/lib/systemd/user-preset",
2316 "/usr/lib/systemd/user-preset",
2317 NULL);
2318 else
2319 return 1; /* Default is "enable" */
2320
2321 if (r < 0)
2322 return r;
2323
2324 STRV_FOREACH(p, files) {
2325 _cleanup_fclose_ FILE *f;
2326 char line[LINE_MAX];
2327
2328 f = fopen(*p, "re");
2329 if (!f) {
2330 if (errno == ENOENT)
2331 continue;
2332
2333 return -errno;
2334 }
2335
2336 FOREACH_LINE(line, f, return -errno) {
2337 const char *parameter;
2338 char *l;
2339
2340 l = strstrip(line);
2341
2342 if (isempty(l))
2343 continue;
2344 if (strchr(COMMENTS, *l))
2345 continue;
2346
2347 parameter = first_word(l, "enable");
2348 if (parameter) {
2349 if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
2350 log_debug("Preset file says enable %s.", name);
2351 return 1;
2352 }
2353
2354 continue;
2355 }
2356
2357 parameter = first_word(l, "disable");
2358 if (parameter) {
2359 if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
2360 log_debug("Preset file says disable %s.", name);
2361 return 0;
2362 }
2363
2364 continue;
2365 }
2366
2367 log_debug("Couldn't parse line '%s'", l);
2368 }
2369 }
2370
2371 /* Default is "enable" */
2372 log_debug("Preset file doesn't say anything about %s, enabling.", name);
2373 return 1;
2374 }
2375
2376 static int execute_preset(
2377 UnitFileScope scope,
2378 InstallContext *plus,
2379 InstallContext *minus,
2380 const LookupPaths *paths,
2381 const char *config_path,
2382 char **files,
2383 UnitFilePresetMode mode,
2384 bool force,
2385 UnitFileChange **changes,
2386 unsigned *n_changes) {
2387
2388 int r;
2389
2390 assert(plus);
2391 assert(minus);
2392 assert(paths);
2393 assert(config_path);
2394
2395 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
2396 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2397
2398 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
2399 if (r < 0)
2400 return r;
2401
2402 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes);
2403 } else
2404 r = 0;
2405
2406 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
2407 int q;
2408
2409 /* Returns number of symlinks that where supposed to be installed. */
2410 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
2411 if (r >= 0) {
2412 if (q < 0)
2413 r = q;
2414 else
2415 r += q;
2416 }
2417 }
2418
2419 return r;
2420 }
2421
2422 static int preset_prepare_one(
2423 UnitFileScope scope,
2424 InstallContext *plus,
2425 InstallContext *minus,
2426 LookupPaths *paths,
2427 UnitFilePresetMode mode,
2428 const char *name) {
2429
2430 UnitFileInstallInfo *i;
2431 int r;
2432
2433 if (install_info_find(plus, name) ||
2434 install_info_find(minus, name))
2435 return 0;
2436
2437 r = unit_file_query_preset(scope, paths->root_dir, name);
2438 if (r < 0)
2439 return r;
2440
2441 if (r > 0) {
2442 r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2443 if (r < 0)
2444 return r;
2445
2446 r = install_info_may_process(i, paths);
2447 if (r < 0)
2448 return r;
2449 } else
2450 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2451
2452 return r;
2453 }
2454
2455 int unit_file_preset(
2456 UnitFileScope scope,
2457 bool runtime,
2458 const char *root_dir,
2459 char **files,
2460 UnitFilePresetMode mode,
2461 bool force,
2462 UnitFileChange **changes,
2463 unsigned *n_changes) {
2464
2465 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
2466 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2467 const char *config_path;
2468 char **i;
2469 int r;
2470
2471 assert(scope >= 0);
2472 assert(scope < _UNIT_FILE_SCOPE_MAX);
2473 assert(mode < _UNIT_FILE_PRESET_MAX);
2474
2475 r = lookup_paths_init(&paths, scope, 0, root_dir);
2476 if (r < 0)
2477 return r;
2478
2479 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2480
2481 STRV_FOREACH(i, files) {
2482 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2483 return -EINVAL;
2484
2485 r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i);
2486 if (r < 0)
2487 return r;
2488 }
2489
2490 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes);
2491 }
2492
2493 int unit_file_preset_all(
2494 UnitFileScope scope,
2495 bool runtime,
2496 const char *root_dir,
2497 UnitFilePresetMode mode,
2498 bool force,
2499 UnitFileChange **changes,
2500 unsigned *n_changes) {
2501
2502 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
2503 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2504 const char *config_path = NULL;
2505 char **i;
2506 int r;
2507
2508 assert(scope >= 0);
2509 assert(scope < _UNIT_FILE_SCOPE_MAX);
2510 assert(mode < _UNIT_FILE_PRESET_MAX);
2511
2512 r = lookup_paths_init(&paths, scope, 0, root_dir);
2513 if (r < 0)
2514 return r;
2515
2516 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2517
2518 STRV_FOREACH(i, paths.search_path) {
2519 _cleanup_closedir_ DIR *d = NULL;
2520 struct dirent *de;
2521
2522 d = opendir(*i);
2523 if (!d) {
2524 if (errno == ENOENT)
2525 continue;
2526
2527 return -errno;
2528 }
2529
2530 FOREACH_DIRENT(de, d, return -errno) {
2531
2532 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
2533 continue;
2534
2535 dirent_ensure_type(d, de);
2536
2537 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
2538 continue;
2539
2540 r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name);
2541 if (r == -ERFKILL)
2542 r = unit_file_changes_add(changes, n_changes,
2543 UNIT_FILE_IS_MASKED, de->d_name, NULL);
2544 if (r < 0)
2545 return r;
2546 }
2547 }
2548
2549 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes);
2550 }
2551
2552 static void unit_file_list_free_one(UnitFileList *f) {
2553 if (!f)
2554 return;
2555
2556 free(f->path);
2557 free(f);
2558 }
2559
2560 Hashmap* unit_file_list_free(Hashmap *h) {
2561 UnitFileList *i;
2562
2563 while ((i = hashmap_steal_first(h)))
2564 unit_file_list_free_one(i);
2565
2566 return hashmap_free(h);
2567 }
2568
2569 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
2570
2571 int unit_file_get_list(
2572 UnitFileScope scope,
2573 const char *root_dir,
2574 Hashmap *h) {
2575
2576 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2577 char **i;
2578 int r;
2579
2580 assert(scope >= 0);
2581 assert(scope < _UNIT_FILE_SCOPE_MAX);
2582 assert(h);
2583
2584 r = lookup_paths_init(&paths, scope, 0, root_dir);
2585 if (r < 0)
2586 return r;
2587
2588 STRV_FOREACH(i, paths.search_path) {
2589 _cleanup_closedir_ DIR *d = NULL;
2590 struct dirent *de;
2591
2592 d = opendir(*i);
2593 if (!d) {
2594 if (errno == ENOENT)
2595 continue;
2596
2597 return -errno;
2598 }
2599
2600 FOREACH_DIRENT(de, d, return -errno) {
2601 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
2602
2603 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
2604 continue;
2605
2606 if (hashmap_get(h, de->d_name))
2607 continue;
2608
2609 dirent_ensure_type(d, de);
2610
2611 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
2612 continue;
2613
2614 f = new0(UnitFileList, 1);
2615 if (!f)
2616 return -ENOMEM;
2617
2618 f->path = path_make_absolute(de->d_name, *i);
2619 if (!f->path)
2620 return -ENOMEM;
2621
2622 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
2623 if (r < 0)
2624 f->state = UNIT_FILE_BAD;
2625
2626 r = hashmap_put(h, basename(f->path), f);
2627 if (r < 0)
2628 return r;
2629
2630 f = NULL; /* prevent cleanup */
2631 }
2632 }
2633
2634 return 0;
2635 }
2636
2637 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2638 [UNIT_FILE_ENABLED] = "enabled",
2639 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
2640 [UNIT_FILE_LINKED] = "linked",
2641 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2642 [UNIT_FILE_MASKED] = "masked",
2643 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2644 [UNIT_FILE_STATIC] = "static",
2645 [UNIT_FILE_DISABLED] = "disabled",
2646 [UNIT_FILE_INDIRECT] = "indirect",
2647 [UNIT_FILE_GENERATED] = "generated",
2648 [UNIT_FILE_TRANSIENT] = "transient",
2649 [UNIT_FILE_BAD] = "bad",
2650 };
2651
2652 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
2653
2654 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2655 [UNIT_FILE_SYMLINK] = "symlink",
2656 [UNIT_FILE_UNLINK] = "unlink",
2657 [UNIT_FILE_IS_MASKED] = "masked",
2658 };
2659
2660 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
2661
2662 static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
2663 [UNIT_FILE_PRESET_FULL] = "full",
2664 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
2665 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
2666 };
2667
2668 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);