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