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