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