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