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