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