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