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