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