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