]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
tree-wide: Remove O_CLOEXEC from fdopen
[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
d23aeead 1051 i = new(UnitFileInstallInfo, 1);
83096483
LP
1052 if (!i)
1053 return -ENOMEM;
d23aeead
LP
1054
1055 *i = (UnitFileInstallInfo) {
1056 .type = _UNIT_FILE_TYPE_INVALID,
1057 .auxiliary = auxiliary,
1058 };
83096483
LP
1059
1060 i->name = strdup(name);
1061 if (!i->name) {
1062 r = -ENOMEM;
1063 goto fail;
1064 }
1065
1066 if (path) {
1067 i->path = strdup(path);
1068 if (!i->path) {
1069 r = -ENOMEM;
1070 goto fail;
1071 }
1072 }
1073
0ec0deaa 1074 r = ordered_hashmap_put(c->will_process, i->name, i);
83096483
LP
1075 if (r < 0)
1076 goto fail;
1077
0ec0deaa
LP
1078 if (ret)
1079 *ret = i;
1080
19539807 1081 return 1;
83096483
LP
1082
1083fail:
d25e100b 1084 install_info_free(i);
83096483
LP
1085 return r;
1086}
1087
a7724589
ZJS
1088static int config_parse_alias(
1089 const char *unit,
1090 const char *filename,
1091 unsigned line,
1092 const char *section,
1093 unsigned section_line,
1094 const char *lvalue,
1095 int ltype,
1096 const char *rvalue,
1097 void *data,
1098 void *userdata) {
1099
a7724589
ZJS
1100 UnitType type;
1101
142468d8 1102 assert(unit);
a7724589
ZJS
1103 assert(filename);
1104 assert(lvalue);
1105 assert(rvalue);
1106
142468d8 1107 type = unit_name_to_type(unit);
a7724589
ZJS
1108 if (!unit_type_may_alias(type))
1109 return log_syntax(unit, LOG_WARNING, filename, line, 0,
3b8769bd 1110 "Alias= is not allowed for %s units, ignoring.",
a7724589
ZJS
1111 unit_type_to_string(type));
1112
1113 return config_parse_strv(unit, filename, line, section, section_line,
1114 lvalue, ltype, rvalue, data, userdata);
1115}
1116
d54c4993
LP
1117static int config_parse_also(
1118 const char *unit,
1119 const char *filename,
1120 unsigned line,
1121 const char *section,
1122 unsigned section_line,
1123 const char *lvalue,
1124 int ltype,
1125 const char *rvalue,
1126 void *data,
1127 void *userdata) {
83096483 1128
19539807 1129 UnitFileInstallInfo *info = userdata, *alsoinfo = NULL;
0ec0deaa
LP
1130 InstallContext *c = data;
1131 int r;
83096483 1132
142468d8 1133 assert(unit);
83096483
LP
1134 assert(filename);
1135 assert(lvalue);
1136 assert(rvalue);
1137
0ec0deaa 1138 for (;;) {
a6612e65 1139 _cleanup_free_ char *word = NULL, *printed = NULL;
03da6513 1140
0ec0deaa
LP
1141 r = extract_first_word(&rvalue, &word, NULL, 0);
1142 if (r < 0)
1143 return r;
03da6513
SS
1144 if (r == 0)
1145 break;
83096483 1146
a6612e65 1147 r = install_full_printf(info, word, &printed);
d9e5e694 1148 if (r < 0)
83096483 1149 return r;
aedd4012 1150
a6612e65
ZJS
1151 if (!unit_name_is_valid(printed, UNIT_NAME_ANY))
1152 return -EINVAL;
1153
1154 r = install_info_add(c, printed, NULL, true, &alsoinfo);
d9e5e694 1155 if (r < 0)
83096483 1156 return r;
aedd4012 1157
a6612e65 1158 r = strv_push(&info->also, printed);
aedd4012
JS
1159 if (r < 0)
1160 return r;
0ec0deaa 1161
a6612e65 1162 printed = NULL;
83096483
LP
1163 }
1164
1165 return 0;
1166}
1167
d54c4993
LP
1168static int config_parse_default_instance(
1169 const char *unit,
1170 const char *filename,
1171 unsigned line,
1172 const char *section,
1173 unsigned section_line,
1174 const char *lvalue,
1175 int ltype,
1176 const char *rvalue,
1177 void *data,
1178 void *userdata) {
1179
cab6235f 1180 UnitFileInstallInfo *i = data;
d7604756 1181 _cleanup_free_ char *printed = NULL;
d54c4993
LP
1182 int r;
1183
142468d8 1184 assert(unit);
d54c4993
LP
1185 assert(filename);
1186 assert(lvalue);
1187 assert(rvalue);
1188
142468d8 1189 if (unit_name_is_valid(unit, UNIT_NAME_INSTANCE))
6597fa61
ZJS
1190 /* When enabling an instance, we might be using a template unit file,
1191 * but we should ignore DefaultInstance silently. */
1192 return 0;
142468d8 1193 if (!unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
6597fa61 1194 return log_syntax(unit, LOG_WARNING, filename, line, 0,
10d67460 1195 "DefaultInstance= only makes sense for template units, ignoring.");
6597fa61 1196
d54c4993
LP
1197 r = install_full_printf(i, rvalue, &printed);
1198 if (r < 0)
1199 return r;
1200
d7604756 1201 if (!unit_instance_is_valid(printed))
d54c4993
LP
1202 return -EINVAL;
1203
3b319885 1204 return free_and_replace(i->default_instance, printed);
d54c4993
LP
1205}
1206
83096483
LP
1207static int unit_file_load(
1208 InstallContext *c,
cab6235f 1209 UnitFileInstallInfo *info,
83096483 1210 const char *path,
d04a9386 1211 const char *root_dir,
0ec0deaa 1212 SearchFlags flags) {
83096483 1213
f975e971 1214 const ConfigTableItem items[] = {
a7724589 1215 { "Install", "Alias", config_parse_alias, 0, &info->aliases },
d54c4993
LP
1216 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1217 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1218 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
1219 { "Install", "Also", config_parse_also, 0, c },
d54c4993 1220 {}
83096483
LP
1221 };
1222
133e5b36 1223 UnitType type;
7fd1b19b 1224 _cleanup_fclose_ FILE *f = NULL;
0ec0deaa
LP
1225 _cleanup_close_ int fd = -1;
1226 struct stat st;
1227 int r;
83096483 1228
83096483
LP
1229 assert(info);
1230 assert(path);
1231
d04a9386
LP
1232 if (!(flags & SEARCH_DROPIN)) {
1233 /* Loading or checking for the main unit file… */
133e5b36 1234
d04a9386
LP
1235 type = unit_name_to_type(info->name);
1236 if (type < 0)
1237 return -EINVAL;
baaa35ad
ZJS
1238 if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) && !unit_type_may_template(type))
1239 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1240 "Unit type %s cannot be templated.", unit_type_to_string(type));
d04a9386
LP
1241
1242 if (!(flags & SEARCH_LOAD)) {
1243 r = lstat(path, &st);
1244 if (r < 0)
1245 return -errno;
1246
1247 if (null_or_empty(&st))
1248 info->type = UNIT_FILE_TYPE_MASKED;
1249 else if (S_ISREG(st.st_mode))
1250 info->type = UNIT_FILE_TYPE_REGULAR;
1251 else if (S_ISLNK(st.st_mode))
1252 return -ELOOP;
1253 else if (S_ISDIR(st.st_mode))
1254 return -EISDIR;
1255 else
1256 return -ENOTTY;
1257
1258 return 0;
1259 }
1260
1261 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
1262 if (fd < 0)
d25e100b 1263 return -errno;
d04a9386
LP
1264 } else {
1265 /* Operating on a drop-in file. If we aren't supposed to load the unit file drop-ins don't matter, let's hence shortcut this. */
d25e100b 1266
d04a9386
LP
1267 if (!(flags & SEARCH_LOAD))
1268 return 0;
0ec0deaa 1269
d04a9386
LP
1270 fd = chase_symlinks_and_open(path, root_dir, 0, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
1271 if (fd < 0)
1272 return fd;
e94937df
LN
1273 }
1274
0ec0deaa
LP
1275 if (fstat(fd, &st) < 0)
1276 return -errno;
d04a9386 1277
0ec0deaa 1278 if (null_or_empty(&st)) {
d04a9386
LP
1279 if ((flags & SEARCH_DROPIN) == 0)
1280 info->type = UNIT_FILE_TYPE_MASKED;
1281
0ec0deaa
LP
1282 return 0;
1283 }
3cc44114
LP
1284
1285 r = stat_verify_regular(&st);
1286 if (r < 0)
1287 return r;
83096483 1288
e92aaed3 1289 f = fdopen(fd, "r");
0ec0deaa
LP
1290 if (!f)
1291 return -errno;
1292 fd = -1;
83096483 1293
d04a9386
LP
1294 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1295 assert(c);
1296
142468d8 1297 r = config_parse(info->name, path, f,
36f822c4
ZJS
1298 NULL,
1299 config_item_table_lookup, items,
bcde742e 1300 CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
83096483 1301 if (r < 0)
59108fbe 1302 return log_debug_errno(r, "Failed to parse %s: %m", info->name);
83096483 1303
d04a9386
LP
1304 if ((flags & SEARCH_DROPIN) == 0)
1305 info->type = UNIT_FILE_TYPE_REGULAR;
aedd4012 1306
78d54bd4 1307 return
693eb9a2
LP
1308 (int) strv_length(info->aliases) +
1309 (int) strv_length(info->wanted_by) +
1310 (int) strv_length(info->required_by);
83096483
LP
1311}
1312
0ec0deaa
LP
1313static int unit_file_load_or_readlink(
1314 InstallContext *c,
1315 UnitFileInstallInfo *info,
1316 const char *path,
1317 const char *root_dir,
1318 SearchFlags flags) {
1319
401017e0 1320 _cleanup_free_ char *target = NULL;
0ec0deaa
LP
1321 int r;
1322
d04a9386
LP
1323 r = unit_file_load(c, info, path, root_dir, flags);
1324 if (r != -ELOOP || (flags & SEARCH_DROPIN))
0ec0deaa
LP
1325 return r;
1326
1327 /* This is a symlink, let's read it. */
1328
401017e0 1329 r = readlink_malloc(path, &target);
0ec0deaa
LP
1330 if (r < 0)
1331 return r;
1332
401017e0 1333 if (path_equal(target, "/dev/null"))
0ec0deaa
LP
1334 info->type = UNIT_FILE_TYPE_MASKED;
1335 else {
1336 const char *bn;
1337 UnitType a, b;
1338
401017e0 1339 bn = basename(target);
0ec0deaa
LP
1340
1341 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1342
1343 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1344 return -EINVAL;
1345
1346 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1347
1348 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1349 return -EINVAL;
1350
1351 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1352
1353 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1354 return -EINVAL;
1355 } else
1356 return -EINVAL;
1357
1358 /* Enforce that the symlink destination does not
1359 * change the unit file type. */
1360
1361 a = unit_name_to_type(info->name);
1362 b = unit_name_to_type(bn);
1363 if (a < 0 || b < 0 || a != b)
1364 return -EINVAL;
1365
401017e0
LP
1366 if (path_is_absolute(target))
1367 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1368 info->symlink_target = prefix_root(root_dir, target);
1369 else
1370 /* This is a relative path, take it relative to the dir the symlink is located in. */
1371 info->symlink_target = file_in_same_dir(path, target);
1372 if (!info->symlink_target)
1373 return -ENOMEM;
1374
0ec0deaa 1375 info->type = UNIT_FILE_TYPE_SYMLINK;
0ec0deaa
LP
1376 }
1377
1378 return 0;
1379}
1380
83096483
LP
1381static int unit_file_search(
1382 InstallContext *c,
cab6235f 1383 UnitFileInstallInfo *info,
a8ffe6fb 1384 const LookupPaths *paths,
0ec0deaa 1385 SearchFlags flags) {
83096483 1386
d04a9386
LP
1387 const char *dropin_dir_name = NULL, *dropin_template_dir_name = NULL;
1388 _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
64f9280e 1389 _cleanup_free_ char *template = NULL;
142468d8 1390 bool found_unit = false;
d04a9386
LP
1391 int r, result;
1392 char **p;
83096483 1393
83096483
LP
1394 assert(info);
1395 assert(paths);
1396
0ec0deaa
LP
1397 /* Was this unit already loaded? */
1398 if (info->type != _UNIT_FILE_TYPE_INVALID)
1399 return 0;
1400
278fa575 1401 if (info->path)
e4bb56c7 1402 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
83096483
LP
1403
1404 assert(info->name);
1405
142468d8
JL
1406 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1407 r = unit_name_template(info->name, &template);
1408 if (r < 0)
1409 return r;
1410 }
1411
a3c4eb07 1412 STRV_FOREACH(p, paths->search_path) {
e50bd775 1413 _cleanup_free_ char *path = NULL;
83096483 1414
605405c6 1415 path = strjoin(*p, "/", info->name);
83096483
LP
1416 if (!path)
1417 return -ENOMEM;
1418
e4bb56c7 1419 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
0155928c 1420 if (r >= 0) {
ae2a15bc 1421 info->path = TAKE_PTR(path);
142468d8
JL
1422 result = r;
1423 found_unit = true;
1424 break;
a1feacf7 1425 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
0155928c 1426 return r;
e50bd775 1427 }
62b00233 1428
142468d8
JL
1429 if (!found_unit && template) {
1430
e50bd775
LP
1431 /* Unit file doesn't exist, however instance
1432 * enablement was requested. We will check if it is
1433 * possible to load template unit file. */
29283ea4 1434
a3c4eb07 1435 STRV_FOREACH(p, paths->search_path) {
e50bd775
LP
1436 _cleanup_free_ char *path = NULL;
1437
605405c6 1438 path = strjoin(*p, "/", template);
62b00233
ZJS
1439 if (!path)
1440 return -ENOMEM;
29283ea4 1441
e4bb56c7 1442 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
0155928c 1443 if (r >= 0) {
ae2a15bc 1444 info->path = TAKE_PTR(path);
142468d8
JL
1445 result = r;
1446 found_unit = true;
1447 break;
a1feacf7 1448 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
0155928c 1449 return r;
29283ea4 1450 }
83096483
LP
1451 }
1452
baaa35ad
ZJS
1453 if (!found_unit)
1454 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
1455 "Cannot find unit %s%s%s.",
1456 info->name, template ? " or " : "", strempty(template));
142468d8 1457
9639b175
FB
1458 if (info->type == UNIT_FILE_TYPE_MASKED)
1459 return result;
1460
142468d8
JL
1461 /* Search for drop-in directories */
1462
1463 dropin_dir_name = strjoina(info->name, ".d");
1464 STRV_FOREACH(p, paths->search_path) {
1465 char *path;
1466
62a85ee0 1467 path = path_join(*p, dropin_dir_name);
142468d8
JL
1468 if (!path)
1469 return -ENOMEM;
1470
1471 r = strv_consume(&dirs, path);
1472 if (r < 0)
1473 return r;
1474 }
1475
1476 if (template) {
1477 dropin_template_dir_name = strjoina(template, ".d");
1478 STRV_FOREACH(p, paths->search_path) {
1479 char *path;
1480
62a85ee0 1481 path = path_join(*p, dropin_template_dir_name);
142468d8
JL
1482 if (!path)
1483 return -ENOMEM;
1484
1485 r = strv_consume(&dirs, path);
1486 if (r < 0)
1487 return r;
1488 }
1489 }
1490
1491 /* Load drop-in conf files */
1492
1493 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) dirs);
1494 if (r < 0)
1495 return log_debug_errno(r, "Failed to get list of conf files: %m");
1496
1497 STRV_FOREACH(p, files) {
d04a9386 1498 r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags | SEARCH_DROPIN);
142468d8
JL
1499 if (r < 0)
1500 return log_debug_errno(r, "Failed to load conf file %s: %m", *p);
1501 }
1502
1503 return result;
83096483
LP
1504}
1505
0ec0deaa
LP
1506static int install_info_follow(
1507 InstallContext *c,
1508 UnitFileInstallInfo *i,
83096483 1509 const char *root_dir,
9f6cbcf5
LP
1510 SearchFlags flags,
1511 bool ignore_different_name) {
0ec0deaa
LP
1512
1513 assert(c);
1514 assert(i);
1515
1516 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1517 return -EINVAL;
1518 if (!i->symlink_target)
1519 return -EINVAL;
1520
1521 /* If the basename doesn't match, the caller should add a
1522 * complete new entry for this. */
1523
9f6cbcf5 1524 if (!ignore_different_name && !streq(basename(i->symlink_target), i->name))
0ec0deaa
LP
1525 return -EXDEV;
1526
3b319885 1527 free_and_replace(i->path, i->symlink_target);
0ec0deaa
LP
1528 i->type = _UNIT_FILE_TYPE_INVALID;
1529
1530 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1531}
1532
64f9280e 1533/**
ff56349d
ZJS
1534 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1535 * target, maybe more than once. Propagate the instance name if present.
64f9280e 1536 */
0ec0deaa
LP
1537static int install_info_traverse(
1538 UnitFileScope scope,
1539 InstallContext *c,
0ec0deaa
LP
1540 const LookupPaths *paths,
1541 UnitFileInstallInfo *start,
1542 SearchFlags flags,
1543 UnitFileInstallInfo **ret) {
83096483 1544
cab6235f 1545 UnitFileInstallInfo *i;
0ec0deaa 1546 unsigned k = 0;
83096483
LP
1547 int r;
1548
1549 assert(paths);
0ec0deaa
LP
1550 assert(start);
1551 assert(c);
83096483 1552
e4bb56c7 1553 r = unit_file_search(c, start, paths, flags);
83096483
LP
1554 if (r < 0)
1555 return r;
1556
0ec0deaa
LP
1557 i = start;
1558 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1559 /* Follow the symlink */
83096483 1560
0ec0deaa
LP
1561 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
1562 return -ELOOP;
83096483 1563
e1c5c2b0 1564 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
dfead90d 1565 r = path_is_config(paths, i->path, true);
e1c5c2b0
LP
1566 if (r < 0)
1567 return r;
1568 if (r > 0)
1569 return -ELOOP;
1570 }
83096483 1571
9f6cbcf5 1572 r = install_info_follow(c, i, paths->root_dir, flags, false);
0155928c 1573 if (r == -EXDEV) {
0ec0deaa
LP
1574 _cleanup_free_ char *buffer = NULL;
1575 const char *bn;
83096483 1576
0ec0deaa
LP
1577 /* Target has a different name, create a new
1578 * install info object for that, and continue
1579 * with that. */
83096483 1580
0ec0deaa 1581 bn = basename(i->symlink_target);
83096483 1582
0ec0deaa
LP
1583 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1584 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
83096483 1585
0ec0deaa
LP
1586 _cleanup_free_ char *instance = NULL;
1587
1588 r = unit_name_to_instance(i->name, &instance);
1589 if (r < 0)
1590 return r;
1591
1592 r = unit_name_replace_instance(bn, instance, &buffer);
1593 if (r < 0)
1594 return r;
1595
9f6cbcf5
LP
1596 if (streq(buffer, i->name)) {
1597
1598 /* We filled in the instance, and the target stayed the same? If so, then let's
1599 * honour the link as it is. */
1600
1601 r = install_info_follow(c, i, paths->root_dir, flags, true);
1602 if (r < 0)
1603 return r;
1604
1605 continue;
1606 }
1607
0ec0deaa
LP
1608 bn = buffer;
1609 }
1610
19539807 1611 r = install_info_add(c, bn, NULL, false, &i);
0ec0deaa
LP
1612 if (r < 0)
1613 return r;
1614
0155928c 1615 /* Try again, with the new target we found. */
e4bb56c7 1616 r = unit_file_search(c, i, paths, flags);
893275df
ZJS
1617 if (r == -ENOENT)
1618 /* Translate error code to highlight this specific case */
1619 return -ENOLINK;
0ec0deaa
LP
1620 }
1621
0155928c
ZJS
1622 if (r < 0)
1623 return r;
83096483
LP
1624 }
1625
0ec0deaa
LP
1626 if (ret)
1627 *ret = i;
83096483 1628
0ec0deaa
LP
1629 return 0;
1630}
83096483 1631
ff56349d
ZJS
1632/**
1633 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1634 * or the name (otherwise). root_dir is prepended to the path.
1635 */
401017e0
LP
1636static int install_info_add_auto(
1637 InstallContext *c,
1638 const LookupPaths *paths,
1639 const char *name_or_path,
1640 UnitFileInstallInfo **ret) {
1641
1642 assert(c);
1643 assert(name_or_path);
1644
1645 if (path_is_absolute(name_or_path)) {
1646 const char *pp;
1647
1648 pp = prefix_roota(paths->root_dir, name_or_path);
1649
19539807 1650 return install_info_add(c, NULL, pp, false, ret);
401017e0 1651 } else
19539807 1652 return install_info_add(c, name_or_path, NULL, false, ret);
401017e0
LP
1653}
1654
0ec0deaa
LP
1655static int install_info_discover(
1656 UnitFileScope scope,
1657 InstallContext *c,
0ec0deaa
LP
1658 const LookupPaths *paths,
1659 const char *name,
1660 SearchFlags flags,
59108fbe
ZJS
1661 UnitFileInstallInfo **ret,
1662 UnitFileChange **changes,
da6053d0 1663 size_t *n_changes) {
83096483 1664
0ec0deaa
LP
1665 UnitFileInstallInfo *i;
1666 int r;
83096483 1667
0ec0deaa
LP
1668 assert(c);
1669 assert(paths);
1670 assert(name);
1671
401017e0 1672 r = install_info_add_auto(c, paths, name, &i);
59108fbe
ZJS
1673 if (r >= 0)
1674 r = install_info_traverse(scope, c, paths, i, flags, ret);
83096483 1675
59108fbe
ZJS
1676 if (r < 0)
1677 unit_file_changes_add(changes, n_changes, r, name, NULL);
1678 return r;
83096483
LP
1679}
1680
1e475a0a
RB
1681static int install_info_discover_and_check(
1682 UnitFileScope scope,
1683 InstallContext *c,
1684 const LookupPaths *paths,
1685 const char *name,
1686 SearchFlags flags,
1687 UnitFileInstallInfo **ret,
1688 UnitFileChange **changes,
1689 size_t *n_changes) {
1690
1691 int r;
1692
1693 r = install_info_discover(scope, c, paths, name, flags, ret, changes, n_changes);
1694 if (r < 0)
1695 return r;
1696
1697 return install_info_may_process(ret ? *ret : NULL, paths, changes, n_changes);
1698}
1699
83096483 1700static int install_info_symlink_alias(
cab6235f 1701 UnitFileInstallInfo *i,
401017e0 1702 const LookupPaths *paths,
83096483
LP
1703 const char *config_path,
1704 bool force,
1705 UnitFileChange **changes,
da6053d0 1706 size_t *n_changes) {
83096483
LP
1707
1708 char **s;
1709 int r = 0, q;
1710
1711 assert(i);
401017e0 1712 assert(paths);
83096483
LP
1713 assert(config_path);
1714
1715 STRV_FOREACH(s, i->aliases) {
7fd1b19b 1716 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
83096483 1717
19f6d710
LP
1718 q = install_full_printf(i, *s, &dst);
1719 if (q < 0)
1720 return q;
83096483 1721
7584d236 1722 alias_path = path_make_absolute(dst, config_path);
83096483
LP
1723 if (!alias_path)
1724 return -ENOMEM;
1725
60bec8e4 1726 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
83096483
LP
1727 if (r == 0)
1728 r = q;
1729 }
1730
1731 return r;
1732}
1733
1734static int install_info_symlink_wants(
cab6235f 1735 UnitFileInstallInfo *i,
401017e0 1736 const LookupPaths *paths,
83096483 1737 const char *config_path,
d54c4993
LP
1738 char **list,
1739 const char *suffix,
83096483 1740 UnitFileChange **changes,
da6053d0 1741 size_t *n_changes) {
83096483 1742
d54c4993
LP
1743 _cleanup_free_ char *buf = NULL;
1744 const char *n;
83096483
LP
1745 char **s;
1746 int r = 0, q;
1747
1748 assert(i);
401017e0 1749 assert(paths);
83096483
LP
1750 assert(config_path);
1751
047d91f9
ZJS
1752 if (strv_isempty(list))
1753 return 0;
1754
e4086ae0 1755 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
047d91f9
ZJS
1756 UnitFileInstallInfo instance = {
1757 .type = _UNIT_FILE_TYPE_INVALID,
1758 };
1759 _cleanup_free_ char *path = NULL;
0a327d75 1760
e4086ae0
LP
1761 /* If this is a template, and we have no instance, don't do anything */
1762 if (!i->default_instance)
1763 return 1;
1764
7410616c
LP
1765 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1766 if (r < 0)
1767 return r;
83096483 1768
047d91f9
ZJS
1769 instance.name = buf;
1770 r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
1771 if (r < 0)
1772 return r;
1773
ae2a15bc 1774 path = TAKE_PTR(instance.path);
047d91f9
ZJS
1775
1776 if (instance.type == UNIT_FILE_TYPE_MASKED) {
1777 unit_file_changes_add(changes, n_changes, -ERFKILL, path, NULL);
1778 return -ERFKILL;
1779 }
1780
d54c4993
LP
1781 n = buf;
1782 } else
1783 n = i->name;
78d54bd4 1784
d54c4993 1785 STRV_FOREACH(s, list) {
7fd1b19b 1786 _cleanup_free_ char *path = NULL, *dst = NULL;
78d54bd4 1787
19f6d710
LP
1788 q = install_full_printf(i, *s, &dst);
1789 if (q < 0)
1790 return q;
7584d236 1791
7410616c 1792 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
78d54bd4
LP
1793 r = -EINVAL;
1794 continue;
1795 }
1796
605405c6 1797 path = strjoin(config_path, "/", dst, suffix, n);
d54c4993 1798 if (!path)
78d54bd4
LP
1799 return -ENOMEM;
1800
60bec8e4 1801 q = create_symlink(paths, i->path, path, true, changes, n_changes);
78d54bd4
LP
1802 if (r == 0)
1803 r = q;
1804 }
1805
1806 return r;
1807}
1808
83096483 1809static int install_info_symlink_link(
cab6235f 1810 UnitFileInstallInfo *i,
a8ffe6fb 1811 const LookupPaths *paths,
83096483
LP
1812 const char *config_path,
1813 bool force,
1814 UnitFileChange **changes,
da6053d0 1815 size_t *n_changes) {
83096483 1816
7fd1b19b 1817 _cleanup_free_ char *path = NULL;
1dacfd2a 1818 int r;
83096483
LP
1819
1820 assert(i);
1821 assert(paths);
1822 assert(config_path);
1823 assert(i->path);
1824
32c0ed7b 1825 r = in_search_path(paths, i->path);
fe4aede9 1826 if (r < 0)
83096483 1827 return r;
fe4aede9
ZJS
1828 if (r > 0)
1829 return 0;
83096483 1830
605405c6 1831 path = strjoin(config_path, "/", i->name);
1dacfd2a 1832 if (!path)
83096483
LP
1833 return -ENOMEM;
1834
60bec8e4 1835 return create_symlink(paths, i->path, path, force, changes, n_changes);
83096483
LP
1836}
1837
1838static int install_info_apply(
cab6235f 1839 UnitFileInstallInfo *i,
a8ffe6fb 1840 const LookupPaths *paths,
83096483
LP
1841 const char *config_path,
1842 bool force,
1843 UnitFileChange **changes,
da6053d0 1844 size_t *n_changes) {
83096483
LP
1845
1846 int r, q;
1847
1848 assert(i);
1849 assert(paths);
1850 assert(config_path);
1851
0ec0deaa
LP
1852 if (i->type != UNIT_FILE_TYPE_REGULAR)
1853 return 0;
1854
401017e0 1855 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
83096483 1856
29380daf 1857 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
83096483
LP
1858 if (r == 0)
1859 r = q;
1860
29380daf 1861 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
78d54bd4
LP
1862 if (r == 0)
1863 r = q;
1864
e4bb56c7 1865 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
fe4aede9
ZJS
1866 /* Do not count links to the unit file towards the "carries_install_info" count */
1867 if (r == 0 && q < 0)
83096483
LP
1868 r = q;
1869
1870 return r;
1871}
1872
1873static int install_context_apply(
0ec0deaa 1874 UnitFileScope scope,
83096483 1875 InstallContext *c,
a8ffe6fb 1876 const LookupPaths *paths,
83096483 1877 const char *config_path,
83096483 1878 bool force,
0ec0deaa 1879 SearchFlags flags,
83096483 1880 UnitFileChange **changes,
da6053d0 1881 size_t *n_changes) {
83096483 1882
cab6235f 1883 UnitFileInstallInfo *i;
0ec0deaa 1884 int r;
83096483
LP
1885
1886 assert(c);
1887 assert(paths);
1888 assert(config_path);
1889
0ec0deaa 1890 if (ordered_hashmap_isempty(c->will_process))
d25e100b 1891 return 0;
83096483 1892
0ec0deaa 1893 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
d25e100b
LP
1894 if (r < 0)
1895 return r;
83096483 1896
2d5c93c7 1897 r = 0;
0ec0deaa
LP
1898 while ((i = ordered_hashmap_first(c->will_process))) {
1899 int q;
83096483 1900
0ec0deaa
LP
1901 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1902 if (q < 0)
1903 return q;
83096483 1904
459500a3
ZJS
1905 q = install_info_traverse(scope, c, paths, i, flags, NULL);
1906 if (q < 0) {
db093eed 1907 unit_file_changes_add(changes, n_changes, r, i->name, NULL);
459500a3 1908 return q;
db093eed 1909 }
0ec0deaa 1910
f1651715 1911 /* We can attempt to process a masked unit when a different unit
047d91f9 1912 * that we were processing specifies it in Also=. */
f1651715
ZJS
1913 if (i->type == UNIT_FILE_TYPE_MASKED) {
1914 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL);
1915 if (r >= 0)
047d91f9
ZJS
1916 /* Assume that something *could* have been enabled here,
1917 * avoid "empty [Install] section" warning. */
f1651715
ZJS
1918 r += 1;
1919 continue;
1920 }
1921
0ec0deaa
LP
1922 if (i->type != UNIT_FILE_TYPE_REGULAR)
1923 continue;
83096483 1924
e4bb56c7 1925 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
0ec0deaa
LP
1926 if (r >= 0) {
1927 if (q < 0)
1928 r = q;
1929 else
596fc263 1930 r += q;
0ec0deaa 1931 }
83096483
LP
1932 }
1933
1934 return r;
1935}
1936
1937static int install_context_mark_for_removal(
0ec0deaa 1938 UnitFileScope scope,
83096483 1939 InstallContext *c,
a8ffe6fb 1940 const LookupPaths *paths,
83096483 1941 Set **remove_symlinks_to,
1830ac51 1942 const char *config_path,
637d6e5b 1943 UnitFileChange **changes,
da6053d0 1944 size_t *n_changes) {
83096483 1945
cab6235f 1946 UnitFileInstallInfo *i;
0ec0deaa 1947 int r;
83096483
LP
1948
1949 assert(c);
1950 assert(paths);
1830ac51 1951 assert(config_path);
83096483
LP
1952
1953 /* Marks all items for removal */
1954
0ec0deaa 1955 if (ordered_hashmap_isempty(c->will_process))
d25e100b 1956 return 0;
83096483 1957
0ec0deaa 1958 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
d25e100b
LP
1959 if (r < 0)
1960 return r;
83096483 1961
0ec0deaa 1962 while ((i = ordered_hashmap_first(c->will_process))) {
83096483 1963
0ec0deaa
LP
1964 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1965 if (r < 0)
83096483 1966 return r;
29283ea4 1967
e4bb56c7 1968 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
19539807 1969 if (r == -ENOLINK) {
637d6e5b
LP
1970 log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name);
1971 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL);
1972 } else if (r == -ENOENT) {
1973
1974 if (i->auxiliary) /* some unit specified in Also= or similar is missing */
1975 log_debug_errno(r, "Auxiliary unit of %s not found, removing name.", i->name);
1976 else {
1977 log_debug_errno(r, "Unit %s not found, removing name.", i->name);
1978 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
1979 }
0ec0deaa 1980
637d6e5b
LP
1981 } else if (r < 0) {
1982 log_debug_errno(r, "Failed to find unit %s, removing name: %m", i->name);
1983 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
1984 } else if (i->type == UNIT_FILE_TYPE_MASKED) {
1985 log_debug("Unit file %s is masked, ignoring.", i->name);
1986 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path ?: i->name, NULL);
1987 continue;
1988 } else if (i->type != UNIT_FILE_TYPE_REGULAR) {
1989 log_debug("Unit %s has type %s, ignoring.", i->name, unit_file_type_to_string(i->type) ?: "invalid");
0ec0deaa 1990 continue;
64f9280e 1991 }
0ec0deaa
LP
1992
1993 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1994 if (r < 0)
1995 return r;
1996 }
1997
1998 return 0;
1999}
2000
2001int unit_file_mask(
2002 UnitFileScope scope,
b3796dd8 2003 UnitFileFlags flags,
0ec0deaa
LP
2004 const char *root_dir,
2005 char **files,
0ec0deaa 2006 UnitFileChange **changes,
da6053d0 2007 size_t *n_changes) {
0ec0deaa 2008
8e766630 2009 _cleanup_(lookup_paths_free) LookupPaths paths = {};
e1c5c2b0 2010 const char *config_path;
0ec0deaa
LP
2011 char **i;
2012 int r;
2013
2014 assert(scope >= 0);
2015 assert(scope < _UNIT_FILE_SCOPE_MAX);
2016
4943d143 2017 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2018 if (r < 0)
2019 return r;
2020
b3796dd8 2021 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2022 if (!config_path)
2023 return -ENXIO;
e1c5c2b0 2024
0ec0deaa
LP
2025 STRV_FOREACH(i, files) {
2026 _cleanup_free_ char *path = NULL;
2027 int q;
2028
2029 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
2030 if (r == 0)
2031 r = -EINVAL;
2032 continue;
2033 }
2034
e1c5c2b0 2035 path = path_make_absolute(*i, config_path);
0ec0deaa
LP
2036 if (!path)
2037 return -ENOMEM;
29283ea4 2038
b3796dd8 2039 q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
0ec0deaa 2040 if (q < 0 && r >= 0)
83096483
LP
2041 r = q;
2042 }
2043
2044 return r;
2045}
2046
0ec0deaa
LP
2047int unit_file_unmask(
2048 UnitFileScope scope,
b3796dd8 2049 UnitFileFlags flags,
0ec0deaa
LP
2050 const char *root_dir,
2051 char **files,
2052 UnitFileChange **changes,
da6053d0 2053 size_t *n_changes) {
0ec0deaa 2054
8e766630 2055 _cleanup_(lookup_paths_free) LookupPaths paths = {};
0ec0deaa 2056 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
dc7dd61d 2057 _cleanup_strv_free_ char **todo = NULL;
0ec0deaa 2058 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 2059 const char *config_path;
0ec0deaa 2060 char **i;
1830ac51 2061 bool dry_run;
0ec0deaa
LP
2062 int r, q;
2063
2064 assert(scope >= 0);
2065 assert(scope < _UNIT_FILE_SCOPE_MAX);
2066
4943d143 2067 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2068 if (r < 0)
2069 return r;
2070
1830ac51
MB
2071 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2072 if (!config_path)
2073 return -ENXIO;
2074
2075 dry_run = !!(flags & UNIT_FILE_DRY_RUN);
2076
0ec0deaa 2077 STRV_FOREACH(i, files) {
1830ac51
MB
2078 _cleanup_free_ char *path = NULL;
2079
0ec0deaa
LP
2080 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2081 return -EINVAL;
2082
1830ac51
MB
2083 path = path_make_absolute(*i, config_path);
2084 if (!path)
2085 return -ENOMEM;
0ec0deaa 2086
1830ac51
MB
2087 r = null_or_empty_path(path);
2088 if (r == -ENOENT)
2089 continue;
2090 if (r < 0)
2091 return r;
2092 if (r == 0)
2093 continue;
0ec0deaa 2094
1830ac51
MB
2095 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2096 return -ENOMEM;
d054eae6 2097
1830ac51
MB
2098 todo[n_todo] = strdup(*i);
2099 if (!todo[n_todo])
2100 return -ENOMEM;
4910b350 2101
1830ac51 2102 n_todo++;
0ec0deaa
LP
2103 }
2104
2105 strv_uniq(todo);
2106
2107 r = 0;
1830ac51
MB
2108 STRV_FOREACH(i, todo) {
2109 _cleanup_free_ char *path = NULL;
2110 const char *rp;
0ec0deaa 2111
1830ac51
MB
2112 path = path_make_absolute(*i, config_path);
2113 if (!path)
2114 return -ENOMEM;
4910b350 2115
1830ac51
MB
2116 if (!dry_run && unlink(path) < 0) {
2117 if (errno != ENOENT) {
2118 if (r >= 0)
2119 r = -errno;
2120 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
af3d8113 2121 }
0ec0deaa 2122
1830ac51 2123 continue;
4910b350 2124 }
401017e0 2125
1830ac51
MB
2126 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
2127
2128 rp = skip_root(&paths, path);
2129 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
2130 if (q < 0)
2131 return q;
0ec0deaa
LP
2132 }
2133
1830ac51
MB
2134 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
2135 if (r >= 0)
2136 r = q;
2137
0ec0deaa
LP
2138 return r;
2139}
2140
2141int unit_file_link(
e94937df 2142 UnitFileScope scope,
b3796dd8 2143 UnitFileFlags flags,
e94937df
LN
2144 const char *root_dir,
2145 char **files,
e94937df 2146 UnitFileChange **changes,
da6053d0 2147 size_t *n_changes) {
e94937df 2148
8e766630 2149 _cleanup_(lookup_paths_free) LookupPaths paths = {};
8af35ba6 2150 _cleanup_strv_free_ char **todo = NULL;
0ec0deaa 2151 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 2152 const char *config_path;
e94937df 2153 char **i;
0ec0deaa 2154 int r, q;
e94937df
LN
2155
2156 assert(scope >= 0);
2157 assert(scope < _UNIT_FILE_SCOPE_MAX);
2158
4943d143 2159 r = lookup_paths_init(&paths, scope, 0, root_dir);
e94937df
LN
2160 if (r < 0)
2161 return r;
2162
b3796dd8 2163 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2164 if (!config_path)
2165 return -ENXIO;
e94937df
LN
2166
2167 STRV_FOREACH(i, files) {
0ec0deaa
LP
2168 _cleanup_free_ char *full = NULL;
2169 struct stat st;
2170 char *fn;
e94937df 2171
0ec0deaa
LP
2172 if (!path_is_absolute(*i))
2173 return -EINVAL;
e94937df 2174
0ec0deaa
LP
2175 fn = basename(*i);
2176 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
2177 return -EINVAL;
2178
e4bb56c7 2179 full = prefix_root(paths.root_dir, *i);
0ec0deaa
LP
2180 if (!full)
2181 return -ENOMEM;
2182
2183 if (lstat(full, &st) < 0)
2184 return -errno;
3cc44114
LP
2185 r = stat_verify_regular(&st);
2186 if (r < 0)
2187 return r;
0ec0deaa 2188
32c0ed7b 2189 q = in_search_path(&paths, *i);
0ec0deaa
LP
2190 if (q < 0)
2191 return q;
2192 if (q > 0)
2193 continue;
2194
2195 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2196 return -ENOMEM;
2197
8af35ba6
EV
2198 todo[n_todo] = strdup(*i);
2199 if (!todo[n_todo])
2200 return -ENOMEM;
2201
2202 n_todo++;
e94937df
LN
2203 }
2204
0ec0deaa 2205 strv_uniq(todo);
e94937df 2206
0ec0deaa
LP
2207 r = 0;
2208 STRV_FOREACH(i, todo) {
401017e0 2209 _cleanup_free_ char *new_path = NULL;
0ec0deaa 2210
401017e0
LP
2211 new_path = path_make_absolute(basename(*i), config_path);
2212 if (!new_path)
0ec0deaa
LP
2213 return -ENOMEM;
2214
b3796dd8 2215 q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
0ec0deaa
LP
2216 if (q < 0 && r >= 0)
2217 r = q;
2d5c93c7
MS
2218 }
2219
0ec0deaa
LP
2220 return r;
2221}
2222
344ca755
LP
2223static int path_shall_revert(const LookupPaths *paths, const char *path) {
2224 int r;
2225
2226 assert(paths);
2227 assert(path);
2228
2229 /* Checks whether the path is one where the drop-in directories shall be removed. */
2230
dfead90d 2231 r = path_is_config(paths, path, true);
344ca755
LP
2232 if (r != 0)
2233 return r;
2234
2235 r = path_is_control(paths, path);
2236 if (r != 0)
2237 return r;
2238
2239 return path_is_transient(paths, path);
2240}
2241
2242int unit_file_revert(
2243 UnitFileScope scope,
2244 const char *root_dir,
2245 char **files,
2246 UnitFileChange **changes,
da6053d0 2247 size_t *n_changes) {
344ca755
LP
2248
2249 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
8e766630 2250 _cleanup_(lookup_paths_free) LookupPaths paths = {};
344ca755
LP
2251 _cleanup_strv_free_ char **todo = NULL;
2252 size_t n_todo = 0, n_allocated = 0;
2253 char **i;
2254 int r, q;
2255
2256 /* Puts a unit file back into vendor state. This means:
2257 *
2258 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2259 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2260 *
2261 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2262 * "config", but not in "transient" or "control" or even "generated").
2263 *
4f25723c 2264 * We remove all that in both the runtime and the persistent directories, if that applies.
344ca755
LP
2265 */
2266
2267 r = lookup_paths_init(&paths, scope, 0, root_dir);
2268 if (r < 0)
2269 return r;
2270
2271 STRV_FOREACH(i, files) {
2272 bool has_vendor = false;
2273 char **p;
2274
2275 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2276 return -EINVAL;
2277
2278 STRV_FOREACH(p, paths.search_path) {
2279 _cleanup_free_ char *path = NULL, *dropin = NULL;
2280 struct stat st;
2281
2282 path = path_make_absolute(*i, *p);
2283 if (!path)
2284 return -ENOMEM;
2285
2286 r = lstat(path, &st);
2287 if (r < 0) {
2288 if (errno != ENOENT)
2289 return -errno;
2290 } else if (S_ISREG(st.st_mode)) {
2291 /* Check if there's a vendor version */
2292 r = path_is_vendor(&paths, path);
2293 if (r < 0)
2294 return r;
2295 if (r > 0)
2296 has_vendor = true;
2297 }
2298
2299 dropin = strappend(path, ".d");
2300 if (!dropin)
2301 return -ENOMEM;
2302
2303 r = lstat(dropin, &st);
2304 if (r < 0) {
2305 if (errno != ENOENT)
2306 return -errno;
2307 } else if (S_ISDIR(st.st_mode)) {
2308 /* Remove the drop-ins */
2309 r = path_shall_revert(&paths, dropin);
2310 if (r < 0)
2311 return r;
2312 if (r > 0) {
2313 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2314 return -ENOMEM;
2315
1cc6c93a 2316 todo[n_todo++] = TAKE_PTR(dropin);
344ca755
LP
2317 }
2318 }
2319 }
2320
2321 if (!has_vendor)
2322 continue;
2323
2324 /* OK, there's a vendor version, hence drop all configuration versions */
2325 STRV_FOREACH(p, paths.search_path) {
2326 _cleanup_free_ char *path = NULL;
2327 struct stat st;
2328
2329 path = path_make_absolute(*i, *p);
2330 if (!path)
2331 return -ENOMEM;
2332
2333 r = lstat(path, &st);
2334 if (r < 0) {
2335 if (errno != ENOENT)
2336 return -errno;
2337 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
dfead90d 2338 r = path_is_config(&paths, path, true);
344ca755
LP
2339 if (r < 0)
2340 return r;
2341 if (r > 0) {
2342 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2343 return -ENOMEM;
2344
1cc6c93a 2345 todo[n_todo++] = TAKE_PTR(path);
344ca755
LP
2346 }
2347 }
2348 }
2349 }
2350
2351 strv_uniq(todo);
2352
2353 r = 0;
2354 STRV_FOREACH(i, todo) {
2355 _cleanup_strv_free_ char **fs = NULL;
2356 const char *rp;
2357 char **j;
2358
2359 (void) get_files_in_directory(*i, &fs);
2360
2361 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2362 if (q < 0 && q != -ENOENT && r >= 0) {
2363 r = q;
2364 continue;
2365 }
2366
2367 STRV_FOREACH(j, fs) {
2368 _cleanup_free_ char *t = NULL;
2369
605405c6 2370 t = strjoin(*i, "/", *j);
344ca755
LP
2371 if (!t)
2372 return -ENOMEM;
2373
2374 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
2375 }
2376
2377 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
2378
2379 rp = skip_root(&paths, *i);
2380 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2381 if (q < 0)
2382 return q;
2383 }
2384
3b3557c4 2385 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes);
344ca755
LP
2386 if (r >= 0)
2387 r = q;
2388
3b3557c4 2389 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes);
344ca755
LP
2390 if (r >= 0)
2391 r = q;
2392
2393 return r;
2394}
2395
0ec0deaa
LP
2396int unit_file_add_dependency(
2397 UnitFileScope scope,
b3796dd8 2398 UnitFileFlags flags,
0ec0deaa
LP
2399 const char *root_dir,
2400 char **files,
2401 const char *target,
2402 UnitDependency dep,
0ec0deaa 2403 UnitFileChange **changes,
da6053d0 2404 size_t *n_changes) {
0ec0deaa 2405
8e766630 2406 _cleanup_(lookup_paths_free) LookupPaths paths = {};
0ec0deaa 2407 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2408 UnitFileInstallInfo *i, *target_info;
e1c5c2b0 2409 const char *config_path;
0ec0deaa
LP
2410 char **f;
2411 int r;
2412
2413 assert(scope >= 0);
2414 assert(scope < _UNIT_FILE_SCOPE_MAX);
2415 assert(target);
2416
2417 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
2418 return -EINVAL;
2419
2420 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2421 return -EINVAL;
2422
4943d143 2423 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2424 if (r < 0)
2425 return r;
2426
b3796dd8 2427 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2428 if (!config_path)
2429 return -ENXIO;
0ec0deaa 2430
1e475a0a
RB
2431 r = install_info_discover_and_check(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2432 &target_info, changes, n_changes);
76adb5b8
LP
2433 if (r < 0)
2434 return r;
0ec0deaa
LP
2435
2436 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
e94937df 2437
0ec0deaa
LP
2438 STRV_FOREACH(f, files) {
2439 char ***l;
2440
1e475a0a
RB
2441 r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2442 &i, changes, n_changes);
76adb5b8
LP
2443 if (r < 0)
2444 return r;
0ec0deaa
LP
2445
2446 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2447
2448 /* We didn't actually load anything from the unit
2449 * file, but instead just add in our new symlink to
2450 * create. */
e94937df
LN
2451
2452 if (dep == UNIT_WANTS)
0ec0deaa 2453 l = &i->wanted_by;
e94937df 2454 else
0ec0deaa 2455 l = &i->required_by;
e94937df 2456
0ec0deaa 2457 strv_free(*l);
bea1a013 2458 *l = strv_new(target_info->name);
0ec0deaa
LP
2459 if (!*l)
2460 return -ENOMEM;
e94937df
LN
2461 }
2462
b3796dd8 2463 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
e94937df
LN
2464}
2465
83096483
LP
2466int unit_file_enable(
2467 UnitFileScope scope,
b3796dd8 2468 UnitFileFlags flags,
83096483 2469 const char *root_dir,
7195aa42 2470 char **files,
83096483 2471 UnitFileChange **changes,
da6053d0 2472 size_t *n_changes) {
83096483 2473
8e766630 2474 _cleanup_(lookup_paths_free) LookupPaths paths = {};
59ccf93d 2475 _cleanup_(install_context_done) InstallContext c = {};
e1c5c2b0 2476 const char *config_path;
0ec0deaa
LP
2477 UnitFileInstallInfo *i;
2478 char **f;
83096483
LP
2479 int r;
2480
2481 assert(scope >= 0);
2482 assert(scope < _UNIT_FILE_SCOPE_MAX);
2483
4943d143 2484 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2485 if (r < 0)
2486 return r;
2487
b3796dd8 2488 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2489 if (!config_path)
2490 return -ENXIO;
83096483 2491
0ec0deaa 2492 STRV_FOREACH(f, files) {
1e475a0a
RB
2493 r = install_info_discover_and_check(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2494 &i, changes, n_changes);
76adb5b8
LP
2495 if (r < 0)
2496 return r;
0ec0deaa
LP
2497
2498 assert(i->type == UNIT_FILE_TYPE_REGULAR);
83096483
LP
2499 }
2500
729e3769 2501 /* This will return the number of symlink rules that were
d25e100b
LP
2502 supposed to be created, not the ones actually created. This
2503 is useful to determine whether the passed files had any
2504 installation data at all. */
b91a3b02 2505
b3796dd8 2506 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
83096483
LP
2507}
2508
2509int unit_file_disable(
2510 UnitFileScope scope,
b3796dd8 2511 UnitFileFlags flags,
83096483 2512 const char *root_dir,
7195aa42 2513 char **files,
83096483 2514 UnitFileChange **changes,
da6053d0 2515 size_t *n_changes) {
83096483 2516
8e766630 2517 _cleanup_(lookup_paths_free) LookupPaths paths = {};
59ccf93d 2518 _cleanup_(install_context_done) InstallContext c = {};
7fd1b19b 2519 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
e1c5c2b0 2520 const char *config_path;
0ec0deaa
LP
2521 char **i;
2522 int r;
83096483
LP
2523
2524 assert(scope >= 0);
2525 assert(scope < _UNIT_FILE_SCOPE_MAX);
2526
4943d143 2527 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2528 if (r < 0)
2529 return r;
2530
1830ac51
MB
2531 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
2532 if (!config_path)
2533 return -ENXIO;
2534
83096483 2535 STRV_FOREACH(i, files) {
0ec0deaa
LP
2536 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2537 return -EINVAL;
2538
19539807 2539 r = install_info_add(&c, *i, NULL, false, NULL);
83096483 2540 if (r < 0)
d9e5e694 2541 return r;
83096483
LP
2542 }
2543
1830ac51 2544 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
0ec0deaa
LP
2545 if (r < 0)
2546 return r;
83096483 2547
1830ac51 2548 return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
83096483
LP
2549}
2550
2551int unit_file_reenable(
2552 UnitFileScope scope,
b3796dd8 2553 UnitFileFlags flags,
83096483 2554 const char *root_dir,
7195aa42 2555 char **files,
83096483 2556 UnitFileChange **changes,
da6053d0 2557 size_t *n_changes) {
0ec0deaa
LP
2558
2559 char **n;
92d430a9 2560 int r;
0ec0deaa 2561 size_t l, i;
83096483 2562
0ec0deaa
LP
2563 /* First, we invoke the disable command with only the basename... */
2564 l = strv_length(files);
2565 n = newa(char*, l+1);
2566 for (i = 0; i < l; i++)
2567 n[i] = basename(files[i]);
2568 n[i] = NULL;
2569
b3796dd8 2570 r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
83096483 2571 if (r < 0)
d9e5e694 2572 return r;
83096483 2573
0ec0deaa 2574 /* But the enable command with the full name */
b3796dd8 2575 return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
83096483
LP
2576}
2577
99504dd4
VP
2578int unit_file_set_default(
2579 UnitFileScope scope,
b3796dd8 2580 UnitFileFlags flags,
99504dd4 2581 const char *root_dir,
0ec0deaa 2582 const char *name,
99504dd4 2583 UnitFileChange **changes,
da6053d0 2584 size_t *n_changes) {
99504dd4 2585
8e766630 2586 _cleanup_(lookup_paths_free) LookupPaths paths = {};
59ccf93d 2587 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2588 UnitFileInstallInfo *i;
60bec8e4 2589 const char *new_path;
99504dd4 2590 int r;
99504dd4
VP
2591
2592 assert(scope >= 0);
2593 assert(scope < _UNIT_FILE_SCOPE_MAX);
0ec0deaa 2594 assert(name);
99504dd4 2595
401017e0 2596 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
0ec0deaa
LP
2597 return -EINVAL;
2598 if (streq(name, SPECIAL_DEFAULT_TARGET))
99504dd4
VP
2599 return -EINVAL;
2600
4943d143 2601 r = lookup_paths_init(&paths, scope, 0, root_dir);
99504dd4
VP
2602 if (r < 0)
2603 return r;
2604
1e475a0a 2605 r = install_info_discover_and_check(scope, &c, &paths, name, 0, &i, changes, n_changes);
76adb5b8
LP
2606 if (r < 0)
2607 return r;
99504dd4 2608
401017e0 2609 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
b3796dd8 2610 return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
99504dd4
VP
2611}
2612
2613int unit_file_get_default(
2614 UnitFileScope scope,
2615 const char *root_dir,
2616 char **name) {
2617
8e766630 2618 _cleanup_(lookup_paths_free) LookupPaths paths = {};
0ec0deaa
LP
2619 _cleanup_(install_context_done) InstallContext c = {};
2620 UnitFileInstallInfo *i;
2621 char *n;
99504dd4
VP
2622 int r;
2623
16ed0233
LP
2624 assert(scope >= 0);
2625 assert(scope < _UNIT_FILE_SCOPE_MAX);
2626 assert(name);
2627
4943d143 2628 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2629 if (r < 0)
2630 return r;
99504dd4 2631
59108fbe
ZJS
2632 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2633 &i, NULL, NULL);
0ec0deaa
LP
2634 if (r < 0)
2635 return r;
af3d8113 2636 r = install_info_may_process(i, &paths, NULL, 0);
76adb5b8
LP
2637 if (r < 0)
2638 return r;
99504dd4 2639
0ec0deaa
LP
2640 n = strdup(i->name);
2641 if (!n)
2642 return -ENOMEM;
99504dd4 2643
0ec0deaa
LP
2644 *name = n;
2645 return 0;
99504dd4
VP
2646}
2647
d6d98276 2648int unit_file_lookup_state(
83096483 2649 UnitFileScope scope,
a8ffe6fb 2650 const LookupPaths *paths,
0ec0deaa
LP
2651 const char *name,
2652 UnitFileState *ret) {
83096483 2653
0ec0deaa
LP
2654 _cleanup_(install_context_done) InstallContext c = {};
2655 UnitFileInstallInfo *i;
2656 UnitFileState state;
2657 int r;
83096483 2658
a8ffe6fb 2659 assert(paths);
0ec0deaa 2660 assert(name);
83096483 2661
7410616c 2662 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
83096483
LP
2663 return -EINVAL;
2664
59108fbe
ZJS
2665 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2666 &i, NULL, NULL);
0ec0deaa
LP
2667 if (r < 0)
2668 return r;
83096483 2669
0ec0deaa
LP
2670 /* Shortcut things, if the caller just wants to know if this unit exists. */
2671 if (!ret)
2672 return 0;
83096483 2673
0ec0deaa 2674 switch (i->type) {
67820a0c 2675
0ec0deaa 2676 case UNIT_FILE_TYPE_MASKED:
dfead90d 2677 r = path_is_runtime(paths, i->path, true);
385eb996
LP
2678 if (r < 0)
2679 return r;
2680
2681 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
0ec0deaa 2682 break;
83096483 2683
0ec0deaa 2684 case UNIT_FILE_TYPE_REGULAR:
f4dc1e65 2685 r = path_is_generator(paths, i->path);
f4139308
LP
2686 if (r < 0)
2687 return r;
2688 if (r > 0) {
2689 state = UNIT_FILE_GENERATED;
2690 break;
2691 }
2692
e4fca67f
LP
2693 r = path_is_transient(paths, i->path);
2694 if (r < 0)
2695 return r;
2696 if (r > 0) {
2697 state = UNIT_FILE_TRANSIENT;
2698 break;
2699 }
2700
5cd8ae31
ZJS
2701 /* Check if any of the Alias= symlinks have been created.
2702 * We ignore other aliases, and only check those that would
2703 * be created by systemctl enable for this unit. */
d2561cfd 2704 r = find_symlinks_in_scope(scope, paths, i, true, &state);
d9b4b48f
ZJS
2705 if (r < 0)
2706 return r;
2707 if (r > 0)
2708 break;
2709
2710 /* Check if the file is known under other names. If it is,
2711 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
d2561cfd 2712 r = find_symlinks_in_scope(scope, paths, i, false, &state);
d9e5e694
ZJS
2713 if (r < 0)
2714 return r;
d9b4b48f
ZJS
2715 if (r > 0)
2716 state = UNIT_FILE_INDIRECT;
2717 else {
7a7ec2bf 2718 if (unit_file_install_info_has_rules(i))
0ec0deaa 2719 state = UNIT_FILE_DISABLED;
7a7ec2bf 2720 else if (unit_file_install_info_has_also(i))
0ec0deaa
LP
2721 state = UNIT_FILE_INDIRECT;
2722 else
2723 state = UNIT_FILE_STATIC;
2724 }
83096483 2725
0ec0deaa
LP
2726 break;
2727
2728 default:
2729 assert_not_reached("Unexpect unit file type.");
83096483
LP
2730 }
2731
0ec0deaa
LP
2732 *ret = state;
2733 return 0;
83096483
LP
2734}
2735
0ec0deaa 2736int unit_file_get_state(
a8ffe6fb
ZJS
2737 UnitFileScope scope,
2738 const char *root_dir,
0ec0deaa
LP
2739 const char *name,
2740 UnitFileState *ret) {
a8ffe6fb 2741
8e766630 2742 _cleanup_(lookup_paths_free) LookupPaths paths = {};
a8ffe6fb
ZJS
2743 int r;
2744
2745 assert(scope >= 0);
2746 assert(scope < _UNIT_FILE_SCOPE_MAX);
2747 assert(name);
2748
4943d143 2749 r = lookup_paths_init(&paths, scope, 0, root_dir);
a8ffe6fb
ZJS
2750 if (r < 0)
2751 return r;
2752
e4bb56c7 2753 return unit_file_lookup_state(scope, &paths, name, ret);
a8ffe6fb
ZJS
2754}
2755
e735decc
LP
2756int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2757 _cleanup_(install_context_done) InstallContext c = {};
2758 int r;
2759
2760 assert(paths);
2761 assert(name);
2762
2763 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2764 return -EINVAL;
2765
59108fbe 2766 r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
e735decc
LP
2767 if (r == -ENOENT)
2768 return 0;
2769 if (r < 0)
2770 return r;
2771
2772 return 1;
2773}
2774
4c9565ee
RB
2775static int split_pattern_into_name_and_instances(const char *pattern, char **out_unit_name, char ***out_instances) {
2776 _cleanup_strv_free_ char **instances = NULL;
2777 _cleanup_free_ char *unit_name = NULL;
2778 int r;
2779
2780 assert(pattern);
2781 assert(out_instances);
2782 assert(out_unit_name);
2783
2784 r = extract_first_word(&pattern, &unit_name, NULL, 0);
2785 if (r < 0)
2786 return r;
2787
2788 /* We handle the instances logic when unit name is extracted */
2789 if (pattern) {
2790 /* We only create instances when a rule of templated unit
2791 * is seen. A rule like enable foo@.service a b c will
2792 * result in an array of (a, b, c) as instance names */
2793 if (!unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE))
2794 return -EINVAL;
2795
2796 instances = strv_split(pattern, WHITESPACE);
2797 if (!instances)
2798 return -ENOMEM;
2799
2800 *out_instances = TAKE_PTR(instances);
2801 }
2802
2803 *out_unit_name = TAKE_PTR(unit_name);
2804
2805 return 0;
2806}
2807
8965d9f8
AC
2808static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2809 _cleanup_(presets_freep) Presets ps = {};
2810 size_t n_allocated = 0;
7fd1b19b 2811 _cleanup_strv_free_ char **files = NULL;
cba2ef02 2812 char **p;
83096483
LP
2813 int r;
2814
2815 assert(scope >= 0);
2816 assert(scope < _UNIT_FILE_SCOPE_MAX);
8965d9f8 2817 assert(presets);
0ec0deaa 2818
264afce0
FB
2819 switch (scope) {
2820 case UNIT_FILE_SYSTEM:
b5084605 2821 r = conf_files_list(&files, ".preset", root_dir, 0,
a7480dba 2822 "/etc/systemd/system-preset",
7c59ab4b 2823 "/run/systemd/system-preset",
a7480dba
LP
2824 "/usr/local/lib/systemd/system-preset",
2825 "/usr/lib/systemd/system-preset",
349cc4a5 2826#if HAVE_SPLIT_USR
a7480dba 2827 "/lib/systemd/system-preset",
b4bdfefa 2828#endif
83096483 2829 NULL);
264afce0
FB
2830 break;
2831
2832 case UNIT_FILE_GLOBAL:
2833 case UNIT_FILE_USER:
b5084605 2834 r = conf_files_list(&files, ".preset", root_dir, 0,
a7480dba 2835 "/etc/systemd/user-preset",
7c59ab4b 2836 "/run/systemd/user-preset",
a7480dba
LP
2837 "/usr/local/lib/systemd/user-preset",
2838 "/usr/lib/systemd/user-preset",
83096483 2839 NULL);
264afce0 2840 break;
8965d9f8 2841
264afce0
FB
2842 default:
2843 assert_not_reached("Invalid unit file scope");
8965d9f8 2844 }
83096483
LP
2845
2846 if (r < 0)
2847 return r;
2848
cba2ef02 2849 STRV_FOREACH(p, files) {
7fd1b19b 2850 _cleanup_fclose_ FILE *f;
d544d1a4 2851 int n = 0;
83096483 2852
cba2ef02 2853 f = fopen(*p, "re");
83096483
LP
2854 if (!f) {
2855 if (errno == ENOENT)
2856 continue;
2857
d9e5e694 2858 return -errno;
83096483
LP
2859 }
2860
bef77f37
LP
2861 for (;;) {
2862 _cleanup_free_ char *line = NULL;
8965d9f8 2863 PresetRule rule = {};
0ec0deaa
LP
2864 const char *parameter;
2865 char *l;
83096483 2866
bef77f37
LP
2867 r = read_line(f, LONG_LINE_MAX, &line);
2868 if (r < 0)
2869 return r;
2870 if (r == 0)
2871 break;
2872
83096483 2873 l = strstrip(line);
d544d1a4 2874 n++;
83096483 2875
0ec0deaa
LP
2876 if (isempty(l))
2877 continue;
2878 if (strchr(COMMENTS, *l))
83096483
LP
2879 continue;
2880
0ec0deaa
LP
2881 parameter = first_word(l, "enable");
2882 if (parameter) {
4c9565ee
RB
2883 char *unit_name;
2884 char **instances = NULL;
d9e5e694 2885
4c9565ee
RB
2886 /* Unit_name will remain the same as parameter when no instances are specified */
2887 r = split_pattern_into_name_and_instances(parameter, &unit_name, &instances);
2888 if (r < 0) {
8ac3c9ab 2889 log_syntax(NULL, LOG_WARNING, *p, n, r, "Couldn't parse line '%s'. Ignoring.", line);
4c9565ee
RB
2890 continue;
2891 }
8965d9f8
AC
2892
2893 rule = (PresetRule) {
4c9565ee 2894 .pattern = unit_name,
8965d9f8 2895 .action = PRESET_ENABLE,
4c9565ee 2896 .instances = instances,
8965d9f8 2897 };
0ec0deaa 2898 }
83096483 2899
0ec0deaa
LP
2900 parameter = first_word(l, "disable");
2901 if (parameter) {
8965d9f8 2902 char *pattern;
d9e5e694 2903
8965d9f8
AC
2904 pattern = strdup(parameter);
2905 if (!pattern)
2906 return -ENOMEM;
2907
2908 rule = (PresetRule) {
2909 .pattern = pattern,
2910 .action = PRESET_DISABLE,
2911 };
2912 }
2913
2914 if (rule.action) {
2915 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
2916 return -ENOMEM;
2917
2918 ps.rules[ps.n_rules++] = rule;
0ec0deaa
LP
2919 continue;
2920 }
2921
d544d1a4 2922 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
83096483 2923 }
83096483
LP
2924 }
2925
8965d9f8
AC
2926 *presets = ps;
2927 ps = (Presets){};
2928
2929 return 0;
2930}
2931
4c9565ee
RB
2932static int pattern_match_multiple_instances(
2933 const PresetRule rule,
2934 const char *unit_name,
2935 char ***ret) {
2936
2937 _cleanup_free_ char *templated_name = NULL;
2938 int r;
2939
2940 /* If no ret is needed or the rule itself does not have instances
2941 * initalized, we return not matching */
2942 if (!ret || !rule.instances)
2943 return 0;
2944
2945 r = unit_name_template(unit_name, &templated_name);
2946 if (r < 0)
2947 return r;
2948 if (!streq(rule.pattern, templated_name))
2949 return 0;
2950
2951 /* Compose a list of specified instances when unit name is a template */
2952 if (unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
2953 _cleanup_free_ char *prefix = NULL;
2954 _cleanup_strv_free_ char **out_strv = NULL;
2955 char **iter;
2956
2957 r = unit_name_to_prefix(unit_name, &prefix);
2958 if (r < 0)
2959 return r;
2960
2961 STRV_FOREACH(iter, rule.instances) {
2962 _cleanup_free_ char *name = NULL;
2963 r = unit_name_build(prefix, *iter, ".service", &name);
2964 if (r < 0)
2965 return r;
2966 r = strv_extend(&out_strv, name);
2967 if (r < 0)
2968 return r;
2969 }
2970
2971 *ret = TAKE_PTR(out_strv);
2972 return 1;
2973 } else {
2974 /* We now know the input unit name is an instance name */
2975 _cleanup_free_ char *instance_name = NULL;
2976
2977 r = unit_name_to_instance(unit_name, &instance_name);
2978 if (r < 0)
2979 return r;
2980
2981 if (strv_find(rule.instances, instance_name))
2982 return 1;
2983 }
2984 return 0;
2985}
2986
2987static int query_presets(const char *name, const Presets presets, char ***instance_name_list) {
8965d9f8
AC
2988 PresetAction action = PRESET_UNKNOWN;
2989 size_t i;
4c9565ee 2990 char **s;
8965d9f8
AC
2991 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2992 return -EINVAL;
2993
2994 for (i = 0; i < presets.n_rules; i++)
4c9565ee
RB
2995 if (pattern_match_multiple_instances(presets.rules[i], name, instance_name_list) > 0 ||
2996 fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
8965d9f8
AC
2997 action = presets.rules[i].action;
2998 break;
2999 }
3000
3001 switch (action) {
3002 case PRESET_UNKNOWN:
3003 log_debug("Preset files don't specify rule for %s. Enabling.", name);
3004 return 1;
3005 case PRESET_ENABLE:
4c9565ee
RB
3006 if (instance_name_list && *instance_name_list)
3007 STRV_FOREACH(s, *instance_name_list)
3008 log_debug("Preset files say enable %s.", *s);
3009 else
3010 log_debug("Preset files say enable %s.", name);
8965d9f8
AC
3011 return 1;
3012 case PRESET_DISABLE:
3013 log_debug("Preset files say disable %s.", name);
3014 return 0;
3015 default:
3016 assert_not_reached("invalid preset action");
3017 }
3018}
3019
3020int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
3021 _cleanup_(presets_freep) Presets presets = {};
3022 int r;
3023
3024 r = read_presets(scope, root_dir, &presets);
3025 if (r < 0)
3026 return r;
3027
4c9565ee 3028 return query_presets(name, presets, NULL);
83096483
LP
3029}
3030
0ec0deaa
LP
3031static int execute_preset(
3032 UnitFileScope scope,
3033 InstallContext *plus,
3034 InstallContext *minus,
3035 const LookupPaths *paths,
1830ac51 3036 const char *config_path,
0ec0deaa
LP
3037 char **files,
3038 UnitFilePresetMode mode,
1830ac51 3039 bool force,
0ec0deaa 3040 UnitFileChange **changes,
da6053d0 3041 size_t *n_changes) {
0ec0deaa 3042
1830ac51 3043 int r;
0ec0deaa
LP
3044
3045 assert(plus);
3046 assert(minus);
3047 assert(paths);
1830ac51 3048 assert(config_path);
0ec0deaa
LP
3049
3050 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
3051 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
3052
1830ac51
MB
3053 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
3054 if (r < 0)
3055 return r;
0ec0deaa 3056
1830ac51
MB
3057 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
3058 } else
3059 r = 0;
0ec0deaa
LP
3060
3061 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
1830ac51
MB
3062 int q;
3063
0ec0deaa 3064 /* Returns number of symlinks that where supposed to be installed. */
1830ac51
MB
3065 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
3066 if (r >= 0) {
3067 if (q < 0)
3068 r = q;
3069 else
3070 r += q;
3071 }
0ec0deaa
LP
3072 }
3073
3074 return r;
3075}
3076
3077static int preset_prepare_one(
3078 UnitFileScope scope,
3079 InstallContext *plus,
3080 InstallContext *minus,
3081 LookupPaths *paths,
af3d8113 3082 const char *name,
8965d9f8 3083 Presets presets,
af3d8113 3084 UnitFileChange **changes,
da6053d0 3085 size_t *n_changes) {
0ec0deaa 3086
11e11fd5 3087 _cleanup_(install_context_done) InstallContext tmp = {};
4c9565ee 3088 _cleanup_strv_free_ char **instance_name_list = NULL;
0ec0deaa
LP
3089 UnitFileInstallInfo *i;
3090 int r;
3091
11e11fd5 3092 if (install_info_find(plus, name) || install_info_find(minus, name))
0ec0deaa
LP
3093 return 0;
3094
59108fbe
ZJS
3095 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
3096 &i, changes, n_changes);
11e11fd5
ZJS
3097 if (r < 0)
3098 return r;
3099 if (!streq(name, i->name)) {
10d67460 3100 log_debug("Skipping %s because it is an alias for %s.", name, i->name);
11e11fd5
ZJS
3101 return 0;
3102 }
3103
4c9565ee 3104 r = query_presets(name, presets, &instance_name_list);
0ec0deaa
LP
3105 if (r < 0)
3106 return r;
3107
3108 if (r > 0) {
4c9565ee
RB
3109 if (instance_name_list) {
3110 char **s;
3111 STRV_FOREACH(s, instance_name_list) {
1e475a0a
RB
3112 r = install_info_discover_and_check(scope, plus, paths, *s, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
3113 &i, changes, n_changes);
4c9565ee
RB
3114 if (r < 0)
3115 return r;
3116 }
3117 } else {
1e475a0a
RB
3118 r = install_info_discover_and_check(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
3119 &i, changes, n_changes);
4c9565ee
RB
3120 if (r < 0)
3121 return r;
3122 }
0ec0deaa 3123
0ec0deaa 3124 } else
59108fbe
ZJS
3125 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
3126 &i, changes, n_changes);
0ec0deaa
LP
3127
3128 return r;
3129}
3130
83096483
LP
3131int unit_file_preset(
3132 UnitFileScope scope,
b3796dd8 3133 UnitFileFlags flags,
83096483 3134 const char *root_dir,
7195aa42 3135 char **files,
d309c1c3 3136 UnitFilePresetMode mode,
83096483 3137 UnitFileChange **changes,
da6053d0 3138 size_t *n_changes) {
83096483 3139
59ccf93d 3140 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
8e766630 3141 _cleanup_(lookup_paths_free) LookupPaths paths = {};
8965d9f8 3142 _cleanup_(presets_freep) Presets presets = {};
1830ac51 3143 const char *config_path;
da39f6a6 3144 char **i;
0ec0deaa 3145 int r;
83096483
LP
3146
3147 assert(scope >= 0);
3148 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 3149 assert(mode < _UNIT_FILE_PRESET_MAX);
83096483 3150
4943d143 3151 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
3152 if (r < 0)
3153 return r;
3154
1830ac51
MB
3155 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
3156 if (!config_path)
3157 return -ENXIO;
3158
8965d9f8
AC
3159 r = read_presets(scope, root_dir, &presets);
3160 if (r < 0)
3161 return r;
83096483 3162
8965d9f8 3163 STRV_FOREACH(i, files) {
ff56349d 3164 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
83096483 3165 if (r < 0)
d9e5e694 3166 return r;
83096483
LP
3167 }
3168
1830ac51 3169 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
d309c1c3
LP
3170}
3171
3172int unit_file_preset_all(
3173 UnitFileScope scope,
b3796dd8 3174 UnitFileFlags flags,
d309c1c3
LP
3175 const char *root_dir,
3176 UnitFilePresetMode mode,
d309c1c3 3177 UnitFileChange **changes,
da6053d0 3178 size_t *n_changes) {
d309c1c3 3179
59ccf93d 3180 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
8e766630 3181 _cleanup_(lookup_paths_free) LookupPaths paths = {};
8965d9f8 3182 _cleanup_(presets_freep) Presets presets = {};
1830ac51 3183 const char *config_path = NULL;
d309c1c3 3184 char **i;
0ec0deaa 3185 int r;
d309c1c3
LP
3186
3187 assert(scope >= 0);
3188 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 3189 assert(mode < _UNIT_FILE_PRESET_MAX);
d309c1c3 3190
4943d143 3191 r = lookup_paths_init(&paths, scope, 0, root_dir);
d309c1c3
LP
3192 if (r < 0)
3193 return r;
3194
1830ac51
MB
3195 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
3196 if (!config_path)
3197 return -ENXIO;
3198
8965d9f8
AC
3199 r = read_presets(scope, root_dir, &presets);
3200 if (r < 0)
3201 return r;
3202
a3c4eb07 3203 STRV_FOREACH(i, paths.search_path) {
d309c1c3 3204 _cleanup_closedir_ DIR *d = NULL;
d25e100b 3205 struct dirent *de;
d309c1c3 3206
401017e0 3207 d = opendir(*i);
d309c1c3
LP
3208 if (!d) {
3209 if (errno == ENOENT)
3210 continue;
3211
3212 return -errno;
3213 }
3214
d25e100b 3215 FOREACH_DIRENT(de, d, return -errno) {
1830ac51 3216
7410616c 3217 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
d309c1c3
LP
3218 continue;
3219
3220 dirent_ensure_type(d, de);
3221
0ec0deaa 3222 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
d309c1c3
LP
3223 continue;
3224
af3d8113 3225 /* we don't pass changes[] in, because we want to handle errors on our own */
ff56349d 3226 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
9a0a413a
ZJS
3227 if (r == -ERFKILL)
3228 r = unit_file_changes_add(changes, n_changes,
3229 UNIT_FILE_IS_MASKED, de->d_name, NULL);
893275df
ZJS
3230 else if (r == -ENOLINK)
3231 r = unit_file_changes_add(changes, n_changes,
3232 UNIT_FILE_IS_DANGLING, de->d_name, NULL);
26421228
LP
3233 else if (r == -EADDRNOTAVAIL) /* Ignore generated/transient units when applying preset */
3234 continue;
d309c1c3
LP
3235 if (r < 0)
3236 return r;
3237 }
3238 }
3239
1830ac51 3240 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
83096483
LP
3241}
3242
59ccf93d
LP
3243static void unit_file_list_free_one(UnitFileList *f) {
3244 if (!f)
d9e5e694
ZJS
3245 return;
3246
59ccf93d
LP
3247 free(f->path);
3248 free(f);
d9e5e694 3249}
59ccf93d 3250
0ec0deaa 3251Hashmap* unit_file_list_free(Hashmap *h) {
224b0e7a 3252 return hashmap_free_with_destructor(h, unit_file_list_free_one);
0ec0deaa
LP
3253}
3254
59ccf93d 3255DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
d9e5e694 3256
83096483
LP
3257int unit_file_get_list(
3258 UnitFileScope scope,
3259 const char *root_dir,
313fe66f 3260 Hashmap *h,
3261 char **states,
3262 char **patterns) {
83096483 3263
8e766630 3264 _cleanup_(lookup_paths_free) LookupPaths paths = {};
d9e5e694 3265 char **i;
83096483
LP
3266 int r;
3267
3268 assert(scope >= 0);
3269 assert(scope < _UNIT_FILE_SCOPE_MAX);
3270 assert(h);
3271
4943d143 3272 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
3273 if (r < 0)
3274 return r;
3275
a3c4eb07 3276 STRV_FOREACH(i, paths.search_path) {
da39f6a6 3277 _cleanup_closedir_ DIR *d = NULL;
d25e100b 3278 struct dirent *de;
83096483 3279
401017e0 3280 d = opendir(*i);
83096483
LP
3281 if (!d) {
3282 if (errno == ENOENT)
3283 continue;
a1feacf7 3284 if (IN_SET(errno, ENOTDIR, EACCES)) {
25f027c5 3285 log_debug_errno(errno, "Failed to open \"%s\": %m", *i);
a1feacf7
ZJS
3286 continue;
3287 }
83096483 3288
d9e5e694 3289 return -errno;
83096483
LP
3290 }
3291
d25e100b 3292 FOREACH_DIRENT(de, d, return -errno) {
59ccf93d 3293 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
83096483 3294
7410616c 3295 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
83096483
LP
3296 continue;
3297
313fe66f 3298 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
3299 continue;
3300
83096483
LP
3301 if (hashmap_get(h, de->d_name))
3302 continue;
3303
da39f6a6 3304 dirent_ensure_type(d, de);
83096483 3305
da39f6a6 3306 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
83096483
LP
3307 continue;
3308
3309 f = new0(UnitFileList, 1);
d9e5e694
ZJS
3310 if (!f)
3311 return -ENOMEM;
83096483 3312
401017e0 3313 f->path = path_make_absolute(de->d_name, *i);
d9e5e694
ZJS
3314 if (!f->path)
3315 return -ENOMEM;
83096483 3316
401017e0 3317 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
d9e5e694 3318 if (r < 0)
0ec0deaa 3319 f->state = UNIT_FILE_BAD;
81fc054d 3320
313fe66f 3321 if (!strv_isempty(states) &&
3322 !strv_contains(states, unit_file_state_to_string(f->state)))
3323 continue;
3324
2b6bf07d 3325 r = hashmap_put(h, basename(f->path), f);
d9e5e694
ZJS
3326 if (r < 0)
3327 return r;
0ec0deaa 3328
d9e5e694 3329 f = NULL; /* prevent cleanup */
83096483
LP
3330 }
3331 }
3332
77cd2c87 3333 return 0;
83096483
LP
3334}
3335
3336static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
3337 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 3338 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
3339 [UNIT_FILE_LINKED] = "linked",
3340 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
3341 [UNIT_FILE_MASKED] = "masked",
3342 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
3343 [UNIT_FILE_STATIC] = "static",
b5b46d59 3344 [UNIT_FILE_DISABLED] = "disabled",
aedd4012 3345 [UNIT_FILE_INDIRECT] = "indirect",
f4139308 3346 [UNIT_FILE_GENERATED] = "generated",
e4fca67f 3347 [UNIT_FILE_TRANSIENT] = "transient",
0ec0deaa 3348 [UNIT_FILE_BAD] = "bad",
83096483
LP
3349};
3350
3351DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
3352
3353static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
3354 [UNIT_FILE_SYMLINK] = "symlink",
3355 [UNIT_FILE_UNLINK] = "unlink",
9a0a413a 3356 [UNIT_FILE_IS_MASKED] = "masked",
893275df 3357 [UNIT_FILE_IS_DANGLING] = "dangling",
c0576cd6
LP
3358};
3359
3360DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
d309c1c3 3361
86bbe5bf 3362static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
d309c1c3
LP
3363 [UNIT_FILE_PRESET_FULL] = "full",
3364 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
3365 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
3366};
3367
3368DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);