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