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