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