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