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