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