]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
Add SPDX license identifiers to source files under the LGPL
[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
d5099efc 525 r = set_ensure_allocated(remove_symlinks_to, &string_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 OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) {
996 UnitFileInstallInfo *i;
83096483 997
0ec0deaa
LP
998 if (!m)
999 return NULL;
83096483 1000
0ec0deaa
LP
1001 while ((i = ordered_hashmap_steal_first(m)))
1002 install_info_free(i);
83096483 1003
0ec0deaa
LP
1004 return ordered_hashmap_free(m);
1005}
83096483 1006
0ec0deaa
LP
1007static void install_context_done(InstallContext *c) {
1008 assert(c);
83096483 1009
0ec0deaa
LP
1010 c->will_process = install_info_hashmap_free(c->will_process);
1011 c->have_processed = install_info_hashmap_free(c->have_processed);
1012}
83096483 1013
0ec0deaa
LP
1014static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
1015 UnitFileInstallInfo *i;
83096483 1016
0ec0deaa
LP
1017 i = ordered_hashmap_get(c->have_processed, name);
1018 if (i)
1019 return i;
83096483 1020
0ec0deaa 1021 return ordered_hashmap_get(c->will_process, name);
83096483
LP
1022}
1023
af3d8113
ZJS
1024static int install_info_may_process(
1025 UnitFileInstallInfo *i,
1026 const LookupPaths *paths,
1027 UnitFileChange **changes,
1028 unsigned *n_changes) {
76adb5b8
LP
1029 assert(i);
1030 assert(paths);
1031
047d91f9
ZJS
1032 /* Checks whether the loaded unit file is one we should process, or is masked,
1033 * transient or generated and thus not subject to enable/disable operations. */
76adb5b8 1034
af3d8113
ZJS
1035 if (i->type == UNIT_FILE_TYPE_MASKED) {
1036 unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
76ec966f 1037 return -ERFKILL;
af3d8113
ZJS
1038 }
1039 if (path_is_generator(paths, i->path) ||
1040 path_is_transient(paths, i->path)) {
1041 unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
76adb5b8 1042 return -EADDRNOTAVAIL;
af3d8113 1043 }
76adb5b8
LP
1044
1045 return 0;
1046}
1047
ff56349d
ZJS
1048/**
1049 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1050 * hashmap, or retrieves the existing one if already present.
19539807
ZJS
1051 *
1052 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
ff56349d 1053 */
83096483
LP
1054static int install_info_add(
1055 InstallContext *c,
1056 const char *name,
0ec0deaa 1057 const char *path,
19539807 1058 bool auxiliary,
0ec0deaa
LP
1059 UnitFileInstallInfo **ret) {
1060
cab6235f 1061 UnitFileInstallInfo *i = NULL;
83096483
LP
1062 int r;
1063
1064 assert(c);
1065 assert(name || path);
1066
1067 if (!name)
2b6bf07d 1068 name = basename(path);
83096483 1069
7410616c 1070 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
83096483
LP
1071 return -EINVAL;
1072
0ec0deaa
LP
1073 i = install_info_find(c, name);
1074 if (i) {
19539807
ZJS
1075 i->auxiliary = i->auxiliary && auxiliary;
1076
0ec0deaa
LP
1077 if (ret)
1078 *ret = i;
83096483 1079 return 0;
0ec0deaa 1080 }
83096483 1081
0ec0deaa 1082 r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops);
83096483
LP
1083 if (r < 0)
1084 return r;
1085
cab6235f 1086 i = new0(UnitFileInstallInfo, 1);
83096483
LP
1087 if (!i)
1088 return -ENOMEM;
0ec0deaa 1089 i->type = _UNIT_FILE_TYPE_INVALID;
19539807 1090 i->auxiliary = auxiliary;
83096483
LP
1091
1092 i->name = strdup(name);
1093 if (!i->name) {
1094 r = -ENOMEM;
1095 goto fail;
1096 }
1097
1098 if (path) {
1099 i->path = strdup(path);
1100 if (!i->path) {
1101 r = -ENOMEM;
1102 goto fail;
1103 }
1104 }
1105
0ec0deaa 1106 r = ordered_hashmap_put(c->will_process, i->name, i);
83096483
LP
1107 if (r < 0)
1108 goto fail;
1109
0ec0deaa
LP
1110 if (ret)
1111 *ret = i;
1112
19539807 1113 return 1;
83096483
LP
1114
1115fail:
d25e100b 1116 install_info_free(i);
83096483
LP
1117 return r;
1118}
1119
a7724589
ZJS
1120static int config_parse_alias(
1121 const char *unit,
1122 const char *filename,
1123 unsigned line,
1124 const char *section,
1125 unsigned section_line,
1126 const char *lvalue,
1127 int ltype,
1128 const char *rvalue,
1129 void *data,
1130 void *userdata) {
1131
a7724589
ZJS
1132 UnitType type;
1133
142468d8 1134 assert(unit);
a7724589
ZJS
1135 assert(filename);
1136 assert(lvalue);
1137 assert(rvalue);
1138
142468d8 1139 type = unit_name_to_type(unit);
a7724589
ZJS
1140 if (!unit_type_may_alias(type))
1141 return log_syntax(unit, LOG_WARNING, filename, line, 0,
3b8769bd 1142 "Alias= is not allowed for %s units, ignoring.",
a7724589
ZJS
1143 unit_type_to_string(type));
1144
1145 return config_parse_strv(unit, filename, line, section, section_line,
1146 lvalue, ltype, rvalue, data, userdata);
1147}
1148
d54c4993
LP
1149static int config_parse_also(
1150 const char *unit,
1151 const char *filename,
1152 unsigned line,
1153 const char *section,
1154 unsigned section_line,
1155 const char *lvalue,
1156 int ltype,
1157 const char *rvalue,
1158 void *data,
1159 void *userdata) {
83096483 1160
19539807 1161 UnitFileInstallInfo *info = userdata, *alsoinfo = NULL;
0ec0deaa
LP
1162 InstallContext *c = data;
1163 int r;
83096483 1164
142468d8 1165 assert(unit);
83096483
LP
1166 assert(filename);
1167 assert(lvalue);
1168 assert(rvalue);
1169
0ec0deaa 1170 for (;;) {
a6612e65 1171 _cleanup_free_ char *word = NULL, *printed = NULL;
03da6513 1172
0ec0deaa
LP
1173 r = extract_first_word(&rvalue, &word, NULL, 0);
1174 if (r < 0)
1175 return r;
03da6513
SS
1176 if (r == 0)
1177 break;
83096483 1178
a6612e65 1179 r = install_full_printf(info, word, &printed);
d9e5e694 1180 if (r < 0)
83096483 1181 return r;
aedd4012 1182
a6612e65
ZJS
1183 if (!unit_name_is_valid(printed, UNIT_NAME_ANY))
1184 return -EINVAL;
1185
1186 r = install_info_add(c, printed, NULL, true, &alsoinfo);
d9e5e694 1187 if (r < 0)
83096483 1188 return r;
aedd4012 1189
a6612e65 1190 r = strv_push(&info->also, printed);
aedd4012
JS
1191 if (r < 0)
1192 return r;
0ec0deaa 1193
a6612e65 1194 printed = NULL;
83096483
LP
1195 }
1196
1197 return 0;
1198}
1199
d54c4993
LP
1200static int config_parse_default_instance(
1201 const char *unit,
1202 const char *filename,
1203 unsigned line,
1204 const char *section,
1205 unsigned section_line,
1206 const char *lvalue,
1207 int ltype,
1208 const char *rvalue,
1209 void *data,
1210 void *userdata) {
1211
cab6235f 1212 UnitFileInstallInfo *i = data;
d7604756 1213 _cleanup_free_ char *printed = NULL;
d54c4993
LP
1214 int r;
1215
142468d8 1216 assert(unit);
d54c4993
LP
1217 assert(filename);
1218 assert(lvalue);
1219 assert(rvalue);
1220
142468d8 1221 if (unit_name_is_valid(unit, UNIT_NAME_INSTANCE))
6597fa61
ZJS
1222 /* When enabling an instance, we might be using a template unit file,
1223 * but we should ignore DefaultInstance silently. */
1224 return 0;
142468d8 1225 if (!unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
6597fa61 1226 return log_syntax(unit, LOG_WARNING, filename, line, 0,
10d67460 1227 "DefaultInstance= only makes sense for template units, ignoring.");
6597fa61 1228
d54c4993
LP
1229 r = install_full_printf(i, rvalue, &printed);
1230 if (r < 0)
1231 return r;
1232
d7604756 1233 if (!unit_instance_is_valid(printed))
d54c4993
LP
1234 return -EINVAL;
1235
3b319885 1236 return free_and_replace(i->default_instance, printed);
d54c4993
LP
1237}
1238
83096483
LP
1239static int unit_file_load(
1240 InstallContext *c,
cab6235f 1241 UnitFileInstallInfo *info,
83096483 1242 const char *path,
0ec0deaa 1243 SearchFlags flags) {
83096483 1244
f975e971 1245 const ConfigTableItem items[] = {
a7724589 1246 { "Install", "Alias", config_parse_alias, 0, &info->aliases },
d54c4993
LP
1247 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1248 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1249 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
1250 { "Install", "Also", config_parse_also, 0, c },
d54c4993 1251 {}
83096483
LP
1252 };
1253
133e5b36 1254 UnitType type;
7fd1b19b 1255 _cleanup_fclose_ FILE *f = NULL;
0ec0deaa
LP
1256 _cleanup_close_ int fd = -1;
1257 struct stat st;
1258 int r;
83096483 1259
83096483
LP
1260 assert(info);
1261 assert(path);
1262
142468d8
JL
1263 type = unit_name_to_type(info->name);
1264 if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
133e5b36
ZJS
1265 !unit_type_may_template(type))
1266 return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
1267
0ec0deaa
LP
1268 if (!(flags & SEARCH_LOAD)) {
1269 r = lstat(path, &st);
1270 if (r < 0)
d25e100b
LP
1271 return -errno;
1272
0ec0deaa
LP
1273 if (null_or_empty(&st))
1274 info->type = UNIT_FILE_TYPE_MASKED;
1275 else if (S_ISREG(st.st_mode))
1276 info->type = UNIT_FILE_TYPE_REGULAR;
1277 else if (S_ISLNK(st.st_mode))
1278 return -ELOOP;
1279 else if (S_ISDIR(st.st_mode))
1280 return -EISDIR;
1281 else
1282 return -ENOTTY;
1283
d25e100b 1284 return 0;
e94937df
LN
1285 }
1286
047d91f9
ZJS
1287 /* c is only needed if we actually load the file */
1288 assert(c);
1289
0ec0deaa 1290 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
83096483
LP
1291 if (fd < 0)
1292 return -errno;
0ec0deaa
LP
1293 if (fstat(fd, &st) < 0)
1294 return -errno;
1295 if (null_or_empty(&st)) {
d986e364 1296 info->type = UNIT_FILE_TYPE_MASKED;
0ec0deaa
LP
1297 return 0;
1298 }
1299 if (S_ISDIR(st.st_mode))
1300 return -EISDIR;
1301 if (!S_ISREG(st.st_mode))
1302 return -ENOTTY;
83096483
LP
1303
1304 f = fdopen(fd, "re");
0ec0deaa
LP
1305 if (!f)
1306 return -errno;
1307 fd = -1;
83096483 1308
142468d8 1309 r = config_parse(info->name, path, f,
36f822c4
ZJS
1310 NULL,
1311 config_item_table_lookup, items,
bcde742e 1312 CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
83096483 1313 if (r < 0)
59108fbe 1314 return log_debug_errno(r, "Failed to parse %s: %m", info->name);
83096483 1315
0ec0deaa 1316 info->type = UNIT_FILE_TYPE_REGULAR;
aedd4012 1317
78d54bd4 1318 return
693eb9a2
LP
1319 (int) strv_length(info->aliases) +
1320 (int) strv_length(info->wanted_by) +
1321 (int) strv_length(info->required_by);
83096483
LP
1322}
1323
0ec0deaa
LP
1324static int unit_file_load_or_readlink(
1325 InstallContext *c,
1326 UnitFileInstallInfo *info,
1327 const char *path,
1328 const char *root_dir,
1329 SearchFlags flags) {
1330
401017e0 1331 _cleanup_free_ char *target = NULL;
0ec0deaa
LP
1332 int r;
1333
401017e0 1334 r = unit_file_load(c, info, path, flags);
0ec0deaa
LP
1335 if (r != -ELOOP)
1336 return r;
1337
1338 /* This is a symlink, let's read it. */
1339
401017e0 1340 r = readlink_malloc(path, &target);
0ec0deaa
LP
1341 if (r < 0)
1342 return r;
1343
401017e0 1344 if (path_equal(target, "/dev/null"))
0ec0deaa
LP
1345 info->type = UNIT_FILE_TYPE_MASKED;
1346 else {
1347 const char *bn;
1348 UnitType a, b;
1349
401017e0 1350 bn = basename(target);
0ec0deaa
LP
1351
1352 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1353
1354 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1355 return -EINVAL;
1356
1357 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1358
1359 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1360 return -EINVAL;
1361
1362 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1363
1364 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1365 return -EINVAL;
1366 } else
1367 return -EINVAL;
1368
1369 /* Enforce that the symlink destination does not
1370 * change the unit file type. */
1371
1372 a = unit_name_to_type(info->name);
1373 b = unit_name_to_type(bn);
1374 if (a < 0 || b < 0 || a != b)
1375 return -EINVAL;
1376
401017e0
LP
1377 if (path_is_absolute(target))
1378 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1379 info->symlink_target = prefix_root(root_dir, target);
1380 else
1381 /* This is a relative path, take it relative to the dir the symlink is located in. */
1382 info->symlink_target = file_in_same_dir(path, target);
1383 if (!info->symlink_target)
1384 return -ENOMEM;
1385
0ec0deaa 1386 info->type = UNIT_FILE_TYPE_SYMLINK;
0ec0deaa
LP
1387 }
1388
1389 return 0;
1390}
1391
83096483
LP
1392static int unit_file_search(
1393 InstallContext *c,
cab6235f 1394 UnitFileInstallInfo *info,
a8ffe6fb 1395 const LookupPaths *paths,
0ec0deaa 1396 SearchFlags flags) {
83096483 1397
64f9280e 1398 _cleanup_free_ char *template = NULL;
142468d8 1399 _cleanup_strv_free_ char **dirs = NULL;
ff210466 1400 _cleanup_strv_free_ char **files = NULL;
142468d8
JL
1401 const char *dropin_dir_name = NULL;
1402 const char *dropin_template_dir_name = NULL;
1403
83096483
LP
1404 char **p;
1405 int r;
142468d8
JL
1406 int result;
1407 bool found_unit = false;
83096483 1408
83096483
LP
1409 assert(info);
1410 assert(paths);
1411
0ec0deaa
LP
1412 /* Was this unit already loaded? */
1413 if (info->type != _UNIT_FILE_TYPE_INVALID)
1414 return 0;
1415
278fa575 1416 if (info->path)
e4bb56c7 1417 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
83096483
LP
1418
1419 assert(info->name);
1420
142468d8
JL
1421 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1422 r = unit_name_template(info->name, &template);
1423 if (r < 0)
1424 return r;
1425 }
1426
a3c4eb07 1427 STRV_FOREACH(p, paths->search_path) {
e50bd775 1428 _cleanup_free_ char *path = NULL;
83096483 1429
605405c6 1430 path = strjoin(*p, "/", info->name);
83096483
LP
1431 if (!path)
1432 return -ENOMEM;
1433
e4bb56c7 1434 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
142468d8 1435
0155928c 1436 if (r >= 0) {
83096483 1437 info->path = path;
62b00233 1438 path = NULL;
142468d8
JL
1439 result = r;
1440 found_unit = true;
1441 break;
a1feacf7 1442 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
0155928c 1443 return r;
e50bd775 1444 }
62b00233 1445
142468d8
JL
1446 if (!found_unit && template) {
1447
e50bd775
LP
1448 /* Unit file doesn't exist, however instance
1449 * enablement was requested. We will check if it is
1450 * possible to load template unit file. */
29283ea4 1451
a3c4eb07 1452 STRV_FOREACH(p, paths->search_path) {
e50bd775
LP
1453 _cleanup_free_ char *path = NULL;
1454
605405c6 1455 path = strjoin(*p, "/", template);
62b00233
ZJS
1456 if (!path)
1457 return -ENOMEM;
29283ea4 1458
e4bb56c7 1459 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
0155928c 1460 if (r >= 0) {
62b00233
ZJS
1461 info->path = path;
1462 path = NULL;
142468d8
JL
1463 result = r;
1464 found_unit = true;
1465 break;
a1feacf7 1466 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
0155928c 1467 return r;
29283ea4 1468 }
83096483
LP
1469 }
1470
142468d8
JL
1471 if (!found_unit) {
1472 log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
1473 return -ENOENT;
1474 }
1475
1476 /* Search for drop-in directories */
1477
1478 dropin_dir_name = strjoina(info->name, ".d");
1479 STRV_FOREACH(p, paths->search_path) {
1480 char *path;
1481
1482 path = path_join(NULL, *p, dropin_dir_name);
1483 if (!path)
1484 return -ENOMEM;
1485
1486 r = strv_consume(&dirs, path);
1487 if (r < 0)
1488 return r;
1489 }
1490
1491 if (template) {
1492 dropin_template_dir_name = strjoina(template, ".d");
1493 STRV_FOREACH(p, paths->search_path) {
1494 char *path;
1495
1496 path = path_join(NULL, *p, dropin_template_dir_name);
1497 if (!path)
1498 return -ENOMEM;
1499
1500 r = strv_consume(&dirs, path);
1501 if (r < 0)
1502 return r;
1503 }
1504 }
1505
1506 /* Load drop-in conf files */
1507
1508 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) dirs);
1509 if (r < 0)
1510 return log_debug_errno(r, "Failed to get list of conf files: %m");
1511
1512 STRV_FOREACH(p, files) {
1513 r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags);
1514 if (r < 0)
1515 return log_debug_errno(r, "Failed to load conf file %s: %m", *p);
1516 }
1517
1518 return result;
83096483
LP
1519}
1520
0ec0deaa
LP
1521static int install_info_follow(
1522 InstallContext *c,
1523 UnitFileInstallInfo *i,
83096483 1524 const char *root_dir,
9f6cbcf5
LP
1525 SearchFlags flags,
1526 bool ignore_different_name) {
0ec0deaa
LP
1527
1528 assert(c);
1529 assert(i);
1530
1531 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1532 return -EINVAL;
1533 if (!i->symlink_target)
1534 return -EINVAL;
1535
1536 /* If the basename doesn't match, the caller should add a
1537 * complete new entry for this. */
1538
9f6cbcf5 1539 if (!ignore_different_name && !streq(basename(i->symlink_target), i->name))
0ec0deaa
LP
1540 return -EXDEV;
1541
3b319885 1542 free_and_replace(i->path, i->symlink_target);
0ec0deaa
LP
1543 i->type = _UNIT_FILE_TYPE_INVALID;
1544
1545 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1546}
1547
64f9280e 1548/**
ff56349d
ZJS
1549 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1550 * target, maybe more than once. Propagate the instance name if present.
64f9280e 1551 */
0ec0deaa
LP
1552static int install_info_traverse(
1553 UnitFileScope scope,
1554 InstallContext *c,
0ec0deaa
LP
1555 const LookupPaths *paths,
1556 UnitFileInstallInfo *start,
1557 SearchFlags flags,
1558 UnitFileInstallInfo **ret) {
83096483 1559
cab6235f 1560 UnitFileInstallInfo *i;
0ec0deaa 1561 unsigned k = 0;
83096483
LP
1562 int r;
1563
1564 assert(paths);
0ec0deaa
LP
1565 assert(start);
1566 assert(c);
83096483 1567
e4bb56c7 1568 r = unit_file_search(c, start, paths, flags);
83096483
LP
1569 if (r < 0)
1570 return r;
1571
0ec0deaa
LP
1572 i = start;
1573 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1574 /* Follow the symlink */
83096483 1575
0ec0deaa
LP
1576 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
1577 return -ELOOP;
83096483 1578
e1c5c2b0 1579 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
dfead90d 1580 r = path_is_config(paths, i->path, true);
e1c5c2b0
LP
1581 if (r < 0)
1582 return r;
1583 if (r > 0)
1584 return -ELOOP;
1585 }
83096483 1586
9f6cbcf5 1587 r = install_info_follow(c, i, paths->root_dir, flags, false);
0155928c 1588 if (r == -EXDEV) {
0ec0deaa
LP
1589 _cleanup_free_ char *buffer = NULL;
1590 const char *bn;
83096483 1591
0ec0deaa
LP
1592 /* Target has a different name, create a new
1593 * install info object for that, and continue
1594 * with that. */
83096483 1595
0ec0deaa 1596 bn = basename(i->symlink_target);
83096483 1597
0ec0deaa
LP
1598 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1599 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
83096483 1600
0ec0deaa
LP
1601 _cleanup_free_ char *instance = NULL;
1602
1603 r = unit_name_to_instance(i->name, &instance);
1604 if (r < 0)
1605 return r;
1606
1607 r = unit_name_replace_instance(bn, instance, &buffer);
1608 if (r < 0)
1609 return r;
1610
9f6cbcf5
LP
1611 if (streq(buffer, i->name)) {
1612
1613 /* We filled in the instance, and the target stayed the same? If so, then let's
1614 * honour the link as it is. */
1615
1616 r = install_info_follow(c, i, paths->root_dir, flags, true);
1617 if (r < 0)
1618 return r;
1619
1620 continue;
1621 }
1622
0ec0deaa
LP
1623 bn = buffer;
1624 }
1625
19539807 1626 r = install_info_add(c, bn, NULL, false, &i);
0ec0deaa
LP
1627 if (r < 0)
1628 return r;
1629
0155928c 1630 /* Try again, with the new target we found. */
e4bb56c7 1631 r = unit_file_search(c, i, paths, flags);
893275df
ZJS
1632 if (r == -ENOENT)
1633 /* Translate error code to highlight this specific case */
1634 return -ENOLINK;
0ec0deaa
LP
1635 }
1636
0155928c
ZJS
1637 if (r < 0)
1638 return r;
83096483
LP
1639 }
1640
0ec0deaa
LP
1641 if (ret)
1642 *ret = i;
83096483 1643
0ec0deaa
LP
1644 return 0;
1645}
83096483 1646
ff56349d
ZJS
1647/**
1648 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1649 * or the name (otherwise). root_dir is prepended to the path.
1650 */
401017e0
LP
1651static int install_info_add_auto(
1652 InstallContext *c,
1653 const LookupPaths *paths,
1654 const char *name_or_path,
1655 UnitFileInstallInfo **ret) {
1656
1657 assert(c);
1658 assert(name_or_path);
1659
1660 if (path_is_absolute(name_or_path)) {
1661 const char *pp;
1662
1663 pp = prefix_roota(paths->root_dir, name_or_path);
1664
19539807 1665 return install_info_add(c, NULL, pp, false, ret);
401017e0 1666 } else
19539807 1667 return install_info_add(c, name_or_path, NULL, false, ret);
401017e0
LP
1668}
1669
0ec0deaa
LP
1670static int install_info_discover(
1671 UnitFileScope scope,
1672 InstallContext *c,
0ec0deaa
LP
1673 const LookupPaths *paths,
1674 const char *name,
1675 SearchFlags flags,
59108fbe
ZJS
1676 UnitFileInstallInfo **ret,
1677 UnitFileChange **changes,
1678 unsigned *n_changes) {
83096483 1679
0ec0deaa
LP
1680 UnitFileInstallInfo *i;
1681 int r;
83096483 1682
0ec0deaa
LP
1683 assert(c);
1684 assert(paths);
1685 assert(name);
1686
401017e0 1687 r = install_info_add_auto(c, paths, name, &i);
59108fbe
ZJS
1688 if (r >= 0)
1689 r = install_info_traverse(scope, c, paths, i, flags, ret);
83096483 1690
59108fbe
ZJS
1691 if (r < 0)
1692 unit_file_changes_add(changes, n_changes, r, name, NULL);
1693 return r;
83096483
LP
1694}
1695
1696static int install_info_symlink_alias(
cab6235f 1697 UnitFileInstallInfo *i,
401017e0 1698 const LookupPaths *paths,
83096483
LP
1699 const char *config_path,
1700 bool force,
1701 UnitFileChange **changes,
1702 unsigned *n_changes) {
1703
1704 char **s;
1705 int r = 0, q;
1706
1707 assert(i);
401017e0 1708 assert(paths);
83096483
LP
1709 assert(config_path);
1710
1711 STRV_FOREACH(s, i->aliases) {
7fd1b19b 1712 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
83096483 1713
19f6d710
LP
1714 q = install_full_printf(i, *s, &dst);
1715 if (q < 0)
1716 return q;
83096483 1717
7584d236 1718 alias_path = path_make_absolute(dst, config_path);
83096483
LP
1719 if (!alias_path)
1720 return -ENOMEM;
1721
60bec8e4 1722 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
83096483
LP
1723 if (r == 0)
1724 r = q;
1725 }
1726
1727 return r;
1728}
1729
1730static int install_info_symlink_wants(
cab6235f 1731 UnitFileInstallInfo *i,
401017e0 1732 const LookupPaths *paths,
83096483 1733 const char *config_path,
d54c4993
LP
1734 char **list,
1735 const char *suffix,
83096483
LP
1736 UnitFileChange **changes,
1737 unsigned *n_changes) {
1738
d54c4993
LP
1739 _cleanup_free_ char *buf = NULL;
1740 const char *n;
83096483
LP
1741 char **s;
1742 int r = 0, q;
1743
1744 assert(i);
401017e0 1745 assert(paths);
83096483
LP
1746 assert(config_path);
1747
047d91f9
ZJS
1748 if (strv_isempty(list))
1749 return 0;
1750
be704916 1751 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE) && i->default_instance) {
047d91f9
ZJS
1752 UnitFileInstallInfo instance = {
1753 .type = _UNIT_FILE_TYPE_INVALID,
1754 };
1755 _cleanup_free_ char *path = NULL;
0a327d75 1756
7410616c
LP
1757 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1758 if (r < 0)
1759 return r;
83096483 1760
047d91f9
ZJS
1761 instance.name = buf;
1762 r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
1763 if (r < 0)
1764 return r;
1765
1766 path = instance.path;
1767 instance.path = NULL;
1768
1769 if (instance.type == UNIT_FILE_TYPE_MASKED) {
1770 unit_file_changes_add(changes, n_changes, -ERFKILL, path, NULL);
1771 return -ERFKILL;
1772 }
1773
d54c4993
LP
1774 n = buf;
1775 } else
1776 n = i->name;
78d54bd4 1777
d54c4993 1778 STRV_FOREACH(s, list) {
7fd1b19b 1779 _cleanup_free_ char *path = NULL, *dst = NULL;
78d54bd4 1780
19f6d710
LP
1781 q = install_full_printf(i, *s, &dst);
1782 if (q < 0)
1783 return q;
7584d236 1784
7410616c 1785 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
78d54bd4
LP
1786 r = -EINVAL;
1787 continue;
1788 }
1789
605405c6 1790 path = strjoin(config_path, "/", dst, suffix, n);
d54c4993 1791 if (!path)
78d54bd4
LP
1792 return -ENOMEM;
1793
60bec8e4 1794 q = create_symlink(paths, i->path, path, true, changes, n_changes);
78d54bd4
LP
1795 if (r == 0)
1796 r = q;
1797 }
1798
1799 return r;
1800}
1801
83096483 1802static int install_info_symlink_link(
cab6235f 1803 UnitFileInstallInfo *i,
a8ffe6fb 1804 const LookupPaths *paths,
83096483
LP
1805 const char *config_path,
1806 bool force,
1807 UnitFileChange **changes,
1808 unsigned *n_changes) {
1809
7fd1b19b 1810 _cleanup_free_ char *path = NULL;
1dacfd2a 1811 int r;
83096483
LP
1812
1813 assert(i);
1814 assert(paths);
1815 assert(config_path);
1816 assert(i->path);
1817
32c0ed7b 1818 r = in_search_path(paths, i->path);
fe4aede9 1819 if (r < 0)
83096483 1820 return r;
fe4aede9
ZJS
1821 if (r > 0)
1822 return 0;
83096483 1823
605405c6 1824 path = strjoin(config_path, "/", i->name);
1dacfd2a 1825 if (!path)
83096483
LP
1826 return -ENOMEM;
1827
60bec8e4 1828 return create_symlink(paths, i->path, path, force, changes, n_changes);
83096483
LP
1829}
1830
1831static int install_info_apply(
cab6235f 1832 UnitFileInstallInfo *i,
a8ffe6fb 1833 const LookupPaths *paths,
83096483
LP
1834 const char *config_path,
1835 bool force,
1836 UnitFileChange **changes,
1837 unsigned *n_changes) {
1838
1839 int r, q;
1840
1841 assert(i);
1842 assert(paths);
1843 assert(config_path);
1844
0ec0deaa
LP
1845 if (i->type != UNIT_FILE_TYPE_REGULAR)
1846 return 0;
1847
401017e0 1848 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
83096483 1849
29380daf 1850 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
83096483
LP
1851 if (r == 0)
1852 r = q;
1853
29380daf 1854 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
78d54bd4
LP
1855 if (r == 0)
1856 r = q;
1857
e4bb56c7 1858 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
fe4aede9
ZJS
1859 /* Do not count links to the unit file towards the "carries_install_info" count */
1860 if (r == 0 && q < 0)
83096483
LP
1861 r = q;
1862
1863 return r;
1864}
1865
1866static int install_context_apply(
0ec0deaa 1867 UnitFileScope scope,
83096483 1868 InstallContext *c,
a8ffe6fb 1869 const LookupPaths *paths,
83096483 1870 const char *config_path,
83096483 1871 bool force,
0ec0deaa 1872 SearchFlags flags,
83096483
LP
1873 UnitFileChange **changes,
1874 unsigned *n_changes) {
1875
cab6235f 1876 UnitFileInstallInfo *i;
0ec0deaa 1877 int r;
83096483
LP
1878
1879 assert(c);
1880 assert(paths);
1881 assert(config_path);
1882
0ec0deaa 1883 if (ordered_hashmap_isempty(c->will_process))
d25e100b 1884 return 0;
83096483 1885
0ec0deaa 1886 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
d25e100b
LP
1887 if (r < 0)
1888 return r;
83096483 1889
2d5c93c7 1890 r = 0;
0ec0deaa
LP
1891 while ((i = ordered_hashmap_first(c->will_process))) {
1892 int q;
83096483 1893
0ec0deaa
LP
1894 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1895 if (q < 0)
1896 return q;
83096483 1897
e4bb56c7 1898 r = install_info_traverse(scope, c, paths, i, flags, NULL);
db093eed
ZJS
1899 if (r < 0) {
1900 unit_file_changes_add(changes, n_changes, r, i->name, NULL);
83096483 1901 return r;
db093eed 1902 }
0ec0deaa 1903
f1651715 1904 /* We can attempt to process a masked unit when a different unit
047d91f9 1905 * that we were processing specifies it in Also=. */
f1651715
ZJS
1906 if (i->type == UNIT_FILE_TYPE_MASKED) {
1907 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL);
1908 if (r >= 0)
047d91f9
ZJS
1909 /* Assume that something *could* have been enabled here,
1910 * avoid "empty [Install] section" warning. */
f1651715
ZJS
1911 r += 1;
1912 continue;
1913 }
1914
0ec0deaa
LP
1915 if (i->type != UNIT_FILE_TYPE_REGULAR)
1916 continue;
83096483 1917
e4bb56c7 1918 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
0ec0deaa
LP
1919 if (r >= 0) {
1920 if (q < 0)
1921 r = q;
1922 else
596fc263 1923 r += q;
0ec0deaa 1924 }
83096483
LP
1925 }
1926
1927 return r;
1928}
1929
1930static int install_context_mark_for_removal(
0ec0deaa 1931 UnitFileScope scope,
83096483 1932 InstallContext *c,
a8ffe6fb 1933 const LookupPaths *paths,
83096483 1934 Set **remove_symlinks_to,
637d6e5b
LP
1935 const char *config_path,
1936 UnitFileChange **changes,
1937 unsigned *n_changes) {
83096483 1938
cab6235f 1939 UnitFileInstallInfo *i;
0ec0deaa 1940 int r;
83096483
LP
1941
1942 assert(c);
1943 assert(paths);
1944 assert(config_path);
1945
1946 /* Marks all items for removal */
1947
0ec0deaa 1948 if (ordered_hashmap_isempty(c->will_process))
d25e100b 1949 return 0;
83096483 1950
0ec0deaa 1951 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
d25e100b
LP
1952 if (r < 0)
1953 return r;
83096483 1954
0ec0deaa 1955 while ((i = ordered_hashmap_first(c->will_process))) {
83096483 1956
0ec0deaa
LP
1957 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1958 if (r < 0)
83096483 1959 return r;
29283ea4 1960
e4bb56c7 1961 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
19539807 1962 if (r == -ENOLINK) {
637d6e5b
LP
1963 log_debug_errno(r, "Name %s leads to a dangling symlink, removing name.", i->name);
1964 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_DANGLING, i->path ?: i->name, NULL);
1965 } else if (r == -ENOENT) {
1966
1967 if (i->auxiliary) /* some unit specified in Also= or similar is missing */
1968 log_debug_errno(r, "Auxiliary unit of %s not found, removing name.", i->name);
1969 else {
1970 log_debug_errno(r, "Unit %s not found, removing name.", i->name);
1971 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
1972 }
0ec0deaa 1973
637d6e5b
LP
1974 } else if (r < 0) {
1975 log_debug_errno(r, "Failed to find unit %s, removing name: %m", i->name);
1976 unit_file_changes_add(changes, n_changes, r, i->path ?: i->name, NULL);
1977 } else if (i->type == UNIT_FILE_TYPE_MASKED) {
1978 log_debug("Unit file %s is masked, ignoring.", i->name);
1979 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path ?: i->name, NULL);
1980 continue;
1981 } else if (i->type != UNIT_FILE_TYPE_REGULAR) {
1982 log_debug("Unit %s has type %s, ignoring.", i->name, unit_file_type_to_string(i->type) ?: "invalid");
0ec0deaa 1983 continue;
64f9280e 1984 }
0ec0deaa
LP
1985
1986 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1987 if (r < 0)
1988 return r;
1989 }
1990
1991 return 0;
1992}
1993
1994int unit_file_mask(
1995 UnitFileScope scope,
b3796dd8 1996 UnitFileFlags flags,
0ec0deaa
LP
1997 const char *root_dir,
1998 char **files,
0ec0deaa
LP
1999 UnitFileChange **changes,
2000 unsigned *n_changes) {
2001
e1c5c2b0
LP
2002 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2003 const char *config_path;
0ec0deaa
LP
2004 char **i;
2005 int r;
2006
2007 assert(scope >= 0);
2008 assert(scope < _UNIT_FILE_SCOPE_MAX);
2009
4943d143 2010 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2011 if (r < 0)
2012 return r;
2013
b3796dd8 2014 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2015 if (!config_path)
2016 return -ENXIO;
e1c5c2b0 2017
0ec0deaa
LP
2018 STRV_FOREACH(i, files) {
2019 _cleanup_free_ char *path = NULL;
2020 int q;
2021
2022 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
2023 if (r == 0)
2024 r = -EINVAL;
2025 continue;
2026 }
2027
e1c5c2b0 2028 path = path_make_absolute(*i, config_path);
0ec0deaa
LP
2029 if (!path)
2030 return -ENOMEM;
29283ea4 2031
b3796dd8 2032 q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
0ec0deaa 2033 if (q < 0 && r >= 0)
83096483
LP
2034 r = q;
2035 }
2036
2037 return r;
2038}
2039
0ec0deaa
LP
2040int unit_file_unmask(
2041 UnitFileScope scope,
b3796dd8 2042 UnitFileFlags flags,
0ec0deaa
LP
2043 const char *root_dir,
2044 char **files,
2045 UnitFileChange **changes,
2046 unsigned *n_changes) {
2047
e1c5c2b0 2048 _cleanup_lookup_paths_free_ LookupPaths paths = {};
0ec0deaa 2049 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
dc7dd61d 2050 _cleanup_strv_free_ char **todo = NULL;
0ec0deaa 2051 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 2052 const char *config_path;
0ec0deaa 2053 char **i;
3b3557c4 2054 bool dry_run;
0ec0deaa
LP
2055 int r, q;
2056
2057 assert(scope >= 0);
2058 assert(scope < _UNIT_FILE_SCOPE_MAX);
2059
4943d143 2060 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2061 if (r < 0)
2062 return r;
2063
b3796dd8 2064 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2065 if (!config_path)
2066 return -ENXIO;
2067
3b3557c4 2068 dry_run = !!(flags & UNIT_FILE_DRY_RUN);
e1c5c2b0 2069
0ec0deaa
LP
2070 STRV_FOREACH(i, files) {
2071 _cleanup_free_ char *path = NULL;
2072
2073 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2074 return -EINVAL;
2075
2076 path = path_make_absolute(*i, config_path);
2077 if (!path)
2078 return -ENOMEM;
2079
2080 r = null_or_empty_path(path);
2081 if (r == -ENOENT)
2082 continue;
2083 if (r < 0)
2084 return r;
2085 if (r == 0)
2086 continue;
2087
2088 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2089 return -ENOMEM;
2090
d054eae6
EV
2091 todo[n_todo] = strdup(*i);
2092 if (!todo[n_todo])
2093 return -ENOMEM;
2094
2095 n_todo++;
0ec0deaa
LP
2096 }
2097
2098 strv_uniq(todo);
2099
2100 r = 0;
2101 STRV_FOREACH(i, todo) {
2102 _cleanup_free_ char *path = NULL;
401017e0 2103 const char *rp;
0ec0deaa
LP
2104
2105 path = path_make_absolute(*i, config_path);
2106 if (!path)
2107 return -ENOMEM;
2108
3b3557c4 2109 if (!dry_run && unlink(path) < 0) {
af3d8113
ZJS
2110 if (errno != ENOENT) {
2111 if (r >= 0)
2112 r = -errno;
2113 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
2114 }
0ec0deaa 2115
401017e0 2116 continue;
0ec0deaa 2117 }
401017e0
LP
2118
2119 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
2120
2121 rp = skip_root(&paths, path);
2122 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
2123 if (q < 0)
2124 return q;
0ec0deaa
LP
2125 }
2126
3b3557c4 2127 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
0ec0deaa
LP
2128 if (r >= 0)
2129 r = q;
2130
2131 return r;
2132}
2133
2134int unit_file_link(
e94937df 2135 UnitFileScope scope,
b3796dd8 2136 UnitFileFlags flags,
e94937df
LN
2137 const char *root_dir,
2138 char **files,
e94937df
LN
2139 UnitFileChange **changes,
2140 unsigned *n_changes) {
2141
2142 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8af35ba6 2143 _cleanup_strv_free_ char **todo = NULL;
0ec0deaa 2144 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 2145 const char *config_path;
e94937df 2146 char **i;
0ec0deaa 2147 int r, q;
e94937df
LN
2148
2149 assert(scope >= 0);
2150 assert(scope < _UNIT_FILE_SCOPE_MAX);
2151
4943d143 2152 r = lookup_paths_init(&paths, scope, 0, root_dir);
e94937df
LN
2153 if (r < 0)
2154 return r;
2155
b3796dd8 2156 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2157 if (!config_path)
2158 return -ENXIO;
e94937df
LN
2159
2160 STRV_FOREACH(i, files) {
0ec0deaa
LP
2161 _cleanup_free_ char *full = NULL;
2162 struct stat st;
2163 char *fn;
e94937df 2164
0ec0deaa
LP
2165 if (!path_is_absolute(*i))
2166 return -EINVAL;
e94937df 2167
0ec0deaa
LP
2168 fn = basename(*i);
2169 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
2170 return -EINVAL;
2171
e4bb56c7 2172 full = prefix_root(paths.root_dir, *i);
0ec0deaa
LP
2173 if (!full)
2174 return -ENOMEM;
2175
2176 if (lstat(full, &st) < 0)
2177 return -errno;
2178 if (S_ISLNK(st.st_mode))
2179 return -ELOOP;
2180 if (S_ISDIR(st.st_mode))
2181 return -EISDIR;
2182 if (!S_ISREG(st.st_mode))
2183 return -ENOTTY;
2184
32c0ed7b 2185 q = in_search_path(&paths, *i);
0ec0deaa
LP
2186 if (q < 0)
2187 return q;
2188 if (q > 0)
2189 continue;
2190
2191 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2192 return -ENOMEM;
2193
8af35ba6
EV
2194 todo[n_todo] = strdup(*i);
2195 if (!todo[n_todo])
2196 return -ENOMEM;
2197
2198 n_todo++;
e94937df
LN
2199 }
2200
0ec0deaa 2201 strv_uniq(todo);
e94937df 2202
0ec0deaa
LP
2203 r = 0;
2204 STRV_FOREACH(i, todo) {
401017e0 2205 _cleanup_free_ char *new_path = NULL;
0ec0deaa 2206
401017e0
LP
2207 new_path = path_make_absolute(basename(*i), config_path);
2208 if (!new_path)
0ec0deaa
LP
2209 return -ENOMEM;
2210
b3796dd8 2211 q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
0ec0deaa
LP
2212 if (q < 0 && r >= 0)
2213 r = q;
2d5c93c7
MS
2214 }
2215
0ec0deaa
LP
2216 return r;
2217}
2218
344ca755
LP
2219static int path_shall_revert(const LookupPaths *paths, const char *path) {
2220 int r;
2221
2222 assert(paths);
2223 assert(path);
2224
2225 /* Checks whether the path is one where the drop-in directories shall be removed. */
2226
dfead90d 2227 r = path_is_config(paths, path, true);
344ca755
LP
2228 if (r != 0)
2229 return r;
2230
2231 r = path_is_control(paths, path);
2232 if (r != 0)
2233 return r;
2234
2235 return path_is_transient(paths, path);
2236}
2237
2238int unit_file_revert(
2239 UnitFileScope scope,
2240 const char *root_dir,
2241 char **files,
2242 UnitFileChange **changes,
2243 unsigned *n_changes) {
2244
2245 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
344ca755
LP
2246 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2247 _cleanup_strv_free_ char **todo = NULL;
2248 size_t n_todo = 0, n_allocated = 0;
2249 char **i;
2250 int r, q;
2251
2252 /* Puts a unit file back into vendor state. This means:
2253 *
2254 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2255 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2256 *
2257 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2258 * "config", but not in "transient" or "control" or even "generated").
2259 *
4f25723c 2260 * We remove all that in both the runtime and the persistent directories, if that applies.
344ca755
LP
2261 */
2262
2263 r = lookup_paths_init(&paths, scope, 0, root_dir);
2264 if (r < 0)
2265 return r;
2266
2267 STRV_FOREACH(i, files) {
2268 bool has_vendor = false;
2269 char **p;
2270
2271 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2272 return -EINVAL;
2273
2274 STRV_FOREACH(p, paths.search_path) {
2275 _cleanup_free_ char *path = NULL, *dropin = NULL;
2276 struct stat st;
2277
2278 path = path_make_absolute(*i, *p);
2279 if (!path)
2280 return -ENOMEM;
2281
2282 r = lstat(path, &st);
2283 if (r < 0) {
2284 if (errno != ENOENT)
2285 return -errno;
2286 } else if (S_ISREG(st.st_mode)) {
2287 /* Check if there's a vendor version */
2288 r = path_is_vendor(&paths, path);
2289 if (r < 0)
2290 return r;
2291 if (r > 0)
2292 has_vendor = true;
2293 }
2294
2295 dropin = strappend(path, ".d");
2296 if (!dropin)
2297 return -ENOMEM;
2298
2299 r = lstat(dropin, &st);
2300 if (r < 0) {
2301 if (errno != ENOENT)
2302 return -errno;
2303 } else if (S_ISDIR(st.st_mode)) {
2304 /* Remove the drop-ins */
2305 r = path_shall_revert(&paths, dropin);
2306 if (r < 0)
2307 return r;
2308 if (r > 0) {
2309 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2310 return -ENOMEM;
2311
2312 todo[n_todo++] = dropin;
2313 dropin = NULL;
2314 }
2315 }
2316 }
2317
2318 if (!has_vendor)
2319 continue;
2320
2321 /* OK, there's a vendor version, hence drop all configuration versions */
2322 STRV_FOREACH(p, paths.search_path) {
2323 _cleanup_free_ char *path = NULL;
2324 struct stat st;
2325
2326 path = path_make_absolute(*i, *p);
2327 if (!path)
2328 return -ENOMEM;
2329
2330 r = lstat(path, &st);
2331 if (r < 0) {
2332 if (errno != ENOENT)
2333 return -errno;
2334 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
dfead90d 2335 r = path_is_config(&paths, path, true);
344ca755
LP
2336 if (r < 0)
2337 return r;
2338 if (r > 0) {
2339 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2340 return -ENOMEM;
2341
2342 todo[n_todo++] = path;
2343 path = NULL;
2344 }
2345 }
2346 }
2347 }
2348
2349 strv_uniq(todo);
2350
2351 r = 0;
2352 STRV_FOREACH(i, todo) {
2353 _cleanup_strv_free_ char **fs = NULL;
2354 const char *rp;
2355 char **j;
2356
2357 (void) get_files_in_directory(*i, &fs);
2358
2359 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2360 if (q < 0 && q != -ENOENT && r >= 0) {
2361 r = q;
2362 continue;
2363 }
2364
2365 STRV_FOREACH(j, fs) {
2366 _cleanup_free_ char *t = NULL;
2367
605405c6 2368 t = strjoin(*i, "/", *j);
344ca755
LP
2369 if (!t)
2370 return -ENOMEM;
2371
2372 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
2373 }
2374
2375 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
2376
2377 rp = skip_root(&paths, *i);
2378 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2379 if (q < 0)
2380 return q;
2381 }
2382
3b3557c4 2383 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes);
344ca755
LP
2384 if (r >= 0)
2385 r = q;
2386
3b3557c4 2387 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes);
344ca755
LP
2388 if (r >= 0)
2389 r = q;
2390
2391 return r;
2392}
2393
0ec0deaa
LP
2394int unit_file_add_dependency(
2395 UnitFileScope scope,
b3796dd8 2396 UnitFileFlags flags,
0ec0deaa
LP
2397 const char *root_dir,
2398 char **files,
2399 const char *target,
2400 UnitDependency dep,
0ec0deaa
LP
2401 UnitFileChange **changes,
2402 unsigned *n_changes) {
2403
2404 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2405 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2406 UnitFileInstallInfo *i, *target_info;
e1c5c2b0 2407 const char *config_path;
0ec0deaa
LP
2408 char **f;
2409 int r;
2410
2411 assert(scope >= 0);
2412 assert(scope < _UNIT_FILE_SCOPE_MAX);
2413 assert(target);
2414
2415 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
2416 return -EINVAL;
2417
2418 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2419 return -EINVAL;
2420
4943d143 2421 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2422 if (r < 0)
2423 return r;
2424
b3796dd8 2425 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2426 if (!config_path)
2427 return -ENXIO;
0ec0deaa 2428
59108fbe
ZJS
2429 r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2430 &target_info, changes, n_changes);
0ec0deaa
LP
2431 if (r < 0)
2432 return r;
af3d8113 2433 r = install_info_may_process(target_info, &paths, changes, n_changes);
76adb5b8
LP
2434 if (r < 0)
2435 return r;
0ec0deaa
LP
2436
2437 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
e94937df 2438
0ec0deaa
LP
2439 STRV_FOREACH(f, files) {
2440 char ***l;
2441
59108fbe
ZJS
2442 r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2443 &i, changes, n_changes);
e94937df
LN
2444 if (r < 0)
2445 return r;
af3d8113 2446 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2447 if (r < 0)
2448 return r;
0ec0deaa
LP
2449
2450 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2451
2452 /* We didn't actually load anything from the unit
2453 * file, but instead just add in our new symlink to
2454 * create. */
e94937df
LN
2455
2456 if (dep == UNIT_WANTS)
0ec0deaa 2457 l = &i->wanted_by;
e94937df 2458 else
0ec0deaa 2459 l = &i->required_by;
e94937df 2460
0ec0deaa
LP
2461 strv_free(*l);
2462 *l = strv_new(target_info->name, NULL);
2463 if (!*l)
2464 return -ENOMEM;
e94937df
LN
2465 }
2466
b3796dd8 2467 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
e94937df
LN
2468}
2469
83096483
LP
2470int unit_file_enable(
2471 UnitFileScope scope,
b3796dd8 2472 UnitFileFlags flags,
83096483 2473 const char *root_dir,
7195aa42 2474 char **files,
83096483
LP
2475 UnitFileChange **changes,
2476 unsigned *n_changes) {
2477
7fd1b19b 2478 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2479 _cleanup_(install_context_done) InstallContext c = {};
e1c5c2b0 2480 const char *config_path;
0ec0deaa
LP
2481 UnitFileInstallInfo *i;
2482 char **f;
83096483
LP
2483 int r;
2484
2485 assert(scope >= 0);
2486 assert(scope < _UNIT_FILE_SCOPE_MAX);
2487
4943d143 2488 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2489 if (r < 0)
2490 return r;
2491
b3796dd8 2492 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2493 if (!config_path)
2494 return -ENXIO;
83096483 2495
0ec0deaa 2496 STRV_FOREACH(f, files) {
59108fbe
ZJS
2497 r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2498 &i, changes, n_changes);
83096483 2499 if (r < 0)
d9e5e694 2500 return r;
af3d8113 2501 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2502 if (r < 0)
2503 return r;
0ec0deaa
LP
2504
2505 assert(i->type == UNIT_FILE_TYPE_REGULAR);
83096483
LP
2506 }
2507
729e3769 2508 /* This will return the number of symlink rules that were
d25e100b
LP
2509 supposed to be created, not the ones actually created. This
2510 is useful to determine whether the passed files had any
2511 installation data at all. */
b91a3b02 2512
b3796dd8 2513 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
83096483
LP
2514}
2515
2516int unit_file_disable(
2517 UnitFileScope scope,
b3796dd8 2518 UnitFileFlags flags,
83096483 2519 const char *root_dir,
7195aa42 2520 char **files,
83096483
LP
2521 UnitFileChange **changes,
2522 unsigned *n_changes) {
2523
7fd1b19b 2524 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2525 _cleanup_(install_context_done) InstallContext c = {};
7fd1b19b 2526 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
e1c5c2b0 2527 const char *config_path;
0ec0deaa
LP
2528 char **i;
2529 int r;
83096483
LP
2530
2531 assert(scope >= 0);
2532 assert(scope < _UNIT_FILE_SCOPE_MAX);
2533
4943d143 2534 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2535 if (r < 0)
2536 return r;
2537
b3796dd8 2538 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
2539 if (!config_path)
2540 return -ENXIO;
83096483
LP
2541
2542 STRV_FOREACH(i, files) {
0ec0deaa
LP
2543 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2544 return -EINVAL;
2545
19539807 2546 r = install_info_add(&c, *i, NULL, false, NULL);
83096483 2547 if (r < 0)
d9e5e694 2548 return r;
83096483
LP
2549 }
2550
637d6e5b 2551 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
0ec0deaa
LP
2552 if (r < 0)
2553 return r;
83096483 2554
3b3557c4 2555 return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
83096483
LP
2556}
2557
2558int unit_file_reenable(
2559 UnitFileScope scope,
b3796dd8 2560 UnitFileFlags flags,
83096483 2561 const char *root_dir,
7195aa42 2562 char **files,
83096483
LP
2563 UnitFileChange **changes,
2564 unsigned *n_changes) {
0ec0deaa
LP
2565
2566 char **n;
92d430a9 2567 int r;
0ec0deaa 2568 size_t l, i;
83096483 2569
0ec0deaa
LP
2570 /* First, we invoke the disable command with only the basename... */
2571 l = strv_length(files);
2572 n = newa(char*, l+1);
2573 for (i = 0; i < l; i++)
2574 n[i] = basename(files[i]);
2575 n[i] = NULL;
2576
b3796dd8 2577 r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
83096483 2578 if (r < 0)
d9e5e694 2579 return r;
83096483 2580
0ec0deaa 2581 /* But the enable command with the full name */
b3796dd8 2582 return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
83096483
LP
2583}
2584
99504dd4
VP
2585int unit_file_set_default(
2586 UnitFileScope scope,
b3796dd8 2587 UnitFileFlags flags,
99504dd4 2588 const char *root_dir,
0ec0deaa 2589 const char *name,
99504dd4
VP
2590 UnitFileChange **changes,
2591 unsigned *n_changes) {
2592
2593 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2594 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2595 UnitFileInstallInfo *i;
60bec8e4 2596 const char *new_path;
99504dd4 2597 int r;
99504dd4
VP
2598
2599 assert(scope >= 0);
2600 assert(scope < _UNIT_FILE_SCOPE_MAX);
0ec0deaa 2601 assert(name);
99504dd4 2602
401017e0 2603 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
0ec0deaa
LP
2604 return -EINVAL;
2605 if (streq(name, SPECIAL_DEFAULT_TARGET))
99504dd4
VP
2606 return -EINVAL;
2607
4943d143 2608 r = lookup_paths_init(&paths, scope, 0, root_dir);
99504dd4
VP
2609 if (r < 0)
2610 return r;
2611
59108fbe 2612 r = install_info_discover(scope, &c, &paths, name, 0, &i, changes, n_changes);
99504dd4
VP
2613 if (r < 0)
2614 return r;
af3d8113 2615 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2616 if (r < 0)
2617 return r;
99504dd4 2618
401017e0 2619 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
b3796dd8 2620 return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
99504dd4
VP
2621}
2622
2623int unit_file_get_default(
2624 UnitFileScope scope,
2625 const char *root_dir,
2626 char **name) {
2627
2628 _cleanup_lookup_paths_free_ LookupPaths paths = {};
0ec0deaa
LP
2629 _cleanup_(install_context_done) InstallContext c = {};
2630 UnitFileInstallInfo *i;
2631 char *n;
99504dd4
VP
2632 int r;
2633
16ed0233
LP
2634 assert(scope >= 0);
2635 assert(scope < _UNIT_FILE_SCOPE_MAX);
2636 assert(name);
2637
4943d143 2638 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2639 if (r < 0)
2640 return r;
99504dd4 2641
59108fbe
ZJS
2642 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2643 &i, NULL, NULL);
0ec0deaa
LP
2644 if (r < 0)
2645 return r;
af3d8113 2646 r = install_info_may_process(i, &paths, NULL, 0);
76adb5b8
LP
2647 if (r < 0)
2648 return r;
99504dd4 2649
0ec0deaa
LP
2650 n = strdup(i->name);
2651 if (!n)
2652 return -ENOMEM;
99504dd4 2653
0ec0deaa
LP
2654 *name = n;
2655 return 0;
99504dd4
VP
2656}
2657
2c52204c 2658static int unit_file_lookup_state(
83096483 2659 UnitFileScope scope,
a8ffe6fb 2660 const LookupPaths *paths,
0ec0deaa
LP
2661 const char *name,
2662 UnitFileState *ret) {
83096483 2663
0ec0deaa
LP
2664 _cleanup_(install_context_done) InstallContext c = {};
2665 UnitFileInstallInfo *i;
2666 UnitFileState state;
2667 int r;
83096483 2668
a8ffe6fb 2669 assert(paths);
0ec0deaa 2670 assert(name);
83096483 2671
7410616c 2672 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
83096483
LP
2673 return -EINVAL;
2674
59108fbe
ZJS
2675 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2676 &i, NULL, NULL);
0ec0deaa
LP
2677 if (r < 0)
2678 return r;
83096483 2679
0ec0deaa
LP
2680 /* Shortcut things, if the caller just wants to know if this unit exists. */
2681 if (!ret)
2682 return 0;
83096483 2683
0ec0deaa 2684 switch (i->type) {
67820a0c 2685
0ec0deaa 2686 case UNIT_FILE_TYPE_MASKED:
dfead90d 2687 r = path_is_runtime(paths, i->path, true);
385eb996
LP
2688 if (r < 0)
2689 return r;
2690
2691 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
0ec0deaa 2692 break;
83096483 2693
0ec0deaa 2694 case UNIT_FILE_TYPE_REGULAR:
f4dc1e65 2695 r = path_is_generator(paths, i->path);
f4139308
LP
2696 if (r < 0)
2697 return r;
2698 if (r > 0) {
2699 state = UNIT_FILE_GENERATED;
2700 break;
2701 }
2702
e4fca67f
LP
2703 r = path_is_transient(paths, i->path);
2704 if (r < 0)
2705 return r;
2706 if (r > 0) {
2707 state = UNIT_FILE_TRANSIENT;
2708 break;
2709 }
2710
5cd8ae31
ZJS
2711 /* Check if any of the Alias= symlinks have been created.
2712 * We ignore other aliases, and only check those that would
2713 * be created by systemctl enable for this unit. */
d2561cfd 2714 r = find_symlinks_in_scope(scope, paths, i, true, &state);
d9b4b48f
ZJS
2715 if (r < 0)
2716 return r;
2717 if (r > 0)
2718 break;
2719
2720 /* Check if the file is known under other names. If it is,
2721 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
d2561cfd 2722 r = find_symlinks_in_scope(scope, paths, i, false, &state);
d9e5e694
ZJS
2723 if (r < 0)
2724 return r;
d9b4b48f
ZJS
2725 if (r > 0)
2726 state = UNIT_FILE_INDIRECT;
2727 else {
7a7ec2bf 2728 if (unit_file_install_info_has_rules(i))
0ec0deaa 2729 state = UNIT_FILE_DISABLED;
7a7ec2bf 2730 else if (unit_file_install_info_has_also(i))
0ec0deaa
LP
2731 state = UNIT_FILE_INDIRECT;
2732 else
2733 state = UNIT_FILE_STATIC;
2734 }
83096483 2735
0ec0deaa
LP
2736 break;
2737
2738 default:
2739 assert_not_reached("Unexpect unit file type.");
83096483
LP
2740 }
2741
0ec0deaa
LP
2742 *ret = state;
2743 return 0;
83096483
LP
2744}
2745
0ec0deaa 2746int unit_file_get_state(
a8ffe6fb
ZJS
2747 UnitFileScope scope,
2748 const char *root_dir,
0ec0deaa
LP
2749 const char *name,
2750 UnitFileState *ret) {
a8ffe6fb
ZJS
2751
2752 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2753 int r;
2754
2755 assert(scope >= 0);
2756 assert(scope < _UNIT_FILE_SCOPE_MAX);
2757 assert(name);
2758
4943d143 2759 r = lookup_paths_init(&paths, scope, 0, root_dir);
a8ffe6fb
ZJS
2760 if (r < 0)
2761 return r;
2762
e4bb56c7 2763 return unit_file_lookup_state(scope, &paths, name, ret);
a8ffe6fb
ZJS
2764}
2765
e735decc
LP
2766int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2767 _cleanup_(install_context_done) InstallContext c = {};
2768 int r;
2769
2770 assert(paths);
2771 assert(name);
2772
2773 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2774 return -EINVAL;
2775
59108fbe 2776 r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
e735decc
LP
2777 if (r == -ENOENT)
2778 return 0;
2779 if (r < 0)
2780 return r;
2781
2782 return 1;
2783}
2784
8965d9f8
AC
2785static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2786 _cleanup_(presets_freep) Presets ps = {};
2787 size_t n_allocated = 0;
7fd1b19b 2788 _cleanup_strv_free_ char **files = NULL;
cba2ef02 2789 char **p;
83096483
LP
2790 int r;
2791
2792 assert(scope >= 0);
2793 assert(scope < _UNIT_FILE_SCOPE_MAX);
8965d9f8 2794 assert(presets);
0ec0deaa 2795
83096483 2796 if (scope == UNIT_FILE_SYSTEM)
b5084605 2797 r = conf_files_list(&files, ".preset", root_dir, 0,
a7480dba
LP
2798 "/etc/systemd/system-preset",
2799 "/usr/local/lib/systemd/system-preset",
2800 "/usr/lib/systemd/system-preset",
349cc4a5 2801#if HAVE_SPLIT_USR
a7480dba 2802 "/lib/systemd/system-preset",
b4bdfefa 2803#endif
83096483
LP
2804 NULL);
2805 else if (scope == UNIT_FILE_GLOBAL)
b5084605 2806 r = conf_files_list(&files, ".preset", root_dir, 0,
a7480dba
LP
2807 "/etc/systemd/user-preset",
2808 "/usr/local/lib/systemd/user-preset",
2809 "/usr/lib/systemd/user-preset",
83096483 2810 NULL);
8965d9f8
AC
2811 else {
2812 *presets = (Presets){};
2813
2814 return 0;
2815 }
83096483
LP
2816
2817 if (r < 0)
2818 return r;
2819
cba2ef02 2820 STRV_FOREACH(p, files) {
7fd1b19b 2821 _cleanup_fclose_ FILE *f;
0ec0deaa 2822 char line[LINE_MAX];
d544d1a4 2823 int n = 0;
83096483 2824
cba2ef02 2825 f = fopen(*p, "re");
83096483
LP
2826 if (!f) {
2827 if (errno == ENOENT)
2828 continue;
2829
d9e5e694 2830 return -errno;
83096483
LP
2831 }
2832
0ec0deaa 2833 FOREACH_LINE(line, f, return -errno) {
8965d9f8 2834 PresetRule rule = {};
0ec0deaa
LP
2835 const char *parameter;
2836 char *l;
83096483
LP
2837
2838 l = strstrip(line);
d544d1a4 2839 n++;
83096483 2840
0ec0deaa
LP
2841 if (isempty(l))
2842 continue;
2843 if (strchr(COMMENTS, *l))
83096483
LP
2844 continue;
2845
0ec0deaa
LP
2846 parameter = first_word(l, "enable");
2847 if (parameter) {
8965d9f8 2848 char *pattern;
d9e5e694 2849
8965d9f8
AC
2850 pattern = strdup(parameter);
2851 if (!pattern)
2852 return -ENOMEM;
2853
2854 rule = (PresetRule) {
2855 .pattern = pattern,
2856 .action = PRESET_ENABLE,
2857 };
0ec0deaa 2858 }
83096483 2859
0ec0deaa
LP
2860 parameter = first_word(l, "disable");
2861 if (parameter) {
8965d9f8 2862 char *pattern;
d9e5e694 2863
8965d9f8
AC
2864 pattern = strdup(parameter);
2865 if (!pattern)
2866 return -ENOMEM;
2867
2868 rule = (PresetRule) {
2869 .pattern = pattern,
2870 .action = PRESET_DISABLE,
2871 };
2872 }
2873
2874 if (rule.action) {
2875 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
2876 return -ENOMEM;
2877
2878 ps.rules[ps.n_rules++] = rule;
0ec0deaa
LP
2879 continue;
2880 }
2881
d544d1a4 2882 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
83096483 2883 }
83096483
LP
2884 }
2885
8965d9f8
AC
2886 *presets = ps;
2887 ps = (Presets){};
2888
2889 return 0;
2890}
2891
2892static int query_presets(const char *name, const Presets presets) {
2893 PresetAction action = PRESET_UNKNOWN;
2894 size_t i;
2895
2896 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2897 return -EINVAL;
2898
2899 for (i = 0; i < presets.n_rules; i++)
2900 if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
2901 action = presets.rules[i].action;
2902 break;
2903 }
2904
2905 switch (action) {
2906 case PRESET_UNKNOWN:
2907 log_debug("Preset files don't specify rule for %s. Enabling.", name);
2908 return 1;
2909 case PRESET_ENABLE:
2910 log_debug("Preset files say enable %s.", name);
2911 return 1;
2912 case PRESET_DISABLE:
2913 log_debug("Preset files say disable %s.", name);
2914 return 0;
2915 default:
2916 assert_not_reached("invalid preset action");
2917 }
2918}
2919
2920int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
2921 _cleanup_(presets_freep) Presets presets = {};
2922 int r;
2923
2924 r = read_presets(scope, root_dir, &presets);
2925 if (r < 0)
2926 return r;
2927
2928 return query_presets(name, presets);
83096483
LP
2929}
2930
0ec0deaa
LP
2931static int execute_preset(
2932 UnitFileScope scope,
2933 InstallContext *plus,
2934 InstallContext *minus,
2935 const LookupPaths *paths,
2936 const char *config_path,
0ec0deaa
LP
2937 char **files,
2938 UnitFilePresetMode mode,
2939 bool force,
2940 UnitFileChange **changes,
2941 unsigned *n_changes) {
2942
2943 int r;
2944
2945 assert(plus);
2946 assert(minus);
2947 assert(paths);
2948 assert(config_path);
2949
2950 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
2951 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2952
637d6e5b 2953 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
0ec0deaa
LP
2954 if (r < 0)
2955 return r;
2956
3b3557c4 2957 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
0ec0deaa
LP
2958 } else
2959 r = 0;
2960
2961 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
2962 int q;
2963
2964 /* Returns number of symlinks that where supposed to be installed. */
e4bb56c7 2965 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
0ec0deaa
LP
2966 if (r >= 0) {
2967 if (q < 0)
2968 r = q;
2969 else
596fc263 2970 r += q;
0ec0deaa
LP
2971 }
2972 }
2973
2974 return r;
2975}
2976
2977static int preset_prepare_one(
2978 UnitFileScope scope,
2979 InstallContext *plus,
2980 InstallContext *minus,
2981 LookupPaths *paths,
af3d8113 2982 const char *name,
8965d9f8 2983 Presets presets,
af3d8113
ZJS
2984 UnitFileChange **changes,
2985 unsigned *n_changes) {
0ec0deaa 2986
11e11fd5 2987 _cleanup_(install_context_done) InstallContext tmp = {};
0ec0deaa
LP
2988 UnitFileInstallInfo *i;
2989 int r;
2990
11e11fd5 2991 if (install_info_find(plus, name) || install_info_find(minus, name))
0ec0deaa
LP
2992 return 0;
2993
59108fbe
ZJS
2994 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2995 &i, changes, n_changes);
11e11fd5
ZJS
2996 if (r < 0)
2997 return r;
2998 if (!streq(name, i->name)) {
10d67460 2999 log_debug("Skipping %s because it is an alias for %s.", name, i->name);
11e11fd5
ZJS
3000 return 0;
3001 }
3002
8965d9f8 3003 r = query_presets(name, presets);
0ec0deaa
LP
3004 if (r < 0)
3005 return r;
3006
3007 if (r > 0) {
59108fbe
ZJS
3008 r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
3009 &i, changes, n_changes);
0ec0deaa
LP
3010 if (r < 0)
3011 return r;
3012
af3d8113 3013 r = install_info_may_process(i, paths, changes, n_changes);
76adb5b8
LP
3014 if (r < 0)
3015 return r;
0ec0deaa 3016 } else
59108fbe
ZJS
3017 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
3018 &i, changes, n_changes);
0ec0deaa
LP
3019
3020 return r;
3021}
3022
83096483
LP
3023int unit_file_preset(
3024 UnitFileScope scope,
b3796dd8 3025 UnitFileFlags flags,
83096483 3026 const char *root_dir,
7195aa42 3027 char **files,
d309c1c3 3028 UnitFilePresetMode mode,
83096483
LP
3029 UnitFileChange **changes,
3030 unsigned *n_changes) {
3031
59ccf93d 3032 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
da39f6a6 3033 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8965d9f8 3034 _cleanup_(presets_freep) Presets presets = {};
e1c5c2b0 3035 const char *config_path;
da39f6a6 3036 char **i;
0ec0deaa 3037 int r;
83096483
LP
3038
3039 assert(scope >= 0);
3040 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 3041 assert(mode < _UNIT_FILE_PRESET_MAX);
83096483 3042
4943d143 3043 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
3044 if (r < 0)
3045 return r;
3046
b3796dd8 3047 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
3048 if (!config_path)
3049 return -ENXIO;
83096483 3050
8965d9f8
AC
3051 r = read_presets(scope, root_dir, &presets);
3052 if (r < 0)
3053 return r;
83096483 3054
8965d9f8 3055 STRV_FOREACH(i, files) {
ff56349d 3056 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
83096483 3057 if (r < 0)
d9e5e694 3058 return r;
83096483
LP
3059 }
3060
b3796dd8 3061 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
d309c1c3
LP
3062}
3063
3064int unit_file_preset_all(
3065 UnitFileScope scope,
b3796dd8 3066 UnitFileFlags flags,
d309c1c3
LP
3067 const char *root_dir,
3068 UnitFilePresetMode mode,
d309c1c3
LP
3069 UnitFileChange **changes,
3070 unsigned *n_changes) {
3071
59ccf93d 3072 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
d309c1c3 3073 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8965d9f8 3074 _cleanup_(presets_freep) Presets presets = {};
e1c5c2b0 3075 const char *config_path = NULL;
d309c1c3 3076 char **i;
0ec0deaa 3077 int r;
d309c1c3
LP
3078
3079 assert(scope >= 0);
3080 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 3081 assert(mode < _UNIT_FILE_PRESET_MAX);
d309c1c3 3082
4943d143 3083 r = lookup_paths_init(&paths, scope, 0, root_dir);
d309c1c3
LP
3084 if (r < 0)
3085 return r;
3086
b3796dd8 3087 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d0fd66a3
LP
3088 if (!config_path)
3089 return -ENXIO;
d309c1c3 3090
8965d9f8
AC
3091 r = read_presets(scope, root_dir, &presets);
3092 if (r < 0)
3093 return r;
3094
a3c4eb07 3095 STRV_FOREACH(i, paths.search_path) {
d309c1c3 3096 _cleanup_closedir_ DIR *d = NULL;
d25e100b 3097 struct dirent *de;
d309c1c3 3098
401017e0 3099 d = opendir(*i);
d309c1c3
LP
3100 if (!d) {
3101 if (errno == ENOENT)
3102 continue;
3103
3104 return -errno;
3105 }
3106
d25e100b 3107 FOREACH_DIRENT(de, d, return -errno) {
d309c1c3 3108
7410616c 3109 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
d309c1c3
LP
3110 continue;
3111
3112 dirent_ensure_type(d, de);
3113
0ec0deaa 3114 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
d309c1c3
LP
3115 continue;
3116
af3d8113 3117 /* we don't pass changes[] in, because we want to handle errors on our own */
ff56349d 3118 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
9a0a413a
ZJS
3119 if (r == -ERFKILL)
3120 r = unit_file_changes_add(changes, n_changes,
3121 UNIT_FILE_IS_MASKED, de->d_name, NULL);
893275df
ZJS
3122 else if (r == -ENOLINK)
3123 r = unit_file_changes_add(changes, n_changes,
3124 UNIT_FILE_IS_DANGLING, de->d_name, NULL);
26421228
LP
3125 else if (r == -EADDRNOTAVAIL) /* Ignore generated/transient units when applying preset */
3126 continue;
d309c1c3
LP
3127 if (r < 0)
3128 return r;
3129 }
3130 }
3131
b3796dd8 3132 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
83096483
LP
3133}
3134
59ccf93d
LP
3135static void unit_file_list_free_one(UnitFileList *f) {
3136 if (!f)
d9e5e694
ZJS
3137 return;
3138
59ccf93d
LP
3139 free(f->path);
3140 free(f);
d9e5e694 3141}
59ccf93d 3142
0ec0deaa
LP
3143Hashmap* unit_file_list_free(Hashmap *h) {
3144 UnitFileList *i;
3145
3146 while ((i = hashmap_steal_first(h)))
3147 unit_file_list_free_one(i);
3148
3149 return hashmap_free(h);
3150}
3151
59ccf93d 3152DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
d9e5e694 3153
83096483
LP
3154int unit_file_get_list(
3155 UnitFileScope scope,
3156 const char *root_dir,
313fe66f 3157 Hashmap *h,
3158 char **states,
3159 char **patterns) {
83096483 3160
7fd1b19b 3161 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 3162 char **i;
83096483
LP
3163 int r;
3164
3165 assert(scope >= 0);
3166 assert(scope < _UNIT_FILE_SCOPE_MAX);
3167 assert(h);
3168
4943d143 3169 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
3170 if (r < 0)
3171 return r;
3172
a3c4eb07 3173 STRV_FOREACH(i, paths.search_path) {
da39f6a6 3174 _cleanup_closedir_ DIR *d = NULL;
d25e100b 3175 struct dirent *de;
83096483 3176
401017e0 3177 d = opendir(*i);
83096483
LP
3178 if (!d) {
3179 if (errno == ENOENT)
3180 continue;
a1feacf7 3181 if (IN_SET(errno, ENOTDIR, EACCES)) {
25f027c5 3182 log_debug_errno(errno, "Failed to open \"%s\": %m", *i);
a1feacf7
ZJS
3183 continue;
3184 }
83096483 3185
d9e5e694 3186 return -errno;
83096483
LP
3187 }
3188
d25e100b 3189 FOREACH_DIRENT(de, d, return -errno) {
59ccf93d 3190 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
83096483 3191
7410616c 3192 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
83096483
LP
3193 continue;
3194
313fe66f 3195 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
3196 continue;
3197
83096483
LP
3198 if (hashmap_get(h, de->d_name))
3199 continue;
3200
da39f6a6 3201 dirent_ensure_type(d, de);
83096483 3202
da39f6a6 3203 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
83096483
LP
3204 continue;
3205
3206 f = new0(UnitFileList, 1);
d9e5e694
ZJS
3207 if (!f)
3208 return -ENOMEM;
83096483 3209
401017e0 3210 f->path = path_make_absolute(de->d_name, *i);
d9e5e694
ZJS
3211 if (!f->path)
3212 return -ENOMEM;
83096483 3213
401017e0 3214 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
d9e5e694 3215 if (r < 0)
0ec0deaa 3216 f->state = UNIT_FILE_BAD;
81fc054d 3217
313fe66f 3218 if (!strv_isempty(states) &&
3219 !strv_contains(states, unit_file_state_to_string(f->state)))
3220 continue;
3221
2b6bf07d 3222 r = hashmap_put(h, basename(f->path), f);
d9e5e694
ZJS
3223 if (r < 0)
3224 return r;
0ec0deaa 3225
d9e5e694 3226 f = NULL; /* prevent cleanup */
83096483
LP
3227 }
3228 }
3229
77cd2c87 3230 return 0;
83096483
LP
3231}
3232
3233static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
3234 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 3235 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
3236 [UNIT_FILE_LINKED] = "linked",
3237 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
3238 [UNIT_FILE_MASKED] = "masked",
3239 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
3240 [UNIT_FILE_STATIC] = "static",
b5b46d59 3241 [UNIT_FILE_DISABLED] = "disabled",
aedd4012 3242 [UNIT_FILE_INDIRECT] = "indirect",
f4139308 3243 [UNIT_FILE_GENERATED] = "generated",
e4fca67f 3244 [UNIT_FILE_TRANSIENT] = "transient",
0ec0deaa 3245 [UNIT_FILE_BAD] = "bad",
83096483
LP
3246};
3247
3248DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
3249
3250static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
3251 [UNIT_FILE_SYMLINK] = "symlink",
3252 [UNIT_FILE_UNLINK] = "unlink",
9a0a413a 3253 [UNIT_FILE_IS_MASKED] = "masked",
893275df 3254 [UNIT_FILE_IS_DANGLING] = "dangling",
c0576cd6
LP
3255};
3256
3257DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
d309c1c3 3258
86bbe5bf 3259static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
d309c1c3
LP
3260 [UNIT_FILE_PRESET_FULL] = "full",
3261 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
3262 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
3263};
3264
3265DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);