]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/shared/install.c
shared/install: move root skipping into create_symlink()
[thirdparty/systemd.git] / src / shared / install.c
... / ...
CommitLineData
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 "locale-util.h"
44#include "log.h"
45#include "macro.h"
46#include "mkdir.h"
47#include "path-lookup.h"
48#include "path-util.h"
49#include "rm-rf.h"
50#include "set.h"
51#include "special.h"
52#include "stat-util.h"
53#include "string-table.h"
54#include "string-util.h"
55#include "strv.h"
56#include "unit-name.h"
57
58#define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
59
60typedef enum SearchFlags {
61 SEARCH_LOAD = 1,
62 SEARCH_FOLLOW_CONFIG_SYMLINKS = 2,
63} SearchFlags;
64
65typedef struct {
66 OrderedHashmap *will_process;
67 OrderedHashmap *have_processed;
68} InstallContext;
69
70typedef enum {
71 PRESET_UNKNOWN,
72 PRESET_ENABLE,
73 PRESET_DISABLE,
74} PresetAction;
75
76typedef struct {
77 char *pattern;
78 PresetAction action;
79} PresetRule;
80
81typedef struct {
82 PresetRule *rules;
83 size_t n_rules;
84} Presets;
85
86static inline void presets_freep(Presets *p) {
87 size_t i;
88
89 if (!p)
90 return;
91
92 for (i = 0; i < p->n_rules; i++)
93 free(p->rules[i].pattern);
94
95 free(p->rules);
96 p->n_rules = 0;
97}
98
99static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret);
100
101bool unit_type_may_alias(UnitType type) {
102 return IN_SET(type,
103 UNIT_SERVICE,
104 UNIT_SOCKET,
105 UNIT_TARGET,
106 UNIT_DEVICE,
107 UNIT_TIMER,
108 UNIT_PATH);
109}
110
111bool unit_type_may_template(UnitType type) {
112 return IN_SET(type,
113 UNIT_SERVICE,
114 UNIT_SOCKET,
115 UNIT_TARGET,
116 UNIT_TIMER,
117 UNIT_PATH);
118}
119
120static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
121 [UNIT_FILE_TYPE_REGULAR] = "regular",
122 [UNIT_FILE_TYPE_SYMLINK] = "symlink",
123 [UNIT_FILE_TYPE_MASKED] = "masked",
124};
125
126DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
127
128static int in_search_path(const LookupPaths *p, const char *path) {
129 _cleanup_free_ char *parent = NULL;
130 char **i;
131
132 assert(path);
133
134 parent = dirname_malloc(path);
135 if (!parent)
136 return -ENOMEM;
137
138 STRV_FOREACH(i, p->search_path)
139 if (path_equal(parent, *i))
140 return true;
141
142 return false;
143}
144
145static const char* skip_root(const LookupPaths *p, const char *path) {
146 char *e;
147
148 assert(p);
149 assert(path);
150
151 if (!p->root_dir)
152 return path;
153
154 e = path_startswith(path, p->root_dir);
155 if (!e)
156 return NULL;
157
158 /* Make sure the returned path starts with a slash */
159 if (e[0] != '/') {
160 if (e == path || e[-1] != '/')
161 return NULL;
162
163 e--;
164 }
165
166 return e;
167}
168
169static int path_is_generator(const LookupPaths *p, const char *path) {
170 _cleanup_free_ char *parent = NULL;
171
172 assert(p);
173 assert(path);
174
175 parent = dirname_malloc(path);
176 if (!parent)
177 return -ENOMEM;
178
179 return path_equal_ptr(parent, p->generator) ||
180 path_equal_ptr(parent, p->generator_early) ||
181 path_equal_ptr(parent, p->generator_late);
182}
183
184static int path_is_transient(const LookupPaths *p, const char *path) {
185 _cleanup_free_ char *parent = NULL;
186
187 assert(p);
188 assert(path);
189
190 parent = dirname_malloc(path);
191 if (!parent)
192 return -ENOMEM;
193
194 return path_equal_ptr(parent, p->transient);
195}
196
197static int path_is_control(const LookupPaths *p, const char *path) {
198 _cleanup_free_ char *parent = NULL;
199
200 assert(p);
201 assert(path);
202
203 parent = dirname_malloc(path);
204 if (!parent)
205 return -ENOMEM;
206
207 return path_equal_ptr(parent, p->persistent_control) ||
208 path_equal_ptr(parent, p->runtime_control);
209}
210
211static int path_is_config(const LookupPaths *p, const char *path) {
212 _cleanup_free_ char *parent = NULL;
213
214 assert(p);
215 assert(path);
216
217 /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern
218 * configuration from transient or generated units */
219
220 parent = dirname_malloc(path);
221 if (!parent)
222 return -ENOMEM;
223
224 return path_equal_ptr(parent, p->persistent_config) ||
225 path_equal_ptr(parent, p->runtime_config);
226}
227
228static int path_is_runtime(const LookupPaths *p, const char *path) {
229 _cleanup_free_ char *parent = NULL;
230 const char *rpath;
231
232 assert(p);
233 assert(path);
234
235 /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime
236 * directories, as safety net. */
237
238 rpath = skip_root(p, path);
239 if (rpath && path_startswith(rpath, "/run"))
240 return true;
241
242 parent = dirname_malloc(path);
243 if (!parent)
244 return -ENOMEM;
245
246 return path_equal_ptr(parent, p->runtime_config) ||
247 path_equal_ptr(parent, p->generator) ||
248 path_equal_ptr(parent, p->generator_early) ||
249 path_equal_ptr(parent, p->generator_late) ||
250 path_equal_ptr(parent, p->transient) ||
251 path_equal_ptr(parent, p->runtime_control);
252}
253
254static int path_is_vendor(const LookupPaths *p, const char *path) {
255 const char *rpath;
256
257 assert(p);
258 assert(path);
259
260 rpath = skip_root(p, path);
261 if (!rpath)
262 return 0;
263
264 if (path_startswith(rpath, "/usr"))
265 return true;
266
267#ifdef HAVE_SPLIT_USR
268 if (path_startswith(rpath, "/lib"))
269 return true;
270#endif
271
272 return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
273}
274
275int unit_file_changes_add(
276 UnitFileChange **changes,
277 unsigned *n_changes,
278 UnitFileChangeType type,
279 const char *path,
280 const char *source) {
281
282 _cleanup_free_ char *p = NULL, *s = NULL;
283 UnitFileChange *c;
284
285 assert(path);
286 assert(!changes == !n_changes);
287
288 if (!changes)
289 return 0;
290
291 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
292 if (!c)
293 return -ENOMEM;
294 *changes = c;
295
296 p = strdup(path);
297 if (source)
298 s = strdup(source);
299
300 if (!p || (source && !s))
301 return -ENOMEM;
302
303 path_kill_slashes(p);
304 if (s)
305 path_kill_slashes(s);
306
307 c[*n_changes] = (UnitFileChange) { type, p, s };
308 p = s = NULL;
309 (*n_changes) ++;
310 return 0;
311}
312
313void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
314 unsigned i;
315
316 assert(changes || n_changes == 0);
317
318 for (i = 0; i < n_changes; i++) {
319 free(changes[i].path);
320 free(changes[i].source);
321 }
322
323 free(changes);
324}
325
326void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet) {
327 unsigned i;
328 bool logged = false;
329
330 assert(changes || n_changes == 0);
331 /* If verb is not specified, errors are not allowed! */
332 assert(verb || r >= 0);
333
334 for (i = 0; i < n_changes; i++) {
335 assert(verb || changes[i].type >= 0);
336
337 switch(changes[i].type) {
338 case UNIT_FILE_SYMLINK:
339 if (!quiet)
340 log_info("Created symlink %s %s %s.",
341 changes[i].path,
342 special_glyph(ARROW),
343 changes[i].source);
344 break;
345 case UNIT_FILE_UNLINK:
346 if (!quiet)
347 log_info("Removed %s.", changes[i].path);
348 break;
349 case UNIT_FILE_IS_MASKED:
350 if (!quiet)
351 log_info("Unit %s is masked, ignoring.", changes[i].path);
352 break;
353 case UNIT_FILE_IS_DANGLING:
354 if (!quiet)
355 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
356 changes[i].path);
357 break;
358 case -EEXIST:
359 if (changes[i].source)
360 log_error_errno(changes[i].type,
361 "Failed to %s unit, file %s already exists and is a symlink to %s.",
362 verb, changes[i].path, changes[i].source);
363 else
364 log_error_errno(changes[i].type,
365 "Failed to %s unit, file %s already exists.",
366 verb, changes[i].path);
367 logged = true;
368 break;
369 case -ERFKILL:
370 log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
371 verb, changes[i].path);
372 logged = true;
373 break;
374 case -EADDRNOTAVAIL:
375 log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
376 verb, changes[i].path);
377 logged = true;
378 break;
379 case -ELOOP:
380 log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
381 verb, changes[i].path);
382 logged = true;
383 break;
384 default:
385 assert(changes[i].type < 0);
386 log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
387 verb, changes[i].path);
388 logged = true;
389 }
390 }
391
392 if (r < 0 && !logged)
393 log_error_errno(r, "Failed to %s: %m.", verb);
394}
395
396static int create_symlink(
397 const LookupPaths *paths,
398 const char *old_path,
399 const char *new_path,
400 bool force,
401 UnitFileChange **changes,
402 unsigned *n_changes) {
403
404 _cleanup_free_ char *dest = NULL;
405 const char *rp;
406 int r;
407
408 assert(old_path);
409 assert(new_path);
410
411 rp = skip_root(paths, old_path);
412 if (rp)
413 old_path = rp;
414
415 /* Actually create a symlink, and remember that we did. Is
416 * smart enough to check if there's already a valid symlink in
417 * place.
418 *
419 * Returns 1 if a symlink was created or already exists and points to
420 * the right place, or negative on error.
421 */
422
423 mkdir_parents_label(new_path, 0755);
424
425 if (symlink(old_path, new_path) >= 0) {
426 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
427 return 1;
428 }
429
430 if (errno != EEXIST) {
431 unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
432 return -errno;
433 }
434
435 r = readlink_malloc(new_path, &dest);
436 if (r < 0) {
437 /* translate EINVAL (non-symlink exists) to EEXIST */
438 if (r == -EINVAL)
439 r = -EEXIST;
440
441 unit_file_changes_add(changes, n_changes, r, new_path, NULL);
442 return r;
443 }
444
445 if (path_equal(dest, old_path))
446 return 1;
447
448 if (!force) {
449 unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
450 return -EEXIST;
451 }
452
453 r = symlink_atomic(old_path, new_path);
454 if (r < 0) {
455 unit_file_changes_add(changes, n_changes, r, new_path, NULL);
456 return r;
457 }
458
459 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
460 unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
461
462 return 1;
463}
464
465static int mark_symlink_for_removal(
466 Set **remove_symlinks_to,
467 const char *p) {
468
469 char *n;
470 int r;
471
472 assert(p);
473
474 r = set_ensure_allocated(remove_symlinks_to, &string_hash_ops);
475 if (r < 0)
476 return r;
477
478 n = strdup(p);
479 if (!n)
480 return -ENOMEM;
481
482 path_kill_slashes(n);
483
484 r = set_consume(*remove_symlinks_to, n);
485 if (r == -EEXIST)
486 return 0;
487 if (r < 0)
488 return r;
489
490 return 1;
491}
492
493static int remove_marked_symlinks_fd(
494 Set *remove_symlinks_to,
495 int fd,
496 const char *path,
497 const char *config_path,
498 const LookupPaths *lp,
499 bool *restart,
500 UnitFileChange **changes,
501 unsigned *n_changes) {
502
503 _cleanup_closedir_ DIR *d = NULL;
504 struct dirent *de;
505 int r = 0;
506
507 assert(remove_symlinks_to);
508 assert(fd >= 0);
509 assert(path);
510 assert(config_path);
511 assert(lp);
512 assert(restart);
513
514 d = fdopendir(fd);
515 if (!d) {
516 safe_close(fd);
517 return -errno;
518 }
519
520 rewinddir(d);
521
522 FOREACH_DIRENT(de, d, return -errno) {
523
524 dirent_ensure_type(d, de);
525
526 if (de->d_type == DT_DIR) {
527 _cleanup_free_ char *p = NULL;
528 int nfd, q;
529
530 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
531 if (nfd < 0) {
532 if (errno == ENOENT)
533 continue;
534
535 if (r == 0)
536 r = -errno;
537 continue;
538 }
539
540 p = path_make_absolute(de->d_name, path);
541 if (!p) {
542 safe_close(nfd);
543 return -ENOMEM;
544 }
545
546 /* This will close nfd, regardless whether it succeeds or not */
547 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes);
548 if (q < 0 && r == 0)
549 r = q;
550
551 } else if (de->d_type == DT_LNK) {
552 _cleanup_free_ char *p = NULL, *dest = NULL;
553 const char *rp;
554 bool found;
555 int q;
556
557 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
558 continue;
559
560 p = path_make_absolute(de->d_name, path);
561 if (!p)
562 return -ENOMEM;
563 path_kill_slashes(p);
564
565 q = readlink_malloc(p, &dest);
566 if (q == -ENOENT)
567 continue;
568 if (q < 0) {
569 if (r == 0)
570 r = q;
571 continue;
572 }
573
574 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
575 * the same name as a file that is marked. */
576
577 found = set_contains(remove_symlinks_to, dest) ||
578 set_contains(remove_symlinks_to, basename(dest)) ||
579 set_contains(remove_symlinks_to, de->d_name);
580
581 if (!found)
582 continue;
583
584 if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
585 if (r == 0)
586 r = -errno;
587 unit_file_changes_add(changes, n_changes, -errno, p, NULL);
588 continue;
589 }
590
591 (void) rmdir_parents(p, config_path);
592
593 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
594
595 /* Now, remember the full path (but with the root prefix removed) of
596 * the symlink we just removed, and remove any symlinks to it, too. */
597
598 rp = skip_root(lp, p);
599 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
600 if (q < 0)
601 return q;
602 if (q > 0)
603 *restart = true;
604 }
605 }
606
607 return r;
608}
609
610static int remove_marked_symlinks(
611 Set *remove_symlinks_to,
612 const char *config_path,
613 const LookupPaths *lp,
614 UnitFileChange **changes,
615 unsigned *n_changes) {
616
617 _cleanup_close_ int fd = -1;
618 bool restart;
619 int r = 0;
620
621 assert(config_path);
622 assert(lp);
623
624 if (set_size(remove_symlinks_to) <= 0)
625 return 0;
626
627 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
628 if (fd < 0)
629 return errno == ENOENT ? 0 : -errno;
630
631 do {
632 int q, cfd;
633 restart = false;
634
635 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
636 if (cfd < 0)
637 return -errno;
638
639 /* This takes possession of cfd and closes it */
640 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes);
641 if (r == 0)
642 r = q;
643 } while (restart);
644
645 return r;
646}
647
648static int find_symlinks_fd(
649 const char *root_dir,
650 const char *name,
651 int fd,
652 const char *path,
653 const char *config_path,
654 const LookupPaths *lp,
655 bool *same_name_link) {
656
657 _cleanup_closedir_ DIR *d = NULL;
658 struct dirent *de;
659 int r = 0;
660
661 assert(name);
662 assert(fd >= 0);
663 assert(path);
664 assert(config_path);
665 assert(lp);
666 assert(same_name_link);
667
668 d = fdopendir(fd);
669 if (!d) {
670 safe_close(fd);
671 return -errno;
672 }
673
674 FOREACH_DIRENT(de, d, return -errno) {
675
676 dirent_ensure_type(d, de);
677
678 if (de->d_type == DT_DIR) {
679 _cleanup_free_ char *p = NULL;
680 int nfd, q;
681
682 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
683 if (nfd < 0) {
684 if (errno == ENOENT)
685 continue;
686
687 if (r == 0)
688 r = -errno;
689 continue;
690 }
691
692 p = path_make_absolute(de->d_name, path);
693 if (!p) {
694 safe_close(nfd);
695 return -ENOMEM;
696 }
697
698 /* This will close nfd, regardless whether it succeeds or not */
699 q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link);
700 if (q > 0)
701 return 1;
702 if (r == 0)
703 r = q;
704
705 } else if (de->d_type == DT_LNK) {
706 _cleanup_free_ char *p = NULL, *dest = NULL;
707 bool found_path, found_dest, b = false;
708 int q;
709
710 /* Acquire symlink name */
711 p = path_make_absolute(de->d_name, path);
712 if (!p)
713 return -ENOMEM;
714
715 /* Acquire symlink destination */
716 q = readlink_malloc(p, &dest);
717 if (q == -ENOENT)
718 continue;
719 if (q < 0) {
720 if (r == 0)
721 r = q;
722 continue;
723 }
724
725 /* Make absolute */
726 if (!path_is_absolute(dest)) {
727 char *x;
728
729 x = prefix_root(root_dir, dest);
730 if (!x)
731 return -ENOMEM;
732
733 free(dest);
734 dest = x;
735 }
736
737 /* Check if the symlink itself matches what we
738 * are looking for */
739 if (path_is_absolute(name))
740 found_path = path_equal(p, name);
741 else
742 found_path = streq(de->d_name, name);
743
744 /* Check if what the symlink points to
745 * matches what we are looking for */
746 if (path_is_absolute(name))
747 found_dest = path_equal(dest, name);
748 else
749 found_dest = streq(basename(dest), name);
750
751 if (found_path && found_dest) {
752 _cleanup_free_ char *t = NULL;
753
754 /* Filter out same name links in the main
755 * config path */
756 t = path_make_absolute(name, config_path);
757 if (!t)
758 return -ENOMEM;
759
760 b = path_equal(t, p);
761 }
762
763 if (b)
764 *same_name_link = true;
765 else if (found_path || found_dest)
766 return 1;
767 }
768 }
769
770 return r;
771}
772
773static int find_symlinks(
774 const char *root_dir,
775 const char *name,
776 const char *config_path,
777 const LookupPaths *lp,
778 bool *same_name_link) {
779
780 int fd;
781
782 assert(name);
783 assert(config_path);
784 assert(same_name_link);
785
786 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
787 if (fd < 0) {
788 if (IN_SET(errno, ENOENT, ENOTDIR, EACCES))
789 return 0;
790 return -errno;
791 }
792
793 /* This takes possession of fd and closes it */
794 return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link);
795}
796
797static int find_symlinks_in_scope(
798 UnitFileScope scope,
799 const LookupPaths *paths,
800 const char *name,
801 UnitFileState *state) {
802
803 bool same_name_link_runtime = false, same_name_link = false;
804 int r;
805
806 assert(scope >= 0);
807 assert(scope < _UNIT_FILE_SCOPE_MAX);
808 assert(paths);
809 assert(name);
810
811 /* First look in the persistent config path */
812 r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link);
813 if (r < 0)
814 return r;
815 if (r > 0) {
816 *state = UNIT_FILE_ENABLED;
817 return r;
818 }
819
820 /* Then look in runtime config path */
821 r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime);
822 if (r < 0)
823 return r;
824 if (r > 0) {
825 *state = UNIT_FILE_ENABLED_RUNTIME;
826 return r;
827 }
828
829 /* Hmm, we didn't find it, but maybe we found the same name
830 * link? */
831 if (same_name_link) {
832 *state = UNIT_FILE_LINKED;
833 return 1;
834 }
835 if (same_name_link_runtime) {
836 *state = UNIT_FILE_LINKED_RUNTIME;
837 return 1;
838 }
839
840 return 0;
841}
842
843static void install_info_free(UnitFileInstallInfo *i) {
844
845 if (!i)
846 return;
847
848 free(i->name);
849 free(i->path);
850 strv_free(i->aliases);
851 strv_free(i->wanted_by);
852 strv_free(i->required_by);
853 strv_free(i->also);
854 free(i->default_instance);
855 free(i->symlink_target);
856 free(i);
857}
858
859static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) {
860 UnitFileInstallInfo *i;
861
862 if (!m)
863 return NULL;
864
865 while ((i = ordered_hashmap_steal_first(m)))
866 install_info_free(i);
867
868 return ordered_hashmap_free(m);
869}
870
871static void install_context_done(InstallContext *c) {
872 assert(c);
873
874 c->will_process = install_info_hashmap_free(c->will_process);
875 c->have_processed = install_info_hashmap_free(c->have_processed);
876}
877
878static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
879 UnitFileInstallInfo *i;
880
881 i = ordered_hashmap_get(c->have_processed, name);
882 if (i)
883 return i;
884
885 return ordered_hashmap_get(c->will_process, name);
886}
887
888static int install_info_may_process(
889 UnitFileInstallInfo *i,
890 const LookupPaths *paths,
891 UnitFileChange **changes,
892 unsigned *n_changes) {
893 assert(i);
894 assert(paths);
895
896 /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
897 * not subject to enable/disable operations. */
898
899 if (i->type == UNIT_FILE_TYPE_MASKED) {
900 unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
901 return -ERFKILL;
902 }
903 if (path_is_generator(paths, i->path) ||
904 path_is_transient(paths, i->path)) {
905 unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
906 return -EADDRNOTAVAIL;
907 }
908
909 return 0;
910}
911
912/**
913 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
914 * hashmap, or retrieves the existing one if already present.
915 */
916static int install_info_add(
917 InstallContext *c,
918 const char *name,
919 const char *path,
920 UnitFileInstallInfo **ret) {
921
922 UnitFileInstallInfo *i = NULL;
923 int r;
924
925 assert(c);
926 assert(name || path);
927
928 if (!name)
929 name = basename(path);
930
931 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
932 return -EINVAL;
933
934 i = install_info_find(c, name);
935 if (i) {
936 if (ret)
937 *ret = i;
938 return 0;
939 }
940
941 r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops);
942 if (r < 0)
943 return r;
944
945 i = new0(UnitFileInstallInfo, 1);
946 if (!i)
947 return -ENOMEM;
948 i->type = _UNIT_FILE_TYPE_INVALID;
949
950 i->name = strdup(name);
951 if (!i->name) {
952 r = -ENOMEM;
953 goto fail;
954 }
955
956 if (path) {
957 i->path = strdup(path);
958 if (!i->path) {
959 r = -ENOMEM;
960 goto fail;
961 }
962 }
963
964 r = ordered_hashmap_put(c->will_process, i->name, i);
965 if (r < 0)
966 goto fail;
967
968 if (ret)
969 *ret = i;
970
971 return 0;
972
973fail:
974 install_info_free(i);
975 return r;
976}
977
978static int config_parse_alias(
979 const char *unit,
980 const char *filename,
981 unsigned line,
982 const char *section,
983 unsigned section_line,
984 const char *lvalue,
985 int ltype,
986 const char *rvalue,
987 void *data,
988 void *userdata) {
989
990 const char *name;
991 UnitType type;
992
993 assert(filename);
994 assert(lvalue);
995 assert(rvalue);
996
997 name = basename(filename);
998 type = unit_name_to_type(name);
999 if (!unit_type_may_alias(type))
1000 return log_syntax(unit, LOG_WARNING, filename, line, 0,
1001 "Aliases are not allowed for %s units, ignoring.",
1002 unit_type_to_string(type));
1003
1004 return config_parse_strv(unit, filename, line, section, section_line,
1005 lvalue, ltype, rvalue, data, userdata);
1006}
1007
1008static int config_parse_also(
1009 const char *unit,
1010 const char *filename,
1011 unsigned line,
1012 const char *section,
1013 unsigned section_line,
1014 const char *lvalue,
1015 int ltype,
1016 const char *rvalue,
1017 void *data,
1018 void *userdata) {
1019
1020 UnitFileInstallInfo *i = userdata;
1021 InstallContext *c = data;
1022 int r;
1023
1024 assert(filename);
1025 assert(lvalue);
1026 assert(rvalue);
1027
1028 for (;;) {
1029 _cleanup_free_ char *word = NULL;
1030
1031 r = extract_first_word(&rvalue, &word, NULL, 0);
1032 if (r < 0)
1033 return r;
1034 if (r == 0)
1035 break;
1036
1037 r = install_info_add(c, word, NULL, NULL);
1038 if (r < 0)
1039 return r;
1040
1041 r = strv_push(&i->also, word);
1042 if (r < 0)
1043 return r;
1044
1045 word = NULL;
1046 }
1047
1048 return 0;
1049}
1050
1051static int config_parse_default_instance(
1052 const char *unit,
1053 const char *filename,
1054 unsigned line,
1055 const char *section,
1056 unsigned section_line,
1057 const char *lvalue,
1058 int ltype,
1059 const char *rvalue,
1060 void *data,
1061 void *userdata) {
1062
1063 UnitFileInstallInfo *i = data;
1064 const char *name;
1065 char *printed;
1066 int r;
1067
1068 assert(filename);
1069 assert(lvalue);
1070 assert(rvalue);
1071
1072 name = basename(filename);
1073 if (unit_name_is_valid(name, UNIT_NAME_INSTANCE))
1074 /* When enabling an instance, we might be using a template unit file,
1075 * but we should ignore DefaultInstance silently. */
1076 return 0;
1077 if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
1078 return log_syntax(unit, LOG_WARNING, filename, line, 0,
1079 "DefaultInstance only makes sense for template units, ignoring.");
1080
1081 r = install_full_printf(i, rvalue, &printed);
1082 if (r < 0)
1083 return r;
1084
1085 if (!unit_instance_is_valid(printed)) {
1086 free(printed);
1087 return -EINVAL;
1088 }
1089
1090 free(i->default_instance);
1091 i->default_instance = printed;
1092
1093 return 0;
1094}
1095
1096static int unit_file_load(
1097 InstallContext *c,
1098 UnitFileInstallInfo *info,
1099 const char *path,
1100 SearchFlags flags) {
1101
1102 const ConfigTableItem items[] = {
1103 { "Install", "Alias", config_parse_alias, 0, &info->aliases },
1104 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1105 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1106 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
1107 { "Install", "Also", config_parse_also, 0, c },
1108 {}
1109 };
1110
1111 const char *name;
1112 UnitType type;
1113 _cleanup_fclose_ FILE *f = NULL;
1114 _cleanup_close_ int fd = -1;
1115 struct stat st;
1116 int r;
1117
1118 assert(c);
1119 assert(info);
1120 assert(path);
1121
1122 name = basename(path);
1123 type = unit_name_to_type(name);
1124 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
1125 !unit_type_may_template(type))
1126 return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
1127
1128 if (!(flags & SEARCH_LOAD)) {
1129 r = lstat(path, &st);
1130 if (r < 0)
1131 return -errno;
1132
1133 if (null_or_empty(&st))
1134 info->type = UNIT_FILE_TYPE_MASKED;
1135 else if (S_ISREG(st.st_mode))
1136 info->type = UNIT_FILE_TYPE_REGULAR;
1137 else if (S_ISLNK(st.st_mode))
1138 return -ELOOP;
1139 else if (S_ISDIR(st.st_mode))
1140 return -EISDIR;
1141 else
1142 return -ENOTTY;
1143
1144 return 0;
1145 }
1146
1147 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
1148 if (fd < 0)
1149 return -errno;
1150 if (fstat(fd, &st) < 0)
1151 return -errno;
1152 if (null_or_empty(&st)) {
1153 info->type = UNIT_FILE_TYPE_MASKED;
1154 return 0;
1155 }
1156 if (S_ISDIR(st.st_mode))
1157 return -EISDIR;
1158 if (!S_ISREG(st.st_mode))
1159 return -ENOTTY;
1160
1161 f = fdopen(fd, "re");
1162 if (!f)
1163 return -errno;
1164 fd = -1;
1165
1166 r = config_parse(NULL, path, f,
1167 NULL,
1168 config_item_table_lookup, items,
1169 true, true, false, info);
1170 if (r < 0)
1171 return r;
1172
1173 info->type = UNIT_FILE_TYPE_REGULAR;
1174
1175 return
1176 (int) strv_length(info->aliases) +
1177 (int) strv_length(info->wanted_by) +
1178 (int) strv_length(info->required_by);
1179}
1180
1181static int unit_file_load_or_readlink(
1182 InstallContext *c,
1183 UnitFileInstallInfo *info,
1184 const char *path,
1185 const char *root_dir,
1186 SearchFlags flags) {
1187
1188 _cleanup_free_ char *target = NULL;
1189 int r;
1190
1191 r = unit_file_load(c, info, path, flags);
1192 if (r != -ELOOP)
1193 return r;
1194
1195 /* This is a symlink, let's read it. */
1196
1197 r = readlink_malloc(path, &target);
1198 if (r < 0)
1199 return r;
1200
1201 if (path_equal(target, "/dev/null"))
1202 info->type = UNIT_FILE_TYPE_MASKED;
1203 else {
1204 const char *bn;
1205 UnitType a, b;
1206
1207 bn = basename(target);
1208
1209 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1210
1211 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1212 return -EINVAL;
1213
1214 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1215
1216 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1217 return -EINVAL;
1218
1219 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1220
1221 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1222 return -EINVAL;
1223 } else
1224 return -EINVAL;
1225
1226 /* Enforce that the symlink destination does not
1227 * change the unit file type. */
1228
1229 a = unit_name_to_type(info->name);
1230 b = unit_name_to_type(bn);
1231 if (a < 0 || b < 0 || a != b)
1232 return -EINVAL;
1233
1234 if (path_is_absolute(target))
1235 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1236 info->symlink_target = prefix_root(root_dir, target);
1237 else
1238 /* This is a relative path, take it relative to the dir the symlink is located in. */
1239 info->symlink_target = file_in_same_dir(path, target);
1240 if (!info->symlink_target)
1241 return -ENOMEM;
1242
1243 info->type = UNIT_FILE_TYPE_SYMLINK;
1244 }
1245
1246 return 0;
1247}
1248
1249static int unit_file_search(
1250 InstallContext *c,
1251 UnitFileInstallInfo *info,
1252 const LookupPaths *paths,
1253 SearchFlags flags) {
1254
1255 _cleanup_free_ char *template = NULL;
1256 char **p;
1257 int r;
1258
1259 assert(c);
1260 assert(info);
1261 assert(paths);
1262
1263 /* Was this unit already loaded? */
1264 if (info->type != _UNIT_FILE_TYPE_INVALID)
1265 return 0;
1266
1267 if (info->path)
1268 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
1269
1270 assert(info->name);
1271
1272 STRV_FOREACH(p, paths->search_path) {
1273 _cleanup_free_ char *path = NULL;
1274
1275 path = strjoin(*p, "/", info->name, NULL);
1276 if (!path)
1277 return -ENOMEM;
1278
1279 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1280 if (r >= 0) {
1281 info->path = path;
1282 path = NULL;
1283 return r;
1284 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
1285 return r;
1286 }
1287
1288 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1289 /* Unit file doesn't exist, however instance
1290 * enablement was requested. We will check if it is
1291 * possible to load template unit file. */
1292
1293 r = unit_name_template(info->name, &template);
1294 if (r < 0)
1295 return r;
1296
1297 STRV_FOREACH(p, paths->search_path) {
1298 _cleanup_free_ char *path = NULL;
1299
1300 path = strjoin(*p, "/", template, NULL);
1301 if (!path)
1302 return -ENOMEM;
1303
1304 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
1305 if (r >= 0) {
1306 info->path = path;
1307 path = NULL;
1308 return r;
1309 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
1310 return r;
1311 }
1312 }
1313
1314 log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
1315 return -ENOENT;
1316}
1317
1318static int install_info_follow(
1319 InstallContext *c,
1320 UnitFileInstallInfo *i,
1321 const char *root_dir,
1322 SearchFlags flags) {
1323
1324 assert(c);
1325 assert(i);
1326
1327 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1328 return -EINVAL;
1329 if (!i->symlink_target)
1330 return -EINVAL;
1331
1332 /* If the basename doesn't match, the caller should add a
1333 * complete new entry for this. */
1334
1335 if (!streq(basename(i->symlink_target), i->name))
1336 return -EXDEV;
1337
1338 free(i->path);
1339 i->path = i->symlink_target;
1340 i->symlink_target = NULL;
1341 i->type = _UNIT_FILE_TYPE_INVALID;
1342
1343 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1344}
1345
1346/**
1347 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1348 * target, maybe more than once. Propagate the instance name if present.
1349 */
1350static int install_info_traverse(
1351 UnitFileScope scope,
1352 InstallContext *c,
1353 const LookupPaths *paths,
1354 UnitFileInstallInfo *start,
1355 SearchFlags flags,
1356 UnitFileInstallInfo **ret) {
1357
1358 UnitFileInstallInfo *i;
1359 unsigned k = 0;
1360 int r;
1361
1362 assert(paths);
1363 assert(start);
1364 assert(c);
1365
1366 r = unit_file_search(c, start, paths, flags);
1367 if (r < 0)
1368 return r;
1369
1370 i = start;
1371 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1372 /* Follow the symlink */
1373
1374 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
1375 return -ELOOP;
1376
1377 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
1378 r = path_is_config(paths, i->path);
1379 if (r < 0)
1380 return r;
1381 if (r > 0)
1382 return -ELOOP;
1383 }
1384
1385 r = install_info_follow(c, i, paths->root_dir, flags);
1386 if (r == -EXDEV) {
1387 _cleanup_free_ char *buffer = NULL;
1388 const char *bn;
1389
1390 /* Target has a different name, create a new
1391 * install info object for that, and continue
1392 * with that. */
1393
1394 bn = basename(i->symlink_target);
1395
1396 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1397 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
1398
1399 _cleanup_free_ char *instance = NULL;
1400
1401 r = unit_name_to_instance(i->name, &instance);
1402 if (r < 0)
1403 return r;
1404
1405 r = unit_name_replace_instance(bn, instance, &buffer);
1406 if (r < 0)
1407 return r;
1408
1409 bn = buffer;
1410 }
1411
1412 r = install_info_add(c, bn, NULL, &i);
1413 if (r < 0)
1414 return r;
1415
1416 /* Try again, with the new target we found. */
1417 r = unit_file_search(c, i, paths, flags);
1418 if (r == -ENOENT)
1419 /* Translate error code to highlight this specific case */
1420 return -ENOLINK;
1421 }
1422
1423 if (r < 0)
1424 return r;
1425 }
1426
1427 if (ret)
1428 *ret = i;
1429
1430 return 0;
1431}
1432
1433/**
1434 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1435 * or the name (otherwise). root_dir is prepended to the path.
1436 */
1437static int install_info_add_auto(
1438 InstallContext *c,
1439 const LookupPaths *paths,
1440 const char *name_or_path,
1441 UnitFileInstallInfo **ret) {
1442
1443 assert(c);
1444 assert(name_or_path);
1445
1446 if (path_is_absolute(name_or_path)) {
1447 const char *pp;
1448
1449 pp = prefix_roota(paths->root_dir, name_or_path);
1450
1451 return install_info_add(c, NULL, pp, ret);
1452 } else
1453 return install_info_add(c, name_or_path, NULL, ret);
1454}
1455
1456static int install_info_discover(
1457 UnitFileScope scope,
1458 InstallContext *c,
1459 const LookupPaths *paths,
1460 const char *name,
1461 SearchFlags flags,
1462 UnitFileInstallInfo **ret) {
1463
1464 UnitFileInstallInfo *i;
1465 int r;
1466
1467 assert(c);
1468 assert(paths);
1469 assert(name);
1470
1471 r = install_info_add_auto(c, paths, name, &i);
1472 if (r < 0)
1473 return r;
1474
1475 return install_info_traverse(scope, c, paths, i, flags, ret);
1476}
1477
1478static int install_info_symlink_alias(
1479 UnitFileInstallInfo *i,
1480 const LookupPaths *paths,
1481 const char *config_path,
1482 bool force,
1483 UnitFileChange **changes,
1484 unsigned *n_changes) {
1485
1486 char **s;
1487 int r = 0, q;
1488
1489 assert(i);
1490 assert(paths);
1491 assert(config_path);
1492
1493 STRV_FOREACH(s, i->aliases) {
1494 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
1495
1496 q = install_full_printf(i, *s, &dst);
1497 if (q < 0)
1498 return q;
1499
1500 alias_path = path_make_absolute(dst, config_path);
1501 if (!alias_path)
1502 return -ENOMEM;
1503
1504 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
1505 if (r == 0)
1506 r = q;
1507 }
1508
1509 return r;
1510}
1511
1512static int install_info_symlink_wants(
1513 UnitFileInstallInfo *i,
1514 const LookupPaths *paths,
1515 const char *config_path,
1516 char **list,
1517 const char *suffix,
1518 UnitFileChange **changes,
1519 unsigned *n_changes) {
1520
1521 _cleanup_free_ char *buf = NULL;
1522 const char *n;
1523 char **s;
1524 int r = 0, q;
1525
1526 assert(i);
1527 assert(paths);
1528 assert(config_path);
1529
1530 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
1531
1532 /* Don't install any symlink if there's no default
1533 * instance configured */
1534
1535 if (!i->default_instance)
1536 return 0;
1537
1538 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1539 if (r < 0)
1540 return r;
1541
1542 n = buf;
1543 } else
1544 n = i->name;
1545
1546 STRV_FOREACH(s, list) {
1547 _cleanup_free_ char *path = NULL, *dst = NULL;
1548
1549 q = install_full_printf(i, *s, &dst);
1550 if (q < 0)
1551 return q;
1552
1553 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
1554 r = -EINVAL;
1555 continue;
1556 }
1557
1558 path = strjoin(config_path, "/", dst, suffix, n, NULL);
1559 if (!path)
1560 return -ENOMEM;
1561
1562 q = create_symlink(paths, i->path, path, true, changes, n_changes);
1563 if (r == 0)
1564 r = q;
1565 }
1566
1567 return r;
1568}
1569
1570static int install_info_symlink_link(
1571 UnitFileInstallInfo *i,
1572 const LookupPaths *paths,
1573 const char *config_path,
1574 bool force,
1575 UnitFileChange **changes,
1576 unsigned *n_changes) {
1577
1578 _cleanup_free_ char *path = NULL;
1579 int r;
1580
1581 assert(i);
1582 assert(paths);
1583 assert(config_path);
1584 assert(i->path);
1585
1586 r = in_search_path(paths, i->path);
1587 if (r < 0)
1588 return r;
1589 if (r > 0)
1590 return 0;
1591
1592 path = strjoin(config_path, "/", i->name, NULL);
1593 if (!path)
1594 return -ENOMEM;
1595
1596 return create_symlink(paths, i->path, path, force, changes, n_changes);
1597}
1598
1599static int install_info_apply(
1600 UnitFileInstallInfo *i,
1601 const LookupPaths *paths,
1602 const char *config_path,
1603 bool force,
1604 UnitFileChange **changes,
1605 unsigned *n_changes) {
1606
1607 int r, q;
1608
1609 assert(i);
1610 assert(paths);
1611 assert(config_path);
1612
1613 if (i->type != UNIT_FILE_TYPE_REGULAR)
1614 return 0;
1615
1616 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
1617
1618 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
1619 if (r == 0)
1620 r = q;
1621
1622 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
1623 if (r == 0)
1624 r = q;
1625
1626 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1627 /* Do not count links to the unit file towards the "carries_install_info" count */
1628 if (r == 0 && q < 0)
1629 r = q;
1630
1631 return r;
1632}
1633
1634static int install_context_apply(
1635 UnitFileScope scope,
1636 InstallContext *c,
1637 const LookupPaths *paths,
1638 const char *config_path,
1639 bool force,
1640 SearchFlags flags,
1641 UnitFileChange **changes,
1642 unsigned *n_changes) {
1643
1644 UnitFileInstallInfo *i;
1645 int r;
1646
1647 assert(c);
1648 assert(paths);
1649 assert(config_path);
1650
1651 if (ordered_hashmap_isempty(c->will_process))
1652 return 0;
1653
1654 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
1655 if (r < 0)
1656 return r;
1657
1658 r = 0;
1659 while ((i = ordered_hashmap_first(c->will_process))) {
1660 int q;
1661
1662 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1663 if (q < 0)
1664 return q;
1665
1666 r = install_info_traverse(scope, c, paths, i, flags, NULL);
1667 if (r < 0)
1668 return r;
1669
1670 if (i->type != UNIT_FILE_TYPE_REGULAR)
1671 continue;
1672
1673 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1674 if (r >= 0) {
1675 if (q < 0)
1676 r = q;
1677 else
1678 r += q;
1679 }
1680 }
1681
1682 return r;
1683}
1684
1685static int install_context_mark_for_removal(
1686 UnitFileScope scope,
1687 InstallContext *c,
1688 const LookupPaths *paths,
1689 Set **remove_symlinks_to,
1690 const char *config_path) {
1691
1692 UnitFileInstallInfo *i;
1693 int r;
1694
1695 assert(c);
1696 assert(paths);
1697 assert(config_path);
1698
1699 /* Marks all items for removal */
1700
1701 if (ordered_hashmap_isempty(c->will_process))
1702 return 0;
1703
1704 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
1705 if (r < 0)
1706 return r;
1707
1708 while ((i = ordered_hashmap_first(c->will_process))) {
1709
1710 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1711 if (r < 0)
1712 return r;
1713
1714 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
1715 if (r == -ENOLINK)
1716 return 0;
1717 else if (r < 0)
1718 return r;
1719
1720 if (i->type != UNIT_FILE_TYPE_REGULAR) {
1721 log_debug("Unit %s has type %s, ignoring.",
1722 i->name,
1723 unit_file_type_to_string(i->type) ?: "invalid");
1724 continue;
1725 }
1726
1727 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1728 if (r < 0)
1729 return r;
1730 }
1731
1732 return 0;
1733}
1734
1735int unit_file_mask(
1736 UnitFileScope scope,
1737 bool runtime,
1738 const char *root_dir,
1739 char **files,
1740 bool force,
1741 UnitFileChange **changes,
1742 unsigned *n_changes) {
1743
1744 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1745 const char *config_path;
1746 char **i;
1747 int r;
1748
1749 assert(scope >= 0);
1750 assert(scope < _UNIT_FILE_SCOPE_MAX);
1751
1752 r = lookup_paths_init(&paths, scope, 0, root_dir);
1753 if (r < 0)
1754 return r;
1755
1756 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1757
1758 STRV_FOREACH(i, files) {
1759 _cleanup_free_ char *path = NULL;
1760 int q;
1761
1762 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
1763 if (r == 0)
1764 r = -EINVAL;
1765 continue;
1766 }
1767
1768 path = path_make_absolute(*i, config_path);
1769 if (!path)
1770 return -ENOMEM;
1771
1772 q = create_symlink(&paths, "/dev/null", path, force, changes, n_changes);
1773 if (q < 0 && r >= 0)
1774 r = q;
1775 }
1776
1777 return r;
1778}
1779
1780int unit_file_unmask(
1781 UnitFileScope scope,
1782 bool runtime,
1783 const char *root_dir,
1784 char **files,
1785 UnitFileChange **changes,
1786 unsigned *n_changes) {
1787
1788 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1789 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1790 _cleanup_free_ char **todo = NULL;
1791 size_t n_todo = 0, n_allocated = 0;
1792 const char *config_path;
1793 char **i;
1794 int r, q;
1795
1796 assert(scope >= 0);
1797 assert(scope < _UNIT_FILE_SCOPE_MAX);
1798
1799 r = lookup_paths_init(&paths, scope, 0, root_dir);
1800 if (r < 0)
1801 return r;
1802
1803 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1804
1805 STRV_FOREACH(i, files) {
1806 _cleanup_free_ char *path = NULL;
1807
1808 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
1809 return -EINVAL;
1810
1811 path = path_make_absolute(*i, config_path);
1812 if (!path)
1813 return -ENOMEM;
1814
1815 r = null_or_empty_path(path);
1816 if (r == -ENOENT)
1817 continue;
1818 if (r < 0)
1819 return r;
1820 if (r == 0)
1821 continue;
1822
1823 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1824 return -ENOMEM;
1825
1826 todo[n_todo++] = *i;
1827 }
1828
1829 strv_uniq(todo);
1830
1831 r = 0;
1832 STRV_FOREACH(i, todo) {
1833 _cleanup_free_ char *path = NULL;
1834 const char *rp;
1835
1836 path = path_make_absolute(*i, config_path);
1837 if (!path)
1838 return -ENOMEM;
1839
1840 if (unlink(path) < 0) {
1841 if (errno != ENOENT) {
1842 if (r >= 0)
1843 r = -errno;
1844 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
1845 }
1846
1847 continue;
1848 }
1849
1850 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
1851
1852 rp = skip_root(&paths, path);
1853 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
1854 if (q < 0)
1855 return q;
1856 }
1857
1858 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
1859 if (r >= 0)
1860 r = q;
1861
1862 return r;
1863}
1864
1865int unit_file_link(
1866 UnitFileScope scope,
1867 bool runtime,
1868 const char *root_dir,
1869 char **files,
1870 bool force,
1871 UnitFileChange **changes,
1872 unsigned *n_changes) {
1873
1874 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1875 _cleanup_free_ char **todo = NULL;
1876 size_t n_todo = 0, n_allocated = 0;
1877 const char *config_path;
1878 char **i;
1879 int r, q;
1880
1881 assert(scope >= 0);
1882 assert(scope < _UNIT_FILE_SCOPE_MAX);
1883
1884 r = lookup_paths_init(&paths, scope, 0, root_dir);
1885 if (r < 0)
1886 return r;
1887
1888 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1889
1890 STRV_FOREACH(i, files) {
1891 _cleanup_free_ char *full = NULL;
1892 struct stat st;
1893 char *fn;
1894
1895 if (!path_is_absolute(*i))
1896 return -EINVAL;
1897
1898 fn = basename(*i);
1899 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
1900 return -EINVAL;
1901
1902 full = prefix_root(paths.root_dir, *i);
1903 if (!full)
1904 return -ENOMEM;
1905
1906 if (lstat(full, &st) < 0)
1907 return -errno;
1908 if (S_ISLNK(st.st_mode))
1909 return -ELOOP;
1910 if (S_ISDIR(st.st_mode))
1911 return -EISDIR;
1912 if (!S_ISREG(st.st_mode))
1913 return -ENOTTY;
1914
1915 q = in_search_path(&paths, *i);
1916 if (q < 0)
1917 return q;
1918 if (q > 0)
1919 continue;
1920
1921 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1922 return -ENOMEM;
1923
1924 todo[n_todo++] = *i;
1925 }
1926
1927 strv_uniq(todo);
1928
1929 r = 0;
1930 STRV_FOREACH(i, todo) {
1931 _cleanup_free_ char *new_path = NULL;
1932
1933 new_path = path_make_absolute(basename(*i), config_path);
1934 if (!new_path)
1935 return -ENOMEM;
1936
1937 q = create_symlink(&paths, *i, new_path, force, changes, n_changes);
1938 if (q < 0 && r >= 0)
1939 r = q;
1940 }
1941
1942 return r;
1943}
1944
1945static int path_shall_revert(const LookupPaths *paths, const char *path) {
1946 int r;
1947
1948 assert(paths);
1949 assert(path);
1950
1951 /* Checks whether the path is one where the drop-in directories shall be removed. */
1952
1953 r = path_is_config(paths, path);
1954 if (r != 0)
1955 return r;
1956
1957 r = path_is_control(paths, path);
1958 if (r != 0)
1959 return r;
1960
1961 return path_is_transient(paths, path);
1962}
1963
1964int unit_file_revert(
1965 UnitFileScope scope,
1966 const char *root_dir,
1967 char **files,
1968 UnitFileChange **changes,
1969 unsigned *n_changes) {
1970
1971 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1972 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1973 _cleanup_strv_free_ char **todo = NULL;
1974 size_t n_todo = 0, n_allocated = 0;
1975 char **i;
1976 int r, q;
1977
1978 /* Puts a unit file back into vendor state. This means:
1979 *
1980 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
1981 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
1982 *
1983 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
1984 * "config", but not in "transient" or "control" or even "generated").
1985 *
1986 * We remove all that in both the runtime and the persistent directories, if that applies.
1987 */
1988
1989 r = lookup_paths_init(&paths, scope, 0, root_dir);
1990 if (r < 0)
1991 return r;
1992
1993 STRV_FOREACH(i, files) {
1994 bool has_vendor = false;
1995 char **p;
1996
1997 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
1998 return -EINVAL;
1999
2000 STRV_FOREACH(p, paths.search_path) {
2001 _cleanup_free_ char *path = NULL, *dropin = NULL;
2002 struct stat st;
2003
2004 path = path_make_absolute(*i, *p);
2005 if (!path)
2006 return -ENOMEM;
2007
2008 r = lstat(path, &st);
2009 if (r < 0) {
2010 if (errno != ENOENT)
2011 return -errno;
2012 } else if (S_ISREG(st.st_mode)) {
2013 /* Check if there's a vendor version */
2014 r = path_is_vendor(&paths, path);
2015 if (r < 0)
2016 return r;
2017 if (r > 0)
2018 has_vendor = true;
2019 }
2020
2021 dropin = strappend(path, ".d");
2022 if (!dropin)
2023 return -ENOMEM;
2024
2025 r = lstat(dropin, &st);
2026 if (r < 0) {
2027 if (errno != ENOENT)
2028 return -errno;
2029 } else if (S_ISDIR(st.st_mode)) {
2030 /* Remove the drop-ins */
2031 r = path_shall_revert(&paths, dropin);
2032 if (r < 0)
2033 return r;
2034 if (r > 0) {
2035 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2036 return -ENOMEM;
2037
2038 todo[n_todo++] = dropin;
2039 dropin = NULL;
2040 }
2041 }
2042 }
2043
2044 if (!has_vendor)
2045 continue;
2046
2047 /* OK, there's a vendor version, hence drop all configuration versions */
2048 STRV_FOREACH(p, paths.search_path) {
2049 _cleanup_free_ char *path = NULL;
2050 struct stat st;
2051
2052 path = path_make_absolute(*i, *p);
2053 if (!path)
2054 return -ENOMEM;
2055
2056 r = lstat(path, &st);
2057 if (r < 0) {
2058 if (errno != ENOENT)
2059 return -errno;
2060 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
2061 r = path_is_config(&paths, path);
2062 if (r < 0)
2063 return r;
2064 if (r > 0) {
2065 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2066 return -ENOMEM;
2067
2068 todo[n_todo++] = path;
2069 path = NULL;
2070 }
2071 }
2072 }
2073 }
2074
2075 strv_uniq(todo);
2076
2077 r = 0;
2078 STRV_FOREACH(i, todo) {
2079 _cleanup_strv_free_ char **fs = NULL;
2080 const char *rp;
2081 char **j;
2082
2083 (void) get_files_in_directory(*i, &fs);
2084
2085 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2086 if (q < 0 && q != -ENOENT && r >= 0) {
2087 r = q;
2088 continue;
2089 }
2090
2091 STRV_FOREACH(j, fs) {
2092 _cleanup_free_ char *t = NULL;
2093
2094 t = strjoin(*i, "/", *j, NULL);
2095 if (!t)
2096 return -ENOMEM;
2097
2098 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
2099 }
2100
2101 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
2102
2103 rp = skip_root(&paths, *i);
2104 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2105 if (q < 0)
2106 return q;
2107 }
2108
2109 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes);
2110 if (r >= 0)
2111 r = q;
2112
2113 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes);
2114 if (r >= 0)
2115 r = q;
2116
2117 return r;
2118}
2119
2120int unit_file_add_dependency(
2121 UnitFileScope scope,
2122 bool runtime,
2123 const char *root_dir,
2124 char **files,
2125 const char *target,
2126 UnitDependency dep,
2127 bool force,
2128 UnitFileChange **changes,
2129 unsigned *n_changes) {
2130
2131 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2132 _cleanup_(install_context_done) InstallContext c = {};
2133 UnitFileInstallInfo *i, *target_info;
2134 const char *config_path;
2135 char **f;
2136 int r;
2137
2138 assert(scope >= 0);
2139 assert(scope < _UNIT_FILE_SCOPE_MAX);
2140 assert(target);
2141
2142 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
2143 return -EINVAL;
2144
2145 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2146 return -EINVAL;
2147
2148 r = lookup_paths_init(&paths, scope, 0, root_dir);
2149 if (r < 0)
2150 return r;
2151
2152 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2153
2154 r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
2155 if (r < 0)
2156 return r;
2157 r = install_info_may_process(target_info, &paths, changes, n_changes);
2158 if (r < 0)
2159 return r;
2160
2161 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
2162
2163 STRV_FOREACH(f, files) {
2164 char ***l;
2165
2166 r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2167 if (r < 0)
2168 return r;
2169 r = install_info_may_process(i, &paths, changes, n_changes);
2170 if (r < 0)
2171 return r;
2172
2173 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2174
2175 /* We didn't actually load anything from the unit
2176 * file, but instead just add in our new symlink to
2177 * create. */
2178
2179 if (dep == UNIT_WANTS)
2180 l = &i->wanted_by;
2181 else
2182 l = &i->required_by;
2183
2184 strv_free(*l);
2185 *l = strv_new(target_info->name, NULL);
2186 if (!*l)
2187 return -ENOMEM;
2188 }
2189
2190 return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
2191}
2192
2193int unit_file_enable(
2194 UnitFileScope scope,
2195 bool runtime,
2196 const char *root_dir,
2197 char **files,
2198 bool force,
2199 UnitFileChange **changes,
2200 unsigned *n_changes) {
2201
2202 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2203 _cleanup_(install_context_done) InstallContext c = {};
2204 const char *config_path;
2205 UnitFileInstallInfo *i;
2206 char **f;
2207 int r;
2208
2209 assert(scope >= 0);
2210 assert(scope < _UNIT_FILE_SCOPE_MAX);
2211
2212 r = lookup_paths_init(&paths, scope, 0, root_dir);
2213 if (r < 0)
2214 return r;
2215
2216 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2217
2218 STRV_FOREACH(f, files) {
2219 r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2220 if (r < 0)
2221 return r;
2222 r = install_info_may_process(i, &paths, changes, n_changes);
2223 if (r < 0)
2224 return r;
2225
2226 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2227 }
2228
2229 /* This will return the number of symlink rules that were
2230 supposed to be created, not the ones actually created. This
2231 is useful to determine whether the passed files had any
2232 installation data at all. */
2233
2234 return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes);
2235}
2236
2237int unit_file_disable(
2238 UnitFileScope scope,
2239 bool runtime,
2240 const char *root_dir,
2241 char **files,
2242 UnitFileChange **changes,
2243 unsigned *n_changes) {
2244
2245 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2246 _cleanup_(install_context_done) InstallContext c = {};
2247 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2248 const char *config_path;
2249 char **i;
2250 int r;
2251
2252 assert(scope >= 0);
2253 assert(scope < _UNIT_FILE_SCOPE_MAX);
2254
2255 r = lookup_paths_init(&paths, scope, 0, root_dir);
2256 if (r < 0)
2257 return r;
2258
2259 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2260
2261 STRV_FOREACH(i, files) {
2262 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2263 return -EINVAL;
2264
2265 r = install_info_add(&c, *i, NULL, NULL);
2266 if (r < 0)
2267 return r;
2268 }
2269
2270 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path);
2271 if (r < 0)
2272 return r;
2273
2274 return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
2275}
2276
2277int unit_file_reenable(
2278 UnitFileScope scope,
2279 bool runtime,
2280 const char *root_dir,
2281 char **files,
2282 bool force,
2283 UnitFileChange **changes,
2284 unsigned *n_changes) {
2285
2286 char **n;
2287 int r;
2288 size_t l, i;
2289
2290 /* First, we invoke the disable command with only the basename... */
2291 l = strv_length(files);
2292 n = newa(char*, l+1);
2293 for (i = 0; i < l; i++)
2294 n[i] = basename(files[i]);
2295 n[i] = NULL;
2296
2297 r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes);
2298 if (r < 0)
2299 return r;
2300
2301 /* But the enable command with the full name */
2302 return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes);
2303}
2304
2305int unit_file_set_default(
2306 UnitFileScope scope,
2307 const char *root_dir,
2308 const char *name,
2309 bool force,
2310 UnitFileChange **changes,
2311 unsigned *n_changes) {
2312
2313 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2314 _cleanup_(install_context_done) InstallContext c = {};
2315 UnitFileInstallInfo *i;
2316 const char *new_path;
2317 int r;
2318
2319 assert(scope >= 0);
2320 assert(scope < _UNIT_FILE_SCOPE_MAX);
2321 assert(name);
2322
2323 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
2324 return -EINVAL;
2325 if (streq(name, SPECIAL_DEFAULT_TARGET))
2326 return -EINVAL;
2327
2328 r = lookup_paths_init(&paths, scope, 0, root_dir);
2329 if (r < 0)
2330 return r;
2331
2332 r = install_info_discover(scope, &c, &paths, name, 0, &i);
2333 if (r < 0)
2334 return r;
2335 r = install_info_may_process(i, &paths, changes, n_changes);
2336 if (r < 0)
2337 return r;
2338
2339 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
2340 return create_symlink(&paths, i->path, new_path, force, changes, n_changes);
2341}
2342
2343int unit_file_get_default(
2344 UnitFileScope scope,
2345 const char *root_dir,
2346 char **name) {
2347
2348 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2349 _cleanup_(install_context_done) InstallContext c = {};
2350 UnitFileInstallInfo *i;
2351 char *n;
2352 int r;
2353
2354 assert(scope >= 0);
2355 assert(scope < _UNIT_FILE_SCOPE_MAX);
2356 assert(name);
2357
2358 r = lookup_paths_init(&paths, scope, 0, root_dir);
2359 if (r < 0)
2360 return r;
2361
2362 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2363 if (r < 0)
2364 return r;
2365 r = install_info_may_process(i, &paths, NULL, 0);
2366 if (r < 0)
2367 return r;
2368
2369 n = strdup(i->name);
2370 if (!n)
2371 return -ENOMEM;
2372
2373 *name = n;
2374 return 0;
2375}
2376
2377static int unit_file_lookup_state(
2378 UnitFileScope scope,
2379 const LookupPaths *paths,
2380 const char *name,
2381 UnitFileState *ret) {
2382
2383 _cleanup_(install_context_done) InstallContext c = {};
2384 UnitFileInstallInfo *i;
2385 UnitFileState state;
2386 int r;
2387
2388 assert(paths);
2389 assert(name);
2390
2391 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2392 return -EINVAL;
2393
2394 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2395 if (r < 0)
2396 return r;
2397
2398 /* Shortcut things, if the caller just wants to know if this unit exists. */
2399 if (!ret)
2400 return 0;
2401
2402 switch (i->type) {
2403
2404 case UNIT_FILE_TYPE_MASKED:
2405 r = path_is_runtime(paths, i->path);
2406 if (r < 0)
2407 return r;
2408
2409 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
2410 break;
2411
2412 case UNIT_FILE_TYPE_REGULAR:
2413 r = path_is_generator(paths, i->path);
2414 if (r < 0)
2415 return r;
2416 if (r > 0) {
2417 state = UNIT_FILE_GENERATED;
2418 break;
2419 }
2420
2421 r = path_is_transient(paths, i->path);
2422 if (r < 0)
2423 return r;
2424 if (r > 0) {
2425 state = UNIT_FILE_TRANSIENT;
2426 break;
2427 }
2428
2429 r = find_symlinks_in_scope(scope, paths, i->name, &state);
2430 if (r < 0)
2431 return r;
2432 if (r == 0) {
2433 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i))
2434 state = UNIT_FILE_DISABLED;
2435 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i))
2436 state = UNIT_FILE_INDIRECT;
2437 else
2438 state = UNIT_FILE_STATIC;
2439 }
2440
2441 break;
2442
2443 default:
2444 assert_not_reached("Unexpect unit file type.");
2445 }
2446
2447 *ret = state;
2448 return 0;
2449}
2450
2451int unit_file_get_state(
2452 UnitFileScope scope,
2453 const char *root_dir,
2454 const char *name,
2455 UnitFileState *ret) {
2456
2457 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2458 int r;
2459
2460 assert(scope >= 0);
2461 assert(scope < _UNIT_FILE_SCOPE_MAX);
2462 assert(name);
2463
2464 r = lookup_paths_init(&paths, scope, 0, root_dir);
2465 if (r < 0)
2466 return r;
2467
2468 return unit_file_lookup_state(scope, &paths, name, ret);
2469}
2470
2471int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2472 _cleanup_(install_context_done) InstallContext c = {};
2473 int r;
2474
2475 assert(paths);
2476 assert(name);
2477
2478 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2479 return -EINVAL;
2480
2481 r = install_info_discover(scope, &c, paths, name, 0, NULL);
2482 if (r == -ENOENT)
2483 return 0;
2484 if (r < 0)
2485 return r;
2486
2487 return 1;
2488}
2489
2490static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2491 _cleanup_(presets_freep) Presets ps = {};
2492 size_t n_allocated = 0;
2493 _cleanup_strv_free_ char **files = NULL;
2494 char **p;
2495 int r;
2496
2497 assert(scope >= 0);
2498 assert(scope < _UNIT_FILE_SCOPE_MAX);
2499 assert(presets);
2500
2501 if (scope == UNIT_FILE_SYSTEM)
2502 r = conf_files_list(&files, ".preset", root_dir,
2503 "/etc/systemd/system-preset",
2504 "/usr/local/lib/systemd/system-preset",
2505 "/usr/lib/systemd/system-preset",
2506#ifdef HAVE_SPLIT_USR
2507 "/lib/systemd/system-preset",
2508#endif
2509 NULL);
2510 else if (scope == UNIT_FILE_GLOBAL)
2511 r = conf_files_list(&files, ".preset", root_dir,
2512 "/etc/systemd/user-preset",
2513 "/usr/local/lib/systemd/user-preset",
2514 "/usr/lib/systemd/user-preset",
2515 NULL);
2516 else {
2517 *presets = (Presets){};
2518
2519 return 0;
2520 }
2521
2522 if (r < 0)
2523 return r;
2524
2525 STRV_FOREACH(p, files) {
2526 _cleanup_fclose_ FILE *f;
2527 char line[LINE_MAX];
2528 int n = 0;
2529
2530 f = fopen(*p, "re");
2531 if (!f) {
2532 if (errno == ENOENT)
2533 continue;
2534
2535 return -errno;
2536 }
2537
2538 FOREACH_LINE(line, f, return -errno) {
2539 PresetRule rule = {};
2540 const char *parameter;
2541 char *l;
2542
2543 l = strstrip(line);
2544 n++;
2545
2546 if (isempty(l))
2547 continue;
2548 if (strchr(COMMENTS, *l))
2549 continue;
2550
2551 parameter = first_word(l, "enable");
2552 if (parameter) {
2553 char *pattern;
2554
2555 pattern = strdup(parameter);
2556 if (!pattern)
2557 return -ENOMEM;
2558
2559 rule = (PresetRule) {
2560 .pattern = pattern,
2561 .action = PRESET_ENABLE,
2562 };
2563 }
2564
2565 parameter = first_word(l, "disable");
2566 if (parameter) {
2567 char *pattern;
2568
2569 pattern = strdup(parameter);
2570 if (!pattern)
2571 return -ENOMEM;
2572
2573 rule = (PresetRule) {
2574 .pattern = pattern,
2575 .action = PRESET_DISABLE,
2576 };
2577 }
2578
2579 if (rule.action) {
2580 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
2581 return -ENOMEM;
2582
2583 ps.rules[ps.n_rules++] = rule;
2584 continue;
2585 }
2586
2587 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
2588 }
2589 }
2590
2591 *presets = ps;
2592 ps = (Presets){};
2593
2594 return 0;
2595}
2596
2597static int query_presets(const char *name, const Presets presets) {
2598 PresetAction action = PRESET_UNKNOWN;
2599 size_t i;
2600
2601 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2602 return -EINVAL;
2603
2604 for (i = 0; i < presets.n_rules; i++)
2605 if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
2606 action = presets.rules[i].action;
2607 break;
2608 }
2609
2610 switch (action) {
2611 case PRESET_UNKNOWN:
2612 log_debug("Preset files don't specify rule for %s. Enabling.", name);
2613 return 1;
2614 case PRESET_ENABLE:
2615 log_debug("Preset files say enable %s.", name);
2616 return 1;
2617 case PRESET_DISABLE:
2618 log_debug("Preset files say disable %s.", name);
2619 return 0;
2620 default:
2621 assert_not_reached("invalid preset action");
2622 }
2623}
2624
2625int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
2626 _cleanup_(presets_freep) Presets presets = {};
2627 int r;
2628
2629 r = read_presets(scope, root_dir, &presets);
2630 if (r < 0)
2631 return r;
2632
2633 return query_presets(name, presets);
2634}
2635
2636static int execute_preset(
2637 UnitFileScope scope,
2638 InstallContext *plus,
2639 InstallContext *minus,
2640 const LookupPaths *paths,
2641 const char *config_path,
2642 char **files,
2643 UnitFilePresetMode mode,
2644 bool force,
2645 UnitFileChange **changes,
2646 unsigned *n_changes) {
2647
2648 int r;
2649
2650 assert(plus);
2651 assert(minus);
2652 assert(paths);
2653 assert(config_path);
2654
2655 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
2656 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2657
2658 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
2659 if (r < 0)
2660 return r;
2661
2662 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes);
2663 } else
2664 r = 0;
2665
2666 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
2667 int q;
2668
2669 /* Returns number of symlinks that where supposed to be installed. */
2670 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
2671 if (r >= 0) {
2672 if (q < 0)
2673 r = q;
2674 else
2675 r += q;
2676 }
2677 }
2678
2679 return r;
2680}
2681
2682static int preset_prepare_one(
2683 UnitFileScope scope,
2684 InstallContext *plus,
2685 InstallContext *minus,
2686 LookupPaths *paths,
2687 const char *name,
2688 Presets presets,
2689 UnitFileChange **changes,
2690 unsigned *n_changes) {
2691
2692 _cleanup_(install_context_done) InstallContext tmp = {};
2693 UnitFileInstallInfo *i;
2694 int r;
2695
2696 if (install_info_find(plus, name) || install_info_find(minus, name))
2697 return 0;
2698
2699 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2700 if (r < 0)
2701 return r;
2702 if (!streq(name, i->name)) {
2703 log_debug("Skipping %s because is an alias for %s", name, i->name);
2704 return 0;
2705 }
2706
2707 r = query_presets(name, presets);
2708 if (r < 0)
2709 return r;
2710
2711 if (r > 0) {
2712 r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2713 if (r < 0)
2714 return r;
2715
2716 r = install_info_may_process(i, paths, changes, n_changes);
2717 if (r < 0)
2718 return r;
2719 } else
2720 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
2721
2722 return r;
2723}
2724
2725int unit_file_preset(
2726 UnitFileScope scope,
2727 bool runtime,
2728 const char *root_dir,
2729 char **files,
2730 UnitFilePresetMode mode,
2731 bool force,
2732 UnitFileChange **changes,
2733 unsigned *n_changes) {
2734
2735 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
2736 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2737 _cleanup_(presets_freep) Presets presets = {};
2738 const char *config_path;
2739 char **i;
2740 int r;
2741
2742 assert(scope >= 0);
2743 assert(scope < _UNIT_FILE_SCOPE_MAX);
2744 assert(mode < _UNIT_FILE_PRESET_MAX);
2745
2746 r = lookup_paths_init(&paths, scope, 0, root_dir);
2747 if (r < 0)
2748 return r;
2749
2750 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2751
2752 r = read_presets(scope, root_dir, &presets);
2753 if (r < 0)
2754 return r;
2755
2756 STRV_FOREACH(i, files) {
2757 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
2758 if (r < 0)
2759 return r;
2760 }
2761
2762 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes);
2763}
2764
2765int unit_file_preset_all(
2766 UnitFileScope scope,
2767 bool runtime,
2768 const char *root_dir,
2769 UnitFilePresetMode mode,
2770 bool force,
2771 UnitFileChange **changes,
2772 unsigned *n_changes) {
2773
2774 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
2775 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2776 _cleanup_(presets_freep) Presets presets = {};
2777 const char *config_path = NULL;
2778 char **i;
2779 int r;
2780
2781 assert(scope >= 0);
2782 assert(scope < _UNIT_FILE_SCOPE_MAX);
2783 assert(mode < _UNIT_FILE_PRESET_MAX);
2784
2785 r = lookup_paths_init(&paths, scope, 0, root_dir);
2786 if (r < 0)
2787 return r;
2788
2789 config_path = runtime ? paths.runtime_config : paths.persistent_config;
2790
2791 r = read_presets(scope, root_dir, &presets);
2792 if (r < 0)
2793 return r;
2794
2795 STRV_FOREACH(i, paths.search_path) {
2796 _cleanup_closedir_ DIR *d = NULL;
2797 struct dirent *de;
2798
2799 d = opendir(*i);
2800 if (!d) {
2801 if (errno == ENOENT)
2802 continue;
2803
2804 return -errno;
2805 }
2806
2807 FOREACH_DIRENT(de, d, return -errno) {
2808
2809 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
2810 continue;
2811
2812 dirent_ensure_type(d, de);
2813
2814 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
2815 continue;
2816
2817 /* we don't pass changes[] in, because we want to handle errors on our own */
2818 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
2819 if (r == -ERFKILL)
2820 r = unit_file_changes_add(changes, n_changes,
2821 UNIT_FILE_IS_MASKED, de->d_name, NULL);
2822 else if (r == -ENOLINK)
2823 r = unit_file_changes_add(changes, n_changes,
2824 UNIT_FILE_IS_DANGLING, de->d_name, NULL);
2825 if (r < 0)
2826 return r;
2827 }
2828 }
2829
2830 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes);
2831}
2832
2833static void unit_file_list_free_one(UnitFileList *f) {
2834 if (!f)
2835 return;
2836
2837 free(f->path);
2838 free(f);
2839}
2840
2841Hashmap* unit_file_list_free(Hashmap *h) {
2842 UnitFileList *i;
2843
2844 while ((i = hashmap_steal_first(h)))
2845 unit_file_list_free_one(i);
2846
2847 return hashmap_free(h);
2848}
2849
2850DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
2851
2852int unit_file_get_list(
2853 UnitFileScope scope,
2854 const char *root_dir,
2855 Hashmap *h,
2856 char **states,
2857 char **patterns) {
2858
2859 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2860 char **i;
2861 int r;
2862
2863 assert(scope >= 0);
2864 assert(scope < _UNIT_FILE_SCOPE_MAX);
2865 assert(h);
2866
2867 r = lookup_paths_init(&paths, scope, 0, root_dir);
2868 if (r < 0)
2869 return r;
2870
2871 STRV_FOREACH(i, paths.search_path) {
2872 _cleanup_closedir_ DIR *d = NULL;
2873 struct dirent *de;
2874
2875 d = opendir(*i);
2876 if (!d) {
2877 if (errno == ENOENT)
2878 continue;
2879 if (IN_SET(errno, ENOTDIR, EACCES)) {
2880 log_debug("Failed to open \"%s\": %m", *i);
2881 continue;
2882 }
2883
2884 return -errno;
2885 }
2886
2887 FOREACH_DIRENT(de, d, return -errno) {
2888 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
2889
2890 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
2891 continue;
2892
2893 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
2894 continue;
2895
2896 if (hashmap_get(h, de->d_name))
2897 continue;
2898
2899 dirent_ensure_type(d, de);
2900
2901 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
2902 continue;
2903
2904 f = new0(UnitFileList, 1);
2905 if (!f)
2906 return -ENOMEM;
2907
2908 f->path = path_make_absolute(de->d_name, *i);
2909 if (!f->path)
2910 return -ENOMEM;
2911
2912 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
2913 if (r < 0)
2914 f->state = UNIT_FILE_BAD;
2915
2916 if (!strv_isempty(states) &&
2917 !strv_contains(states, unit_file_state_to_string(f->state)))
2918 continue;
2919
2920 r = hashmap_put(h, basename(f->path), f);
2921 if (r < 0)
2922 return r;
2923
2924 f = NULL; /* prevent cleanup */
2925 }
2926 }
2927
2928 return 0;
2929}
2930
2931static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2932 [UNIT_FILE_ENABLED] = "enabled",
2933 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
2934 [UNIT_FILE_LINKED] = "linked",
2935 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2936 [UNIT_FILE_MASKED] = "masked",
2937 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2938 [UNIT_FILE_STATIC] = "static",
2939 [UNIT_FILE_DISABLED] = "disabled",
2940 [UNIT_FILE_INDIRECT] = "indirect",
2941 [UNIT_FILE_GENERATED] = "generated",
2942 [UNIT_FILE_TRANSIENT] = "transient",
2943 [UNIT_FILE_BAD] = "bad",
2944};
2945
2946DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
2947
2948static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2949 [UNIT_FILE_SYMLINK] = "symlink",
2950 [UNIT_FILE_UNLINK] = "unlink",
2951 [UNIT_FILE_IS_MASKED] = "masked",
2952 [UNIT_FILE_IS_DANGLING] = "dangling",
2953};
2954
2955DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
2956
2957static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
2958 [UNIT_FILE_PRESET_FULL] = "full",
2959 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
2960 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
2961};
2962
2963DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);