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