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