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