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