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