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