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