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