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