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