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