]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
core: read "debug" from kernel commandline and set log level
[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;
7fd1b19b 509 _cleanup_free_ char *path = 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) {
517
518 /* First look in runtime config path */
519 r = get_config_path(scope, true, root_dir, &path);
520 if (r < 0)
521 return r;
522
523 r = find_symlinks(name, path, &same_name_link_runtime);
83096483
LP
524 if (r < 0)
525 return r;
526 else if (r > 0) {
527 *state = UNIT_FILE_ENABLED_RUNTIME;
528 return r;
529 }
530 }
531
532 /* Then look in the normal config path */
533 r = get_config_path(scope, false, root_dir, &path);
534 if (r < 0)
535 return r;
536
537 r = find_symlinks(name, path, &same_name_link);
83096483
LP
538 if (r < 0)
539 return r;
540 else if (r > 0) {
541 *state = UNIT_FILE_ENABLED;
542 return r;
543 }
544
545 /* Hmm, we didn't find it, but maybe we found the same name
546 * link? */
547 if (same_name_link_runtime) {
548 *state = UNIT_FILE_LINKED_RUNTIME;
549 return 1;
550 } else if (same_name_link) {
551 *state = UNIT_FILE_LINKED;
552 return 1;
553 }
554
555 return 0;
556}
557
558int unit_file_mask(
559 UnitFileScope scope,
560 bool runtime,
561 const char *root_dir,
562 char *files[],
563 bool force,
564 UnitFileChange **changes,
565 unsigned *n_changes) {
566
d8831ed5 567 char **i;
7fd1b19b 568 _cleanup_free_ char *prefix;
83096483
LP
569 int r;
570
571 assert(scope >= 0);
572 assert(scope < _UNIT_FILE_SCOPE_MAX);
573
574 r = get_config_path(scope, runtime, root_dir, &prefix);
575 if (r < 0)
576 return r;
577
578 STRV_FOREACH(i, files) {
7fd1b19b 579 _cleanup_free_ char *path = NULL;
83096483 580
5f739699 581 if (!unit_name_is_valid(*i, true)) {
83096483
LP
582 if (r == 0)
583 r = -EINVAL;
584 continue;
585 }
586
587 path = path_make_absolute(*i, prefix);
588 if (!path) {
589 r = -ENOMEM;
590 break;
591 }
592
593 if (symlink("/dev/null", path) >= 0) {
594 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
595
83096483
LP
596 continue;
597 }
598
599 if (errno == EEXIST) {
600
d8831ed5 601 if (null_or_empty_path(path) > 0)
83096483 602 continue;
83096483
LP
603
604 if (force) {
605 unlink(path);
606
607 if (symlink("/dev/null", path) >= 0) {
608
609 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
610 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
611
83096483
LP
612 continue;
613 }
614 }
615
616 if (r == 0)
617 r = -EEXIST;
618 } else {
619 if (r == 0)
620 r = -errno;
621 }
83096483
LP
622 }
623
83096483
LP
624 return r;
625}
626
627int unit_file_unmask(
628 UnitFileScope scope,
629 bool runtime,
630 const char *root_dir,
631 char *files[],
632 UnitFileChange **changes,
633 unsigned *n_changes) {
634
635 char **i, *config_path = NULL;
636 int r, q;
637 Set *remove_symlinks_to = NULL;
638
639 assert(scope >= 0);
640 assert(scope < _UNIT_FILE_SCOPE_MAX);
641
642 r = get_config_path(scope, runtime, root_dir, &config_path);
643 if (r < 0)
644 goto finish;
645
646 STRV_FOREACH(i, files) {
647 char *path;
648
5f739699 649 if (!unit_name_is_valid(*i, true)) {
83096483
LP
650 if (r == 0)
651 r = -EINVAL;
652 continue;
653 }
654
655 path = path_make_absolute(*i, config_path);
656 if (!path) {
657 r = -ENOMEM;
658 break;
659 }
660
661 q = null_or_empty_path(path);
662 if (q > 0) {
663 if (unlink(path) >= 0) {
664 mark_symlink_for_removal(&remove_symlinks_to, path);
665 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
666
667 free(path);
668 continue;
669 }
670
671 q = -errno;
672 }
673
674 if (q != -ENOENT && r == 0)
675 r = q;
676
677 free(path);
678 }
679
680
681finish:
29283ea4 682 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483
LP
683 if (r == 0)
684 r = q;
685
686 set_free_free(remove_symlinks_to);
687 free(config_path);
688
689 return r;
690}
691
692int unit_file_link(
693 UnitFileScope scope,
694 bool runtime,
695 const char *root_dir,
696 char *files[],
697 bool force,
698 UnitFileChange **changes,
699 unsigned *n_changes) {
700
7fd1b19b 701 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 702 char **i;
7fd1b19b 703 _cleanup_free_ char *config_path = NULL;
83096483
LP
704 int r, q;
705
706 assert(scope >= 0);
707 assert(scope < _UNIT_FILE_SCOPE_MAX);
708
83096483
LP
709 r = lookup_paths_init_from_scope(&paths, scope);
710 if (r < 0)
711 return r;
712
713 r = get_config_path(scope, runtime, root_dir, &config_path);
714 if (r < 0)
d9e5e694 715 return r;
83096483
LP
716
717 STRV_FOREACH(i, files) {
7fd1b19b 718 _cleanup_free_ char *path = NULL;
d9e5e694 719 char *fn;
83096483
LP
720 struct stat st;
721
9eb977db 722 fn = path_get_file_name(*i);
83096483
LP
723
724 if (!path_is_absolute(*i) ||
5f739699 725 !unit_name_is_valid(fn, true)) {
83096483
LP
726 if (r == 0)
727 r = -EINVAL;
728 continue;
729 }
730
731 if (lstat(*i, &st) < 0) {
732 if (r == 0)
733 r = -errno;
734 continue;
735 }
736
737 if (!S_ISREG(st.st_mode)) {
738 r = -ENOENT;
739 continue;
740 }
741
742 q = in_search_path(*i, paths.unit_path);
d9e5e694
ZJS
743 if (q < 0)
744 return q;
83096483
LP
745
746 if (q > 0)
747 continue;
748
749 path = path_make_absolute(fn, config_path);
d9e5e694
ZJS
750 if (!path)
751 return -ENOMEM;
83096483
LP
752
753 if (symlink(*i, path) >= 0) {
754 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
83096483
LP
755 continue;
756 }
757
758 if (errno == EEXIST) {
7fd1b19b 759 _cleanup_free_ char *dest = NULL;
83096483
LP
760
761 q = readlink_and_make_absolute(path, &dest);
762
763 if (q < 0 && errno != ENOENT) {
83096483
LP
764 if (r == 0)
765 r = q;
83096483
LP
766 continue;
767 }
768
d9e5e694 769 if (q >= 0 && path_equal(dest, *i))
83096483 770 continue;
83096483
LP
771
772 if (force) {
773 unlink(path);
774
775 if (symlink(*i, path) >= 0) {
776
777 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
778 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
779
83096483
LP
780 continue;
781 }
782 }
783
784 if (r == 0)
785 r = -EEXIST;
786 } else {
787 if (r == 0)
788 r = -errno;
789 }
83096483
LP
790 }
791
83096483
LP
792 return r;
793}
794
795void unit_file_list_free(Hashmap *h) {
796 UnitFileList *i;
797
798 while ((i = hashmap_steal_first(h))) {
799 free(i->path);
800 free(i);
801 }
802
803 hashmap_free(h);
804}
805
806void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
807 unsigned i;
808
809 assert(changes || n_changes == 0);
810
811 if (!changes)
812 return;
813
814 for (i = 0; i < n_changes; i++) {
815 free(changes[i].path);
816 free(changes[i].source);
817 }
818
819 free(changes);
820}
821
822static void install_info_free(InstallInfo *i) {
823 assert(i);
824
825 free(i->name);
826 free(i->path);
827 strv_free(i->aliases);
828 strv_free(i->wanted_by);
78d54bd4 829 strv_free(i->required_by);
83096483
LP
830 free(i);
831}
832
833static void install_info_hashmap_free(Hashmap *m) {
834 InstallInfo *i;
835
836 if (!m)
837 return;
838
839 while ((i = hashmap_steal_first(m)))
840 install_info_free(i);
841
842 hashmap_free(m);
843}
844
845static void install_context_done(InstallContext *c) {
846 assert(c);
847
848 install_info_hashmap_free(c->will_install);
849 install_info_hashmap_free(c->have_installed);
850
851 c->will_install = c->have_installed = NULL;
852}
853
854static int install_info_add(
855 InstallContext *c,
856 const char *name,
857 const char *path) {
858 InstallInfo *i = NULL;
859 int r;
860
861 assert(c);
862 assert(name || path);
863
864 if (!name)
9eb977db 865 name = path_get_file_name(path);
83096483 866
5f739699 867 if (!unit_name_is_valid(name, true))
83096483
LP
868 return -EINVAL;
869
870 if (hashmap_get(c->have_installed, name) ||
871 hashmap_get(c->will_install, name))
872 return 0;
873
874 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
875 if (r < 0)
876 return r;
877
878 i = new0(InstallInfo, 1);
879 if (!i)
880 return -ENOMEM;
881
882 i->name = strdup(name);
883 if (!i->name) {
884 r = -ENOMEM;
885 goto fail;
886 }
887
888 if (path) {
889 i->path = strdup(path);
890 if (!i->path) {
891 r = -ENOMEM;
892 goto fail;
893 }
894 }
895
896 r = hashmap_put(c->will_install, i->name, i);
897 if (r < 0)
898 goto fail;
899
900 return 0;
901
902fail:
903 if (i)
904 install_info_free(i);
905
906 return r;
907}
908
909static int install_info_add_auto(
910 InstallContext *c,
911 const char *name_or_path) {
912
913 assert(c);
914 assert(name_or_path);
915
916 if (path_is_absolute(name_or_path))
917 return install_info_add(c, NULL, name_or_path);
918 else
919 return install_info_add(c, name_or_path, NULL);
920}
921
e8e581bf
ZJS
922static int config_parse_also(const char *unit,
923 const char *filename,
924 unsigned line,
925 const char *section,
926 const char *lvalue,
927 int ltype,
928 const char *rvalue,
929 void *data,
930 void *userdata) {
83096483
LP
931
932 char *w;
933 size_t l;
934 char *state;
935 InstallContext *c = data;
936
937 assert(filename);
938 assert(lvalue);
939 assert(rvalue);
940
941 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
7fd1b19b 942 _cleanup_free_ char *n;
83096483
LP
943 int r;
944
945 n = strndup(w, l);
946 if (!n)
947 return -ENOMEM;
948
949 r = install_info_add(c, n, NULL);
d9e5e694 950 if (r < 0)
83096483 951 return r;
83096483
LP
952 }
953
954 return 0;
955}
956
e8e581bf
ZJS
957static int config_parse_user(const char *unit,
958 const char *filename,
959 unsigned line,
960 const char *section,
961 const char *lvalue,
962 int ltype,
963 const char *rvalue,
964 void *data,
965 void *userdata) {
3f0b2f0f
ZJS
966
967 InstallInfo *i = data;
968 char* printed;
969
970 assert(filename);
971 assert(lvalue);
972 assert(rvalue);
973
974 printed = install_full_printf(i, rvalue);
975 if (!printed)
976 return -ENOMEM;
977
978 free(i->user);
979 i->user = printed;
980
981 return 0;
982}
983
83096483
LP
984static int unit_file_load(
985 InstallContext *c,
986 InstallInfo *info,
987 const char *path,
988 bool allow_symlink) {
989
f975e971 990 const ConfigTableItem items[] = {
78d54bd4
LP
991 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
992 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
993 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
994 { "Install", "Also", config_parse_also, 0, c },
3f0b2f0f 995 { "Exec", "User", config_parse_user, 0, info },
f975e971 996 { NULL, NULL, NULL, 0, NULL }
83096483
LP
997 };
998
999 int fd;
7fd1b19b 1000 _cleanup_fclose_ FILE *f = NULL;
83096483
LP
1001 int r;
1002
1003 assert(c);
1004 assert(info);
1005 assert(path);
1006
1007 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1008 if (fd < 0)
1009 return -errno;
1010
1011 f = fdopen(fd, "re");
1012 if (!f) {
1013 close_nointr_nofail(fd);
1014 return -ENOMEM;
1015 }
1016
e8e581bf 1017 r = config_parse(NULL, path, f, NULL,
db5c0122 1018 config_item_table_lookup, (void*) items, true, true, info);
83096483
LP
1019 if (r < 0)
1020 return r;
1021
78d54bd4
LP
1022 return
1023 strv_length(info->aliases) +
1024 strv_length(info->wanted_by) +
1025 strv_length(info->required_by);
83096483
LP
1026}
1027
1028static int unit_file_search(
1029 InstallContext *c,
1030 InstallInfo *info,
1031 LookupPaths *paths,
1032 const char *root_dir,
1033 bool allow_symlink) {
1034
1035 char **p;
1036 int r;
1037
1038 assert(c);
1039 assert(info);
1040 assert(paths);
1041
1042 if (info->path)
1043 return unit_file_load(c, info, info->path, allow_symlink);
1044
1045 assert(info->name);
1046
1047 STRV_FOREACH(p, paths->unit_path) {
1048 char *path = NULL;
1049
1050 if (isempty(root_dir))
1051 asprintf(&path, "%s/%s", *p, info->name);
1052 else
1053 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1054
1055 if (!path)
1056 return -ENOMEM;
1057
1058 r = unit_file_load(c, info, path, allow_symlink);
1059
1060 if (r >= 0)
1061 info->path = path;
29283ea4
MS
1062 else {
1063 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1064 /* unit file doesn't exist, however instance enablement was request */
1065 /* we will check if it is possible to load template unit file */
1066 char *template = NULL,
1067 *template_path = NULL,
1068 *template_dir = NULL;
1069
1070 template = unit_name_template(info->name);
1071 if (!template) {
1072 free(path);
1073 return -ENOMEM;
1074 }
1075
1076 /* we will reuse path variable since we don't need it anymore */
1077 template_dir = path;
1078 *(strrchr(path, '/') + 1) = '\0';
1079
1080 template_path = strjoin(template_dir, template, NULL);
1081 if (!template_path) {
1082 free(path);
1083 free(template);
1084 return -ENOMEM;
1085 }
1086
1087 /* let's try to load template unit */
1088 r = unit_file_load(c, info, template_path, allow_symlink);
1089 if (r >= 0) {
1090 info->path = strdup(template_path);
1091 if (!info->path) {
1092 free(path);
1093 free(template);
1094 free(template_path);
1095 return -ENOMEM;
1096 }
1097 }
1098
1099 free(template);
1100 free(template_path);
1101 }
83096483 1102 free(path);
29283ea4 1103 }
83096483
LP
1104
1105 if (r != -ENOENT && r != -ELOOP)
1106 return r;
1107 }
1108
1109 return -ENOENT;
1110}
1111
1112static int unit_file_can_install(
1113 LookupPaths *paths,
1114 const char *root_dir,
1115 const char *name,
1116 bool allow_symlink) {
1117
7fd1b19b 1118 _cleanup_install_context_done_ InstallContext c = {};
83096483
LP
1119 InstallInfo *i;
1120 int r;
1121
1122 assert(paths);
1123 assert(name);
1124
83096483
LP
1125 r = install_info_add_auto(&c, name);
1126 if (r < 0)
1127 return r;
1128
1129 assert_se(i = hashmap_first(c.will_install));
1130
1131 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1132
1133 if (r >= 0)
78d54bd4
LP
1134 r =
1135 strv_length(i->aliases) +
1136 strv_length(i->wanted_by) +
1137 strv_length(i->required_by);
83096483 1138
83096483
LP
1139 return r;
1140}
1141
1142static int create_symlink(
1143 const char *old_path,
1144 const char *new_path,
1145 bool force,
1146 UnitFileChange **changes,
1147 unsigned *n_changes) {
1148
7fd1b19b 1149 _cleanup_free_ char *dest = NULL;
83096483
LP
1150 int r;
1151
1152 assert(old_path);
1153 assert(new_path);
1154
d2e54fae 1155 mkdir_parents_label(new_path, 0755);
83096483
LP
1156
1157 if (symlink(old_path, new_path) >= 0) {
1158 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1159 return 0;
1160 }
1161
1162 if (errno != EEXIST)
1163 return -errno;
1164
1165 r = readlink_and_make_absolute(new_path, &dest);
1166 if (r < 0)
1167 return r;
1168
d9e5e694 1169 if (path_equal(dest, old_path))
83096483 1170 return 0;
83096483 1171
ba49b4a1 1172 if (!force)
83096483
LP
1173 return -EEXIST;
1174
1175 unlink(new_path);
1176
1177 if (symlink(old_path, new_path) >= 0) {
1178 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1179 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1180 return 0;
1181 }
1182
1183 return -errno;
1184}
1185
1186static int install_info_symlink_alias(
1187 InstallInfo *i,
1188 const char *config_path,
1189 bool force,
1190 UnitFileChange **changes,
1191 unsigned *n_changes) {
1192
1193 char **s;
1194 int r = 0, q;
1195
1196 assert(i);
1197 assert(config_path);
1198
1199 STRV_FOREACH(s, i->aliases) {
7fd1b19b 1200 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
83096483 1201
7584d236
ZJS
1202 dst = install_full_printf(i, *s);
1203 if (!dst)
1204 return -ENOMEM;
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
7584d236
ZJS
1234 dst = install_full_printf(i, *s);
1235 if (!dst)
1236 return -ENOMEM;
1237
1238 if (!unit_name_is_valid(dst, true)) {
83096483
LP
1239 r = -EINVAL;
1240 continue;
1241 }
1242
7584d236 1243 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
83096483
LP
1244 return -ENOMEM;
1245
1246 q = create_symlink(i->path, path, force, changes, n_changes);
83096483
LP
1247
1248 if (r == 0)
1249 r = q;
1250 }
1251
1252 return r;
1253}
1254
78d54bd4
LP
1255static int install_info_symlink_requires(
1256 InstallInfo *i,
1257 const char *config_path,
1258 bool force,
1259 UnitFileChange **changes,
1260 unsigned *n_changes) {
1261
1262 char **s;
1263 int r = 0, q;
1264
1265 assert(i);
1266 assert(config_path);
1267
1268 STRV_FOREACH(s, i->required_by) {
7fd1b19b 1269 _cleanup_free_ char *path = NULL, *dst = NULL;
78d54bd4 1270
7584d236
ZJS
1271 dst = install_full_printf(i, *s);
1272 if (!dst)
1273 return -ENOMEM;
1274
1275 if (!unit_name_is_valid(dst, true)) {
78d54bd4
LP
1276 r = -EINVAL;
1277 continue;
1278 }
1279
7584d236 1280 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
78d54bd4
LP
1281 return -ENOMEM;
1282
1283 q = create_symlink(i->path, path, force, changes, n_changes);
78d54bd4
LP
1284
1285 if (r == 0)
1286 r = q;
1287 }
1288
1289 return r;
1290}
1291
83096483
LP
1292static int install_info_symlink_link(
1293 InstallInfo *i,
1294 LookupPaths *paths,
1295 const char *config_path,
1296 bool force,
1297 UnitFileChange **changes,
1298 unsigned *n_changes) {
1299
1300 int r;
7fd1b19b 1301 _cleanup_free_ char *path = NULL;
83096483
LP
1302
1303 assert(i);
1304 assert(paths);
1305 assert(config_path);
1306 assert(i->path);
1307
1308 r = in_search_path(i->path, paths->unit_path);
1309 if (r != 0)
1310 return r;
1311
1312 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1313 return -ENOMEM;
1314
1315 r = create_symlink(i->path, path, force, changes, n_changes);
83096483
LP
1316 return r;
1317}
1318
1319static int install_info_apply(
1320 InstallInfo *i,
1321 LookupPaths *paths,
1322 const char *config_path,
1323 bool force,
1324 UnitFileChange **changes,
1325 unsigned *n_changes) {
1326
1327 int r, q;
1328
1329 assert(i);
1330 assert(paths);
1331 assert(config_path);
1332
1333 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1334
1335 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1336 if (r == 0)
1337 r = q;
1338
78d54bd4
LP
1339 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1340 if (r == 0)
1341 r = q;
1342
83096483
LP
1343 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1344 if (r == 0)
1345 r = q;
1346
1347 return r;
1348}
1349
1350static int install_context_apply(
1351 InstallContext *c,
1352 LookupPaths *paths,
1353 const char *config_path,
1354 const char *root_dir,
1355 bool force,
1356 UnitFileChange **changes,
1357 unsigned *n_changes) {
1358
1359 InstallInfo *i;
1360 int r = 0, q;
1361
1362 assert(c);
1363 assert(paths);
1364 assert(config_path);
1365
1366 while ((i = hashmap_first(c->will_install))) {
1367
1368 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1369 if (q < 0)
1370 return q;
1371
1372 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1373
1374 q = unit_file_search(c, i, paths, root_dir, false);
1375 if (q < 0) {
1376 if (r >= 0)
1377 r = q;
1378
1379 return r;
1380 } else if (r >= 0)
1381 r += q;
1382
1383 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1384 if (r >= 0 && q < 0)
1385 r = q;
1386 }
1387
1388 return r;
1389}
1390
1391static int install_context_mark_for_removal(
1392 InstallContext *c,
1393 LookupPaths *paths,
1394 Set **remove_symlinks_to,
1395 const char *config_path,
1396 const char *root_dir) {
1397
1398 InstallInfo *i;
1399 int r = 0, q;
1400
1401 assert(c);
1402 assert(paths);
1403 assert(config_path);
1404
1405 /* Marks all items for removal */
1406
1407 while ((i = hashmap_first(c->will_install))) {
1408
1409 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1410 if (q < 0)
1411 return q;
1412
1413 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1414
1415 q = unit_file_search(c, i, paths, root_dir, false);
1416 if (q < 0) {
1417 if (r >= 0)
1418 r = q;
1419
1420 return r;
1421 } else if (r >= 0)
1422 r += q;
1423
29283ea4
MS
1424 if (unit_name_is_instance(i->name)) {
1425 char *unit_file = NULL;
1426
1427 unit_file = path_get_file_name(i->path);
1428
1429 if (unit_name_is_instance(unit_file))
1430 /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1431 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1432 else
1433 /* does not exist, thus we will mark for removal symlinks to template unit file */
1434 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1435 } else
1436 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1437
83096483
LP
1438 if (r >= 0 && q < 0)
1439 r = q;
1440 }
1441
1442 return r;
1443}
1444
1445int unit_file_enable(
1446 UnitFileScope scope,
1447 bool runtime,
1448 const char *root_dir,
1449 char *files[],
1450 bool force,
1451 UnitFileChange **changes,
1452 unsigned *n_changes) {
1453
7fd1b19b
HH
1454 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1455 _cleanup_install_context_done_ InstallContext c = {};
d9e5e694 1456 char **i;
7fd1b19b 1457 _cleanup_free_ char *config_path = NULL;
83096483
LP
1458 int r;
1459
1460 assert(scope >= 0);
1461 assert(scope < _UNIT_FILE_SCOPE_MAX);
1462
83096483
LP
1463 r = lookup_paths_init_from_scope(&paths, scope);
1464 if (r < 0)
1465 return r;
1466
1467 r = get_config_path(scope, runtime, root_dir, &config_path);
1468 if (r < 0)
d9e5e694 1469 return r;
83096483
LP
1470
1471 STRV_FOREACH(i, files) {
1472 r = install_info_add_auto(&c, *i);
1473 if (r < 0)
d9e5e694 1474 return r;
83096483
LP
1475 }
1476
729e3769
LP
1477 /* This will return the number of symlink rules that were
1478 supposed to be created, not the ones actually created. This is
20f59e42 1479 useful to determine whether the passed files had any
729e3769 1480 installation data at all. */
83096483 1481 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
83096483
LP
1482 return r;
1483}
1484
1485int unit_file_disable(
1486 UnitFileScope scope,
1487 bool runtime,
1488 const char *root_dir,
1489 char *files[],
1490 UnitFileChange **changes,
1491 unsigned *n_changes) {
1492
7fd1b19b
HH
1493 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1494 _cleanup_install_context_done_ InstallContext c = {};
d9e5e694 1495 char **i;
7fd1b19b
HH
1496 _cleanup_free_ char *config_path = NULL;
1497 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
83096483
LP
1498 int r, q;
1499
1500 assert(scope >= 0);
1501 assert(scope < _UNIT_FILE_SCOPE_MAX);
1502
83096483
LP
1503 r = lookup_paths_init_from_scope(&paths, scope);
1504 if (r < 0)
1505 return r;
1506
1507 r = get_config_path(scope, runtime, root_dir, &config_path);
1508 if (r < 0)
d9e5e694 1509 return r;
83096483
LP
1510
1511 STRV_FOREACH(i, files) {
1512 r = install_info_add_auto(&c, *i);
1513 if (r < 0)
d9e5e694 1514 return r;
83096483
LP
1515 }
1516
1517 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1518
29283ea4 1519 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483 1520 if (r == 0)
034a2a52 1521 r = q;
83096483 1522
83096483
LP
1523 return r;
1524}
1525
1526int unit_file_reenable(
1527 UnitFileScope scope,
1528 bool runtime,
1529 const char *root_dir,
1530 char *files[],
1531 bool force,
1532 UnitFileChange **changes,
1533 unsigned *n_changes) {
1534
7fd1b19b
HH
1535 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1536 _cleanup_install_context_done_ InstallContext c = {};
d9e5e694 1537 char **i;
7fd1b19b
HH
1538 _cleanup_free_ char *config_path = NULL;
1539 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
83096483
LP
1540 int r, q;
1541
1542 assert(scope >= 0);
1543 assert(scope < _UNIT_FILE_SCOPE_MAX);
1544
83096483
LP
1545 r = lookup_paths_init_from_scope(&paths, scope);
1546 if (r < 0)
1547 return r;
1548
1549 r = get_config_path(scope, runtime, root_dir, &config_path);
1550 if (r < 0)
d9e5e694 1551 return r;
83096483
LP
1552
1553 STRV_FOREACH(i, files) {
1554 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1555 if (r < 0)
d9e5e694 1556 return r;
83096483
LP
1557
1558 r = install_info_add_auto(&c, *i);
1559 if (r < 0)
d9e5e694 1560 return r;
83096483
LP
1561 }
1562
29283ea4 1563 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
83096483 1564
729e3769 1565 /* Returns number of symlinks that where supposed to be installed. */
83096483
LP
1566 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1567 if (r == 0)
1568 r = q;
1569
83096483
LP
1570 return r;
1571}
1572
1573UnitFileState unit_file_get_state(
1574 UnitFileScope scope,
1575 const char *root_dir,
1576 const char *name) {
1577
7fd1b19b 1578 _cleanup_lookup_paths_free_ LookupPaths paths = {};
83096483 1579 UnitFileState state = _UNIT_FILE_STATE_INVALID;
d9e5e694 1580 char **i;
7fd1b19b 1581 _cleanup_free_ char *path = NULL;
83096483
LP
1582 int r;
1583
1584 assert(scope >= 0);
1585 assert(scope < _UNIT_FILE_SCOPE_MAX);
1586 assert(name);
1587
83096483
LP
1588 if (root_dir && scope != UNIT_FILE_SYSTEM)
1589 return -EINVAL;
1590
5f739699 1591 if (!unit_name_is_valid(name, true))
83096483
LP
1592 return -EINVAL;
1593
1594 r = lookup_paths_init_from_scope(&paths, scope);
1595 if (r < 0)
1596 return r;
1597
1598 STRV_FOREACH(i, paths.unit_path) {
1599 struct stat st;
1600
1601 free(path);
1602 path = NULL;
1603
1604 if (root_dir)
1605 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1606 else
1607 asprintf(&path, "%s/%s", *i, name);
1608
d9e5e694
ZJS
1609 if (!path)
1610 return -ENOMEM;
83096483 1611
67820a0c
MT
1612 /*
1613 * Search for a unit file in our default paths, to
1614 * be sure, that there are no broken symlinks.
1615 */
83096483 1616 if (lstat(path, &st) < 0) {
81006b8a 1617 r = -errno;
67820a0c
MT
1618 if (errno != ENOENT)
1619 return r;
83096483 1620
67820a0c
MT
1621 if (!unit_name_is_instance(name))
1622 continue;
1623 } else {
1624 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1625 return -ENOENT;
1626
1627 r = null_or_empty_path(path);
1628 if (r < 0 && r != -ENOENT)
1629 return r;
1630 else if (r > 0) {
1631 state = path_startswith(*i, "/run") ?
1632 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1633 return state;
1634 }
83096483
LP
1635 }
1636
1637 r = find_symlinks_in_scope(scope, root_dir, name, &state);
d9e5e694
ZJS
1638 if (r < 0)
1639 return r;
1640 else if (r > 0)
1641 return state;
83096483
LP
1642
1643 r = unit_file_can_install(&paths, root_dir, path, true);
bcb161b0 1644 if (r < 0 && errno != ENOENT)
d9e5e694
ZJS
1645 return r;
1646 else if (r > 0)
1647 return UNIT_FILE_DISABLED;
1648 else if (r == 0)
1649 return UNIT_FILE_STATIC;
83096483
LP
1650 }
1651
83096483
LP
1652 return r < 0 ? r : state;
1653}
1654
1655int unit_file_query_preset(UnitFileScope scope, const char *name) {
7fd1b19b 1656 _cleanup_strv_free_ char **files = NULL;
d9e5e694 1657 char **i;
83096483
LP
1658 int r;
1659
1660 assert(scope >= 0);
1661 assert(scope < _UNIT_FILE_SCOPE_MAX);
1662 assert(name);
1663
1664 if (scope == UNIT_FILE_SYSTEM)
7850b3b8 1665 r = conf_files_list(&files, ".preset", NULL,
a7480dba
LP
1666 "/etc/systemd/system-preset",
1667 "/usr/local/lib/systemd/system-preset",
1668 "/usr/lib/systemd/system-preset",
b4bdfefa 1669#ifdef HAVE_SPLIT_USR
a7480dba 1670 "/lib/systemd/system-preset",
b4bdfefa 1671#endif
83096483
LP
1672 NULL);
1673 else if (scope == UNIT_FILE_GLOBAL)
7850b3b8 1674 r = conf_files_list(&files, ".preset", NULL,
a7480dba
LP
1675 "/etc/systemd/user-preset",
1676 "/usr/local/lib/systemd/user-preset",
1677 "/usr/lib/systemd/user-preset",
83096483
LP
1678 NULL);
1679 else
1680 return 1;
1681
1682 if (r < 0)
1683 return r;
1684
1685 STRV_FOREACH(i, files) {
7fd1b19b 1686 _cleanup_fclose_ FILE *f;
83096483
LP
1687
1688 f = fopen(*i, "re");
1689 if (!f) {
1690 if (errno == ENOENT)
1691 continue;
1692
d9e5e694 1693 return -errno;
83096483
LP
1694 }
1695
1696 for (;;) {
1697 char line[LINE_MAX], *l;
1698
1699 if (!fgets(line, sizeof(line), f))
1700 break;
1701
1702 l = strstrip(line);
1703 if (!*l)
1704 continue;
1705
d3b6d0c2 1706 if (strchr(COMMENTS "\n", *l))
83096483
LP
1707 continue;
1708
1709 if (first_word(l, "enable")) {
1710 l += 6;
1711 l += strspn(l, WHITESPACE);
1712
d9e5e694
ZJS
1713 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1714 return 1;
1715
83096483
LP
1716 } else if (first_word(l, "disable")) {
1717 l += 7;
1718 l += strspn(l, WHITESPACE);
1719
d9e5e694
ZJS
1720 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1721 return 0;
1722
83096483
LP
1723 } else
1724 log_debug("Couldn't parse line '%s'", l);
1725 }
83096483
LP
1726 }
1727
1728 /* Default is "enable" */
d9e5e694 1729 return 1;
83096483
LP
1730}
1731
1732int unit_file_preset(
1733 UnitFileScope scope,
1734 bool runtime,
1735 const char *root_dir,
1736 char *files[],
1737 bool force,
1738 UnitFileChange **changes,
1739 unsigned *n_changes) {
1740
7fd1b19b
HH
1741 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1742 _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
d9e5e694 1743 char **i;
7fd1b19b
HH
1744 _cleanup_free_ char *config_path = NULL;
1745 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
83096483
LP
1746 int r, q;
1747
1748 assert(scope >= 0);
1749 assert(scope < _UNIT_FILE_SCOPE_MAX);
1750
83096483
LP
1751 r = lookup_paths_init_from_scope(&paths, scope);
1752 if (r < 0)
1753 return r;
1754
1755 r = get_config_path(scope, runtime, root_dir, &config_path);
1756 if (r < 0)
d9e5e694 1757 return r;
83096483
LP
1758
1759 STRV_FOREACH(i, files) {
1760
d9e5e694
ZJS
1761 if (!unit_name_is_valid(*i, true))
1762 return -EINVAL;
83096483
LP
1763
1764 r = unit_file_query_preset(scope, *i);
1765 if (r < 0)
d9e5e694 1766 return r;
83096483
LP
1767
1768 if (r)
1769 r = install_info_add_auto(&plus, *i);
1770 else
1771 r = install_info_add_auto(&minus, *i);
1772
1773 if (r < 0)
d9e5e694 1774 return r;
83096483
LP
1775 }
1776
d9e5e694
ZJS
1777 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1778 config_path, root_dir);
83096483 1779
d9e5e694
ZJS
1780 q = remove_marked_symlinks(remove_symlinks_to, config_path,
1781 changes, n_changes, files);
83096483
LP
1782 if (r == 0)
1783 r = q;
1784
729e3769 1785 /* Returns number of symlinks that where supposed to be installed. */
d9e5e694
ZJS
1786 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1787 changes, n_changes);
83096483
LP
1788 if (r == 0)
1789 r = q;
1790
83096483
LP
1791 return r;
1792}
1793
d9e5e694
ZJS
1794static void unitfilelist_free(UnitFileList **f) {
1795 if (!*f)
1796 return;
1797
1798 free((*f)->path);
1799 free(*f);
1800}
1801
83096483
LP
1802int unit_file_get_list(
1803 UnitFileScope scope,
1804 const char *root_dir,
1805 Hashmap *h) {
1806
7fd1b19b 1807 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 1808 char **i;
7fd1b19b
HH
1809 _cleanup_free_ char *buf = NULL;
1810 _cleanup_closedir_ DIR *d = NULL;
83096483
LP
1811 int r;
1812
1813 assert(scope >= 0);
1814 assert(scope < _UNIT_FILE_SCOPE_MAX);
1815 assert(h);
1816
83096483
LP
1817 if (root_dir && scope != UNIT_FILE_SYSTEM)
1818 return -EINVAL;
1819
1820 r = lookup_paths_init_from_scope(&paths, scope);
1821 if (r < 0)
1822 return r;
1823
1824 STRV_FOREACH(i, paths.unit_path) {
83096483
LP
1825 const char *units_dir;
1826
1827 free(buf);
1828 buf = NULL;
1829
1830 if (root_dir) {
d9e5e694
ZJS
1831 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1832 return -ENOMEM;
1833
83096483
LP
1834 units_dir = buf;
1835 } else
1836 units_dir = *i;
1837
1838 if (d)
1839 closedir(d);
1840
1841 d = opendir(units_dir);
1842 if (!d) {
1843 if (errno == ENOENT)
1844 continue;
1845
d9e5e694 1846 return -errno;
83096483
LP
1847 }
1848
1849 for (;;) {
7d5e9c0f
LP
1850 struct dirent *de;
1851 union dirent_storage buffer;
d9e5e694
ZJS
1852 UnitFileList __attribute__((cleanup(unitfilelist_free)))
1853 *f = NULL;
83096483 1854
7d5e9c0f 1855 r = readdir_r(d, &buffer.de, &de);
d9e5e694
ZJS
1856 if (r != 0)
1857 return -r;
83096483
LP
1858
1859 if (!de)
1860 break;
1861
1862 if (ignore_file(de->d_name))
1863 continue;
1864
5f739699 1865 if (!unit_name_is_valid(de->d_name, true))
83096483
LP
1866 continue;
1867
1868 if (hashmap_get(h, de->d_name))
1869 continue;
1870
1871 r = dirent_ensure_type(d, de);
1872 if (r < 0) {
fb5ef067 1873 if (r == -ENOENT)
83096483
LP
1874 continue;
1875
d9e5e694 1876 return r;
83096483
LP
1877 }
1878
1879 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1880 continue;
1881
1882 f = new0(UnitFileList, 1);
d9e5e694
ZJS
1883 if (!f)
1884 return -ENOMEM;
83096483
LP
1885
1886 f->path = path_make_absolute(de->d_name, units_dir);
d9e5e694
ZJS
1887 if (!f->path)
1888 return -ENOMEM;
83096483
LP
1889
1890 r = null_or_empty_path(f->path);
d9e5e694
ZJS
1891 if (r < 0 && r != -ENOENT)
1892 return r;
1893 else if (r > 0) {
83096483
LP
1894 f->state =
1895 path_startswith(*i, "/run") ?
1896 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1897 goto found;
1898 }
1899
1900 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
d9e5e694
ZJS
1901 if (r < 0)
1902 return r;
1903 else if (r > 0) {
b5b46d59 1904 f->state = UNIT_FILE_ENABLED;
83096483 1905 goto found;
b5b46d59 1906 }
83096483
LP
1907
1908 r = unit_file_can_install(&paths, root_dir, f->path, true);
b5b46d59
LP
1909 if (r == -EINVAL || /* Invalid setting? */
1910 r == -EBADMSG || /* Invalid format? */
1911 r == -ENOENT /* Included file not found? */)
1912 f->state = UNIT_FILE_INVALID;
d9e5e694
ZJS
1913 else if (r < 0)
1914 return r;
1915 else if (r > 0)
83096483 1916 f->state = UNIT_FILE_DISABLED;
b5b46d59 1917 else
83096483 1918 f->state = UNIT_FILE_STATIC;
83096483
LP
1919
1920 found:
9eb977db 1921 r = hashmap_put(h, path_get_file_name(f->path), f);
d9e5e694
ZJS
1922 if (r < 0)
1923 return r;
1924 f = NULL; /* prevent cleanup */
83096483
LP
1925 }
1926 }
1927
83096483
LP
1928 return r;
1929}
1930
1931static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1932 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 1933 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
1934 [UNIT_FILE_LINKED] = "linked",
1935 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1936 [UNIT_FILE_MASKED] = "masked",
1937 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1938 [UNIT_FILE_STATIC] = "static",
b5b46d59
LP
1939 [UNIT_FILE_DISABLED] = "disabled",
1940 [UNIT_FILE_INVALID] = "invalid",
83096483
LP
1941};
1942
1943DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
1944
1945static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1946 [UNIT_FILE_SYMLINK] = "symlink",
1947 [UNIT_FILE_UNLINK] = "unlink",
1948};
1949
1950DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);