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