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