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