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