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