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