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