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