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