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