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