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