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