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