]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
pam_systemd: use F_DUPFD_CLOEXEC when dupping session fds
[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) {
03e334a1 207 safe_close(fd);
83096483
LP
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) {
03e334a1 247 safe_close(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
03e334a1 347 safe_close(fd);
83096483
LP
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) {
03e334a1 370 safe_close(fd);
83096483
LP
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) {
03e334a1 406 safe_close(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 }
83096483
LP
472}
473
474static int find_symlinks(
475 const char *name,
476 const char *config_path,
477 bool *same_name_link) {
478
479 int fd;
480
481 assert(name);
482 assert(config_path);
483 assert(same_name_link);
484
485 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
d5891fda
ZJS
486 if (fd < 0) {
487 if (errno == ENOENT)
488 return 0;
83096483 489 return -errno;
d5891fda 490 }
83096483
LP
491
492 /* This takes possession of fd and closes it */
493 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
494}
495
496static int find_symlinks_in_scope(
497 UnitFileScope scope,
498 const char *root_dir,
499 const char *name,
500 UnitFileState *state) {
501
502 int r;
d7b478b4 503 _cleanup_free_ char *path2 = NULL;
83096483
LP
504 bool same_name_link_runtime = false, same_name_link = false;
505
506 assert(scope >= 0);
507 assert(scope < _UNIT_FILE_SCOPE_MAX);
508 assert(name);
509
510 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
d7b478b4 511 _cleanup_free_ char *path = NULL;
83096483
LP
512
513 /* First look in runtime config path */
514 r = get_config_path(scope, true, root_dir, &path);
515 if (r < 0)
516 return r;
517
518 r = find_symlinks(name, path, &same_name_link_runtime);
83096483
LP
519 if (r < 0)
520 return r;
521 else if (r > 0) {
522 *state = UNIT_FILE_ENABLED_RUNTIME;
523 return r;
524 }
525 }
526
527 /* Then look in the normal config path */
d7b478b4 528 r = get_config_path(scope, false, root_dir, &path2);
83096483
LP
529 if (r < 0)
530 return r;
531
d7b478b4 532 r = find_symlinks(name, path2, &same_name_link);
83096483
LP
533 if (r < 0)
534 return r;
535 else if (r > 0) {
536 *state = UNIT_FILE_ENABLED;
537 return r;
538 }
539
540 /* Hmm, we didn't find it, but maybe we found the same name
541 * link? */
542 if (same_name_link_runtime) {
543 *state = UNIT_FILE_LINKED_RUNTIME;
544 return 1;
545 } else if (same_name_link) {
546 *state = UNIT_FILE_LINKED;
547 return 1;
548 }
549
550 return 0;
551}
552
553int unit_file_mask(
554 UnitFileScope scope,
555 bool runtime,
556 const char *root_dir,
7195aa42 557 char **files,
83096483
LP
558 bool force,
559 UnitFileChange **changes,
560 unsigned *n_changes) {
561
d8831ed5 562 char **i;
7fd1b19b 563 _cleanup_free_ char *prefix;
83096483
LP
564 int r;
565
566 assert(scope >= 0);
567 assert(scope < _UNIT_FILE_SCOPE_MAX);
568
569 r = get_config_path(scope, runtime, root_dir, &prefix);
570 if (r < 0)
571 return r;
572
573 STRV_FOREACH(i, files) {
7fd1b19b 574 _cleanup_free_ char *path = NULL;
83096483 575
f78e6385 576 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
83096483
LP
577 if (r == 0)
578 r = -EINVAL;
579 continue;
580 }
581
582 path = path_make_absolute(*i, prefix);
583 if (!path) {
584 r = -ENOMEM;
585 break;
586 }
587
588 if (symlink("/dev/null", path) >= 0) {
589 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
590
83096483
LP
591 continue;
592 }
593
594 if (errno == EEXIST) {
595
d8831ed5 596 if (null_or_empty_path(path) > 0)
83096483 597 continue;
83096483
LP
598
599 if (force) {
600 unlink(path);
601
602 if (symlink("/dev/null", path) >= 0) {
603
604 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
605 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
606
83096483
LP
607 continue;
608 }
609 }
610
611 if (r == 0)
612 r = -EEXIST;
613 } else {
614 if (r == 0)
615 r = -errno;
616 }
83096483
LP
617 }
618
83096483
LP
619 return r;
620}
621
622int unit_file_unmask(
623 UnitFileScope scope,
624 bool runtime,
625 const char *root_dir,
7195aa42 626 char **files,
83096483
LP
627 UnitFileChange **changes,
628 unsigned *n_changes) {
629
630 char **i, *config_path = NULL;
631 int r, q;
632 Set *remove_symlinks_to = NULL;
633
634 assert(scope >= 0);
635 assert(scope < _UNIT_FILE_SCOPE_MAX);
636
637 r = get_config_path(scope, runtime, root_dir, &config_path);
638 if (r < 0)
639 goto finish;
640
641 STRV_FOREACH(i, files) {
642 char *path;
643
f78e6385 644 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
83096483
LP
645 if (r == 0)
646 r = -EINVAL;
647 continue;
648 }
649
650 path = path_make_absolute(*i, config_path);
651 if (!path) {
652 r = -ENOMEM;
653 break;
654 }
655
656 q = null_or_empty_path(path);
657 if (q > 0) {
658 if (unlink(path) >= 0) {
659 mark_symlink_for_removal(&remove_symlinks_to, path);
660 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
661
662 free(path);
663 continue;
664 }
665
666 q = -errno;
667 }
668
669 if (q != -ENOENT && r == 0)
670 r = q;
671
672 free(path);
673 }
674
675
676finish:
29283ea4 677 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483
LP
678 if (r == 0)
679 r = q;
680
681 set_free_free(remove_symlinks_to);
682 free(config_path);
683
684 return r;
685}
686
687int unit_file_link(
688 UnitFileScope scope,
689 bool runtime,
690 const char *root_dir,
7195aa42 691 char **files,
83096483
LP
692 bool force,
693 UnitFileChange **changes,
694 unsigned *n_changes) {
695
7fd1b19b 696 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 697 char **i;
7fd1b19b 698 _cleanup_free_ char *config_path = NULL;
83096483
LP
699 int r, q;
700
701 assert(scope >= 0);
702 assert(scope < _UNIT_FILE_SCOPE_MAX);
703
83096483
LP
704 r = lookup_paths_init_from_scope(&paths, scope);
705 if (r < 0)
706 return r;
707
708 r = get_config_path(scope, runtime, root_dir, &config_path);
709 if (r < 0)
d9e5e694 710 return r;
83096483
LP
711
712 STRV_FOREACH(i, files) {
7fd1b19b 713 _cleanup_free_ char *path = NULL;
d9e5e694 714 char *fn;
83096483
LP
715 struct stat st;
716
2b6bf07d 717 fn = basename(*i);
83096483
LP
718
719 if (!path_is_absolute(*i) ||
f78e6385 720 !unit_name_is_valid(fn, TEMPLATE_VALID)) {
83096483
LP
721 if (r == 0)
722 r = -EINVAL;
723 continue;
724 }
725
726 if (lstat(*i, &st) < 0) {
727 if (r == 0)
728 r = -errno;
729 continue;
730 }
731
732 if (!S_ISREG(st.st_mode)) {
733 r = -ENOENT;
734 continue;
735 }
736
737 q = in_search_path(*i, paths.unit_path);
d9e5e694
ZJS
738 if (q < 0)
739 return q;
83096483
LP
740
741 if (q > 0)
742 continue;
743
744 path = path_make_absolute(fn, config_path);
d9e5e694
ZJS
745 if (!path)
746 return -ENOMEM;
83096483
LP
747
748 if (symlink(*i, path) >= 0) {
749 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
83096483
LP
750 continue;
751 }
752
753 if (errno == EEXIST) {
7fd1b19b 754 _cleanup_free_ char *dest = NULL;
83096483
LP
755
756 q = readlink_and_make_absolute(path, &dest);
757
758 if (q < 0 && errno != ENOENT) {
83096483
LP
759 if (r == 0)
760 r = q;
83096483
LP
761 continue;
762 }
763
d9e5e694 764 if (q >= 0 && path_equal(dest, *i))
83096483 765 continue;
83096483
LP
766
767 if (force) {
768 unlink(path);
769
770 if (symlink(*i, path) >= 0) {
771
772 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
773 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
774
83096483
LP
775 continue;
776 }
777 }
778
779 if (r == 0)
780 r = -EEXIST;
781 } else {
782 if (r == 0)
783 r = -errno;
784 }
83096483
LP
785 }
786
83096483
LP
787 return r;
788}
789
790void unit_file_list_free(Hashmap *h) {
791 UnitFileList *i;
792
793 while ((i = hashmap_steal_first(h))) {
794 free(i->path);
795 free(i);
796 }
797
798 hashmap_free(h);
799}
800
801void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
802 unsigned i;
803
804 assert(changes || n_changes == 0);
805
806 if (!changes)
807 return;
808
809 for (i = 0; i < n_changes; i++) {
810 free(changes[i].path);
811 free(changes[i].source);
812 }
813
814 free(changes);
815}
816
817static void install_info_free(InstallInfo *i) {
818 assert(i);
819
820 free(i->name);
821 free(i->path);
822 strv_free(i->aliases);
823 strv_free(i->wanted_by);
78d54bd4 824 strv_free(i->required_by);
83096483
LP
825 free(i);
826}
827
828static void install_info_hashmap_free(Hashmap *m) {
829 InstallInfo *i;
830
831 if (!m)
832 return;
833
834 while ((i = hashmap_steal_first(m)))
835 install_info_free(i);
836
837 hashmap_free(m);
838}
839
840static void install_context_done(InstallContext *c) {
841 assert(c);
842
843 install_info_hashmap_free(c->will_install);
844 install_info_hashmap_free(c->have_installed);
845
846 c->will_install = c->have_installed = NULL;
847}
848
849static int install_info_add(
850 InstallContext *c,
851 const char *name,
852 const char *path) {
853 InstallInfo *i = NULL;
854 int r;
855
856 assert(c);
857 assert(name || path);
858
859 if (!name)
2b6bf07d 860 name = basename(path);
83096483 861
f78e6385 862 if (!unit_name_is_valid(name, TEMPLATE_VALID))
83096483
LP
863 return -EINVAL;
864
865 if (hashmap_get(c->have_installed, name) ||
866 hashmap_get(c->will_install, name))
867 return 0;
868
869 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
870 if (r < 0)
871 return r;
872
873 i = new0(InstallInfo, 1);
874 if (!i)
875 return -ENOMEM;
876
877 i->name = strdup(name);
878 if (!i->name) {
879 r = -ENOMEM;
880 goto fail;
881 }
882
883 if (path) {
884 i->path = strdup(path);
885 if (!i->path) {
886 r = -ENOMEM;
887 goto fail;
888 }
889 }
890
891 r = hashmap_put(c->will_install, i->name, i);
892 if (r < 0)
893 goto fail;
894
895 return 0;
896
897fail:
898 if (i)
899 install_info_free(i);
900
901 return r;
902}
903
904static int install_info_add_auto(
905 InstallContext *c,
906 const char *name_or_path) {
907
908 assert(c);
909 assert(name_or_path);
910
911 if (path_is_absolute(name_or_path))
912 return install_info_add(c, NULL, name_or_path);
913 else
914 return install_info_add(c, name_or_path, NULL);
915}
916
e8e581bf
ZJS
917static int config_parse_also(const char *unit,
918 const char *filename,
919 unsigned line,
920 const char *section,
71a61510 921 unsigned section_line,
e8e581bf
ZJS
922 const char *lvalue,
923 int ltype,
924 const char *rvalue,
925 void *data,
926 void *userdata) {
83096483
LP
927
928 char *w;
929 size_t l;
930 char *state;
931 InstallContext *c = data;
932
933 assert(filename);
934 assert(lvalue);
935 assert(rvalue);
936
937 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 938 _cleanup_free_ char *n;
83096483
LP
939 int r;
940
941 n = strndup(w, l);
942 if (!n)
943 return -ENOMEM;
944
945 r = install_info_add(c, n, NULL);
d9e5e694 946 if (r < 0)
83096483 947 return r;
83096483
LP
948 }
949
950 return 0;
951}
952
e8e581bf
ZJS
953static int config_parse_user(const char *unit,
954 const char *filename,
955 unsigned line,
956 const char *section,
71a61510 957 unsigned section_line,
e8e581bf
ZJS
958 const char *lvalue,
959 int ltype,
960 const char *rvalue,
961 void *data,
962 void *userdata) {
3f0b2f0f
ZJS
963
964 InstallInfo *i = data;
965 char* printed;
19f6d710 966 int r;
3f0b2f0f
ZJS
967
968 assert(filename);
969 assert(lvalue);
970 assert(rvalue);
971
19f6d710
LP
972 r = install_full_printf(i, rvalue, &printed);
973 if (r < 0)
974 return r;
3f0b2f0f
ZJS
975
976 free(i->user);
977 i->user = printed;
978
979 return 0;
980}
981
83096483
LP
982static int unit_file_load(
983 InstallContext *c,
984 InstallInfo *info,
985 const char *path,
986 bool allow_symlink) {
987
f975e971 988 const ConfigTableItem items[] = {
78d54bd4
LP
989 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
990 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
991 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
992 { "Install", "Also", config_parse_also, 0, c },
3f0b2f0f 993 { "Exec", "User", config_parse_user, 0, info },
f975e971 994 { NULL, NULL, NULL, 0, NULL }
83096483
LP
995 };
996
997 int fd;
7fd1b19b 998 _cleanup_fclose_ FILE *f = NULL;
83096483
LP
999 int r;
1000
1001 assert(c);
1002 assert(info);
1003 assert(path);
1004
1005 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1006 if (fd < 0)
1007 return -errno;
1008
1009 f = fdopen(fd, "re");
1010 if (!f) {
03e334a1 1011 safe_close(fd);
83096483
LP
1012 return -ENOMEM;
1013 }
1014
e8e581bf 1015 r = config_parse(NULL, path, f, NULL,
db5c0122 1016 config_item_table_lookup, (void*) items, true, true, info);
83096483
LP
1017 if (r < 0)
1018 return r;
1019
78d54bd4 1020 return
693eb9a2
LP
1021 (int) strv_length(info->aliases) +
1022 (int) strv_length(info->wanted_by) +
1023 (int) strv_length(info->required_by);
83096483
LP
1024}
1025
1026static int unit_file_search(
1027 InstallContext *c,
1028 InstallInfo *info,
1029 LookupPaths *paths,
1030 const char *root_dir,
1031 bool allow_symlink) {
1032
1033 char **p;
1034 int r;
1035
1036 assert(c);
1037 assert(info);
1038 assert(paths);
1039
1040 if (info->path)
1041 return unit_file_load(c, info, info->path, allow_symlink);
1042
1043 assert(info->name);
1044
1045 STRV_FOREACH(p, paths->unit_path) {
1046 char *path = NULL;
1047
1048 if (isempty(root_dir))
1049 asprintf(&path, "%s/%s", *p, info->name);
1050 else
1051 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1052
1053 if (!path)
1054 return -ENOMEM;
1055
1056 r = unit_file_load(c, info, path, allow_symlink);
1057
1058 if (r >= 0)
1059 info->path = path;
29283ea4
MS
1060 else {
1061 if (r == -ENOENT && unit_name_is_instance(info->name)) {
6c5a2825
ZJS
1062 /* Unit file doesn't exist, however instance enablement was requested.
1063 * We will check if it is possible to load template unit file. */
29283ea4
MS
1064 char *template = NULL,
1065 *template_path = NULL,
1066 *template_dir = NULL;
1067
1068 template = unit_name_template(info->name);
1069 if (!template) {
1070 free(path);
1071 return -ENOMEM;
1072 }
1073
6c5a2825 1074 /* We will reuse path variable since we don't need it anymore. */
29283ea4
MS
1075 template_dir = path;
1076 *(strrchr(path, '/') + 1) = '\0';
1077
1078 template_path = strjoin(template_dir, template, NULL);
1079 if (!template_path) {
1080 free(path);
1081 free(template);
1082 return -ENOMEM;
1083 }
1084
6c5a2825 1085 /* Let's try to load template unit. */
29283ea4
MS
1086 r = unit_file_load(c, info, template_path, allow_symlink);
1087 if (r >= 0) {
1088 info->path = strdup(template_path);
1089 if (!info->path) {
1090 free(path);
1091 free(template);
1092 free(template_path);
1093 return -ENOMEM;
1094 }
1095 }
1096
1097 free(template);
1098 free(template_path);
1099 }
83096483 1100 free(path);
29283ea4 1101 }
83096483
LP
1102
1103 if (r != -ENOENT && r != -ELOOP)
1104 return r;
1105 }
1106
1107 return -ENOENT;
1108}
1109
1110static int unit_file_can_install(
1111 LookupPaths *paths,
1112 const char *root_dir,
1113 const char *name,
1114 bool allow_symlink) {
1115
7fd1b19b 1116 _cleanup_install_context_done_ InstallContext c = {};
83096483
LP
1117 InstallInfo *i;
1118 int r;
1119
1120 assert(paths);
1121 assert(name);
1122
83096483
LP
1123 r = install_info_add_auto(&c, name);
1124 if (r < 0)
1125 return r;
1126
1127 assert_se(i = hashmap_first(c.will_install));
1128
1129 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1130
1131 if (r >= 0)
78d54bd4 1132 r =
693eb9a2
LP
1133 (int) strv_length(i->aliases) +
1134 (int) strv_length(i->wanted_by) +
1135 (int) strv_length(i->required_by);
83096483 1136
83096483
LP
1137 return r;
1138}
1139
1140static int create_symlink(
1141 const char *old_path,
1142 const char *new_path,
1143 bool force,
1144 UnitFileChange **changes,
1145 unsigned *n_changes) {
1146
7fd1b19b 1147 _cleanup_free_ char *dest = NULL;
83096483
LP
1148 int r;
1149
1150 assert(old_path);
1151 assert(new_path);
1152
d2e54fae 1153 mkdir_parents_label(new_path, 0755);
83096483
LP
1154
1155 if (symlink(old_path, new_path) >= 0) {
1156 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1157 return 0;
1158 }
1159
1160 if (errno != EEXIST)
1161 return -errno;
1162
1163 r = readlink_and_make_absolute(new_path, &dest);
1164 if (r < 0)
1165 return r;
1166
d9e5e694 1167 if (path_equal(dest, old_path))
83096483 1168 return 0;
83096483 1169
ba49b4a1 1170 if (!force)
83096483
LP
1171 return -EEXIST;
1172
af7fce1c
DH
1173 r = unlink(new_path);
1174 if (r < 0 && errno != ENOENT)
1175 return -errno;
83096483
LP
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 1237
f78e6385 1238 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
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 1274
f78e6385 1275 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
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,
7195aa42 1465 char **files,
83096483
LP
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. */
b91a3b02
LP
1497
1498 return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
83096483
LP
1499}
1500
1501int unit_file_disable(
1502 UnitFileScope scope,
1503 bool runtime,
1504 const char *root_dir,
7195aa42 1505 char **files,
83096483
LP
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,
7195aa42 1546 char **files,
83096483
LP
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
f78e6385 1678 if (!unit_name_is_valid(name, TEMPLATE_VALID))
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,
7195aa42 1823 char **files,
83096483
LP
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
f78e6385 1848 if (!unit_name_is_valid(*i, TEMPLATE_VALID))
d9e5e694 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
f78e6385 1952 if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
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);