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