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