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