]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
install: various modernizations
[thirdparty/systemd.git] / src / shared / install.c
CommitLineData
83096483
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
83096483
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty <of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
83096483 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
83096483
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <string.h>
26#include <fnmatch.h>
27
28#include "util.h"
49e942b2 29#include "mkdir.h"
83096483
LP
30#include "hashmap.h"
31#include "set.h"
9eb977db 32#include "path-util.h"
83096483
LP
33#include "path-lookup.h"
34#include "strv.h"
35#include "unit-name.h"
36#include "install.h"
37#include "conf-parser.h"
2c21044f 38#include "conf-files.h"
7584d236
ZJS
39#include "specifier.h"
40#include "install-printf.h"
16ed0233 41#include "special.h"
83096483
LP
42
43typedef struct {
44 Hashmap *will_install;
45 Hashmap *have_installed;
46} InstallContext;
47
1ca208fb 48#define _cleanup_install_context_done_ _cleanup_(install_context_done)
d9e5e694 49
12ed81d9
ZJS
50static int lookup_paths_init_from_scope(LookupPaths *paths,
51 UnitFileScope scope,
52 const char *root_dir) {
83096483
LP
53 assert(paths);
54 assert(scope >= 0);
55 assert(scope < _UNIT_FILE_SCOPE_MAX);
56
57 zero(*paths);
58
59 return lookup_paths_init(paths,
67445f4e 60 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
07719a21 61 scope == UNIT_FILE_USER,
12ed81d9 62 root_dir,
07719a21 63 NULL, NULL, NULL);
83096483
LP
64}
65
66static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
67 char *p = NULL;
68 int r;
69
70 assert(scope >= 0);
71 assert(scope < _UNIT_FILE_SCOPE_MAX);
72 assert(ret);
73
74 switch (scope) {
75
76 case UNIT_FILE_SYSTEM:
77
78 if (root_dir && runtime)
d380a3bc
BN
79 asprintf(&p, "%s/run/systemd/system", root_dir);
80 else if (runtime)
83096483
LP
81 p = strdup("/run/systemd/system");
82 else if (root_dir)
83 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
84 else
85 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
86
87 break;
88
89 case UNIT_FILE_GLOBAL:
90
91 if (root_dir)
92 return -EINVAL;
93
94 if (runtime)
95 p = strdup("/run/systemd/user");
96 else
97 p = strdup(USER_CONFIG_UNIT_PATH);
98 break;
99
100 case UNIT_FILE_USER:
101
102 if (root_dir || runtime)
103 return -EINVAL;
104
105 r = user_config_home(&p);
106 if (r <= 0)
107 return r < 0 ? r : -ENOENT;
108
109 break;
110
111 default:
112 assert_not_reached("Bad scope");
113 }
114
115 if (!p)
116 return -ENOMEM;
117
118 *ret = p;
119 return 0;
120}
121
122static int add_file_change(
123 UnitFileChange **changes,
124 unsigned *n_changes,
125 UnitFileChangeType type,
126 const char *path,
127 const char *source) {
128
129 UnitFileChange *c;
130 unsigned i;
131
83096483
LP
132 assert(path);
133 assert(!changes == !n_changes);
134
135 if (!changes)
136 return 0;
137
138 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
139 if (!c)
140 return -ENOMEM;
141
142 *changes = c;
143 i = *n_changes;
144
145 c[i].type = type;
146 c[i].path = strdup(path);
147 if (!c[i].path)
148 return -ENOMEM;
149
150 if (source) {
151 c[i].source = strdup(source);
152 if (!c[i].source) {
153 free(c[i].path);
154 return -ENOMEM;
155 }
156 } else
157 c[i].source = NULL;
158
159 *n_changes = i+1;
160 return 0;
161}
162
163static int mark_symlink_for_removal(
164 Set **remove_symlinks_to,
165 const char *p) {
166
167 char *n;
168 int r;
169
170 assert(p);
171
172 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
173 if (r < 0)
174 return r;
175
176 n = strdup(p);
177 if (!n)
178 return -ENOMEM;
179
180 path_kill_slashes(n);
181
ef42202a
ZJS
182 r = set_consume(*remove_symlinks_to, n);
183 if (r < 0)
83096483 184 return r == -EEXIST ? 0 : r;
83096483
LP
185
186 return 0;
187}
188
189static int remove_marked_symlinks_fd(
190 Set *remove_symlinks_to,
191 int fd,
192 const char *path,
193 const char *config_path,
194 bool *deleted,
195 UnitFileChange **changes,
29283ea4
MS
196 unsigned *n_changes,
197 char** files) {
83096483
LP
198
199 int r = 0;
7fd1b19b 200 _cleanup_closedir_ DIR *d = NULL;
83096483
LP
201
202 assert(remove_symlinks_to);
203 assert(fd >= 0);
204 assert(path);
205 assert(config_path);
206 assert(deleted);
207
208 d = fdopendir(fd);
209 if (!d) {
03e334a1 210 safe_close(fd);
83096483
LP
211 return -errno;
212 }
213
214 rewinddir(d);
215
216 for (;;) {
7d5e9c0f 217 struct dirent *de;
83096483 218
4d993c8c
FW
219 errno = 0;
220 de = readdir(d);
221 if (!de && errno != 0) {
83096483
LP
222 r = -errno;
223 break;
224 }
225
226 if (!de)
227 break;
228
229 if (ignore_file(de->d_name))
230 continue;
231
232 dirent_ensure_type(d, de);
233
234 if (de->d_type == DT_DIR) {
235 int nfd, q;
7fd1b19b 236 _cleanup_free_ char *p = NULL;
83096483
LP
237
238 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
239 if (nfd < 0) {
240 if (errno == ENOENT)
241 continue;
242
243 if (r == 0)
244 r = -errno;
245 continue;
246 }
247
248 p = path_make_absolute(de->d_name, path);
249 if (!p) {
03e334a1 250 safe_close(nfd);
d9e5e694 251 return -ENOMEM;
83096483
LP
252 }
253
254 /* This will close nfd, regardless whether it succeeds or not */
29283ea4 255 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
83096483
LP
256
257 if (r == 0)
258 r = q;
259
260 } else if (de->d_type == DT_LNK) {
7fd1b19b 261 _cleanup_free_ char *p = NULL, *dest = NULL;
83096483
LP
262 int q;
263 bool found;
264
265 p = path_make_absolute(de->d_name, path);
d9e5e694
ZJS
266 if (!p)
267 return -ENOMEM;
83096483
LP
268
269 q = readlink_and_canonicalize(p, &dest);
270 if (q < 0) {
83096483
LP
271 if (q == -ENOENT)
272 continue;
273
274 if (r == 0)
275 r = q;
276 continue;
277 }
278
279 found =
280 set_get(remove_symlinks_to, dest) ||
2b6bf07d 281 set_get(remove_symlinks_to, basename(dest));
83096483 282
29283ea4 283 if (unit_name_is_instance(p))
2b6bf07d 284 found = found && strv_contains(files, basename(p));
29283ea4 285
83096483
LP
286 if (found) {
287
288 if (unlink(p) < 0 && errno != ENOENT) {
289
290 if (r == 0)
291 r = -errno;
292 } else {
293 rmdir_parents(p, config_path);
294 path_kill_slashes(p);
295
296 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
297
298 if (!set_get(remove_symlinks_to, p)) {
299
300 q = mark_symlink_for_removal(&remove_symlinks_to, p);
301 if (q < 0) {
302 if (r == 0)
303 r = q;
304 } else
305 *deleted = true;
306 }
307 }
308 }
83096483
LP
309 }
310 }
311
83096483
LP
312 return r;
313}
314
315static int remove_marked_symlinks(
316 Set *remove_symlinks_to,
317 const char *config_path,
318 UnitFileChange **changes,
29283ea4
MS
319 unsigned *n_changes,
320 char** files) {
83096483 321
da39f6a6
LP
322 _cleanup_close_ int fd = -1;
323 int r = 0;
83096483
LP
324 bool deleted;
325
326 assert(config_path);
327
328 if (set_size(remove_symlinks_to) <= 0)
329 return 0;
330
331 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
332 if (fd < 0)
333 return -errno;
334
335 do {
336 int q, cfd;
337 deleted = false;
338
ead34950 339 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
83096483
LP
340 if (cfd < 0) {
341 r = -errno;
342 break;
343 }
344
345 /* This takes possession of cfd and closes it */
29283ea4 346 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
83096483
LP
347 if (r == 0)
348 r = q;
349 } while (deleted);
350
83096483
LP
351 return r;
352}
353
354static int find_symlinks_fd(
355 const char *name,
356 int fd,
357 const char *path,
358 const char *config_path,
359 bool *same_name_link) {
360
361 int r = 0;
7fd1b19b 362 _cleanup_closedir_ DIR *d = NULL;
83096483
LP
363
364 assert(name);
365 assert(fd >= 0);
366 assert(path);
367 assert(config_path);
368 assert(same_name_link);
369
370 d = fdopendir(fd);
371 if (!d) {
03e334a1 372 safe_close(fd);
83096483
LP
373 return -errno;
374 }
375
376 for (;;) {
7d5e9c0f 377 struct dirent *de;
83096483 378
4d993c8c
FW
379 errno = 0;
380 de = readdir(d);
381 if (!de && errno != 0)
ea55addc 382 return -errno;
83096483
LP
383
384 if (!de)
ea55addc 385 return r;
83096483
LP
386
387 if (ignore_file(de->d_name))
388 continue;
389
390 dirent_ensure_type(d, de);
391
392 if (de->d_type == DT_DIR) {
393 int nfd, q;
7fd1b19b 394 _cleanup_free_ char *p = NULL;
83096483
LP
395
396 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
397 if (nfd < 0) {
398 if (errno == ENOENT)
399 continue;
400
401 if (r == 0)
402 r = -errno;
403 continue;
404 }
405
406 p = path_make_absolute(de->d_name, path);
407 if (!p) {
03e334a1 408 safe_close(nfd);
ea55addc 409 return -ENOMEM;
83096483
LP
410 }
411
412 /* This will close nfd, regardless whether it succeeds or not */
413 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
83096483 414
ea55addc
ZJS
415 if (q > 0)
416 return 1;
83096483
LP
417
418 if (r == 0)
419 r = q;
420
421 } else if (de->d_type == DT_LNK) {
7fd1b19b 422 _cleanup_free_ char *p = NULL, *dest = NULL;
83096483
LP
423 bool found_path, found_dest, b = false;
424 int q;
425
426 /* Acquire symlink name */
427 p = path_make_absolute(de->d_name, path);
ea55addc
ZJS
428 if (!p)
429 return -ENOMEM;
83096483
LP
430
431 /* Acquire symlink destination */
432 q = readlink_and_canonicalize(p, &dest);
433 if (q < 0) {
83096483
LP
434 if (q == -ENOENT)
435 continue;
436
437 if (r == 0)
438 r = q;
439 continue;
440 }
441
442 /* Check if the symlink itself matches what we
443 * are looking for */
444 if (path_is_absolute(name))
445 found_path = path_equal(p, name);
446 else
447 found_path = streq(de->d_name, name);
448
449 /* Check if what the symlink points to
450 * matches what we are looking for */
451 if (path_is_absolute(name))
452 found_dest = path_equal(dest, name);
453 else
2b6bf07d 454 found_dest = streq(basename(dest), name);
83096483 455
83096483 456 if (found_path && found_dest) {
7fd1b19b 457 _cleanup_free_ char *t = NULL;
83096483
LP
458
459 /* Filter out same name links in the main
460 * config path */
461 t = path_make_absolute(name, config_path);
ea55addc
ZJS
462 if (!t)
463 return -ENOMEM;
83096483
LP
464
465 b = path_equal(t, p);
83096483
LP
466 }
467
83096483
LP
468 if (b)
469 *same_name_link = true;
ea55addc
ZJS
470 else if (found_path || found_dest)
471 return 1;
83096483
LP
472 }
473 }
83096483
LP
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,
7195aa42 559 char **files,
83096483
LP
560 bool force,
561 UnitFileChange **changes,
562 unsigned *n_changes) {
563
d8831ed5 564 char **i;
22321774 565 _cleanup_free_ char *prefix = NULL;
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
f78e6385 578 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
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,
7195aa42 628 char **files,
83096483
LP
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
f78e6385 646 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
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,
7195aa42 693 char **files,
83096483
LP
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
12ed81d9 706 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
83096483
LP
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) ||
f78e6385 722 !unit_name_is_valid(fn, TEMPLATE_VALID)) {
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
f78e6385 864 if (!unit_name_is_valid(name, TEMPLATE_VALID))
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) {
03e334a1 1013 safe_close(fd);
83096483
LP
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 1022 return
693eb9a2
LP
1023 (int) strv_length(info->aliases) +
1024 (int) strv_length(info->wanted_by) +
1025 (int) 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
62b00233
ZJS
1042 if (info->path) {
1043 char *full_path = NULL;
1044
1045 if (!isempty(root_dir))
1046 full_path = strappenda(root_dir, info->path);
1047
1048 return unit_file_load(c, info, full_path ?: info->path, allow_symlink);
1049 }
83096483
LP
1050
1051 assert(info->name);
1052
1053 STRV_FOREACH(p, paths->unit_path) {
62b00233 1054 _cleanup_free_ char *path = NULL, *full_path = NULL;
83096483 1055
62b00233 1056 path = strjoin(*p, "/", info->name, NULL);
83096483
LP
1057 if (!path)
1058 return -ENOMEM;
1059
62b00233
ZJS
1060 if (!isempty(root_dir)) {
1061 full_path = strappend(root_dir, path);
1062 if (!full_path)
1063 return -ENOMEM;
1064 }
83096483 1065
62b00233
ZJS
1066 r = unit_file_load(c, info, full_path ?: path, allow_symlink);
1067 if (r >= 0) {
83096483 1068 info->path = path;
62b00233
ZJS
1069 path = NULL;
1070 } else if (r == -ENOENT && unit_name_is_instance(info->name)) {
1071 /* Unit file doesn't exist, however instance enablement was requested.
1072 * We will check if it is possible to load template unit file. */
1073 _cleanup_free_ char *template = NULL, *template_dir = NULL;
1074
1075 template = unit_name_template(info->name);
1076 if (!template)
1077 return -ENOMEM;
29283ea4 1078
62b00233
ZJS
1079 /* We will reuse path variable since we don't need it anymore. */
1080 template_dir = path;
1081 *(strrchr(template_dir, '/') + 1) = '\0';
29283ea4 1082
62b00233
ZJS
1083 path = strappend(template_dir, template);
1084 if (!path)
1085 return -ENOMEM;
29283ea4 1086
62b00233
ZJS
1087 if (!isempty(root_dir)) {
1088 free(full_path);
1089 full_path = strappend(root_dir, path);
1090 if (!full_path)
1091 return -ENOMEM;
1092 }
29283ea4 1093
62b00233
ZJS
1094 /* Let's try to load template unit. */
1095 r = unit_file_load(c, info, full_path ?: path, allow_symlink);
1096 if (r >= 0) {
1097 info->path = path;
1098 path = NULL;
29283ea4 1099 }
29283ea4 1100 }
83096483
LP
1101
1102 if (r != -ENOENT && r != -ELOOP)
1103 return r;
1104 }
1105
1106 return -ENOENT;
1107}
1108
1109static int unit_file_can_install(
1110 LookupPaths *paths,
1111 const char *root_dir,
1112 const char *name,
1113 bool allow_symlink) {
1114
7fd1b19b 1115 _cleanup_install_context_done_ InstallContext c = {};
83096483
LP
1116 InstallInfo *i;
1117 int r;
1118
1119 assert(paths);
1120 assert(name);
1121
83096483
LP
1122 r = install_info_add_auto(&c, name);
1123 if (r < 0)
1124 return r;
1125
1126 assert_se(i = hashmap_first(c.will_install));
1127
1128 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1129
1130 if (r >= 0)
78d54bd4 1131 r =
693eb9a2
LP
1132 (int) strv_length(i->aliases) +
1133 (int) strv_length(i->wanted_by) +
1134 (int) strv_length(i->required_by);
83096483 1135
83096483
LP
1136 return r;
1137}
1138
1139static int create_symlink(
1140 const char *old_path,
1141 const char *new_path,
1142 bool force,
1143 UnitFileChange **changes,
1144 unsigned *n_changes) {
1145
7fd1b19b 1146 _cleanup_free_ char *dest = NULL;
83096483
LP
1147 int r;
1148
1149 assert(old_path);
1150 assert(new_path);
1151
d2e54fae 1152 mkdir_parents_label(new_path, 0755);
83096483
LP
1153
1154 if (symlink(old_path, new_path) >= 0) {
1155 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1156 return 0;
1157 }
1158
1159 if (errno != EEXIST)
1160 return -errno;
1161
1162 r = readlink_and_make_absolute(new_path, &dest);
1163 if (r < 0)
1164 return r;
1165
d9e5e694 1166 if (path_equal(dest, old_path))
83096483 1167 return 0;
83096483 1168
ba49b4a1 1169 if (!force)
83096483
LP
1170 return -EEXIST;
1171
af7fce1c
DH
1172 r = unlink(new_path);
1173 if (r < 0 && errno != ENOENT)
1174 return -errno;
83096483
LP
1175
1176 if (symlink(old_path, new_path) >= 0) {
1177 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1178 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1179 return 0;
1180 }
1181
1182 return -errno;
1183}
1184
1185static int install_info_symlink_alias(
1186 InstallInfo *i,
1187 const char *config_path,
1188 bool force,
1189 UnitFileChange **changes,
1190 unsigned *n_changes) {
1191
1192 char **s;
1193 int r = 0, q;
1194
1195 assert(i);
1196 assert(config_path);
1197
1198 STRV_FOREACH(s, i->aliases) {
7fd1b19b 1199 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
83096483 1200
19f6d710
LP
1201 q = install_full_printf(i, *s, &dst);
1202 if (q < 0)
1203 return q;
83096483 1204
7584d236 1205 alias_path = path_make_absolute(dst, config_path);
83096483
LP
1206 if (!alias_path)
1207 return -ENOMEM;
1208
1209 q = create_symlink(i->path, alias_path, force, changes, n_changes);
83096483
LP
1210 if (r == 0)
1211 r = q;
1212 }
1213
1214 return r;
1215}
1216
1217static int install_info_symlink_wants(
1218 InstallInfo *i,
1219 const char *config_path,
1220 bool force,
1221 UnitFileChange **changes,
1222 unsigned *n_changes) {
1223
1224 char **s;
1225 int r = 0, q;
1226
1227 assert(i);
1228 assert(config_path);
1229
1230 STRV_FOREACH(s, i->wanted_by) {
7fd1b19b 1231 _cleanup_free_ char *path = NULL, *dst = NULL;
83096483 1232
19f6d710
LP
1233 q = install_full_printf(i, *s, &dst);
1234 if (q < 0)
1235 return q;
7584d236 1236
f78e6385 1237 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
83096483
LP
1238 r = -EINVAL;
1239 continue;
1240 }
1241
7584d236 1242 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
83096483
LP
1243 return -ENOMEM;
1244
1245 q = create_symlink(i->path, path, force, changes, n_changes);
83096483
LP
1246
1247 if (r == 0)
1248 r = q;
1249 }
1250
1251 return r;
1252}
1253
78d54bd4
LP
1254static int install_info_symlink_requires(
1255 InstallInfo *i,
1256 const char *config_path,
1257 bool force,
1258 UnitFileChange **changes,
1259 unsigned *n_changes) {
1260
1261 char **s;
1262 int r = 0, q;
1263
1264 assert(i);
1265 assert(config_path);
1266
1267 STRV_FOREACH(s, i->required_by) {
7fd1b19b 1268 _cleanup_free_ char *path = NULL, *dst = NULL;
78d54bd4 1269
19f6d710
LP
1270 q = install_full_printf(i, *s, &dst);
1271 if (q < 0)
1272 return q;
7584d236 1273
f78e6385 1274 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
78d54bd4
LP
1275 r = -EINVAL;
1276 continue;
1277 }
1278
7584d236 1279 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
78d54bd4
LP
1280 return -ENOMEM;
1281
1282 q = create_symlink(i->path, path, force, changes, n_changes);
78d54bd4
LP
1283
1284 if (r == 0)
1285 r = q;
1286 }
1287
1288 return r;
1289}
1290
83096483
LP
1291static int install_info_symlink_link(
1292 InstallInfo *i,
1293 LookupPaths *paths,
1294 const char *config_path,
1295 bool force,
1296 UnitFileChange **changes,
1297 unsigned *n_changes) {
1298
1299 int r;
7fd1b19b 1300 _cleanup_free_ char *path = NULL;
83096483
LP
1301
1302 assert(i);
1303 assert(paths);
1304 assert(config_path);
1305 assert(i->path);
1306
1307 r = in_search_path(i->path, paths->unit_path);
1308 if (r != 0)
1309 return r;
1310
1311 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1312 return -ENOMEM;
1313
1314 r = create_symlink(i->path, path, force, changes, n_changes);
83096483
LP
1315 return r;
1316}
1317
1318static int install_info_apply(
1319 InstallInfo *i,
1320 LookupPaths *paths,
1321 const char *config_path,
1322 bool force,
1323 UnitFileChange **changes,
1324 unsigned *n_changes) {
1325
1326 int r, q;
1327
1328 assert(i);
1329 assert(paths);
1330 assert(config_path);
1331
1332 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1333
1334 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1335 if (r == 0)
1336 r = q;
1337
78d54bd4
LP
1338 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1339 if (r == 0)
1340 r = q;
1341
83096483
LP
1342 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1343 if (r == 0)
1344 r = q;
1345
1346 return r;
1347}
1348
1349static int install_context_apply(
1350 InstallContext *c,
1351 LookupPaths *paths,
1352 const char *config_path,
1353 const char *root_dir,
1354 bool force,
1355 UnitFileChange **changes,
1356 unsigned *n_changes) {
1357
1358 InstallInfo *i;
1359 int r = 0, q;
1360
1361 assert(c);
1362 assert(paths);
1363 assert(config_path);
1364
1365 while ((i = hashmap_first(c->will_install))) {
1366
1367 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1368 if (q < 0)
1369 return q;
1370
1371 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1372
1373 q = unit_file_search(c, i, paths, root_dir, false);
1374 if (q < 0) {
1375 if (r >= 0)
1376 r = q;
1377
1378 return r;
1379 } else if (r >= 0)
1380 r += q;
1381
1382 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1383 if (r >= 0 && q < 0)
1384 r = q;
1385 }
1386
1387 return r;
1388}
1389
1390static int install_context_mark_for_removal(
1391 InstallContext *c,
1392 LookupPaths *paths,
1393 Set **remove_symlinks_to,
1394 const char *config_path,
1395 const char *root_dir) {
1396
1397 InstallInfo *i;
1398 int r = 0, q;
1399
1400 assert(c);
1401 assert(paths);
1402 assert(config_path);
1403
1404 /* Marks all items for removal */
1405
1406 while ((i = hashmap_first(c->will_install))) {
1407
1408 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1409 if (q < 0)
1410 return q;
1411
1412 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1413
1414 q = unit_file_search(c, i, paths, root_dir, false);
02b9e969
ZJS
1415 if (q == -ENOENT) {
1416 /* do nothing */
1417 } else if (q < 0) {
83096483
LP
1418 if (r >= 0)
1419 r = q;
1420
1421 return r;
1422 } else if (r >= 0)
1423 r += q;
1424
29283ea4 1425 if (unit_name_is_instance(i->name)) {
6c5a2825
ZJS
1426 char *unit_file;
1427
1428 if (i->path) {
2b6bf07d 1429 unit_file = basename(i->path);
6c5a2825
ZJS
1430
1431 if (unit_name_is_instance(unit_file))
1432 /* unit file named as instance exists, thus all symlinks
1433 * pointing to it will be removed */
1434 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1435 else
1436 /* does not exist, thus we will mark for removal symlinks
1437 * to template unit file */
1438 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1439 } else {
1440 /* If i->path is not set, it means that we didn't actually find
1441 * the unit file. But we can still remove symlinks to the
1442 * nonexistent template. */
1443 unit_file = unit_name_template(i->name);
1444 if (!unit_file)
1445 return log_oom();
29283ea4 1446
29283ea4 1447 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
6c5a2825
ZJS
1448 free(unit_file);
1449 }
29283ea4
MS
1450 } else
1451 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1452
83096483
LP
1453 if (r >= 0 && q < 0)
1454 r = q;
1455 }
1456
1457 return r;
1458}
1459
1460int unit_file_enable(
1461 UnitFileScope scope,
1462 bool runtime,
1463 const char *root_dir,
7195aa42 1464 char **files,
83096483
LP
1465 bool force,
1466 UnitFileChange **changes,
1467 unsigned *n_changes) {
1468
7fd1b19b
HH
1469 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1470 _cleanup_install_context_done_ InstallContext c = {};
d9e5e694 1471 char **i;
7fd1b19b 1472 _cleanup_free_ char *config_path = NULL;
83096483
LP
1473 int r;
1474
1475 assert(scope >= 0);
1476 assert(scope < _UNIT_FILE_SCOPE_MAX);
1477
12ed81d9 1478 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
83096483
LP
1479 if (r < 0)
1480 return r;
1481
1482 r = get_config_path(scope, runtime, root_dir, &config_path);
1483 if (r < 0)
d9e5e694 1484 return r;
83096483
LP
1485
1486 STRV_FOREACH(i, files) {
1487 r = install_info_add_auto(&c, *i);
1488 if (r < 0)
d9e5e694 1489 return r;
83096483
LP
1490 }
1491
729e3769
LP
1492 /* This will return the number of symlink rules that were
1493 supposed to be created, not the ones actually created. This is
20f59e42 1494 useful to determine whether the passed files had any
729e3769 1495 installation data at all. */
b91a3b02
LP
1496
1497 return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
83096483
LP
1498}
1499
1500int unit_file_disable(
1501 UnitFileScope scope,
1502 bool runtime,
1503 const char *root_dir,
7195aa42 1504 char **files,
83096483
LP
1505 UnitFileChange **changes,
1506 unsigned *n_changes) {
1507
7fd1b19b
HH
1508 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1509 _cleanup_install_context_done_ InstallContext c = {};
d9e5e694 1510 char **i;
7fd1b19b
HH
1511 _cleanup_free_ char *config_path = NULL;
1512 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
83096483
LP
1513 int r, q;
1514
1515 assert(scope >= 0);
1516 assert(scope < _UNIT_FILE_SCOPE_MAX);
1517
12ed81d9 1518 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
83096483
LP
1519 if (r < 0)
1520 return r;
1521
1522 r = get_config_path(scope, runtime, root_dir, &config_path);
1523 if (r < 0)
d9e5e694 1524 return r;
83096483
LP
1525
1526 STRV_FOREACH(i, files) {
1527 r = install_info_add_auto(&c, *i);
1528 if (r < 0)
d9e5e694 1529 return r;
83096483
LP
1530 }
1531
1532 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1533
29283ea4 1534 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483 1535 if (r == 0)
034a2a52 1536 r = q;
83096483 1537
83096483
LP
1538 return r;
1539}
1540
1541int unit_file_reenable(
1542 UnitFileScope scope,
1543 bool runtime,
1544 const char *root_dir,
7195aa42 1545 char **files,
83096483
LP
1546 bool force,
1547 UnitFileChange **changes,
1548 unsigned *n_changes) {
92d430a9 1549 int r;
83096483 1550
92d430a9
RL
1551 r = unit_file_disable(scope, runtime, root_dir, files,
1552 changes, n_changes);
83096483 1553 if (r < 0)
d9e5e694 1554 return r;
83096483 1555
92d430a9
RL
1556 return unit_file_enable(scope, runtime, root_dir, files, force,
1557 changes, n_changes);
83096483
LP
1558}
1559
99504dd4
VP
1560int unit_file_set_default(
1561 UnitFileScope scope,
1562 const char *root_dir,
16ed0233 1563 const char *file,
718db961 1564 bool force,
99504dd4
VP
1565 UnitFileChange **changes,
1566 unsigned *n_changes) {
1567
1568 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1569 _cleanup_install_context_done_ InstallContext c = {};
1570 _cleanup_free_ char *config_path = NULL;
1571 char *path;
1572 int r;
1573 InstallInfo *i = NULL;
1574
1575 assert(scope >= 0);
1576 assert(scope < _UNIT_FILE_SCOPE_MAX);
16ed0233 1577 assert(file);
99504dd4
VP
1578
1579 if (unit_name_to_type(file) != UNIT_TARGET)
1580 return -EINVAL;
1581
12ed81d9 1582 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
99504dd4
VP
1583 if (r < 0)
1584 return r;
1585
1586 r = get_config_path(scope, false, root_dir, &config_path);
1587 if (r < 0)
1588 return r;
1589
1590 r = install_info_add_auto(&c, file);
1591 if (r < 0)
1592 return r;
1593
16ed0233 1594 assert_se(i = hashmap_first(c.will_install));
99504dd4
VP
1595
1596 r = unit_file_search(&c, i, &paths, root_dir, false);
1597 if (r < 0)
1598 return r;
1599
16ed0233
LP
1600 path = strappenda(config_path, "/" SPECIAL_DEFAULT_TARGET);
1601
718db961 1602 r = create_symlink(i->path, path, force, changes, n_changes);
99504dd4
VP
1603 if (r < 0)
1604 return r;
1605
1606 return 0;
1607}
1608
1609int unit_file_get_default(
1610 UnitFileScope scope,
1611 const char *root_dir,
1612 char **name) {
1613
1614 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1615 char **p;
1616 int r;
1617
16ed0233
LP
1618 assert(scope >= 0);
1619 assert(scope < _UNIT_FILE_SCOPE_MAX);
1620 assert(name);
1621
12ed81d9 1622 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
99504dd4
VP
1623 if (r < 0)
1624 return r;
1625
1626 STRV_FOREACH(p, paths.unit_path) {
1627 _cleanup_free_ char *path = NULL, *tmp = NULL;
97137ecc 1628 char *n;
99504dd4
VP
1629
1630 if (isempty(root_dir))
16ed0233 1631 path = strappend(*p, "/" SPECIAL_DEFAULT_TARGET);
99504dd4 1632 else
16ed0233 1633 path = strjoin(root_dir, "/", *p, "/" SPECIAL_DEFAULT_TARGET, NULL);
99504dd4
VP
1634
1635 if (!path)
1636 return -ENOMEM;
1637
1638 r = readlink_malloc(path, &tmp);
1639 if (r == -ENOENT)
1640 continue;
e8372f7e
LP
1641 else if (r == -EINVAL)
1642 /* not a symlink */
1643 n = strdup(SPECIAL_DEFAULT_TARGET);
1644 else if (r < 0)
99504dd4 1645 return r;
e8372f7e 1646 else
2b6bf07d 1647 n = strdup(basename(tmp));
99504dd4 1648
97137ecc 1649 if (!n)
99504dd4
VP
1650 return -ENOMEM;
1651
97137ecc 1652 *name = n;
99504dd4
VP
1653 return 0;
1654 }
1655
1656 return -ENOENT;
1657}
1658
83096483
LP
1659UnitFileState unit_file_get_state(
1660 UnitFileScope scope,
1661 const char *root_dir,
1662 const char *name) {
1663
7fd1b19b 1664 _cleanup_lookup_paths_free_ LookupPaths paths = {};
83096483 1665 UnitFileState state = _UNIT_FILE_STATE_INVALID;
d9e5e694 1666 char **i;
7fd1b19b 1667 _cleanup_free_ char *path = NULL;
83096483
LP
1668 int r;
1669
1670 assert(scope >= 0);
1671 assert(scope < _UNIT_FILE_SCOPE_MAX);
1672 assert(name);
1673
83096483
LP
1674 if (root_dir && scope != UNIT_FILE_SYSTEM)
1675 return -EINVAL;
1676
f78e6385 1677 if (!unit_name_is_valid(name, TEMPLATE_VALID))
83096483
LP
1678 return -EINVAL;
1679
12ed81d9 1680 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
83096483
LP
1681 if (r < 0)
1682 return r;
1683
1684 STRV_FOREACH(i, paths.unit_path) {
1685 struct stat st;
12ed81d9 1686 char *partial;
83096483
LP
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);
d9e5e694
ZJS
1695 if (!path)
1696 return -ENOMEM;
83096483 1697
12ed81d9
ZJS
1698 if (root_dir)
1699 partial = path + strlen(root_dir) + 1;
1700 else
1701 partial = path;
1702
67820a0c
MT
1703 /*
1704 * Search for a unit file in our default paths, to
1705 * be sure, that there are no broken symlinks.
1706 */
83096483 1707 if (lstat(path, &st) < 0) {
81006b8a 1708 r = -errno;
67820a0c
MT
1709 if (errno != ENOENT)
1710 return r;
83096483 1711
67820a0c
MT
1712 if (!unit_name_is_instance(name))
1713 continue;
1714 } else {
1715 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1716 return -ENOENT;
1717
1718 r = null_or_empty_path(path);
1719 if (r < 0 && r != -ENOENT)
1720 return r;
1721 else if (r > 0) {
1722 state = path_startswith(*i, "/run") ?
1723 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1724 return state;
1725 }
83096483
LP
1726 }
1727
1728 r = find_symlinks_in_scope(scope, root_dir, name, &state);
d9e5e694
ZJS
1729 if (r < 0)
1730 return r;
1731 else if (r > 0)
1732 return state;
83096483 1733
12ed81d9 1734 r = unit_file_can_install(&paths, root_dir, partial, true);
bcb161b0 1735 if (r < 0 && errno != ENOENT)
d9e5e694
ZJS
1736 return r;
1737 else if (r > 0)
1738 return UNIT_FILE_DISABLED;
1739 else if (r == 0)
1740 return UNIT_FILE_STATIC;
83096483
LP
1741 }
1742
83096483
LP
1743 return r < 0 ? r : state;
1744}
1745
1746int unit_file_query_preset(UnitFileScope scope, const char *name) {
7fd1b19b 1747 _cleanup_strv_free_ char **files = NULL;
d9e5e694 1748 char **i;
83096483
LP
1749 int r;
1750
1751 assert(scope >= 0);
1752 assert(scope < _UNIT_FILE_SCOPE_MAX);
1753 assert(name);
1754
1755 if (scope == UNIT_FILE_SYSTEM)
7850b3b8 1756 r = conf_files_list(&files, ".preset", NULL,
a7480dba
LP
1757 "/etc/systemd/system-preset",
1758 "/usr/local/lib/systemd/system-preset",
1759 "/usr/lib/systemd/system-preset",
b4bdfefa 1760#ifdef HAVE_SPLIT_USR
a7480dba 1761 "/lib/systemd/system-preset",
b4bdfefa 1762#endif
83096483
LP
1763 NULL);
1764 else if (scope == UNIT_FILE_GLOBAL)
7850b3b8 1765 r = conf_files_list(&files, ".preset", NULL,
a7480dba
LP
1766 "/etc/systemd/user-preset",
1767 "/usr/local/lib/systemd/user-preset",
1768 "/usr/lib/systemd/user-preset",
83096483
LP
1769 NULL);
1770 else
1771 return 1;
1772
1773 if (r < 0)
1774 return r;
1775
1776 STRV_FOREACH(i, files) {
7fd1b19b 1777 _cleanup_fclose_ FILE *f;
83096483
LP
1778
1779 f = fopen(*i, "re");
1780 if (!f) {
1781 if (errno == ENOENT)
1782 continue;
1783
d9e5e694 1784 return -errno;
83096483
LP
1785 }
1786
1787 for (;;) {
1788 char line[LINE_MAX], *l;
1789
1790 if (!fgets(line, sizeof(line), f))
1791 break;
1792
1793 l = strstrip(line);
1794 if (!*l)
1795 continue;
1796
d3b6d0c2 1797 if (strchr(COMMENTS "\n", *l))
83096483
LP
1798 continue;
1799
1800 if (first_word(l, "enable")) {
1801 l += 6;
1802 l += strspn(l, WHITESPACE);
1803
d9e5e694
ZJS
1804 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1805 return 1;
1806
83096483
LP
1807 } else if (first_word(l, "disable")) {
1808 l += 7;
1809 l += strspn(l, WHITESPACE);
1810
d9e5e694
ZJS
1811 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1812 return 0;
1813
83096483
LP
1814 } else
1815 log_debug("Couldn't parse line '%s'", l);
1816 }
83096483
LP
1817 }
1818
1819 /* Default is "enable" */
d9e5e694 1820 return 1;
83096483
LP
1821}
1822
1823int unit_file_preset(
1824 UnitFileScope scope,
1825 bool runtime,
1826 const char *root_dir,
7195aa42 1827 char **files,
83096483
LP
1828 bool force,
1829 UnitFileChange **changes,
1830 unsigned *n_changes) {
1831
7fd1b19b 1832 _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
7fd1b19b 1833 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
da39f6a6
LP
1834 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1835 _cleanup_free_ char *config_path = NULL;
1836 char **i;
83096483
LP
1837 int r, q;
1838
1839 assert(scope >= 0);
1840 assert(scope < _UNIT_FILE_SCOPE_MAX);
1841
12ed81d9 1842 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
83096483
LP
1843 if (r < 0)
1844 return r;
1845
1846 r = get_config_path(scope, runtime, root_dir, &config_path);
1847 if (r < 0)
d9e5e694 1848 return r;
83096483
LP
1849
1850 STRV_FOREACH(i, files) {
1851
f78e6385 1852 if (!unit_name_is_valid(*i, TEMPLATE_VALID))
d9e5e694 1853 return -EINVAL;
83096483
LP
1854
1855 r = unit_file_query_preset(scope, *i);
1856 if (r < 0)
d9e5e694 1857 return r;
83096483
LP
1858
1859 if (r)
1860 r = install_info_add_auto(&plus, *i);
1861 else
1862 r = install_info_add_auto(&minus, *i);
83096483 1863 if (r < 0)
d9e5e694 1864 return r;
83096483
LP
1865 }
1866
da39f6a6 1867 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
83096483 1868
da39f6a6 1869 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483
LP
1870 if (r == 0)
1871 r = q;
1872
729e3769 1873 /* Returns number of symlinks that where supposed to be installed. */
d9e5e694
ZJS
1874 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1875 changes, n_changes);
83096483
LP
1876 if (r == 0)
1877 r = q;
1878
83096483
LP
1879 return r;
1880}
1881
d9e5e694
ZJS
1882static void unitfilelist_free(UnitFileList **f) {
1883 if (!*f)
1884 return;
1885
1886 free((*f)->path);
1887 free(*f);
1888}
b47d419c 1889#define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
d9e5e694 1890
83096483
LP
1891int unit_file_get_list(
1892 UnitFileScope scope,
1893 const char *root_dir,
1894 Hashmap *h) {
1895
7fd1b19b 1896 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 1897 char **i;
83096483
LP
1898 int r;
1899
1900 assert(scope >= 0);
1901 assert(scope < _UNIT_FILE_SCOPE_MAX);
1902 assert(h);
1903
83096483
LP
1904 if (root_dir && scope != UNIT_FILE_SYSTEM)
1905 return -EINVAL;
1906
12ed81d9 1907 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
83096483
LP
1908 if (r < 0)
1909 return r;
1910
1911 STRV_FOREACH(i, paths.unit_path) {
da39f6a6
LP
1912 _cleanup_closedir_ DIR *d = NULL;
1913 _cleanup_free_ char *buf = NULL;
83096483
LP
1914 const char *units_dir;
1915
da39f6a6
LP
1916 if (!isempty(root_dir)) {
1917 buf = strjoin(root_dir, "/", *i, NULL);
1918 if (!buf)
d9e5e694
ZJS
1919 return -ENOMEM;
1920
83096483
LP
1921 units_dir = buf;
1922 } else
1923 units_dir = *i;
1924
83096483
LP
1925 d = opendir(units_dir);
1926 if (!d) {
1927 if (errno == ENOENT)
1928 continue;
1929
d9e5e694 1930 return -errno;
83096483
LP
1931 }
1932
1933 for (;;) {
7d5e9c0f 1934 struct dirent *de;
b47d419c 1935 _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
83096483 1936
4d993c8c
FW
1937 errno = 0;
1938 de = readdir(d);
1939 if (!de && errno != 0)
1940 return -errno;
83096483
LP
1941
1942 if (!de)
1943 break;
1944
1945 if (ignore_file(de->d_name))
1946 continue;
1947
f78e6385 1948 if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
83096483
LP
1949 continue;
1950
1951 if (hashmap_get(h, de->d_name))
1952 continue;
1953
da39f6a6 1954 dirent_ensure_type(d, de);
83096483 1955
da39f6a6 1956 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
83096483
LP
1957 continue;
1958
1959 f = new0(UnitFileList, 1);
d9e5e694
ZJS
1960 if (!f)
1961 return -ENOMEM;
83096483
LP
1962
1963 f->path = path_make_absolute(de->d_name, units_dir);
d9e5e694
ZJS
1964 if (!f->path)
1965 return -ENOMEM;
83096483
LP
1966
1967 r = null_or_empty_path(f->path);
d9e5e694
ZJS
1968 if (r < 0 && r != -ENOENT)
1969 return r;
1970 else if (r > 0) {
83096483
LP
1971 f->state =
1972 path_startswith(*i, "/run") ?
1973 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1974 goto found;
1975 }
1976
1977 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
d9e5e694
ZJS
1978 if (r < 0)
1979 return r;
1980 else if (r > 0) {
b5b46d59 1981 f->state = UNIT_FILE_ENABLED;
83096483 1982 goto found;
b5b46d59 1983 }
83096483
LP
1984
1985 r = unit_file_can_install(&paths, root_dir, f->path, true);
b5b46d59
LP
1986 if (r == -EINVAL || /* Invalid setting? */
1987 r == -EBADMSG || /* Invalid format? */
1988 r == -ENOENT /* Included file not found? */)
1989 f->state = UNIT_FILE_INVALID;
d9e5e694
ZJS
1990 else if (r < 0)
1991 return r;
1992 else if (r > 0)
83096483 1993 f->state = UNIT_FILE_DISABLED;
b5b46d59 1994 else
83096483 1995 f->state = UNIT_FILE_STATIC;
83096483
LP
1996
1997 found:
2b6bf07d 1998 r = hashmap_put(h, basename(f->path), f);
d9e5e694
ZJS
1999 if (r < 0)
2000 return r;
2001 f = NULL; /* prevent cleanup */
83096483
LP
2002 }
2003 }
2004
83096483
LP
2005 return r;
2006}
2007
2008static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2009 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 2010 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
2011 [UNIT_FILE_LINKED] = "linked",
2012 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2013 [UNIT_FILE_MASKED] = "masked",
2014 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2015 [UNIT_FILE_STATIC] = "static",
b5b46d59
LP
2016 [UNIT_FILE_DISABLED] = "disabled",
2017 [UNIT_FILE_INVALID] = "invalid",
83096483
LP
2018};
2019
2020DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
2021
2022static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2023 [UNIT_FILE_SYMLINK] = "symlink",
2024 [UNIT_FILE_UNLINK] = "unlink",
2025};
2026
2027DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);