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