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