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