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