]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/shared/install.c
pam_systemd: use F_DUPFD_CLOEXEC when dupping session fds
[thirdparty/systemd.git] / src / shared / install.c
... / ...
CommitLineData
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty <of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <string.h>
26#include <fnmatch.h>
27
28#include "util.h"
29#include "mkdir.h"
30#include "hashmap.h"
31#include "set.h"
32#include "path-util.h"
33#include "path-lookup.h"
34#include "strv.h"
35#include "unit-name.h"
36#include "install.h"
37#include "conf-parser.h"
38#include "conf-files.h"
39#include "specifier.h"
40#include "install-printf.h"
41#include "special.h"
42
43typedef struct {
44 Hashmap *will_install;
45 Hashmap *have_installed;
46} InstallContext;
47
48#define _cleanup_install_context_done_ _cleanup_(install_context_done)
49
50static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
51 assert(paths);
52 assert(scope >= 0);
53 assert(scope < _UNIT_FILE_SCOPE_MAX);
54
55 zero(*paths);
56
57 return lookup_paths_init(paths,
58 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
59 scope == UNIT_FILE_USER,
60 NULL, NULL, NULL);
61}
62
63static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
64 char *p = NULL;
65 int r;
66
67 assert(scope >= 0);
68 assert(scope < _UNIT_FILE_SCOPE_MAX);
69 assert(ret);
70
71 switch (scope) {
72
73 case UNIT_FILE_SYSTEM:
74
75 if (root_dir && runtime)
76 asprintf(&p, "%s/run/systemd/system", root_dir);
77 else if (runtime)
78 p = strdup("/run/systemd/system");
79 else if (root_dir)
80 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
81 else
82 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
83
84 break;
85
86 case UNIT_FILE_GLOBAL:
87
88 if (root_dir)
89 return -EINVAL;
90
91 if (runtime)
92 p = strdup("/run/systemd/user");
93 else
94 p = strdup(USER_CONFIG_UNIT_PATH);
95 break;
96
97 case UNIT_FILE_USER:
98
99 if (root_dir || runtime)
100 return -EINVAL;
101
102 r = user_config_home(&p);
103 if (r <= 0)
104 return r < 0 ? r : -ENOENT;
105
106 break;
107
108 default:
109 assert_not_reached("Bad scope");
110 }
111
112 if (!p)
113 return -ENOMEM;
114
115 *ret = p;
116 return 0;
117}
118
119static int add_file_change(
120 UnitFileChange **changes,
121 unsigned *n_changes,
122 UnitFileChangeType type,
123 const char *path,
124 const char *source) {
125
126 UnitFileChange *c;
127 unsigned i;
128
129 assert(path);
130 assert(!changes == !n_changes);
131
132 if (!changes)
133 return 0;
134
135 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
136 if (!c)
137 return -ENOMEM;
138
139 *changes = c;
140 i = *n_changes;
141
142 c[i].type = type;
143 c[i].path = strdup(path);
144 if (!c[i].path)
145 return -ENOMEM;
146
147 if (source) {
148 c[i].source = strdup(source);
149 if (!c[i].source) {
150 free(c[i].path);
151 return -ENOMEM;
152 }
153 } else
154 c[i].source = NULL;
155
156 *n_changes = i+1;
157 return 0;
158}
159
160static int mark_symlink_for_removal(
161 Set **remove_symlinks_to,
162 const char *p) {
163
164 char *n;
165 int r;
166
167 assert(p);
168
169 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
170 if (r < 0)
171 return r;
172
173 n = strdup(p);
174 if (!n)
175 return -ENOMEM;
176
177 path_kill_slashes(n);
178
179 r = set_consume(*remove_symlinks_to, n);
180 if (r < 0)
181 return r == -EEXIST ? 0 : r;
182
183 return 0;
184}
185
186static int remove_marked_symlinks_fd(
187 Set *remove_symlinks_to,
188 int fd,
189 const char *path,
190 const char *config_path,
191 bool *deleted,
192 UnitFileChange **changes,
193 unsigned *n_changes,
194 char** files) {
195
196 int r = 0;
197 _cleanup_closedir_ DIR *d = NULL;
198
199 assert(remove_symlinks_to);
200 assert(fd >= 0);
201 assert(path);
202 assert(config_path);
203 assert(deleted);
204
205 d = fdopendir(fd);
206 if (!d) {
207 safe_close(fd);
208 return -errno;
209 }
210
211 rewinddir(d);
212
213 for (;;) {
214 struct dirent *de;
215
216 errno = 0;
217 de = readdir(d);
218 if (!de && errno != 0) {
219 r = -errno;
220 break;
221 }
222
223 if (!de)
224 break;
225
226 if (ignore_file(de->d_name))
227 continue;
228
229 dirent_ensure_type(d, de);
230
231 if (de->d_type == DT_DIR) {
232 int nfd, q;
233 _cleanup_free_ char *p = NULL;
234
235 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
236 if (nfd < 0) {
237 if (errno == ENOENT)
238 continue;
239
240 if (r == 0)
241 r = -errno;
242 continue;
243 }
244
245 p = path_make_absolute(de->d_name, path);
246 if (!p) {
247 safe_close(nfd);
248 return -ENOMEM;
249 }
250
251 /* This will close nfd, regardless whether it succeeds or not */
252 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
253
254 if (r == 0)
255 r = q;
256
257 } else if (de->d_type == DT_LNK) {
258 _cleanup_free_ char *p = NULL, *dest = NULL;
259 int q;
260 bool found;
261
262 p = path_make_absolute(de->d_name, path);
263 if (!p)
264 return -ENOMEM;
265
266 q = readlink_and_canonicalize(p, &dest);
267 if (q < 0) {
268 if (q == -ENOENT)
269 continue;
270
271 if (r == 0)
272 r = q;
273 continue;
274 }
275
276 found =
277 set_get(remove_symlinks_to, dest) ||
278 set_get(remove_symlinks_to, basename(dest));
279
280 if (unit_name_is_instance(p))
281 found = found && strv_contains(files, basename(p));
282
283 if (found) {
284
285 if (unlink(p) < 0 && errno != ENOENT) {
286
287 if (r == 0)
288 r = -errno;
289 } else {
290 rmdir_parents(p, config_path);
291 path_kill_slashes(p);
292
293 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
294
295 if (!set_get(remove_symlinks_to, p)) {
296
297 q = mark_symlink_for_removal(&remove_symlinks_to, p);
298 if (q < 0) {
299 if (r == 0)
300 r = q;
301 } else
302 *deleted = true;
303 }
304 }
305 }
306 }
307 }
308
309 return r;
310}
311
312static int remove_marked_symlinks(
313 Set *remove_symlinks_to,
314 const char *config_path,
315 UnitFileChange **changes,
316 unsigned *n_changes,
317 char** files) {
318
319 int fd, r = 0;
320 bool deleted;
321
322 assert(config_path);
323
324 if (set_size(remove_symlinks_to) <= 0)
325 return 0;
326
327 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
328 if (fd < 0)
329 return -errno;
330
331 do {
332 int q, cfd;
333 deleted = false;
334
335 cfd = dup(fd);
336 if (cfd < 0) {
337 r = -errno;
338 break;
339 }
340
341 /* This takes possession of cfd and closes it */
342 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
343 if (r == 0)
344 r = q;
345 } while (deleted);
346
347 safe_close(fd);
348
349 return r;
350}
351
352static int find_symlinks_fd(
353 const char *name,
354 int fd,
355 const char *path,
356 const char *config_path,
357 bool *same_name_link) {
358
359 int r = 0;
360 _cleanup_closedir_ DIR *d = NULL;
361
362 assert(name);
363 assert(fd >= 0);
364 assert(path);
365 assert(config_path);
366 assert(same_name_link);
367
368 d = fdopendir(fd);
369 if (!d) {
370 safe_close(fd);
371 return -errno;
372 }
373
374 for (;;) {
375 struct dirent *de;
376
377 errno = 0;
378 de = readdir(d);
379 if (!de && errno != 0)
380 return -errno;
381
382 if (!de)
383 return r;
384
385 if (ignore_file(de->d_name))
386 continue;
387
388 dirent_ensure_type(d, de);
389
390 if (de->d_type == DT_DIR) {
391 int nfd, q;
392 _cleanup_free_ char *p = NULL;
393
394 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
395 if (nfd < 0) {
396 if (errno == ENOENT)
397 continue;
398
399 if (r == 0)
400 r = -errno;
401 continue;
402 }
403
404 p = path_make_absolute(de->d_name, path);
405 if (!p) {
406 safe_close(nfd);
407 return -ENOMEM;
408 }
409
410 /* This will close nfd, regardless whether it succeeds or not */
411 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
412
413 if (q > 0)
414 return 1;
415
416 if (r == 0)
417 r = q;
418
419 } else if (de->d_type == DT_LNK) {
420 _cleanup_free_ char *p = NULL, *dest = NULL;
421 bool found_path, found_dest, b = false;
422 int q;
423
424 /* Acquire symlink name */
425 p = path_make_absolute(de->d_name, path);
426 if (!p)
427 return -ENOMEM;
428
429 /* Acquire symlink destination */
430 q = readlink_and_canonicalize(p, &dest);
431 if (q < 0) {
432 if (q == -ENOENT)
433 continue;
434
435 if (r == 0)
436 r = q;
437 continue;
438 }
439
440 /* Check if the symlink itself matches what we
441 * are looking for */
442 if (path_is_absolute(name))
443 found_path = path_equal(p, name);
444 else
445 found_path = streq(de->d_name, name);
446
447 /* Check if what the symlink points to
448 * matches what we are looking for */
449 if (path_is_absolute(name))
450 found_dest = path_equal(dest, name);
451 else
452 found_dest = streq(basename(dest), name);
453
454 if (found_path && found_dest) {
455 _cleanup_free_ char *t = NULL;
456
457 /* Filter out same name links in the main
458 * config path */
459 t = path_make_absolute(name, config_path);
460 if (!t)
461 return -ENOMEM;
462
463 b = path_equal(t, p);
464 }
465
466 if (b)
467 *same_name_link = true;
468 else if (found_path || found_dest)
469 return 1;
470 }
471 }
472}
473
474static int find_symlinks(
475 const char *name,
476 const char *config_path,
477 bool *same_name_link) {
478
479 int fd;
480
481 assert(name);
482 assert(config_path);
483 assert(same_name_link);
484
485 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
486 if (fd < 0) {
487 if (errno == ENOENT)
488 return 0;
489 return -errno;
490 }
491
492 /* This takes possession of fd and closes it */
493 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
494}
495
496static int find_symlinks_in_scope(
497 UnitFileScope scope,
498 const char *root_dir,
499 const char *name,
500 UnitFileState *state) {
501
502 int r;
503 _cleanup_free_ char *path2 = NULL;
504 bool same_name_link_runtime = false, same_name_link = false;
505
506 assert(scope >= 0);
507 assert(scope < _UNIT_FILE_SCOPE_MAX);
508 assert(name);
509
510 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
511 _cleanup_free_ char *path = NULL;
512
513 /* First look in runtime config path */
514 r = get_config_path(scope, true, root_dir, &path);
515 if (r < 0)
516 return r;
517
518 r = find_symlinks(name, path, &same_name_link_runtime);
519 if (r < 0)
520 return r;
521 else if (r > 0) {
522 *state = UNIT_FILE_ENABLED_RUNTIME;
523 return r;
524 }
525 }
526
527 /* Then look in the normal config path */
528 r = get_config_path(scope, false, root_dir, &path2);
529 if (r < 0)
530 return r;
531
532 r = find_symlinks(name, path2, &same_name_link);
533 if (r < 0)
534 return r;
535 else if (r > 0) {
536 *state = UNIT_FILE_ENABLED;
537 return r;
538 }
539
540 /* Hmm, we didn't find it, but maybe we found the same name
541 * link? */
542 if (same_name_link_runtime) {
543 *state = UNIT_FILE_LINKED_RUNTIME;
544 return 1;
545 } else if (same_name_link) {
546 *state = UNIT_FILE_LINKED;
547 return 1;
548 }
549
550 return 0;
551}
552
553int unit_file_mask(
554 UnitFileScope scope,
555 bool runtime,
556 const char *root_dir,
557 char **files,
558 bool force,
559 UnitFileChange **changes,
560 unsigned *n_changes) {
561
562 char **i;
563 _cleanup_free_ char *prefix;
564 int r;
565
566 assert(scope >= 0);
567 assert(scope < _UNIT_FILE_SCOPE_MAX);
568
569 r = get_config_path(scope, runtime, root_dir, &prefix);
570 if (r < 0)
571 return r;
572
573 STRV_FOREACH(i, files) {
574 _cleanup_free_ char *path = NULL;
575
576 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
577 if (r == 0)
578 r = -EINVAL;
579 continue;
580 }
581
582 path = path_make_absolute(*i, prefix);
583 if (!path) {
584 r = -ENOMEM;
585 break;
586 }
587
588 if (symlink("/dev/null", path) >= 0) {
589 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
590
591 continue;
592 }
593
594 if (errno == EEXIST) {
595
596 if (null_or_empty_path(path) > 0)
597 continue;
598
599 if (force) {
600 unlink(path);
601
602 if (symlink("/dev/null", path) >= 0) {
603
604 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
605 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
606
607 continue;
608 }
609 }
610
611 if (r == 0)
612 r = -EEXIST;
613 } else {
614 if (r == 0)
615 r = -errno;
616 }
617 }
618
619 return r;
620}
621
622int unit_file_unmask(
623 UnitFileScope scope,
624 bool runtime,
625 const char *root_dir,
626 char **files,
627 UnitFileChange **changes,
628 unsigned *n_changes) {
629
630 char **i, *config_path = NULL;
631 int r, q;
632 Set *remove_symlinks_to = NULL;
633
634 assert(scope >= 0);
635 assert(scope < _UNIT_FILE_SCOPE_MAX);
636
637 r = get_config_path(scope, runtime, root_dir, &config_path);
638 if (r < 0)
639 goto finish;
640
641 STRV_FOREACH(i, files) {
642 char *path;
643
644 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
645 if (r == 0)
646 r = -EINVAL;
647 continue;
648 }
649
650 path = path_make_absolute(*i, config_path);
651 if (!path) {
652 r = -ENOMEM;
653 break;
654 }
655
656 q = null_or_empty_path(path);
657 if (q > 0) {
658 if (unlink(path) >= 0) {
659 mark_symlink_for_removal(&remove_symlinks_to, path);
660 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
661
662 free(path);
663 continue;
664 }
665
666 q = -errno;
667 }
668
669 if (q != -ENOENT && r == 0)
670 r = q;
671
672 free(path);
673 }
674
675
676finish:
677 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
678 if (r == 0)
679 r = q;
680
681 set_free_free(remove_symlinks_to);
682 free(config_path);
683
684 return r;
685}
686
687int unit_file_link(
688 UnitFileScope scope,
689 bool runtime,
690 const char *root_dir,
691 char **files,
692 bool force,
693 UnitFileChange **changes,
694 unsigned *n_changes) {
695
696 _cleanup_lookup_paths_free_ LookupPaths paths = {};
697 char **i;
698 _cleanup_free_ char *config_path = NULL;
699 int r, q;
700
701 assert(scope >= 0);
702 assert(scope < _UNIT_FILE_SCOPE_MAX);
703
704 r = lookup_paths_init_from_scope(&paths, scope);
705 if (r < 0)
706 return r;
707
708 r = get_config_path(scope, runtime, root_dir, &config_path);
709 if (r < 0)
710 return r;
711
712 STRV_FOREACH(i, files) {
713 _cleanup_free_ char *path = NULL;
714 char *fn;
715 struct stat st;
716
717 fn = basename(*i);
718
719 if (!path_is_absolute(*i) ||
720 !unit_name_is_valid(fn, TEMPLATE_VALID)) {
721 if (r == 0)
722 r = -EINVAL;
723 continue;
724 }
725
726 if (lstat(*i, &st) < 0) {
727 if (r == 0)
728 r = -errno;
729 continue;
730 }
731
732 if (!S_ISREG(st.st_mode)) {
733 r = -ENOENT;
734 continue;
735 }
736
737 q = in_search_path(*i, paths.unit_path);
738 if (q < 0)
739 return q;
740
741 if (q > 0)
742 continue;
743
744 path = path_make_absolute(fn, config_path);
745 if (!path)
746 return -ENOMEM;
747
748 if (symlink(*i, path) >= 0) {
749 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
750 continue;
751 }
752
753 if (errno == EEXIST) {
754 _cleanup_free_ char *dest = NULL;
755
756 q = readlink_and_make_absolute(path, &dest);
757
758 if (q < 0 && errno != ENOENT) {
759 if (r == 0)
760 r = q;
761 continue;
762 }
763
764 if (q >= 0 && path_equal(dest, *i))
765 continue;
766
767 if (force) {
768 unlink(path);
769
770 if (symlink(*i, path) >= 0) {
771
772 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
773 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
774
775 continue;
776 }
777 }
778
779 if (r == 0)
780 r = -EEXIST;
781 } else {
782 if (r == 0)
783 r = -errno;
784 }
785 }
786
787 return r;
788}
789
790void unit_file_list_free(Hashmap *h) {
791 UnitFileList *i;
792
793 while ((i = hashmap_steal_first(h))) {
794 free(i->path);
795 free(i);
796 }
797
798 hashmap_free(h);
799}
800
801void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
802 unsigned i;
803
804 assert(changes || n_changes == 0);
805
806 if (!changes)
807 return;
808
809 for (i = 0; i < n_changes; i++) {
810 free(changes[i].path);
811 free(changes[i].source);
812 }
813
814 free(changes);
815}
816
817static void install_info_free(InstallInfo *i) {
818 assert(i);
819
820 free(i->name);
821 free(i->path);
822 strv_free(i->aliases);
823 strv_free(i->wanted_by);
824 strv_free(i->required_by);
825 free(i);
826}
827
828static void install_info_hashmap_free(Hashmap *m) {
829 InstallInfo *i;
830
831 if (!m)
832 return;
833
834 while ((i = hashmap_steal_first(m)))
835 install_info_free(i);
836
837 hashmap_free(m);
838}
839
840static void install_context_done(InstallContext *c) {
841 assert(c);
842
843 install_info_hashmap_free(c->will_install);
844 install_info_hashmap_free(c->have_installed);
845
846 c->will_install = c->have_installed = NULL;
847}
848
849static int install_info_add(
850 InstallContext *c,
851 const char *name,
852 const char *path) {
853 InstallInfo *i = NULL;
854 int r;
855
856 assert(c);
857 assert(name || path);
858
859 if (!name)
860 name = basename(path);
861
862 if (!unit_name_is_valid(name, TEMPLATE_VALID))
863 return -EINVAL;
864
865 if (hashmap_get(c->have_installed, name) ||
866 hashmap_get(c->will_install, name))
867 return 0;
868
869 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
870 if (r < 0)
871 return r;
872
873 i = new0(InstallInfo, 1);
874 if (!i)
875 return -ENOMEM;
876
877 i->name = strdup(name);
878 if (!i->name) {
879 r = -ENOMEM;
880 goto fail;
881 }
882
883 if (path) {
884 i->path = strdup(path);
885 if (!i->path) {
886 r = -ENOMEM;
887 goto fail;
888 }
889 }
890
891 r = hashmap_put(c->will_install, i->name, i);
892 if (r < 0)
893 goto fail;
894
895 return 0;
896
897fail:
898 if (i)
899 install_info_free(i);
900
901 return r;
902}
903
904static int install_info_add_auto(
905 InstallContext *c,
906 const char *name_or_path) {
907
908 assert(c);
909 assert(name_or_path);
910
911 if (path_is_absolute(name_or_path))
912 return install_info_add(c, NULL, name_or_path);
913 else
914 return install_info_add(c, name_or_path, NULL);
915}
916
917static int config_parse_also(const char *unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
921 unsigned section_line,
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
927
928 char *w;
929 size_t l;
930 char *state;
931 InstallContext *c = data;
932
933 assert(filename);
934 assert(lvalue);
935 assert(rvalue);
936
937 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
938 _cleanup_free_ char *n;
939 int r;
940
941 n = strndup(w, l);
942 if (!n)
943 return -ENOMEM;
944
945 r = install_info_add(c, n, NULL);
946 if (r < 0)
947 return r;
948 }
949
950 return 0;
951}
952
953static int config_parse_user(const char *unit,
954 const char *filename,
955 unsigned line,
956 const char *section,
957 unsigned section_line,
958 const char *lvalue,
959 int ltype,
960 const char *rvalue,
961 void *data,
962 void *userdata) {
963
964 InstallInfo *i = data;
965 char* printed;
966 int r;
967
968 assert(filename);
969 assert(lvalue);
970 assert(rvalue);
971
972 r = install_full_printf(i, rvalue, &printed);
973 if (r < 0)
974 return r;
975
976 free(i->user);
977 i->user = printed;
978
979 return 0;
980}
981
982static int unit_file_load(
983 InstallContext *c,
984 InstallInfo *info,
985 const char *path,
986 bool allow_symlink) {
987
988 const ConfigTableItem items[] = {
989 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
990 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
991 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
992 { "Install", "Also", config_parse_also, 0, c },
993 { "Exec", "User", config_parse_user, 0, info },
994 { NULL, NULL, NULL, 0, NULL }
995 };
996
997 int fd;
998 _cleanup_fclose_ FILE *f = NULL;
999 int r;
1000
1001 assert(c);
1002 assert(info);
1003 assert(path);
1004
1005 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1006 if (fd < 0)
1007 return -errno;
1008
1009 f = fdopen(fd, "re");
1010 if (!f) {
1011 safe_close(fd);
1012 return -ENOMEM;
1013 }
1014
1015 r = config_parse(NULL, path, f, NULL,
1016 config_item_table_lookup, (void*) items, true, true, info);
1017 if (r < 0)
1018 return r;
1019
1020 return
1021 (int) strv_length(info->aliases) +
1022 (int) strv_length(info->wanted_by) +
1023 (int) strv_length(info->required_by);
1024}
1025
1026static int unit_file_search(
1027 InstallContext *c,
1028 InstallInfo *info,
1029 LookupPaths *paths,
1030 const char *root_dir,
1031 bool allow_symlink) {
1032
1033 char **p;
1034 int r;
1035
1036 assert(c);
1037 assert(info);
1038 assert(paths);
1039
1040 if (info->path)
1041 return unit_file_load(c, info, info->path, allow_symlink);
1042
1043 assert(info->name);
1044
1045 STRV_FOREACH(p, paths->unit_path) {
1046 char *path = NULL;
1047
1048 if (isempty(root_dir))
1049 asprintf(&path, "%s/%s", *p, info->name);
1050 else
1051 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1052
1053 if (!path)
1054 return -ENOMEM;
1055
1056 r = unit_file_load(c, info, path, allow_symlink);
1057
1058 if (r >= 0)
1059 info->path = path;
1060 else {
1061 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1062 /* Unit file doesn't exist, however instance enablement was requested.
1063 * We will check if it is possible to load template unit file. */
1064 char *template = NULL,
1065 *template_path = NULL,
1066 *template_dir = NULL;
1067
1068 template = unit_name_template(info->name);
1069 if (!template) {
1070 free(path);
1071 return -ENOMEM;
1072 }
1073
1074 /* We will reuse path variable since we don't need it anymore. */
1075 template_dir = path;
1076 *(strrchr(path, '/') + 1) = '\0';
1077
1078 template_path = strjoin(template_dir, template, NULL);
1079 if (!template_path) {
1080 free(path);
1081 free(template);
1082 return -ENOMEM;
1083 }
1084
1085 /* Let's try to load template unit. */
1086 r = unit_file_load(c, info, template_path, allow_symlink);
1087 if (r >= 0) {
1088 info->path = strdup(template_path);
1089 if (!info->path) {
1090 free(path);
1091 free(template);
1092 free(template_path);
1093 return -ENOMEM;
1094 }
1095 }
1096
1097 free(template);
1098 free(template_path);
1099 }
1100 free(path);
1101 }
1102
1103 if (r != -ENOENT && r != -ELOOP)
1104 return r;
1105 }
1106
1107 return -ENOENT;
1108}
1109
1110static int unit_file_can_install(
1111 LookupPaths *paths,
1112 const char *root_dir,
1113 const char *name,
1114 bool allow_symlink) {
1115
1116 _cleanup_install_context_done_ InstallContext c = {};
1117 InstallInfo *i;
1118 int r;
1119
1120 assert(paths);
1121 assert(name);
1122
1123 r = install_info_add_auto(&c, name);
1124 if (r < 0)
1125 return r;
1126
1127 assert_se(i = hashmap_first(c.will_install));
1128
1129 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1130
1131 if (r >= 0)
1132 r =
1133 (int) strv_length(i->aliases) +
1134 (int) strv_length(i->wanted_by) +
1135 (int) strv_length(i->required_by);
1136
1137 return r;
1138}
1139
1140static int create_symlink(
1141 const char *old_path,
1142 const char *new_path,
1143 bool force,
1144 UnitFileChange **changes,
1145 unsigned *n_changes) {
1146
1147 _cleanup_free_ char *dest = NULL;
1148 int r;
1149
1150 assert(old_path);
1151 assert(new_path);
1152
1153 mkdir_parents_label(new_path, 0755);
1154
1155 if (symlink(old_path, new_path) >= 0) {
1156 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1157 return 0;
1158 }
1159
1160 if (errno != EEXIST)
1161 return -errno;
1162
1163 r = readlink_and_make_absolute(new_path, &dest);
1164 if (r < 0)
1165 return r;
1166
1167 if (path_equal(dest, old_path))
1168 return 0;
1169
1170 if (!force)
1171 return -EEXIST;
1172
1173 r = unlink(new_path);
1174 if (r < 0 && errno != ENOENT)
1175 return -errno;
1176
1177 if (symlink(old_path, new_path) >= 0) {
1178 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1179 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1180 return 0;
1181 }
1182
1183 return -errno;
1184}
1185
1186static int install_info_symlink_alias(
1187 InstallInfo *i,
1188 const char *config_path,
1189 bool force,
1190 UnitFileChange **changes,
1191 unsigned *n_changes) {
1192
1193 char **s;
1194 int r = 0, q;
1195
1196 assert(i);
1197 assert(config_path);
1198
1199 STRV_FOREACH(s, i->aliases) {
1200 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
1201
1202 q = install_full_printf(i, *s, &dst);
1203 if (q < 0)
1204 return q;
1205
1206 alias_path = path_make_absolute(dst, config_path);
1207 if (!alias_path)
1208 return -ENOMEM;
1209
1210 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1211 if (r == 0)
1212 r = q;
1213 }
1214
1215 return r;
1216}
1217
1218static int install_info_symlink_wants(
1219 InstallInfo *i,
1220 const char *config_path,
1221 bool force,
1222 UnitFileChange **changes,
1223 unsigned *n_changes) {
1224
1225 char **s;
1226 int r = 0, q;
1227
1228 assert(i);
1229 assert(config_path);
1230
1231 STRV_FOREACH(s, i->wanted_by) {
1232 _cleanup_free_ char *path = NULL, *dst = NULL;
1233
1234 q = install_full_printf(i, *s, &dst);
1235 if (q < 0)
1236 return q;
1237
1238 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
1239 r = -EINVAL;
1240 continue;
1241 }
1242
1243 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
1244 return -ENOMEM;
1245
1246 q = create_symlink(i->path, path, force, changes, n_changes);
1247
1248 if (r == 0)
1249 r = q;
1250 }
1251
1252 return r;
1253}
1254
1255static int install_info_symlink_requires(
1256 InstallInfo *i,
1257 const char *config_path,
1258 bool force,
1259 UnitFileChange **changes,
1260 unsigned *n_changes) {
1261
1262 char **s;
1263 int r = 0, q;
1264
1265 assert(i);
1266 assert(config_path);
1267
1268 STRV_FOREACH(s, i->required_by) {
1269 _cleanup_free_ char *path = NULL, *dst = NULL;
1270
1271 q = install_full_printf(i, *s, &dst);
1272 if (q < 0)
1273 return q;
1274
1275 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
1276 r = -EINVAL;
1277 continue;
1278 }
1279
1280 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
1281 return -ENOMEM;
1282
1283 q = create_symlink(i->path, path, force, changes, n_changes);
1284
1285 if (r == 0)
1286 r = q;
1287 }
1288
1289 return r;
1290}
1291
1292static int install_info_symlink_link(
1293 InstallInfo *i,
1294 LookupPaths *paths,
1295 const char *config_path,
1296 bool force,
1297 UnitFileChange **changes,
1298 unsigned *n_changes) {
1299
1300 int r;
1301 _cleanup_free_ char *path = NULL;
1302
1303 assert(i);
1304 assert(paths);
1305 assert(config_path);
1306 assert(i->path);
1307
1308 r = in_search_path(i->path, paths->unit_path);
1309 if (r != 0)
1310 return r;
1311
1312 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1313 return -ENOMEM;
1314
1315 r = create_symlink(i->path, path, force, changes, n_changes);
1316 return r;
1317}
1318
1319static int install_info_apply(
1320 InstallInfo *i,
1321 LookupPaths *paths,
1322 const char *config_path,
1323 bool force,
1324 UnitFileChange **changes,
1325 unsigned *n_changes) {
1326
1327 int r, q;
1328
1329 assert(i);
1330 assert(paths);
1331 assert(config_path);
1332
1333 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1334
1335 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1336 if (r == 0)
1337 r = q;
1338
1339 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1340 if (r == 0)
1341 r = q;
1342
1343 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1344 if (r == 0)
1345 r = q;
1346
1347 return r;
1348}
1349
1350static int install_context_apply(
1351 InstallContext *c,
1352 LookupPaths *paths,
1353 const char *config_path,
1354 const char *root_dir,
1355 bool force,
1356 UnitFileChange **changes,
1357 unsigned *n_changes) {
1358
1359 InstallInfo *i;
1360 int r = 0, q;
1361
1362 assert(c);
1363 assert(paths);
1364 assert(config_path);
1365
1366 while ((i = hashmap_first(c->will_install))) {
1367
1368 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1369 if (q < 0)
1370 return q;
1371
1372 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1373
1374 q = unit_file_search(c, i, paths, root_dir, false);
1375 if (q < 0) {
1376 if (r >= 0)
1377 r = q;
1378
1379 return r;
1380 } else if (r >= 0)
1381 r += q;
1382
1383 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1384 if (r >= 0 && q < 0)
1385 r = q;
1386 }
1387
1388 return r;
1389}
1390
1391static int install_context_mark_for_removal(
1392 InstallContext *c,
1393 LookupPaths *paths,
1394 Set **remove_symlinks_to,
1395 const char *config_path,
1396 const char *root_dir) {
1397
1398 InstallInfo *i;
1399 int r = 0, q;
1400
1401 assert(c);
1402 assert(paths);
1403 assert(config_path);
1404
1405 /* Marks all items for removal */
1406
1407 while ((i = hashmap_first(c->will_install))) {
1408
1409 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1410 if (q < 0)
1411 return q;
1412
1413 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1414
1415 q = unit_file_search(c, i, paths, root_dir, false);
1416 if (q == -ENOENT) {
1417 /* do nothing */
1418 } else if (q < 0) {
1419 if (r >= 0)
1420 r = q;
1421
1422 return r;
1423 } else if (r >= 0)
1424 r += q;
1425
1426 if (unit_name_is_instance(i->name)) {
1427 char *unit_file;
1428
1429 if (i->path) {
1430 unit_file = basename(i->path);
1431
1432 if (unit_name_is_instance(unit_file))
1433 /* unit file named as instance exists, thus all symlinks
1434 * pointing to it will be removed */
1435 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1436 else
1437 /* does not exist, thus we will mark for removal symlinks
1438 * to template unit file */
1439 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1440 } else {
1441 /* If i->path is not set, it means that we didn't actually find
1442 * the unit file. But we can still remove symlinks to the
1443 * nonexistent template. */
1444 unit_file = unit_name_template(i->name);
1445 if (!unit_file)
1446 return log_oom();
1447
1448 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1449 free(unit_file);
1450 }
1451 } else
1452 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1453
1454 if (r >= 0 && q < 0)
1455 r = q;
1456 }
1457
1458 return r;
1459}
1460
1461int unit_file_enable(
1462 UnitFileScope scope,
1463 bool runtime,
1464 const char *root_dir,
1465 char **files,
1466 bool force,
1467 UnitFileChange **changes,
1468 unsigned *n_changes) {
1469
1470 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1471 _cleanup_install_context_done_ InstallContext c = {};
1472 char **i;
1473 _cleanup_free_ char *config_path = NULL;
1474 int r;
1475
1476 assert(scope >= 0);
1477 assert(scope < _UNIT_FILE_SCOPE_MAX);
1478
1479 r = lookup_paths_init_from_scope(&paths, scope);
1480 if (r < 0)
1481 return r;
1482
1483 r = get_config_path(scope, runtime, root_dir, &config_path);
1484 if (r < 0)
1485 return r;
1486
1487 STRV_FOREACH(i, files) {
1488 r = install_info_add_auto(&c, *i);
1489 if (r < 0)
1490 return r;
1491 }
1492
1493 /* This will return the number of symlink rules that were
1494 supposed to be created, not the ones actually created. This is
1495 useful to determine whether the passed files had any
1496 installation data at all. */
1497
1498 return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1499}
1500
1501int unit_file_disable(
1502 UnitFileScope scope,
1503 bool runtime,
1504 const char *root_dir,
1505 char **files,
1506 UnitFileChange **changes,
1507 unsigned *n_changes) {
1508
1509 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1510 _cleanup_install_context_done_ InstallContext c = {};
1511 char **i;
1512 _cleanup_free_ char *config_path = NULL;
1513 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1514 int r, q;
1515
1516 assert(scope >= 0);
1517 assert(scope < _UNIT_FILE_SCOPE_MAX);
1518
1519 r = lookup_paths_init_from_scope(&paths, scope);
1520 if (r < 0)
1521 return r;
1522
1523 r = get_config_path(scope, runtime, root_dir, &config_path);
1524 if (r < 0)
1525 return r;
1526
1527 STRV_FOREACH(i, files) {
1528 r = install_info_add_auto(&c, *i);
1529 if (r < 0)
1530 return r;
1531 }
1532
1533 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1534
1535 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1536 if (r == 0)
1537 r = q;
1538
1539 return r;
1540}
1541
1542int unit_file_reenable(
1543 UnitFileScope scope,
1544 bool runtime,
1545 const char *root_dir,
1546 char **files,
1547 bool force,
1548 UnitFileChange **changes,
1549 unsigned *n_changes) {
1550 int r;
1551
1552 r = unit_file_disable(scope, runtime, root_dir, files,
1553 changes, n_changes);
1554 if (r < 0)
1555 return r;
1556
1557 return unit_file_enable(scope, runtime, root_dir, files, force,
1558 changes, n_changes);
1559}
1560
1561int unit_file_set_default(
1562 UnitFileScope scope,
1563 const char *root_dir,
1564 const char *file,
1565 bool force,
1566 UnitFileChange **changes,
1567 unsigned *n_changes) {
1568
1569 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1570 _cleanup_install_context_done_ InstallContext c = {};
1571 _cleanup_free_ char *config_path = NULL;
1572 char *path;
1573 int r;
1574 InstallInfo *i = NULL;
1575
1576 assert(scope >= 0);
1577 assert(scope < _UNIT_FILE_SCOPE_MAX);
1578 assert(file);
1579
1580 if (unit_name_to_type(file) != UNIT_TARGET)
1581 return -EINVAL;
1582
1583 r = lookup_paths_init_from_scope(&paths, scope);
1584 if (r < 0)
1585 return r;
1586
1587 r = get_config_path(scope, false, root_dir, &config_path);
1588 if (r < 0)
1589 return r;
1590
1591 r = install_info_add_auto(&c, file);
1592 if (r < 0)
1593 return r;
1594
1595 assert_se(i = hashmap_first(c.will_install));
1596
1597 r = unit_file_search(&c, i, &paths, root_dir, false);
1598 if (r < 0)
1599 return r;
1600
1601 path = strappenda(config_path, "/" SPECIAL_DEFAULT_TARGET);
1602
1603 r = create_symlink(i->path, path, force, changes, n_changes);
1604 if (r < 0)
1605 return r;
1606
1607 return 0;
1608}
1609
1610int unit_file_get_default(
1611 UnitFileScope scope,
1612 const char *root_dir,
1613 char **name) {
1614
1615 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1616 char **p;
1617 int r;
1618
1619 assert(scope >= 0);
1620 assert(scope < _UNIT_FILE_SCOPE_MAX);
1621 assert(name);
1622
1623 r = lookup_paths_init_from_scope(&paths, scope);
1624 if (r < 0)
1625 return r;
1626
1627 STRV_FOREACH(p, paths.unit_path) {
1628 _cleanup_free_ char *path = NULL, *tmp = NULL;
1629 char *n;
1630
1631 if (isempty(root_dir))
1632 path = strappend(*p, "/" SPECIAL_DEFAULT_TARGET);
1633 else
1634 path = strjoin(root_dir, "/", *p, "/" SPECIAL_DEFAULT_TARGET, NULL);
1635
1636 if (!path)
1637 return -ENOMEM;
1638
1639 r = readlink_malloc(path, &tmp);
1640 if (r == -ENOENT)
1641 continue;
1642 else if (r == -EINVAL)
1643 /* not a symlink */
1644 n = strdup(SPECIAL_DEFAULT_TARGET);
1645 else if (r < 0)
1646 return r;
1647 else
1648 n = strdup(basename(tmp));
1649
1650 if (!n)
1651 return -ENOMEM;
1652
1653 *name = n;
1654 return 0;
1655 }
1656
1657 return -ENOENT;
1658}
1659
1660UnitFileState unit_file_get_state(
1661 UnitFileScope scope,
1662 const char *root_dir,
1663 const char *name) {
1664
1665 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1666 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1667 char **i;
1668 _cleanup_free_ char *path = NULL;
1669 int r;
1670
1671 assert(scope >= 0);
1672 assert(scope < _UNIT_FILE_SCOPE_MAX);
1673 assert(name);
1674
1675 if (root_dir && scope != UNIT_FILE_SYSTEM)
1676 return -EINVAL;
1677
1678 if (!unit_name_is_valid(name, TEMPLATE_VALID))
1679 return -EINVAL;
1680
1681 r = lookup_paths_init_from_scope(&paths, scope);
1682 if (r < 0)
1683 return r;
1684
1685 STRV_FOREACH(i, paths.unit_path) {
1686 struct stat st;
1687
1688 free(path);
1689 path = NULL;
1690
1691 if (root_dir)
1692 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1693 else
1694 asprintf(&path, "%s/%s", *i, name);
1695
1696 if (!path)
1697 return -ENOMEM;
1698
1699 /*
1700 * Search for a unit file in our default paths, to
1701 * be sure, that there are no broken symlinks.
1702 */
1703 if (lstat(path, &st) < 0) {
1704 r = -errno;
1705 if (errno != ENOENT)
1706 return r;
1707
1708 if (!unit_name_is_instance(name))
1709 continue;
1710 } else {
1711 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1712 return -ENOENT;
1713
1714 r = null_or_empty_path(path);
1715 if (r < 0 && r != -ENOENT)
1716 return r;
1717 else if (r > 0) {
1718 state = path_startswith(*i, "/run") ?
1719 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1720 return state;
1721 }
1722 }
1723
1724 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1725 if (r < 0)
1726 return r;
1727 else if (r > 0)
1728 return state;
1729
1730 r = unit_file_can_install(&paths, root_dir, path, true);
1731 if (r < 0 && errno != ENOENT)
1732 return r;
1733 else if (r > 0)
1734 return UNIT_FILE_DISABLED;
1735 else if (r == 0)
1736 return UNIT_FILE_STATIC;
1737 }
1738
1739 return r < 0 ? r : state;
1740}
1741
1742int unit_file_query_preset(UnitFileScope scope, const char *name) {
1743 _cleanup_strv_free_ char **files = NULL;
1744 char **i;
1745 int r;
1746
1747 assert(scope >= 0);
1748 assert(scope < _UNIT_FILE_SCOPE_MAX);
1749 assert(name);
1750
1751 if (scope == UNIT_FILE_SYSTEM)
1752 r = conf_files_list(&files, ".preset", NULL,
1753 "/etc/systemd/system-preset",
1754 "/usr/local/lib/systemd/system-preset",
1755 "/usr/lib/systemd/system-preset",
1756#ifdef HAVE_SPLIT_USR
1757 "/lib/systemd/system-preset",
1758#endif
1759 NULL);
1760 else if (scope == UNIT_FILE_GLOBAL)
1761 r = conf_files_list(&files, ".preset", NULL,
1762 "/etc/systemd/user-preset",
1763 "/usr/local/lib/systemd/user-preset",
1764 "/usr/lib/systemd/user-preset",
1765 NULL);
1766 else
1767 return 1;
1768
1769 if (r < 0)
1770 return r;
1771
1772 STRV_FOREACH(i, files) {
1773 _cleanup_fclose_ FILE *f;
1774
1775 f = fopen(*i, "re");
1776 if (!f) {
1777 if (errno == ENOENT)
1778 continue;
1779
1780 return -errno;
1781 }
1782
1783 for (;;) {
1784 char line[LINE_MAX], *l;
1785
1786 if (!fgets(line, sizeof(line), f))
1787 break;
1788
1789 l = strstrip(line);
1790 if (!*l)
1791 continue;
1792
1793 if (strchr(COMMENTS "\n", *l))
1794 continue;
1795
1796 if (first_word(l, "enable")) {
1797 l += 6;
1798 l += strspn(l, WHITESPACE);
1799
1800 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1801 return 1;
1802
1803 } else if (first_word(l, "disable")) {
1804 l += 7;
1805 l += strspn(l, WHITESPACE);
1806
1807 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1808 return 0;
1809
1810 } else
1811 log_debug("Couldn't parse line '%s'", l);
1812 }
1813 }
1814
1815 /* Default is "enable" */
1816 return 1;
1817}
1818
1819int unit_file_preset(
1820 UnitFileScope scope,
1821 bool runtime,
1822 const char *root_dir,
1823 char **files,
1824 bool force,
1825 UnitFileChange **changes,
1826 unsigned *n_changes) {
1827
1828 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1829 _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
1830 char **i;
1831 _cleanup_free_ char *config_path = NULL;
1832 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1833 int r, q;
1834
1835 assert(scope >= 0);
1836 assert(scope < _UNIT_FILE_SCOPE_MAX);
1837
1838 r = lookup_paths_init_from_scope(&paths, scope);
1839 if (r < 0)
1840 return r;
1841
1842 r = get_config_path(scope, runtime, root_dir, &config_path);
1843 if (r < 0)
1844 return r;
1845
1846 STRV_FOREACH(i, files) {
1847
1848 if (!unit_name_is_valid(*i, TEMPLATE_VALID))
1849 return -EINVAL;
1850
1851 r = unit_file_query_preset(scope, *i);
1852 if (r < 0)
1853 return r;
1854
1855 if (r)
1856 r = install_info_add_auto(&plus, *i);
1857 else
1858 r = install_info_add_auto(&minus, *i);
1859
1860 if (r < 0)
1861 return r;
1862 }
1863
1864 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1865 config_path, root_dir);
1866
1867 q = remove_marked_symlinks(remove_symlinks_to, config_path,
1868 changes, n_changes, files);
1869 if (r == 0)
1870 r = q;
1871
1872 /* Returns number of symlinks that where supposed to be installed. */
1873 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1874 changes, n_changes);
1875 if (r == 0)
1876 r = q;
1877
1878 return r;
1879}
1880
1881static void unitfilelist_free(UnitFileList **f) {
1882 if (!*f)
1883 return;
1884
1885 free((*f)->path);
1886 free(*f);
1887}
1888#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
1889
1890int unit_file_get_list(
1891 UnitFileScope scope,
1892 const char *root_dir,
1893 Hashmap *h) {
1894
1895 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1896 char **i;
1897 _cleanup_free_ char *buf = NULL;
1898 _cleanup_closedir_ DIR *d = NULL;
1899 int r;
1900
1901 assert(scope >= 0);
1902 assert(scope < _UNIT_FILE_SCOPE_MAX);
1903 assert(h);
1904
1905 if (root_dir && scope != UNIT_FILE_SYSTEM)
1906 return -EINVAL;
1907
1908 r = lookup_paths_init_from_scope(&paths, scope);
1909 if (r < 0)
1910 return r;
1911
1912 STRV_FOREACH(i, paths.unit_path) {
1913 const char *units_dir;
1914
1915 free(buf);
1916 buf = NULL;
1917
1918 if (root_dir) {
1919 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1920 return -ENOMEM;
1921
1922 units_dir = buf;
1923 } else
1924 units_dir = *i;
1925
1926 if (d)
1927 closedir(d);
1928
1929 d = opendir(units_dir);
1930 if (!d) {
1931 if (errno == ENOENT)
1932 continue;
1933
1934 return -errno;
1935 }
1936
1937 for (;;) {
1938 struct dirent *de;
1939 _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
1940
1941 errno = 0;
1942 de = readdir(d);
1943 if (!de && errno != 0)
1944 return -errno;
1945
1946 if (!de)
1947 break;
1948
1949 if (ignore_file(de->d_name))
1950 continue;
1951
1952 if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
1953 continue;
1954
1955 if (hashmap_get(h, de->d_name))
1956 continue;
1957
1958 r = dirent_ensure_type(d, de);
1959 if (r < 0) {
1960 if (r == -ENOENT)
1961 continue;
1962
1963 return r;
1964 }
1965
1966 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1967 continue;
1968
1969 f = new0(UnitFileList, 1);
1970 if (!f)
1971 return -ENOMEM;
1972
1973 f->path = path_make_absolute(de->d_name, units_dir);
1974 if (!f->path)
1975 return -ENOMEM;
1976
1977 r = null_or_empty_path(f->path);
1978 if (r < 0 && r != -ENOENT)
1979 return r;
1980 else if (r > 0) {
1981 f->state =
1982 path_startswith(*i, "/run") ?
1983 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1984 goto found;
1985 }
1986
1987 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1988 if (r < 0)
1989 return r;
1990 else if (r > 0) {
1991 f->state = UNIT_FILE_ENABLED;
1992 goto found;
1993 }
1994
1995 r = unit_file_can_install(&paths, root_dir, f->path, true);
1996 if (r == -EINVAL || /* Invalid setting? */
1997 r == -EBADMSG || /* Invalid format? */
1998 r == -ENOENT /* Included file not found? */)
1999 f->state = UNIT_FILE_INVALID;
2000 else if (r < 0)
2001 return r;
2002 else if (r > 0)
2003 f->state = UNIT_FILE_DISABLED;
2004 else
2005 f->state = UNIT_FILE_STATIC;
2006
2007 found:
2008 r = hashmap_put(h, basename(f->path), f);
2009 if (r < 0)
2010 return r;
2011 f = NULL; /* prevent cleanup */
2012 }
2013 }
2014
2015 return r;
2016}
2017
2018static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2019 [UNIT_FILE_ENABLED] = "enabled",
2020 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
2021 [UNIT_FILE_LINKED] = "linked",
2022 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2023 [UNIT_FILE_MASKED] = "masked",
2024 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2025 [UNIT_FILE_STATIC] = "static",
2026 [UNIT_FILE_DISABLED] = "disabled",
2027 [UNIT_FILE_INVALID] = "invalid",
2028};
2029
2030DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
2031
2032static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2033 [UNIT_FILE_SYMLINK] = "symlink",
2034 [UNIT_FILE_UNLINK] = "unlink",
2035};
2036
2037DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);