]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
core: move ManagerRunningAs to shared
[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,
67445f4e 62 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_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);
d5891fda
ZJS
527 if (fd < 0) {
528 if (errno == ENOENT)
529 return 0;
83096483 530 return -errno;
d5891fda 531 }
83096483
LP
532
533 /* This takes possession of fd and closes it */
534 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
535}
536
537static int find_symlinks_in_scope(
538 UnitFileScope scope,
539 const char *root_dir,
540 const char *name,
541 UnitFileState *state) {
542
543 int r;
d8831ed5 544 char _cleanup_free_ *path = NULL;
83096483
LP
545 bool same_name_link_runtime = false, same_name_link = false;
546
547 assert(scope >= 0);
548 assert(scope < _UNIT_FILE_SCOPE_MAX);
549 assert(name);
550
551 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
552
553 /* First look in runtime config path */
554 r = get_config_path(scope, true, root_dir, &path);
555 if (r < 0)
556 return r;
557
558 r = find_symlinks(name, path, &same_name_link_runtime);
83096483
LP
559 if (r < 0)
560 return r;
561 else if (r > 0) {
562 *state = UNIT_FILE_ENABLED_RUNTIME;
563 return r;
564 }
565 }
566
567 /* Then look in the normal config path */
568 r = get_config_path(scope, false, root_dir, &path);
569 if (r < 0)
570 return r;
571
572 r = find_symlinks(name, path, &same_name_link);
83096483
LP
573 if (r < 0)
574 return r;
575 else if (r > 0) {
576 *state = UNIT_FILE_ENABLED;
577 return r;
578 }
579
580 /* Hmm, we didn't find it, but maybe we found the same name
581 * link? */
582 if (same_name_link_runtime) {
583 *state = UNIT_FILE_LINKED_RUNTIME;
584 return 1;
585 } else if (same_name_link) {
586 *state = UNIT_FILE_LINKED;
587 return 1;
588 }
589
590 return 0;
591}
592
593int unit_file_mask(
594 UnitFileScope scope,
595 bool runtime,
596 const char *root_dir,
597 char *files[],
598 bool force,
599 UnitFileChange **changes,
600 unsigned *n_changes) {
601
d8831ed5
ZJS
602 char **i;
603 char _cleanup_free_ *prefix;
83096483
LP
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) {
d8831ed5 614 char _cleanup_free_ *path = NULL;
83096483 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
83096483
LP
631 continue;
632 }
633
634 if (errno == EEXIST) {
635
d8831ed5 636 if (null_or_empty_path(path) > 0)
83096483 637 continue;
83096483
LP
638
639 if (force) {
640 unlink(path);
641
642 if (symlink("/dev/null", path) >= 0) {
643
644 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
645 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
646
83096483
LP
647 continue;
648 }
649 }
650
651 if (r == 0)
652 r = -EEXIST;
653 } else {
654 if (r == 0)
655 r = -errno;
656 }
83096483
LP
657 }
658
83096483
LP
659 return r;
660}
661
662int unit_file_unmask(
663 UnitFileScope scope,
664 bool runtime,
665 const char *root_dir,
666 char *files[],
667 UnitFileChange **changes,
668 unsigned *n_changes) {
669
670 char **i, *config_path = NULL;
671 int r, q;
672 Set *remove_symlinks_to = NULL;
673
674 assert(scope >= 0);
675 assert(scope < _UNIT_FILE_SCOPE_MAX);
676
677 r = get_config_path(scope, runtime, root_dir, &config_path);
678 if (r < 0)
679 goto finish;
680
681 STRV_FOREACH(i, files) {
682 char *path;
683
5f739699 684 if (!unit_name_is_valid(*i, true)) {
83096483
LP
685 if (r == 0)
686 r = -EINVAL;
687 continue;
688 }
689
690 path = path_make_absolute(*i, config_path);
691 if (!path) {
692 r = -ENOMEM;
693 break;
694 }
695
696 q = null_or_empty_path(path);
697 if (q > 0) {
698 if (unlink(path) >= 0) {
699 mark_symlink_for_removal(&remove_symlinks_to, path);
700 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
701
702 free(path);
703 continue;
704 }
705
706 q = -errno;
707 }
708
709 if (q != -ENOENT && r == 0)
710 r = q;
711
712 free(path);
713 }
714
715
716finish:
29283ea4 717 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483
LP
718 if (r == 0)
719 r = q;
720
721 set_free_free(remove_symlinks_to);
722 free(config_path);
723
724 return r;
725}
726
727int unit_file_link(
728 UnitFileScope scope,
729 bool runtime,
730 const char *root_dir,
731 char *files[],
732 bool force,
733 UnitFileChange **changes,
734 unsigned *n_changes) {
735
736 LookupPaths paths;
737 char **i, *config_path = NULL;
738 int r, q;
739
740 assert(scope >= 0);
741 assert(scope < _UNIT_FILE_SCOPE_MAX);
742
743 zero(paths);
744
745 r = lookup_paths_init_from_scope(&paths, scope);
746 if (r < 0)
747 return r;
748
749 r = get_config_path(scope, runtime, root_dir, &config_path);
750 if (r < 0)
751 goto finish;
752
753 STRV_FOREACH(i, files) {
754 char *path, *fn;
755 struct stat st;
756
9eb977db 757 fn = path_get_file_name(*i);
83096483
LP
758
759 if (!path_is_absolute(*i) ||
5f739699 760 !unit_name_is_valid(fn, true)) {
83096483
LP
761 if (r == 0)
762 r = -EINVAL;
763 continue;
764 }
765
766 if (lstat(*i, &st) < 0) {
767 if (r == 0)
768 r = -errno;
769 continue;
770 }
771
772 if (!S_ISREG(st.st_mode)) {
773 r = -ENOENT;
774 continue;
775 }
776
777 q = in_search_path(*i, paths.unit_path);
778 if (q < 0) {
779 r = q;
780 break;
781 }
782
783 if (q > 0)
784 continue;
785
786 path = path_make_absolute(fn, config_path);
787 if (!path) {
788 r = -ENOMEM;
789 break;
790 }
791
792 if (symlink(*i, path) >= 0) {
793 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
794
795 free(path);
796 continue;
797 }
798
799 if (errno == EEXIST) {
800 char *dest = NULL;
801
802 q = readlink_and_make_absolute(path, &dest);
803
804 if (q < 0 && errno != ENOENT) {
805 free(path);
806
807 if (r == 0)
808 r = q;
809
810 continue;
811 }
812
813 if (q >= 0 && path_equal(dest, *i)) {
814 free(dest);
815 free(path);
816 continue;
817 }
818
819 free(dest);
820
821 if (force) {
822 unlink(path);
823
824 if (symlink(*i, path) >= 0) {
825
826 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
827 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
828
829 free(path);
830 continue;
831 }
832 }
833
834 if (r == 0)
835 r = -EEXIST;
836 } else {
837 if (r == 0)
838 r = -errno;
839 }
840
841 free(path);
842 }
843
844 finish:
845 lookup_paths_free(&paths);
846 free(config_path);
847
848 return r;
849}
850
851void unit_file_list_free(Hashmap *h) {
852 UnitFileList *i;
853
854 while ((i = hashmap_steal_first(h))) {
855 free(i->path);
856 free(i);
857 }
858
859 hashmap_free(h);
860}
861
862void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
863 unsigned i;
864
865 assert(changes || n_changes == 0);
866
867 if (!changes)
868 return;
869
870 for (i = 0; i < n_changes; i++) {
871 free(changes[i].path);
872 free(changes[i].source);
873 }
874
875 free(changes);
876}
877
878static void install_info_free(InstallInfo *i) {
879 assert(i);
880
881 free(i->name);
882 free(i->path);
883 strv_free(i->aliases);
884 strv_free(i->wanted_by);
78d54bd4 885 strv_free(i->required_by);
83096483
LP
886 free(i);
887}
888
889static void install_info_hashmap_free(Hashmap *m) {
890 InstallInfo *i;
891
892 if (!m)
893 return;
894
895 while ((i = hashmap_steal_first(m)))
896 install_info_free(i);
897
898 hashmap_free(m);
899}
900
901static void install_context_done(InstallContext *c) {
902 assert(c);
903
904 install_info_hashmap_free(c->will_install);
905 install_info_hashmap_free(c->have_installed);
906
907 c->will_install = c->have_installed = NULL;
908}
909
910static int install_info_add(
911 InstallContext *c,
912 const char *name,
913 const char *path) {
914 InstallInfo *i = NULL;
915 int r;
916
917 assert(c);
918 assert(name || path);
919
920 if (!name)
9eb977db 921 name = path_get_file_name(path);
83096483 922
5f739699 923 if (!unit_name_is_valid(name, true))
83096483
LP
924 return -EINVAL;
925
926 if (hashmap_get(c->have_installed, name) ||
927 hashmap_get(c->will_install, name))
928 return 0;
929
930 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
931 if (r < 0)
932 return r;
933
934 i = new0(InstallInfo, 1);
935 if (!i)
936 return -ENOMEM;
937
938 i->name = strdup(name);
939 if (!i->name) {
940 r = -ENOMEM;
941 goto fail;
942 }
943
944 if (path) {
945 i->path = strdup(path);
946 if (!i->path) {
947 r = -ENOMEM;
948 goto fail;
949 }
950 }
951
952 r = hashmap_put(c->will_install, i->name, i);
953 if (r < 0)
954 goto fail;
955
956 return 0;
957
958fail:
959 if (i)
960 install_info_free(i);
961
962 return r;
963}
964
965static int install_info_add_auto(
966 InstallContext *c,
967 const char *name_or_path) {
968
969 assert(c);
970 assert(name_or_path);
971
972 if (path_is_absolute(name_or_path))
973 return install_info_add(c, NULL, name_or_path);
974 else
975 return install_info_add(c, name_or_path, NULL);
976}
977
978static int config_parse_also(
979 const char *filename,
980 unsigned line,
981 const char *section,
982 const char *lvalue,
983 int ltype,
984 const char *rvalue,
985 void *data,
986 void *userdata) {
987
988 char *w;
989 size_t l;
990 char *state;
991 InstallContext *c = data;
992
993 assert(filename);
994 assert(lvalue);
995 assert(rvalue);
996
997 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
998 char *n;
999 int r;
1000
1001 n = strndup(w, l);
1002 if (!n)
1003 return -ENOMEM;
1004
1005 r = install_info_add(c, n, NULL);
1006 if (r < 0) {
1007 free(n);
1008 return r;
1009 }
1010
1011 free(n);
1012 }
1013
1014 return 0;
1015}
1016
1017static int unit_file_load(
1018 InstallContext *c,
1019 InstallInfo *info,
1020 const char *path,
1021 bool allow_symlink) {
1022
f975e971 1023 const ConfigTableItem items[] = {
78d54bd4
LP
1024 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1025 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1026 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1027 { "Install", "Also", config_parse_also, 0, c },
f975e971 1028 { NULL, NULL, NULL, 0, NULL }
83096483
LP
1029 };
1030
1031 int fd;
1032 FILE *f;
1033 int r;
1034
1035 assert(c);
1036 assert(info);
1037 assert(path);
1038
1039 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1040 if (fd < 0)
1041 return -errno;
1042
1043 f = fdopen(fd, "re");
1044 if (!f) {
1045 close_nointr_nofail(fd);
1046 return -ENOMEM;
1047 }
1048
f975e971 1049 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
83096483
LP
1050 fclose(f);
1051 if (r < 0)
1052 return r;
1053
78d54bd4
LP
1054 return
1055 strv_length(info->aliases) +
1056 strv_length(info->wanted_by) +
1057 strv_length(info->required_by);
83096483
LP
1058}
1059
1060static int unit_file_search(
1061 InstallContext *c,
1062 InstallInfo *info,
1063 LookupPaths *paths,
1064 const char *root_dir,
1065 bool allow_symlink) {
1066
1067 char **p;
1068 int r;
1069
1070 assert(c);
1071 assert(info);
1072 assert(paths);
1073
1074 if (info->path)
1075 return unit_file_load(c, info, info->path, allow_symlink);
1076
1077 assert(info->name);
1078
1079 STRV_FOREACH(p, paths->unit_path) {
1080 char *path = NULL;
1081
1082 if (isempty(root_dir))
1083 asprintf(&path, "%s/%s", *p, info->name);
1084 else
1085 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1086
1087 if (!path)
1088 return -ENOMEM;
1089
1090 r = unit_file_load(c, info, path, allow_symlink);
1091
1092 if (r >= 0)
1093 info->path = path;
29283ea4
MS
1094 else {
1095 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1096 /* unit file doesn't exist, however instance enablement was request */
1097 /* we will check if it is possible to load template unit file */
1098 char *template = NULL,
1099 *template_path = NULL,
1100 *template_dir = NULL;
1101
1102 template = unit_name_template(info->name);
1103 if (!template) {
1104 free(path);
1105 return -ENOMEM;
1106 }
1107
1108 /* we will reuse path variable since we don't need it anymore */
1109 template_dir = path;
1110 *(strrchr(path, '/') + 1) = '\0';
1111
1112 template_path = strjoin(template_dir, template, NULL);
1113 if (!template_path) {
1114 free(path);
1115 free(template);
1116 return -ENOMEM;
1117 }
1118
1119 /* let's try to load template unit */
1120 r = unit_file_load(c, info, template_path, allow_symlink);
1121 if (r >= 0) {
1122 info->path = strdup(template_path);
1123 if (!info->path) {
1124 free(path);
1125 free(template);
1126 free(template_path);
1127 return -ENOMEM;
1128 }
1129 }
1130
1131 free(template);
1132 free(template_path);
1133 }
83096483 1134 free(path);
29283ea4 1135 }
83096483
LP
1136
1137 if (r != -ENOENT && r != -ELOOP)
1138 return r;
1139 }
1140
1141 return -ENOENT;
1142}
1143
1144static int unit_file_can_install(
1145 LookupPaths *paths,
1146 const char *root_dir,
1147 const char *name,
1148 bool allow_symlink) {
1149
1150 InstallContext c;
1151 InstallInfo *i;
1152 int r;
1153
1154 assert(paths);
1155 assert(name);
1156
1157 zero(c);
1158
1159 r = install_info_add_auto(&c, name);
1160 if (r < 0)
1161 return r;
1162
1163 assert_se(i = hashmap_first(c.will_install));
1164
1165 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1166
1167 if (r >= 0)
78d54bd4
LP
1168 r =
1169 strv_length(i->aliases) +
1170 strv_length(i->wanted_by) +
1171 strv_length(i->required_by);
83096483
LP
1172
1173 install_context_done(&c);
1174
1175 return r;
1176}
1177
1178static int create_symlink(
1179 const char *old_path,
1180 const char *new_path,
1181 bool force,
1182 UnitFileChange **changes,
1183 unsigned *n_changes) {
1184
1185 char *dest;
1186 int r;
1187
1188 assert(old_path);
1189 assert(new_path);
1190
d2e54fae 1191 mkdir_parents_label(new_path, 0755);
83096483
LP
1192
1193 if (symlink(old_path, new_path) >= 0) {
1194 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1195 return 0;
1196 }
1197
1198 if (errno != EEXIST)
1199 return -errno;
1200
1201 r = readlink_and_make_absolute(new_path, &dest);
1202 if (r < 0)
1203 return r;
1204
1205 if (path_equal(dest, old_path)) {
1206 free(dest);
1207 return 0;
1208 }
1209
1210 free(dest);
1211
ba49b4a1 1212 if (!force)
83096483
LP
1213 return -EEXIST;
1214
1215 unlink(new_path);
1216
1217 if (symlink(old_path, new_path) >= 0) {
1218 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1219 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1220 return 0;
1221 }
1222
1223 return -errno;
1224}
1225
1226static int install_info_symlink_alias(
1227 InstallInfo *i,
1228 const char *config_path,
1229 bool force,
1230 UnitFileChange **changes,
1231 unsigned *n_changes) {
1232
1233 char **s;
1234 int r = 0, q;
1235
1236 assert(i);
1237 assert(config_path);
1238
1239 STRV_FOREACH(s, i->aliases) {
1240 char *alias_path;
1241
1242 alias_path = path_make_absolute(*s, config_path);
1243
1244 if (!alias_path)
1245 return -ENOMEM;
1246
1247 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1248 free(alias_path);
1249
1250 if (r == 0)
1251 r = q;
1252 }
1253
1254 return r;
1255}
1256
1257static int install_info_symlink_wants(
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->wanted_by) {
1271 char *path;
1272
5f739699 1273 if (!unit_name_is_valid(*s, true)) {
83096483
LP
1274 r = -EINVAL;
1275 continue;
1276 }
1277
1278 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1279 return -ENOMEM;
1280
1281 q = create_symlink(i->path, path, force, changes, n_changes);
1282 free(path);
1283
1284 if (r == 0)
1285 r = q;
1286 }
1287
1288 return r;
1289}
1290
78d54bd4
LP
1291static int install_info_symlink_requires(
1292 InstallInfo *i,
1293 const char *config_path,
1294 bool force,
1295 UnitFileChange **changes,
1296 unsigned *n_changes) {
1297
1298 char **s;
1299 int r = 0, q;
1300
1301 assert(i);
1302 assert(config_path);
1303
1304 STRV_FOREACH(s, i->required_by) {
1305 char *path;
1306
5f739699 1307 if (!unit_name_is_valid(*s, true)) {
78d54bd4
LP
1308 r = -EINVAL;
1309 continue;
1310 }
1311
1312 if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0)
1313 return -ENOMEM;
1314
1315 q = create_symlink(i->path, path, force, changes, n_changes);
1316 free(path);
1317
1318 if (r == 0)
1319 r = q;
1320 }
1321
1322 return r;
1323}
1324
83096483
LP
1325static int install_info_symlink_link(
1326 InstallInfo *i,
1327 LookupPaths *paths,
1328 const char *config_path,
1329 bool force,
1330 UnitFileChange **changes,
1331 unsigned *n_changes) {
1332
1333 int r;
1334 char *path;
1335
1336 assert(i);
1337 assert(paths);
1338 assert(config_path);
1339 assert(i->path);
1340
1341 r = in_search_path(i->path, paths->unit_path);
1342 if (r != 0)
1343 return r;
1344
1345 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1346 return -ENOMEM;
1347
1348 r = create_symlink(i->path, path, force, changes, n_changes);
1349 free(path);
1350
1351 return r;
1352}
1353
1354static int install_info_apply(
1355 InstallInfo *i,
1356 LookupPaths *paths,
1357 const char *config_path,
1358 bool force,
1359 UnitFileChange **changes,
1360 unsigned *n_changes) {
1361
1362 int r, q;
1363
1364 assert(i);
1365 assert(paths);
1366 assert(config_path);
1367
1368 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1369
1370 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1371 if (r == 0)
1372 r = q;
1373
78d54bd4
LP
1374 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1375 if (r == 0)
1376 r = q;
1377
83096483
LP
1378 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1379 if (r == 0)
1380 r = q;
1381
1382 return r;
1383}
1384
1385static int install_context_apply(
1386 InstallContext *c,
1387 LookupPaths *paths,
1388 const char *config_path,
1389 const char *root_dir,
1390 bool force,
1391 UnitFileChange **changes,
1392 unsigned *n_changes) {
1393
1394 InstallInfo *i;
1395 int r = 0, q;
1396
1397 assert(c);
1398 assert(paths);
1399 assert(config_path);
1400
1401 while ((i = hashmap_first(c->will_install))) {
1402
1403 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1404 if (q < 0)
1405 return q;
1406
1407 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1408
1409 q = unit_file_search(c, i, paths, root_dir, false);
1410 if (q < 0) {
1411 if (r >= 0)
1412 r = q;
1413
1414 return r;
1415 } else if (r >= 0)
1416 r += q;
1417
1418 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1419 if (r >= 0 && q < 0)
1420 r = q;
1421 }
1422
1423 return r;
1424}
1425
1426static int install_context_mark_for_removal(
1427 InstallContext *c,
1428 LookupPaths *paths,
1429 Set **remove_symlinks_to,
1430 const char *config_path,
1431 const char *root_dir) {
1432
1433 InstallInfo *i;
1434 int r = 0, q;
1435
1436 assert(c);
1437 assert(paths);
1438 assert(config_path);
1439
1440 /* Marks all items for removal */
1441
1442 while ((i = hashmap_first(c->will_install))) {
1443
1444 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1445 if (q < 0)
1446 return q;
1447
1448 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1449
1450 q = unit_file_search(c, i, paths, root_dir, false);
1451 if (q < 0) {
1452 if (r >= 0)
1453 r = q;
1454
1455 return r;
1456 } else if (r >= 0)
1457 r += q;
1458
29283ea4
MS
1459 if (unit_name_is_instance(i->name)) {
1460 char *unit_file = NULL;
1461
1462 unit_file = path_get_file_name(i->path);
1463
1464 if (unit_name_is_instance(unit_file))
1465 /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1466 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1467 else
1468 /* does not exist, thus we will mark for removal symlinks to template unit file */
1469 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1470 } else
1471 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1472
83096483
LP
1473 if (r >= 0 && q < 0)
1474 r = q;
1475 }
1476
1477 return r;
1478}
1479
1480int unit_file_enable(
1481 UnitFileScope scope,
1482 bool runtime,
1483 const char *root_dir,
1484 char *files[],
1485 bool force,
1486 UnitFileChange **changes,
1487 unsigned *n_changes) {
1488
1489 LookupPaths paths;
1490 InstallContext c;
1491 char **i, *config_path = NULL;
1492 int r;
1493
1494 assert(scope >= 0);
1495 assert(scope < _UNIT_FILE_SCOPE_MAX);
1496
1497 zero(paths);
1498 zero(c);
1499
1500 r = lookup_paths_init_from_scope(&paths, scope);
1501 if (r < 0)
1502 return r;
1503
1504 r = get_config_path(scope, runtime, root_dir, &config_path);
1505 if (r < 0)
1506 goto finish;
1507
1508 STRV_FOREACH(i, files) {
1509 r = install_info_add_auto(&c, *i);
1510 if (r < 0)
1511 goto finish;
1512 }
1513
729e3769
LP
1514 /* This will return the number of symlink rules that were
1515 supposed to be created, not the ones actually created. This is
1516 useful to determine whether the passed files hat any
1517 installation data at all. */
83096483
LP
1518 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1519
1520finish:
1521 install_context_done(&c);
1522 lookup_paths_free(&paths);
1523 free(config_path);
1524
1525 return r;
1526}
1527
1528int unit_file_disable(
1529 UnitFileScope scope,
1530 bool runtime,
1531 const char *root_dir,
1532 char *files[],
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 = install_info_add_auto(&c, *i);
1558 if (r < 0)
1559 goto finish;
1560 }
1561
1562 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1563
29283ea4 1564 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483 1565 if (r == 0)
034a2a52 1566 r = q;
83096483
LP
1567
1568finish:
1569 install_context_done(&c);
1570 lookup_paths_free(&paths);
1571 set_free_free(remove_symlinks_to);
1572 free(config_path);
1573
1574 return r;
1575}
1576
1577int unit_file_reenable(
1578 UnitFileScope scope,
1579 bool runtime,
1580 const char *root_dir,
1581 char *files[],
1582 bool force,
1583 UnitFileChange **changes,
1584 unsigned *n_changes) {
1585
1586 LookupPaths paths;
1587 InstallContext c;
1588 char **i, *config_path = NULL;
1589 Set *remove_symlinks_to = NULL;
1590 int r, q;
1591
1592 assert(scope >= 0);
1593 assert(scope < _UNIT_FILE_SCOPE_MAX);
1594
1595 zero(paths);
1596 zero(c);
1597
1598 r = lookup_paths_init_from_scope(&paths, scope);
1599 if (r < 0)
1600 return r;
1601
1602 r = get_config_path(scope, runtime, root_dir, &config_path);
1603 if (r < 0)
1604 goto finish;
1605
1606 STRV_FOREACH(i, files) {
1607 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1608 if (r < 0)
1609 goto finish;
1610
1611 r = install_info_add_auto(&c, *i);
1612 if (r < 0)
1613 goto finish;
1614 }
1615
29283ea4 1616 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483 1617
729e3769 1618 /* Returns number of symlinks that where supposed to be installed. */
83096483
LP
1619 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1620 if (r == 0)
1621 r = q;
1622
1623finish:
1624 lookup_paths_free(&paths);
1625 install_context_done(&c);
1626 set_free_free(remove_symlinks_to);
1627 free(config_path);
1628
1629 return r;
1630}
1631
1632UnitFileState unit_file_get_state(
1633 UnitFileScope scope,
1634 const char *root_dir,
1635 const char *name) {
1636
1637 LookupPaths paths;
1638 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1639 char **i, *path = NULL;
1640 int r;
1641
1642 assert(scope >= 0);
1643 assert(scope < _UNIT_FILE_SCOPE_MAX);
1644 assert(name);
1645
1646 zero(paths);
1647
1648 if (root_dir && scope != UNIT_FILE_SYSTEM)
1649 return -EINVAL;
1650
5f739699 1651 if (!unit_name_is_valid(name, true))
83096483
LP
1652 return -EINVAL;
1653
1654 r = lookup_paths_init_from_scope(&paths, scope);
1655 if (r < 0)
1656 return r;
1657
1658 STRV_FOREACH(i, paths.unit_path) {
1659 struct stat st;
1660
1661 free(path);
1662 path = NULL;
1663
1664 if (root_dir)
1665 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1666 else
1667 asprintf(&path, "%s/%s", *i, name);
1668
1669 if (!path) {
1670 r = -ENOMEM;
1671 goto finish;
1672 }
1673
1674 if (lstat(path, &st) < 0) {
81006b8a 1675 r = -errno;
83096483
LP
1676 if (errno == ENOENT)
1677 continue;
1678
83096483
LP
1679 goto finish;
1680 }
1681
1682 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1683 r = -ENOENT;
1684 goto finish;
1685 }
1686
1687 r = null_or_empty_path(path);
1688 if (r < 0 && r != -ENOENT)
1689 goto finish;
1690 else if (r > 0) {
1691 state = path_startswith(*i, "/run") ?
1692 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1693 r = 0;
1694 goto finish;
1695 }
1696
1697 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1698 if (r < 0) {
1699 goto finish;
1700 } else if (r > 0) {
1701 r = 0;
1702 goto finish;
1703 }
1704
1705 r = unit_file_can_install(&paths, root_dir, path, true);
1706 if (r < 0 && errno != -ENOENT)
1707 goto finish;
1708 else if (r > 0) {
1709 state = UNIT_FILE_DISABLED;
1710 r = 0;
1711 goto finish;
1712 } else if (r == 0) {
1713 state = UNIT_FILE_STATIC;
1714 r = 0;
1715 goto finish;
1716 }
1717 }
1718
1719finish:
1720 lookup_paths_free(&paths);
1721 free(path);
1722
1723 return r < 0 ? r : state;
1724}
1725
1726int unit_file_query_preset(UnitFileScope scope, const char *name) {
1727 char **files, **i;
1728 int r;
1729
1730 assert(scope >= 0);
1731 assert(scope < _UNIT_FILE_SCOPE_MAX);
1732 assert(name);
1733
1734 if (scope == UNIT_FILE_SYSTEM)
1735 r = conf_files_list(&files, ".preset",
a7480dba
LP
1736 "/etc/systemd/system-preset",
1737 "/usr/local/lib/systemd/system-preset",
1738 "/usr/lib/systemd/system-preset",
b4bdfefa 1739#ifdef HAVE_SPLIT_USR
a7480dba 1740 "/lib/systemd/system-preset",
b4bdfefa 1741#endif
83096483
LP
1742 NULL);
1743 else if (scope == UNIT_FILE_GLOBAL)
1744 r = conf_files_list(&files, ".preset",
a7480dba
LP
1745 "/etc/systemd/user-preset",
1746 "/usr/local/lib/systemd/user-preset",
1747 "/usr/lib/systemd/user-preset",
83096483
LP
1748 NULL);
1749 else
1750 return 1;
1751
1752 if (r < 0)
1753 return r;
1754
1755 STRV_FOREACH(i, files) {
1756 FILE *f;
1757
1758 f = fopen(*i, "re");
1759 if (!f) {
1760 if (errno == ENOENT)
1761 continue;
1762
1763 r = -errno;
1764 goto finish;
1765 }
1766
1767 for (;;) {
1768 char line[LINE_MAX], *l;
1769
1770 if (!fgets(line, sizeof(line), f))
1771 break;
1772
1773 l = strstrip(line);
1774 if (!*l)
1775 continue;
1776
1777 if (strchr(COMMENTS, *l))
1778 continue;
1779
1780 if (first_word(l, "enable")) {
1781 l += 6;
1782 l += strspn(l, WHITESPACE);
1783
1784 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1785 r = 1;
1786 fclose(f);
1787 goto finish;
1788 }
1789 } else if (first_word(l, "disable")) {
1790 l += 7;
1791 l += strspn(l, WHITESPACE);
1792
1793 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1794 r = 0;
1795 fclose(f);
1796 goto finish;
1797 }
1798 } else
1799 log_debug("Couldn't parse line '%s'", l);
1800 }
1801
1802 fclose(f);
1803 }
1804
1805 /* Default is "enable" */
1806 r = 1;
1807
1808finish:
1809 strv_free(files);
1810
1811 return r;
1812}
1813
1814int unit_file_preset(
1815 UnitFileScope scope,
1816 bool runtime,
1817 const char *root_dir,
1818 char *files[],
1819 bool force,
1820 UnitFileChange **changes,
1821 unsigned *n_changes) {
1822
1823 LookupPaths paths;
1824 InstallContext plus, minus;
1825 char **i, *config_path = NULL;
1826 Set *remove_symlinks_to = NULL;
1827 int r, q;
1828
1829 assert(scope >= 0);
1830 assert(scope < _UNIT_FILE_SCOPE_MAX);
1831
1832 zero(paths);
1833 zero(plus);
1834 zero(minus);
1835
1836 r = lookup_paths_init_from_scope(&paths, scope);
1837 if (r < 0)
1838 return r;
1839
1840 r = get_config_path(scope, runtime, root_dir, &config_path);
1841 if (r < 0)
1842 goto finish;
1843
1844 STRV_FOREACH(i, files) {
1845
5f739699 1846 if (!unit_name_is_valid(*i, true)) {
83096483
LP
1847 r = -EINVAL;
1848 goto finish;
1849 }
1850
1851 r = unit_file_query_preset(scope, *i);
1852 if (r < 0)
1853 goto finish;
1854
1855 if (r)
1856 r = install_info_add_auto(&plus, *i);
1857 else
1858 r = install_info_add_auto(&minus, *i);
1859
1860 if (r < 0)
1861 goto finish;
1862 }
1863
1864 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1865
29283ea4 1866 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483
LP
1867 if (r == 0)
1868 r = q;
1869
729e3769 1870 /* Returns number of symlinks that where supposed to be installed. */
83096483
LP
1871 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1872 if (r == 0)
1873 r = q;
1874
1875finish:
1876 lookup_paths_free(&paths);
1877 install_context_done(&plus);
1878 install_context_done(&minus);
1879 set_free_free(remove_symlinks_to);
1880 free(config_path);
1881
1882 return r;
1883}
1884
1885int unit_file_get_list(
1886 UnitFileScope scope,
1887 const char *root_dir,
1888 Hashmap *h) {
1889
1890 LookupPaths paths;
1891 char **i, *buf = NULL;
1892 DIR *d = NULL;
1893 int r;
1894
1895 assert(scope >= 0);
1896 assert(scope < _UNIT_FILE_SCOPE_MAX);
1897 assert(h);
1898
1899 zero(paths);
1900
1901 if (root_dir && scope != UNIT_FILE_SYSTEM)
1902 return -EINVAL;
1903
1904 r = lookup_paths_init_from_scope(&paths, scope);
1905 if (r < 0)
1906 return r;
1907
1908 STRV_FOREACH(i, paths.unit_path) {
1909 struct dirent buffer, *de;
1910 const char *units_dir;
1911
1912 free(buf);
1913 buf = NULL;
1914
1915 if (root_dir) {
1916 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1917 r = -ENOMEM;
1918 goto finish;
1919 }
1920 units_dir = buf;
1921 } else
1922 units_dir = *i;
1923
1924 if (d)
1925 closedir(d);
1926
1927 d = opendir(units_dir);
1928 if (!d) {
1929 if (errno == ENOENT)
1930 continue;
1931
1932 r = -errno;
1933 goto finish;
1934 }
1935
1936 for (;;) {
1937 UnitFileList *f;
1938
1939 r = readdir_r(d, &buffer, &de);
1940 if (r != 0) {
1941 r = -r;
1942 goto finish;
1943 }
1944
1945 if (!de)
1946 break;
1947
1948 if (ignore_file(de->d_name))
1949 continue;
1950
5f739699 1951 if (!unit_name_is_valid(de->d_name, true))
83096483
LP
1952 continue;
1953
1954 if (hashmap_get(h, de->d_name))
1955 continue;
1956
1957 r = dirent_ensure_type(d, de);
1958 if (r < 0) {
fb5ef067 1959 if (r == -ENOENT)
83096483
LP
1960 continue;
1961
1962 goto finish;
1963 }
1964
1965 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1966 continue;
1967
1968 f = new0(UnitFileList, 1);
1969 if (!f) {
1970 r = -ENOMEM;
1971 goto finish;
1972 }
1973
1974 f->path = path_make_absolute(de->d_name, units_dir);
1975 if (!f->path) {
1976 free(f);
1977 r = -ENOMEM;
1978 goto finish;
1979 }
1980
1981 r = null_or_empty_path(f->path);
e6a6b406 1982 if (r < 0 && r != -ENOENT) {
83096483
LP
1983 free(f->path);
1984 free(f);
1985 goto finish;
1986 } else if (r > 0) {
1987 f->state =
1988 path_startswith(*i, "/run") ?
1989 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1990 goto found;
1991 }
1992
1993 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1994 if (r < 0) {
1995 free(f->path);
1996 free(f);
1997 goto finish;
b5b46d59
LP
1998 } else if (r > 0) {
1999 f->state = UNIT_FILE_ENABLED;
83096483 2000 goto found;
b5b46d59 2001 }
83096483
LP
2002
2003 r = unit_file_can_install(&paths, root_dir, f->path, true);
b5b46d59
LP
2004 if (r == -EINVAL || /* Invalid setting? */
2005 r == -EBADMSG || /* Invalid format? */
2006 r == -ENOENT /* Included file not found? */)
2007 f->state = UNIT_FILE_INVALID;
2008 else if (r < 0) {
83096483
LP
2009 free(f->path);
2010 free(f);
2011 goto finish;
b5b46d59 2012 } else if (r > 0)
83096483 2013 f->state = UNIT_FILE_DISABLED;
b5b46d59 2014 else
83096483 2015 f->state = UNIT_FILE_STATIC;
83096483
LP
2016
2017 found:
9eb977db 2018 r = hashmap_put(h, path_get_file_name(f->path), f);
83096483
LP
2019 if (r < 0) {
2020 free(f->path);
2021 free(f);
2022 goto finish;
2023 }
2024 }
2025 }
2026
2027finish:
2028 lookup_paths_free(&paths);
2029 free(buf);
2030
2031 if (d)
2032 closedir(d);
2033
2034 return r;
2035}
2036
2037static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2038 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 2039 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
2040 [UNIT_FILE_LINKED] = "linked",
2041 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2042 [UNIT_FILE_MASKED] = "masked",
2043 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2044 [UNIT_FILE_STATIC] = "static",
b5b46d59
LP
2045 [UNIT_FILE_DISABLED] = "disabled",
2046 [UNIT_FILE_INVALID] = "invalid",
83096483
LP
2047};
2048
2049DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
2050
2051static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2052 [UNIT_FILE_SYMLINK] = "symlink",
2053 [UNIT_FILE_UNLINK] = "unlink",
2054};
2055
2056DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);