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