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