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