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