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