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