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