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