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