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