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