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