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