]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
nss-systemd: remove useless define
[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
d7604756
ZJS
217 /* Note that we do *not* have generic checks for /etc or /run in place, since with
218 * them we couldn't discern 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
d7604756
ZJS
235 /* Everything in /run is considered runtime. On top of that we also add
236 * explicit checks for the various runtime directories, as safety net. */
344ca755 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);
d9e5e694 1073 if (r < 0)
83096483 1074 return r;
aedd4012 1075
a6612e65 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;
d7604756 1100 _cleanup_free_ char *printed = NULL;
d54c4993
LP
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
d7604756 1120 if (!unit_instance_is_valid(printed))
d54c4993
LP
1121 return -EINVAL;
1122
3b319885 1123 return free_and_replace(i->default_instance, printed);
d54c4993
LP
1124}
1125
83096483
LP
1126static int unit_file_load(
1127 InstallContext *c,
cab6235f 1128 UnitFileInstallInfo *info,
83096483 1129 const char *path,
0ec0deaa 1130 SearchFlags flags) {
83096483 1131
f975e971 1132 const ConfigTableItem items[] = {
a7724589 1133 { "Install", "Alias", config_parse_alias, 0, &info->aliases },
d54c4993
LP
1134 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1135 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1136 { "Install", "DefaultInstance", config_parse_default_instance, 0, info },
1137 { "Install", "Also", config_parse_also, 0, c },
d54c4993 1138 {}
83096483
LP
1139 };
1140
133e5b36
ZJS
1141 const char *name;
1142 UnitType type;
7fd1b19b 1143 _cleanup_fclose_ FILE *f = NULL;
0ec0deaa
LP
1144 _cleanup_close_ int fd = -1;
1145 struct stat st;
1146 int r;
83096483 1147
83096483
LP
1148 assert(info);
1149 assert(path);
1150
133e5b36
ZJS
1151 name = basename(path);
1152 type = unit_name_to_type(name);
1153 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
1154 !unit_type_may_template(type))
1155 return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
1156
0ec0deaa
LP
1157 if (!(flags & SEARCH_LOAD)) {
1158 r = lstat(path, &st);
1159 if (r < 0)
d25e100b
LP
1160 return -errno;
1161
0ec0deaa
LP
1162 if (null_or_empty(&st))
1163 info->type = UNIT_FILE_TYPE_MASKED;
1164 else if (S_ISREG(st.st_mode))
1165 info->type = UNIT_FILE_TYPE_REGULAR;
1166 else if (S_ISLNK(st.st_mode))
1167 return -ELOOP;
1168 else if (S_ISDIR(st.st_mode))
1169 return -EISDIR;
1170 else
1171 return -ENOTTY;
1172
d25e100b 1173 return 0;
e94937df
LN
1174 }
1175
047d91f9
ZJS
1176 /* c is only needed if we actually load the file */
1177 assert(c);
1178
0ec0deaa 1179 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
83096483
LP
1180 if (fd < 0)
1181 return -errno;
0ec0deaa
LP
1182 if (fstat(fd, &st) < 0)
1183 return -errno;
1184 if (null_or_empty(&st)) {
d986e364 1185 info->type = UNIT_FILE_TYPE_MASKED;
0ec0deaa
LP
1186 return 0;
1187 }
1188 if (S_ISDIR(st.st_mode))
1189 return -EISDIR;
1190 if (!S_ISREG(st.st_mode))
1191 return -ENOTTY;
83096483
LP
1192
1193 f = fdopen(fd, "re");
0ec0deaa
LP
1194 if (!f)
1195 return -errno;
1196 fd = -1;
83096483 1197
36f822c4
ZJS
1198 r = config_parse(NULL, path, f,
1199 NULL,
1200 config_item_table_lookup, items,
1201 true, true, false, info);
83096483 1202 if (r < 0)
59108fbe 1203 return log_debug_errno(r, "Failed to parse %s: %m", info->name);
83096483 1204
0ec0deaa 1205 info->type = UNIT_FILE_TYPE_REGULAR;
aedd4012 1206
78d54bd4 1207 return
693eb9a2
LP
1208 (int) strv_length(info->aliases) +
1209 (int) strv_length(info->wanted_by) +
1210 (int) strv_length(info->required_by);
83096483
LP
1211}
1212
0ec0deaa
LP
1213static int unit_file_load_or_readlink(
1214 InstallContext *c,
1215 UnitFileInstallInfo *info,
1216 const char *path,
1217 const char *root_dir,
1218 SearchFlags flags) {
1219
401017e0 1220 _cleanup_free_ char *target = NULL;
0ec0deaa
LP
1221 int r;
1222
401017e0 1223 r = unit_file_load(c, info, path, flags);
0ec0deaa
LP
1224 if (r != -ELOOP)
1225 return r;
1226
1227 /* This is a symlink, let's read it. */
1228
401017e0 1229 r = readlink_malloc(path, &target);
0ec0deaa
LP
1230 if (r < 0)
1231 return r;
1232
401017e0 1233 if (path_equal(target, "/dev/null"))
0ec0deaa
LP
1234 info->type = UNIT_FILE_TYPE_MASKED;
1235 else {
1236 const char *bn;
1237 UnitType a, b;
1238
401017e0 1239 bn = basename(target);
0ec0deaa
LP
1240
1241 if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
1242
1243 if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN))
1244 return -EINVAL;
1245
1246 } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
1247
1248 if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
1249 return -EINVAL;
1250
1251 } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) {
1252
1253 if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE))
1254 return -EINVAL;
1255 } else
1256 return -EINVAL;
1257
1258 /* Enforce that the symlink destination does not
1259 * change the unit file type. */
1260
1261 a = unit_name_to_type(info->name);
1262 b = unit_name_to_type(bn);
1263 if (a < 0 || b < 0 || a != b)
1264 return -EINVAL;
1265
401017e0
LP
1266 if (path_is_absolute(target))
1267 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1268 info->symlink_target = prefix_root(root_dir, target);
1269 else
1270 /* This is a relative path, take it relative to the dir the symlink is located in. */
1271 info->symlink_target = file_in_same_dir(path, target);
1272 if (!info->symlink_target)
1273 return -ENOMEM;
1274
0ec0deaa 1275 info->type = UNIT_FILE_TYPE_SYMLINK;
0ec0deaa
LP
1276 }
1277
1278 return 0;
1279}
1280
83096483
LP
1281static int unit_file_search(
1282 InstallContext *c,
cab6235f 1283 UnitFileInstallInfo *info,
a8ffe6fb 1284 const LookupPaths *paths,
0ec0deaa 1285 SearchFlags flags) {
83096483 1286
64f9280e 1287 _cleanup_free_ char *template = NULL;
83096483
LP
1288 char **p;
1289 int r;
1290
83096483
LP
1291 assert(info);
1292 assert(paths);
1293
0ec0deaa
LP
1294 /* Was this unit already loaded? */
1295 if (info->type != _UNIT_FILE_TYPE_INVALID)
1296 return 0;
1297
278fa575 1298 if (info->path)
e4bb56c7 1299 return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
83096483
LP
1300
1301 assert(info->name);
1302
a3c4eb07 1303 STRV_FOREACH(p, paths->search_path) {
e50bd775 1304 _cleanup_free_ char *path = NULL;
83096483 1305
278fa575 1306 path = strjoin(*p, "/", info->name, NULL);
83096483
LP
1307 if (!path)
1308 return -ENOMEM;
1309
e4bb56c7 1310 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
0155928c 1311 if (r >= 0) {
83096483 1312 info->path = path;
62b00233 1313 path = NULL;
e50bd775 1314 return r;
a1feacf7 1315 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
0155928c 1316 return r;
e50bd775 1317 }
62b00233 1318
7410616c 1319 if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
e50bd775
LP
1320 /* Unit file doesn't exist, however instance
1321 * enablement was requested. We will check if it is
1322 * possible to load template unit file. */
29283ea4 1323
7410616c
LP
1324 r = unit_name_template(info->name, &template);
1325 if (r < 0)
1326 return r;
e50bd775 1327
a3c4eb07 1328 STRV_FOREACH(p, paths->search_path) {
e50bd775
LP
1329 _cleanup_free_ char *path = NULL;
1330
278fa575 1331 path = strjoin(*p, "/", template, NULL);
62b00233
ZJS
1332 if (!path)
1333 return -ENOMEM;
29283ea4 1334
e4bb56c7 1335 r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
0155928c 1336 if (r >= 0) {
62b00233
ZJS
1337 info->path = path;
1338 path = NULL;
e50bd775 1339 return r;
a1feacf7 1340 } else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
0155928c 1341 return r;
29283ea4 1342 }
83096483
LP
1343 }
1344
64f9280e 1345 log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
83096483
LP
1346 return -ENOENT;
1347}
1348
0ec0deaa
LP
1349static int install_info_follow(
1350 InstallContext *c,
1351 UnitFileInstallInfo *i,
83096483 1352 const char *root_dir,
0ec0deaa
LP
1353 SearchFlags flags) {
1354
1355 assert(c);
1356 assert(i);
1357
1358 if (i->type != UNIT_FILE_TYPE_SYMLINK)
1359 return -EINVAL;
1360 if (!i->symlink_target)
1361 return -EINVAL;
1362
1363 /* If the basename doesn't match, the caller should add a
1364 * complete new entry for this. */
1365
1366 if (!streq(basename(i->symlink_target), i->name))
1367 return -EXDEV;
1368
3b319885 1369 free_and_replace(i->path, i->symlink_target);
0ec0deaa
LP
1370 i->type = _UNIT_FILE_TYPE_INVALID;
1371
1372 return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
1373}
1374
64f9280e 1375/**
ff56349d
ZJS
1376 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1377 * target, maybe more than once. Propagate the instance name if present.
64f9280e 1378 */
0ec0deaa
LP
1379static int install_info_traverse(
1380 UnitFileScope scope,
1381 InstallContext *c,
0ec0deaa
LP
1382 const LookupPaths *paths,
1383 UnitFileInstallInfo *start,
1384 SearchFlags flags,
1385 UnitFileInstallInfo **ret) {
83096483 1386
cab6235f 1387 UnitFileInstallInfo *i;
0ec0deaa 1388 unsigned k = 0;
83096483
LP
1389 int r;
1390
1391 assert(paths);
0ec0deaa
LP
1392 assert(start);
1393 assert(c);
83096483 1394
e4bb56c7 1395 r = unit_file_search(c, start, paths, flags);
83096483
LP
1396 if (r < 0)
1397 return r;
1398
0ec0deaa
LP
1399 i = start;
1400 while (i->type == UNIT_FILE_TYPE_SYMLINK) {
1401 /* Follow the symlink */
83096483 1402
0ec0deaa
LP
1403 if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
1404 return -ELOOP;
83096483 1405
e1c5c2b0
LP
1406 if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
1407 r = path_is_config(paths, i->path);
1408 if (r < 0)
1409 return r;
1410 if (r > 0)
1411 return -ELOOP;
1412 }
83096483 1413
e4bb56c7 1414 r = install_info_follow(c, i, paths->root_dir, flags);
0155928c 1415 if (r == -EXDEV) {
0ec0deaa
LP
1416 _cleanup_free_ char *buffer = NULL;
1417 const char *bn;
83096483 1418
0ec0deaa
LP
1419 /* Target has a different name, create a new
1420 * install info object for that, and continue
1421 * with that. */
83096483 1422
0ec0deaa 1423 bn = basename(i->symlink_target);
83096483 1424
0ec0deaa
LP
1425 if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) &&
1426 unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) {
83096483 1427
0ec0deaa
LP
1428 _cleanup_free_ char *instance = NULL;
1429
1430 r = unit_name_to_instance(i->name, &instance);
1431 if (r < 0)
1432 return r;
1433
1434 r = unit_name_replace_instance(bn, instance, &buffer);
1435 if (r < 0)
1436 return r;
1437
1438 bn = buffer;
1439 }
1440
19539807 1441 r = install_info_add(c, bn, NULL, false, &i);
0ec0deaa
LP
1442 if (r < 0)
1443 return r;
1444
0155928c 1445 /* Try again, with the new target we found. */
e4bb56c7 1446 r = unit_file_search(c, i, paths, flags);
893275df
ZJS
1447 if (r == -ENOENT)
1448 /* Translate error code to highlight this specific case */
1449 return -ENOLINK;
0ec0deaa
LP
1450 }
1451
0155928c
ZJS
1452 if (r < 0)
1453 return r;
83096483
LP
1454 }
1455
0ec0deaa
LP
1456 if (ret)
1457 *ret = i;
83096483 1458
0ec0deaa
LP
1459 return 0;
1460}
83096483 1461
ff56349d
ZJS
1462/**
1463 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1464 * or the name (otherwise). root_dir is prepended to the path.
1465 */
401017e0
LP
1466static int install_info_add_auto(
1467 InstallContext *c,
1468 const LookupPaths *paths,
1469 const char *name_or_path,
1470 UnitFileInstallInfo **ret) {
1471
1472 assert(c);
1473 assert(name_or_path);
1474
1475 if (path_is_absolute(name_or_path)) {
1476 const char *pp;
1477
1478 pp = prefix_roota(paths->root_dir, name_or_path);
1479
19539807 1480 return install_info_add(c, NULL, pp, false, ret);
401017e0 1481 } else
19539807 1482 return install_info_add(c, name_or_path, NULL, false, ret);
401017e0
LP
1483}
1484
0ec0deaa
LP
1485static int install_info_discover(
1486 UnitFileScope scope,
1487 InstallContext *c,
0ec0deaa
LP
1488 const LookupPaths *paths,
1489 const char *name,
1490 SearchFlags flags,
59108fbe
ZJS
1491 UnitFileInstallInfo **ret,
1492 UnitFileChange **changes,
1493 unsigned *n_changes) {
83096483 1494
0ec0deaa
LP
1495 UnitFileInstallInfo *i;
1496 int r;
83096483 1497
0ec0deaa
LP
1498 assert(c);
1499 assert(paths);
1500 assert(name);
1501
401017e0 1502 r = install_info_add_auto(c, paths, name, &i);
59108fbe
ZJS
1503 if (r >= 0)
1504 r = install_info_traverse(scope, c, paths, i, flags, ret);
83096483 1505
59108fbe
ZJS
1506 if (r < 0)
1507 unit_file_changes_add(changes, n_changes, r, name, NULL);
1508 return r;
83096483
LP
1509}
1510
1511static int install_info_symlink_alias(
cab6235f 1512 UnitFileInstallInfo *i,
401017e0 1513 const LookupPaths *paths,
83096483
LP
1514 const char *config_path,
1515 bool force,
1516 UnitFileChange **changes,
1517 unsigned *n_changes) {
1518
1519 char **s;
1520 int r = 0, q;
1521
1522 assert(i);
401017e0 1523 assert(paths);
83096483
LP
1524 assert(config_path);
1525
1526 STRV_FOREACH(s, i->aliases) {
7fd1b19b 1527 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
83096483 1528
19f6d710
LP
1529 q = install_full_printf(i, *s, &dst);
1530 if (q < 0)
1531 return q;
83096483 1532
7584d236 1533 alias_path = path_make_absolute(dst, config_path);
83096483
LP
1534 if (!alias_path)
1535 return -ENOMEM;
1536
60bec8e4 1537 q = create_symlink(paths, i->path, alias_path, force, changes, n_changes);
83096483
LP
1538 if (r == 0)
1539 r = q;
1540 }
1541
1542 return r;
1543}
1544
1545static int install_info_symlink_wants(
cab6235f 1546 UnitFileInstallInfo *i,
401017e0 1547 const LookupPaths *paths,
83096483 1548 const char *config_path,
d54c4993
LP
1549 char **list,
1550 const char *suffix,
83096483
LP
1551 UnitFileChange **changes,
1552 unsigned *n_changes) {
1553
d54c4993
LP
1554 _cleanup_free_ char *buf = NULL;
1555 const char *n;
83096483
LP
1556 char **s;
1557 int r = 0, q;
1558
1559 assert(i);
401017e0 1560 assert(paths);
83096483
LP
1561 assert(config_path);
1562
047d91f9
ZJS
1563 if (strv_isempty(list))
1564 return 0;
1565
7410616c 1566 if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
047d91f9
ZJS
1567 UnitFileInstallInfo instance = {
1568 .type = _UNIT_FILE_TYPE_INVALID,
1569 };
1570 _cleanup_free_ char *path = NULL;
0a327d75
LP
1571
1572 /* Don't install any symlink if there's no default
1573 * instance configured */
1574
1575 if (!i->default_instance)
1576 return 0;
1577
7410616c
LP
1578 r = unit_name_replace_instance(i->name, i->default_instance, &buf);
1579 if (r < 0)
1580 return r;
83096483 1581
047d91f9
ZJS
1582 instance.name = buf;
1583 r = unit_file_search(NULL, &instance, paths, SEARCH_FOLLOW_CONFIG_SYMLINKS);
1584 if (r < 0)
1585 return r;
1586
1587 path = instance.path;
1588 instance.path = NULL;
1589
1590 if (instance.type == UNIT_FILE_TYPE_MASKED) {
1591 unit_file_changes_add(changes, n_changes, -ERFKILL, path, NULL);
1592 return -ERFKILL;
1593 }
1594
d54c4993
LP
1595 n = buf;
1596 } else
1597 n = i->name;
78d54bd4 1598
d54c4993 1599 STRV_FOREACH(s, list) {
7fd1b19b 1600 _cleanup_free_ char *path = NULL, *dst = NULL;
78d54bd4 1601
19f6d710
LP
1602 q = install_full_printf(i, *s, &dst);
1603 if (q < 0)
1604 return q;
7584d236 1605
7410616c 1606 if (!unit_name_is_valid(dst, UNIT_NAME_ANY)) {
78d54bd4
LP
1607 r = -EINVAL;
1608 continue;
1609 }
1610
d54c4993
LP
1611 path = strjoin(config_path, "/", dst, suffix, n, NULL);
1612 if (!path)
78d54bd4
LP
1613 return -ENOMEM;
1614
60bec8e4 1615 q = create_symlink(paths, i->path, path, true, changes, n_changes);
78d54bd4
LP
1616 if (r == 0)
1617 r = q;
1618 }
1619
1620 return r;
1621}
1622
83096483 1623static int install_info_symlink_link(
cab6235f 1624 UnitFileInstallInfo *i,
a8ffe6fb 1625 const LookupPaths *paths,
83096483
LP
1626 const char *config_path,
1627 bool force,
1628 UnitFileChange **changes,
1629 unsigned *n_changes) {
1630
7fd1b19b 1631 _cleanup_free_ char *path = NULL;
1dacfd2a 1632 int r;
83096483
LP
1633
1634 assert(i);
1635 assert(paths);
1636 assert(config_path);
1637 assert(i->path);
1638
32c0ed7b 1639 r = in_search_path(paths, i->path);
fe4aede9 1640 if (r < 0)
83096483 1641 return r;
fe4aede9
ZJS
1642 if (r > 0)
1643 return 0;
83096483 1644
1dacfd2a
LP
1645 path = strjoin(config_path, "/", i->name, NULL);
1646 if (!path)
83096483
LP
1647 return -ENOMEM;
1648
60bec8e4 1649 return create_symlink(paths, i->path, path, force, changes, n_changes);
83096483
LP
1650}
1651
1652static int install_info_apply(
cab6235f 1653 UnitFileInstallInfo *i,
a8ffe6fb 1654 const LookupPaths *paths,
83096483
LP
1655 const char *config_path,
1656 bool force,
1657 UnitFileChange **changes,
1658 unsigned *n_changes) {
1659
1660 int r, q;
1661
1662 assert(i);
1663 assert(paths);
1664 assert(config_path);
1665
0ec0deaa
LP
1666 if (i->type != UNIT_FILE_TYPE_REGULAR)
1667 return 0;
1668
401017e0 1669 r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
83096483 1670
29380daf 1671 q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
83096483
LP
1672 if (r == 0)
1673 r = q;
1674
29380daf 1675 q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
78d54bd4
LP
1676 if (r == 0)
1677 r = q;
1678
e4bb56c7 1679 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
fe4aede9
ZJS
1680 /* Do not count links to the unit file towards the "carries_install_info" count */
1681 if (r == 0 && q < 0)
83096483
LP
1682 r = q;
1683
1684 return r;
1685}
1686
1687static int install_context_apply(
0ec0deaa 1688 UnitFileScope scope,
83096483 1689 InstallContext *c,
a8ffe6fb 1690 const LookupPaths *paths,
83096483 1691 const char *config_path,
83096483 1692 bool force,
0ec0deaa 1693 SearchFlags flags,
83096483
LP
1694 UnitFileChange **changes,
1695 unsigned *n_changes) {
1696
cab6235f 1697 UnitFileInstallInfo *i;
0ec0deaa 1698 int r;
83096483
LP
1699
1700 assert(c);
1701 assert(paths);
1702 assert(config_path);
1703
0ec0deaa 1704 if (ordered_hashmap_isempty(c->will_process))
d25e100b 1705 return 0;
83096483 1706
0ec0deaa 1707 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
d25e100b
LP
1708 if (r < 0)
1709 return r;
83096483 1710
2d5c93c7 1711 r = 0;
0ec0deaa
LP
1712 while ((i = ordered_hashmap_first(c->will_process))) {
1713 int q;
83096483 1714
0ec0deaa
LP
1715 q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1716 if (q < 0)
1717 return q;
83096483 1718
e4bb56c7 1719 r = install_info_traverse(scope, c, paths, i, flags, NULL);
db093eed
ZJS
1720 if (r < 0) {
1721 unit_file_changes_add(changes, n_changes, r, i->name, NULL);
83096483 1722 return r;
db093eed 1723 }
0ec0deaa 1724
f1651715 1725 /* We can attempt to process a masked unit when a different unit
047d91f9 1726 * that we were processing specifies it in Also=. */
f1651715
ZJS
1727 if (i->type == UNIT_FILE_TYPE_MASKED) {
1728 unit_file_changes_add(changes, n_changes, UNIT_FILE_IS_MASKED, i->path, NULL);
1729 if (r >= 0)
047d91f9
ZJS
1730 /* Assume that something *could* have been enabled here,
1731 * avoid "empty [Install] section" warning. */
f1651715
ZJS
1732 r += 1;
1733 continue;
1734 }
1735
0ec0deaa
LP
1736 if (i->type != UNIT_FILE_TYPE_REGULAR)
1737 continue;
83096483 1738
e4bb56c7 1739 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
0ec0deaa
LP
1740 if (r >= 0) {
1741 if (q < 0)
1742 r = q;
1743 else
596fc263 1744 r += q;
0ec0deaa 1745 }
83096483
LP
1746 }
1747
1748 return r;
1749}
1750
1751static int install_context_mark_for_removal(
0ec0deaa 1752 UnitFileScope scope,
83096483 1753 InstallContext *c,
a8ffe6fb 1754 const LookupPaths *paths,
83096483 1755 Set **remove_symlinks_to,
e4bb56c7 1756 const char *config_path) {
83096483 1757
cab6235f 1758 UnitFileInstallInfo *i;
0ec0deaa 1759 int r;
83096483
LP
1760
1761 assert(c);
1762 assert(paths);
1763 assert(config_path);
1764
1765 /* Marks all items for removal */
1766
0ec0deaa 1767 if (ordered_hashmap_isempty(c->will_process))
d25e100b 1768 return 0;
83096483 1769
0ec0deaa 1770 r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops);
d25e100b
LP
1771 if (r < 0)
1772 return r;
83096483 1773
0ec0deaa 1774 while ((i = ordered_hashmap_first(c->will_process))) {
83096483 1775
0ec0deaa
LP
1776 r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name);
1777 if (r < 0)
83096483 1778 return r;
29283ea4 1779
e4bb56c7 1780 r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
19539807
ZJS
1781 if (r == -ENOLINK) {
1782 log_debug_errno(r, "Name %s leads to a dangling symlink, ignoring.", i->name);
010454b4 1783 continue;
19539807
ZJS
1784 } else if (r == -ENOENT && i->auxiliary) {
1785 /* some unit specified in Also= or similar is missing */
1786 log_debug_errno(r, "Auxiliary unit %s not found, ignoring.", i->name);
1787 continue;
1788 } else if (r < 0)
1789 return log_debug_errno(r, "Failed to find unit %s: %m", i->name);
0ec0deaa 1790
64f9280e
ZJS
1791 if (i->type != UNIT_FILE_TYPE_REGULAR) {
1792 log_debug("Unit %s has type %s, ignoring.",
1793 i->name,
1794 unit_file_type_to_string(i->type) ?: "invalid");
0ec0deaa 1795 continue;
64f9280e 1796 }
0ec0deaa
LP
1797
1798 r = mark_symlink_for_removal(remove_symlinks_to, i->name);
1799 if (r < 0)
1800 return r;
1801 }
1802
1803 return 0;
1804}
1805
1806int unit_file_mask(
1807 UnitFileScope scope,
1808 bool runtime,
1809 const char *root_dir,
1810 char **files,
1811 bool force,
1812 UnitFileChange **changes,
1813 unsigned *n_changes) {
1814
e1c5c2b0
LP
1815 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1816 const char *config_path;
0ec0deaa
LP
1817 char **i;
1818 int r;
1819
1820 assert(scope >= 0);
1821 assert(scope < _UNIT_FILE_SCOPE_MAX);
1822
4943d143 1823 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
1824 if (r < 0)
1825 return r;
1826
e1c5c2b0
LP
1827 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1828
0ec0deaa
LP
1829 STRV_FOREACH(i, files) {
1830 _cleanup_free_ char *path = NULL;
1831 int q;
1832
1833 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
1834 if (r == 0)
1835 r = -EINVAL;
1836 continue;
1837 }
1838
e1c5c2b0 1839 path = path_make_absolute(*i, config_path);
0ec0deaa
LP
1840 if (!path)
1841 return -ENOMEM;
29283ea4 1842
60bec8e4 1843 q = create_symlink(&paths, "/dev/null", path, force, changes, n_changes);
0ec0deaa 1844 if (q < 0 && r >= 0)
83096483
LP
1845 r = q;
1846 }
1847
1848 return r;
1849}
1850
0ec0deaa
LP
1851int unit_file_unmask(
1852 UnitFileScope scope,
1853 bool runtime,
1854 const char *root_dir,
1855 char **files,
1856 UnitFileChange **changes,
1857 unsigned *n_changes) {
1858
e1c5c2b0 1859 _cleanup_lookup_paths_free_ LookupPaths paths = {};
0ec0deaa 1860 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
0ec0deaa
LP
1861 _cleanup_free_ char **todo = NULL;
1862 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 1863 const char *config_path;
0ec0deaa
LP
1864 char **i;
1865 int r, q;
1866
1867 assert(scope >= 0);
1868 assert(scope < _UNIT_FILE_SCOPE_MAX);
1869
4943d143 1870 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
1871 if (r < 0)
1872 return r;
1873
e1c5c2b0
LP
1874 config_path = runtime ? paths.runtime_config : paths.persistent_config;
1875
0ec0deaa
LP
1876 STRV_FOREACH(i, files) {
1877 _cleanup_free_ char *path = NULL;
1878
1879 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
1880 return -EINVAL;
1881
1882 path = path_make_absolute(*i, config_path);
1883 if (!path)
1884 return -ENOMEM;
1885
1886 r = null_or_empty_path(path);
1887 if (r == -ENOENT)
1888 continue;
1889 if (r < 0)
1890 return r;
1891 if (r == 0)
1892 continue;
1893
1894 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1895 return -ENOMEM;
1896
1897 todo[n_todo++] = *i;
1898 }
1899
1900 strv_uniq(todo);
1901
1902 r = 0;
1903 STRV_FOREACH(i, todo) {
1904 _cleanup_free_ char *path = NULL;
401017e0 1905 const char *rp;
0ec0deaa
LP
1906
1907 path = path_make_absolute(*i, config_path);
1908 if (!path)
1909 return -ENOMEM;
1910
1911 if (unlink(path) < 0) {
af3d8113
ZJS
1912 if (errno != ENOENT) {
1913 if (r >= 0)
1914 r = -errno;
1915 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
1916 }
0ec0deaa 1917
401017e0 1918 continue;
0ec0deaa 1919 }
401017e0
LP
1920
1921 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
1922
1923 rp = skip_root(&paths, path);
1924 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
1925 if (q < 0)
1926 return q;
0ec0deaa
LP
1927 }
1928
401017e0 1929 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
0ec0deaa
LP
1930 if (r >= 0)
1931 r = q;
1932
1933 return r;
1934}
1935
1936int unit_file_link(
e94937df
LN
1937 UnitFileScope scope,
1938 bool runtime,
1939 const char *root_dir,
1940 char **files,
e94937df
LN
1941 bool force,
1942 UnitFileChange **changes,
1943 unsigned *n_changes) {
1944
1945 _cleanup_lookup_paths_free_ LookupPaths paths = {};
0ec0deaa
LP
1946 _cleanup_free_ char **todo = NULL;
1947 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 1948 const char *config_path;
e94937df 1949 char **i;
0ec0deaa 1950 int r, q;
e94937df
LN
1951
1952 assert(scope >= 0);
1953 assert(scope < _UNIT_FILE_SCOPE_MAX);
1954
4943d143 1955 r = lookup_paths_init(&paths, scope, 0, root_dir);
e94937df
LN
1956 if (r < 0)
1957 return r;
1958
e1c5c2b0 1959 config_path = runtime ? paths.runtime_config : paths.persistent_config;
e94937df
LN
1960
1961 STRV_FOREACH(i, files) {
0ec0deaa
LP
1962 _cleanup_free_ char *full = NULL;
1963 struct stat st;
1964 char *fn;
e94937df 1965
0ec0deaa
LP
1966 if (!path_is_absolute(*i))
1967 return -EINVAL;
e94937df 1968
0ec0deaa
LP
1969 fn = basename(*i);
1970 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
1971 return -EINVAL;
1972
e4bb56c7 1973 full = prefix_root(paths.root_dir, *i);
0ec0deaa
LP
1974 if (!full)
1975 return -ENOMEM;
1976
1977 if (lstat(full, &st) < 0)
1978 return -errno;
1979 if (S_ISLNK(st.st_mode))
1980 return -ELOOP;
1981 if (S_ISDIR(st.st_mode))
1982 return -EISDIR;
1983 if (!S_ISREG(st.st_mode))
1984 return -ENOTTY;
1985
32c0ed7b 1986 q = in_search_path(&paths, *i);
0ec0deaa
LP
1987 if (q < 0)
1988 return q;
1989 if (q > 0)
1990 continue;
1991
1992 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1993 return -ENOMEM;
1994
1995 todo[n_todo++] = *i;
e94937df
LN
1996 }
1997
0ec0deaa 1998 strv_uniq(todo);
e94937df 1999
0ec0deaa
LP
2000 r = 0;
2001 STRV_FOREACH(i, todo) {
401017e0 2002 _cleanup_free_ char *new_path = NULL;
0ec0deaa 2003
401017e0
LP
2004 new_path = path_make_absolute(basename(*i), config_path);
2005 if (!new_path)
0ec0deaa
LP
2006 return -ENOMEM;
2007
60bec8e4 2008 q = create_symlink(&paths, *i, new_path, force, changes, n_changes);
0ec0deaa
LP
2009 if (q < 0 && r >= 0)
2010 r = q;
2d5c93c7
MS
2011 }
2012
0ec0deaa
LP
2013 return r;
2014}
2015
344ca755
LP
2016static int path_shall_revert(const LookupPaths *paths, const char *path) {
2017 int r;
2018
2019 assert(paths);
2020 assert(path);
2021
2022 /* Checks whether the path is one where the drop-in directories shall be removed. */
2023
2024 r = path_is_config(paths, path);
2025 if (r != 0)
2026 return r;
2027
2028 r = path_is_control(paths, path);
2029 if (r != 0)
2030 return r;
2031
2032 return path_is_transient(paths, path);
2033}
2034
2035int unit_file_revert(
2036 UnitFileScope scope,
2037 const char *root_dir,
2038 char **files,
2039 UnitFileChange **changes,
2040 unsigned *n_changes) {
2041
2042 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
344ca755
LP
2043 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2044 _cleanup_strv_free_ char **todo = NULL;
2045 size_t n_todo = 0, n_allocated = 0;
2046 char **i;
2047 int r, q;
2048
2049 /* Puts a unit file back into vendor state. This means:
2050 *
2051 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2052 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2053 *
2054 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2055 * "config", but not in "transient" or "control" or even "generated").
2056 *
4f25723c 2057 * We remove all that in both the runtime and the persistent directories, if that applies.
344ca755
LP
2058 */
2059
2060 r = lookup_paths_init(&paths, scope, 0, root_dir);
2061 if (r < 0)
2062 return r;
2063
2064 STRV_FOREACH(i, files) {
2065 bool has_vendor = false;
2066 char **p;
2067
2068 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2069 return -EINVAL;
2070
2071 STRV_FOREACH(p, paths.search_path) {
2072 _cleanup_free_ char *path = NULL, *dropin = NULL;
2073 struct stat st;
2074
2075 path = path_make_absolute(*i, *p);
2076 if (!path)
2077 return -ENOMEM;
2078
2079 r = lstat(path, &st);
2080 if (r < 0) {
2081 if (errno != ENOENT)
2082 return -errno;
2083 } else if (S_ISREG(st.st_mode)) {
2084 /* Check if there's a vendor version */
2085 r = path_is_vendor(&paths, path);
2086 if (r < 0)
2087 return r;
2088 if (r > 0)
2089 has_vendor = true;
2090 }
2091
2092 dropin = strappend(path, ".d");
2093 if (!dropin)
2094 return -ENOMEM;
2095
2096 r = lstat(dropin, &st);
2097 if (r < 0) {
2098 if (errno != ENOENT)
2099 return -errno;
2100 } else if (S_ISDIR(st.st_mode)) {
2101 /* Remove the drop-ins */
2102 r = path_shall_revert(&paths, dropin);
2103 if (r < 0)
2104 return r;
2105 if (r > 0) {
2106 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2107 return -ENOMEM;
2108
2109 todo[n_todo++] = dropin;
2110 dropin = NULL;
2111 }
2112 }
2113 }
2114
2115 if (!has_vendor)
2116 continue;
2117
2118 /* OK, there's a vendor version, hence drop all configuration versions */
2119 STRV_FOREACH(p, paths.search_path) {
2120 _cleanup_free_ char *path = NULL;
2121 struct stat st;
2122
2123 path = path_make_absolute(*i, *p);
2124 if (!path)
2125 return -ENOMEM;
2126
2127 r = lstat(path, &st);
2128 if (r < 0) {
2129 if (errno != ENOENT)
2130 return -errno;
2131 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
2132 r = path_is_config(&paths, path);
2133 if (r < 0)
2134 return r;
2135 if (r > 0) {
2136 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2137 return -ENOMEM;
2138
2139 todo[n_todo++] = path;
2140 path = NULL;
2141 }
2142 }
2143 }
2144 }
2145
2146 strv_uniq(todo);
2147
2148 r = 0;
2149 STRV_FOREACH(i, todo) {
2150 _cleanup_strv_free_ char **fs = NULL;
2151 const char *rp;
2152 char **j;
2153
2154 (void) get_files_in_directory(*i, &fs);
2155
2156 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2157 if (q < 0 && q != -ENOENT && r >= 0) {
2158 r = q;
2159 continue;
2160 }
2161
2162 STRV_FOREACH(j, fs) {
2163 _cleanup_free_ char *t = NULL;
2164
2165 t = strjoin(*i, "/", *j, NULL);
2166 if (!t)
2167 return -ENOMEM;
2168
2169 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
2170 }
2171
2172 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
2173
2174 rp = skip_root(&paths, *i);
2175 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2176 if (q < 0)
2177 return q;
2178 }
2179
2180 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes);
2181 if (r >= 0)
2182 r = q;
2183
2184 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes);
2185 if (r >= 0)
2186 r = q;
2187
2188 return r;
2189}
2190
0ec0deaa
LP
2191int unit_file_add_dependency(
2192 UnitFileScope scope,
2193 bool runtime,
2194 const char *root_dir,
2195 char **files,
2196 const char *target,
2197 UnitDependency dep,
2198 bool force,
2199 UnitFileChange **changes,
2200 unsigned *n_changes) {
2201
2202 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2203 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2204 UnitFileInstallInfo *i, *target_info;
e1c5c2b0 2205 const char *config_path;
0ec0deaa
LP
2206 char **f;
2207 int r;
2208
2209 assert(scope >= 0);
2210 assert(scope < _UNIT_FILE_SCOPE_MAX);
2211 assert(target);
2212
2213 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
2214 return -EINVAL;
2215
2216 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2217 return -EINVAL;
2218
4943d143 2219 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2220 if (r < 0)
2221 return r;
2222
e1c5c2b0 2223 config_path = runtime ? paths.runtime_config : paths.persistent_config;
0ec0deaa 2224
59108fbe
ZJS
2225 r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2226 &target_info, changes, n_changes);
0ec0deaa
LP
2227 if (r < 0)
2228 return r;
af3d8113 2229 r = install_info_may_process(target_info, &paths, changes, n_changes);
76adb5b8
LP
2230 if (r < 0)
2231 return r;
0ec0deaa
LP
2232
2233 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
e94937df 2234
0ec0deaa
LP
2235 STRV_FOREACH(f, files) {
2236 char ***l;
2237
59108fbe
ZJS
2238 r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2239 &i, changes, n_changes);
e94937df
LN
2240 if (r < 0)
2241 return r;
af3d8113 2242 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2243 if (r < 0)
2244 return r;
0ec0deaa
LP
2245
2246 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2247
2248 /* We didn't actually load anything from the unit
2249 * file, but instead just add in our new symlink to
2250 * create. */
e94937df
LN
2251
2252 if (dep == UNIT_WANTS)
0ec0deaa 2253 l = &i->wanted_by;
e94937df 2254 else
0ec0deaa 2255 l = &i->required_by;
e94937df 2256
0ec0deaa
LP
2257 strv_free(*l);
2258 *l = strv_new(target_info->name, NULL);
2259 if (!*l)
2260 return -ENOMEM;
e94937df
LN
2261 }
2262
e4bb56c7 2263 return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
e94937df
LN
2264}
2265
83096483
LP
2266int unit_file_enable(
2267 UnitFileScope scope,
2268 bool runtime,
2269 const char *root_dir,
7195aa42 2270 char **files,
83096483
LP
2271 bool force,
2272 UnitFileChange **changes,
2273 unsigned *n_changes) {
2274
7fd1b19b 2275 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2276 _cleanup_(install_context_done) InstallContext c = {};
e1c5c2b0 2277 const char *config_path;
0ec0deaa
LP
2278 UnitFileInstallInfo *i;
2279 char **f;
83096483
LP
2280 int r;
2281
2282 assert(scope >= 0);
2283 assert(scope < _UNIT_FILE_SCOPE_MAX);
2284
4943d143 2285 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2286 if (r < 0)
2287 return r;
2288
e1c5c2b0 2289 config_path = runtime ? paths.runtime_config : paths.persistent_config;
83096483 2290
0ec0deaa 2291 STRV_FOREACH(f, files) {
59108fbe
ZJS
2292 r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2293 &i, changes, n_changes);
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
59108fbe 2406 r = install_info_discover(scope, &c, &paths, name, 0, &i, changes, n_changes);
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
59108fbe
ZJS
2436 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2437 &i, NULL, NULL);
0ec0deaa
LP
2438 if (r < 0)
2439 return r;
af3d8113 2440 r = install_info_may_process(i, &paths, NULL, 0);
76adb5b8
LP
2441 if (r < 0)
2442 return r;
99504dd4 2443
0ec0deaa
LP
2444 n = strdup(i->name);
2445 if (!n)
2446 return -ENOMEM;
99504dd4 2447
0ec0deaa
LP
2448 *name = n;
2449 return 0;
99504dd4
VP
2450}
2451
2c52204c 2452static int unit_file_lookup_state(
83096483 2453 UnitFileScope scope,
a8ffe6fb 2454 const LookupPaths *paths,
0ec0deaa
LP
2455 const char *name,
2456 UnitFileState *ret) {
83096483 2457
0ec0deaa
LP
2458 _cleanup_(install_context_done) InstallContext c = {};
2459 UnitFileInstallInfo *i;
2460 UnitFileState state;
2461 int r;
83096483 2462
a8ffe6fb 2463 assert(paths);
0ec0deaa 2464 assert(name);
83096483 2465
7410616c 2466 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
83096483
LP
2467 return -EINVAL;
2468
59108fbe
ZJS
2469 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2470 &i, NULL, NULL);
0ec0deaa
LP
2471 if (r < 0)
2472 return r;
83096483 2473
0ec0deaa
LP
2474 /* Shortcut things, if the caller just wants to know if this unit exists. */
2475 if (!ret)
2476 return 0;
83096483 2477
0ec0deaa 2478 switch (i->type) {
67820a0c 2479
0ec0deaa 2480 case UNIT_FILE_TYPE_MASKED:
385eb996
LP
2481 r = path_is_runtime(paths, i->path);
2482 if (r < 0)
2483 return r;
2484
2485 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
0ec0deaa 2486 break;
83096483 2487
0ec0deaa 2488 case UNIT_FILE_TYPE_REGULAR:
f4dc1e65 2489 r = path_is_generator(paths, i->path);
f4139308
LP
2490 if (r < 0)
2491 return r;
2492 if (r > 0) {
2493 state = UNIT_FILE_GENERATED;
2494 break;
2495 }
2496
e4fca67f
LP
2497 r = path_is_transient(paths, i->path);
2498 if (r < 0)
2499 return r;
2500 if (r > 0) {
2501 state = UNIT_FILE_TRANSIENT;
2502 break;
2503 }
2504
e4bb56c7 2505 r = find_symlinks_in_scope(scope, paths, i->name, &state);
d9e5e694
ZJS
2506 if (r < 0)
2507 return r;
0ec0deaa
LP
2508 if (r == 0) {
2509 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i))
2510 state = UNIT_FILE_DISABLED;
2511 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i))
2512 state = UNIT_FILE_INDIRECT;
2513 else
2514 state = UNIT_FILE_STATIC;
2515 }
83096483 2516
0ec0deaa
LP
2517 break;
2518
2519 default:
2520 assert_not_reached("Unexpect unit file type.");
83096483
LP
2521 }
2522
0ec0deaa
LP
2523 *ret = state;
2524 return 0;
83096483
LP
2525}
2526
0ec0deaa 2527int unit_file_get_state(
a8ffe6fb
ZJS
2528 UnitFileScope scope,
2529 const char *root_dir,
0ec0deaa
LP
2530 const char *name,
2531 UnitFileState *ret) {
a8ffe6fb
ZJS
2532
2533 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2534 int r;
2535
2536 assert(scope >= 0);
2537 assert(scope < _UNIT_FILE_SCOPE_MAX);
2538 assert(name);
2539
4943d143 2540 r = lookup_paths_init(&paths, scope, 0, root_dir);
a8ffe6fb
ZJS
2541 if (r < 0)
2542 return r;
2543
e4bb56c7 2544 return unit_file_lookup_state(scope, &paths, name, ret);
a8ffe6fb
ZJS
2545}
2546
e735decc
LP
2547int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2548 _cleanup_(install_context_done) InstallContext c = {};
2549 int r;
2550
2551 assert(paths);
2552 assert(name);
2553
2554 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2555 return -EINVAL;
2556
59108fbe 2557 r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
e735decc
LP
2558 if (r == -ENOENT)
2559 return 0;
2560 if (r < 0)
2561 return r;
2562
2563 return 1;
2564}
2565
8965d9f8
AC
2566static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2567 _cleanup_(presets_freep) Presets ps = {};
2568 size_t n_allocated = 0;
7fd1b19b 2569 _cleanup_strv_free_ char **files = NULL;
cba2ef02 2570 char **p;
83096483
LP
2571 int r;
2572
2573 assert(scope >= 0);
2574 assert(scope < _UNIT_FILE_SCOPE_MAX);
8965d9f8 2575 assert(presets);
0ec0deaa 2576
83096483 2577 if (scope == UNIT_FILE_SYSTEM)
c2a8d7b0 2578 r = conf_files_list(&files, ".preset", root_dir,
a7480dba
LP
2579 "/etc/systemd/system-preset",
2580 "/usr/local/lib/systemd/system-preset",
2581 "/usr/lib/systemd/system-preset",
b4bdfefa 2582#ifdef HAVE_SPLIT_USR
a7480dba 2583 "/lib/systemd/system-preset",
b4bdfefa 2584#endif
83096483
LP
2585 NULL);
2586 else if (scope == UNIT_FILE_GLOBAL)
c2a8d7b0 2587 r = conf_files_list(&files, ".preset", root_dir,
a7480dba
LP
2588 "/etc/systemd/user-preset",
2589 "/usr/local/lib/systemd/user-preset",
2590 "/usr/lib/systemd/user-preset",
83096483 2591 NULL);
8965d9f8
AC
2592 else {
2593 *presets = (Presets){};
2594
2595 return 0;
2596 }
83096483
LP
2597
2598 if (r < 0)
2599 return r;
2600
cba2ef02 2601 STRV_FOREACH(p, files) {
7fd1b19b 2602 _cleanup_fclose_ FILE *f;
0ec0deaa 2603 char line[LINE_MAX];
d544d1a4 2604 int n = 0;
83096483 2605
cba2ef02 2606 f = fopen(*p, "re");
83096483
LP
2607 if (!f) {
2608 if (errno == ENOENT)
2609 continue;
2610
d9e5e694 2611 return -errno;
83096483
LP
2612 }
2613
0ec0deaa 2614 FOREACH_LINE(line, f, return -errno) {
8965d9f8 2615 PresetRule rule = {};
0ec0deaa
LP
2616 const char *parameter;
2617 char *l;
83096483
LP
2618
2619 l = strstrip(line);
d544d1a4 2620 n++;
83096483 2621
0ec0deaa
LP
2622 if (isempty(l))
2623 continue;
2624 if (strchr(COMMENTS, *l))
83096483
LP
2625 continue;
2626
0ec0deaa
LP
2627 parameter = first_word(l, "enable");
2628 if (parameter) {
8965d9f8 2629 char *pattern;
d9e5e694 2630
8965d9f8
AC
2631 pattern = strdup(parameter);
2632 if (!pattern)
2633 return -ENOMEM;
2634
2635 rule = (PresetRule) {
2636 .pattern = pattern,
2637 .action = PRESET_ENABLE,
2638 };
0ec0deaa 2639 }
83096483 2640
0ec0deaa
LP
2641 parameter = first_word(l, "disable");
2642 if (parameter) {
8965d9f8 2643 char *pattern;
d9e5e694 2644
8965d9f8
AC
2645 pattern = strdup(parameter);
2646 if (!pattern)
2647 return -ENOMEM;
2648
2649 rule = (PresetRule) {
2650 .pattern = pattern,
2651 .action = PRESET_DISABLE,
2652 };
2653 }
2654
2655 if (rule.action) {
2656 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
2657 return -ENOMEM;
2658
2659 ps.rules[ps.n_rules++] = rule;
0ec0deaa
LP
2660 continue;
2661 }
2662
d544d1a4 2663 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
83096483 2664 }
83096483
LP
2665 }
2666
8965d9f8
AC
2667 *presets = ps;
2668 ps = (Presets){};
2669
2670 return 0;
2671}
2672
2673static int query_presets(const char *name, const Presets presets) {
2674 PresetAction action = PRESET_UNKNOWN;
2675 size_t i;
2676
2677 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2678 return -EINVAL;
2679
2680 for (i = 0; i < presets.n_rules; i++)
2681 if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
2682 action = presets.rules[i].action;
2683 break;
2684 }
2685
2686 switch (action) {
2687 case PRESET_UNKNOWN:
2688 log_debug("Preset files don't specify rule for %s. Enabling.", name);
2689 return 1;
2690 case PRESET_ENABLE:
2691 log_debug("Preset files say enable %s.", name);
2692 return 1;
2693 case PRESET_DISABLE:
2694 log_debug("Preset files say disable %s.", name);
2695 return 0;
2696 default:
2697 assert_not_reached("invalid preset action");
2698 }
2699}
2700
2701int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
2702 _cleanup_(presets_freep) Presets presets = {};
2703 int r;
2704
2705 r = read_presets(scope, root_dir, &presets);
2706 if (r < 0)
2707 return r;
2708
2709 return query_presets(name, presets);
83096483
LP
2710}
2711
0ec0deaa
LP
2712static int execute_preset(
2713 UnitFileScope scope,
2714 InstallContext *plus,
2715 InstallContext *minus,
2716 const LookupPaths *paths,
2717 const char *config_path,
0ec0deaa
LP
2718 char **files,
2719 UnitFilePresetMode mode,
2720 bool force,
2721 UnitFileChange **changes,
2722 unsigned *n_changes) {
2723
2724 int r;
2725
2726 assert(plus);
2727 assert(minus);
2728 assert(paths);
2729 assert(config_path);
2730
2731 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
2732 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2733
e4bb56c7 2734 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
0ec0deaa
LP
2735 if (r < 0)
2736 return r;
2737
401017e0 2738 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes);
0ec0deaa
LP
2739 } else
2740 r = 0;
2741
2742 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
2743 int q;
2744
2745 /* Returns number of symlinks that where supposed to be installed. */
e4bb56c7 2746 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
0ec0deaa
LP
2747 if (r >= 0) {
2748 if (q < 0)
2749 r = q;
2750 else
596fc263 2751 r += q;
0ec0deaa
LP
2752 }
2753 }
2754
2755 return r;
2756}
2757
2758static int preset_prepare_one(
2759 UnitFileScope scope,
2760 InstallContext *plus,
2761 InstallContext *minus,
2762 LookupPaths *paths,
af3d8113 2763 const char *name,
8965d9f8 2764 Presets presets,
af3d8113
ZJS
2765 UnitFileChange **changes,
2766 unsigned *n_changes) {
0ec0deaa 2767
11e11fd5 2768 _cleanup_(install_context_done) InstallContext tmp = {};
0ec0deaa
LP
2769 UnitFileInstallInfo *i;
2770 int r;
2771
11e11fd5 2772 if (install_info_find(plus, name) || install_info_find(minus, name))
0ec0deaa
LP
2773 return 0;
2774
59108fbe
ZJS
2775 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2776 &i, changes, n_changes);
11e11fd5
ZJS
2777 if (r < 0)
2778 return r;
2779 if (!streq(name, i->name)) {
2780 log_debug("Skipping %s because is an alias for %s", name, i->name);
2781 return 0;
2782 }
2783
8965d9f8 2784 r = query_presets(name, presets);
0ec0deaa
LP
2785 if (r < 0)
2786 return r;
2787
2788 if (r > 0) {
59108fbe
ZJS
2789 r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2790 &i, changes, n_changes);
0ec0deaa
LP
2791 if (r < 0)
2792 return r;
2793
af3d8113 2794 r = install_info_may_process(i, paths, changes, n_changes);
76adb5b8
LP
2795 if (r < 0)
2796 return r;
0ec0deaa 2797 } else
59108fbe
ZJS
2798 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2799 &i, changes, n_changes);
0ec0deaa
LP
2800
2801 return r;
2802}
2803
83096483
LP
2804int unit_file_preset(
2805 UnitFileScope scope,
2806 bool runtime,
2807 const char *root_dir,
7195aa42 2808 char **files,
d309c1c3 2809 UnitFilePresetMode mode,
83096483
LP
2810 bool force,
2811 UnitFileChange **changes,
2812 unsigned *n_changes) {
2813
59ccf93d 2814 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
da39f6a6 2815 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8965d9f8 2816 _cleanup_(presets_freep) Presets presets = {};
e1c5c2b0 2817 const char *config_path;
da39f6a6 2818 char **i;
0ec0deaa 2819 int r;
83096483
LP
2820
2821 assert(scope >= 0);
2822 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 2823 assert(mode < _UNIT_FILE_PRESET_MAX);
83096483 2824
4943d143 2825 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2826 if (r < 0)
2827 return r;
2828
e1c5c2b0 2829 config_path = runtime ? paths.runtime_config : paths.persistent_config;
83096483 2830
8965d9f8
AC
2831 r = read_presets(scope, root_dir, &presets);
2832 if (r < 0)
2833 return r;
83096483 2834
8965d9f8 2835 STRV_FOREACH(i, files) {
ff56349d 2836 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
83096483 2837 if (r < 0)
d9e5e694 2838 return r;
83096483
LP
2839 }
2840
e4bb56c7 2841 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes);
d309c1c3
LP
2842}
2843
2844int unit_file_preset_all(
2845 UnitFileScope scope,
2846 bool runtime,
2847 const char *root_dir,
2848 UnitFilePresetMode mode,
2849 bool force,
2850 UnitFileChange **changes,
2851 unsigned *n_changes) {
2852
59ccf93d 2853 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
d309c1c3 2854 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8965d9f8 2855 _cleanup_(presets_freep) Presets presets = {};
e1c5c2b0 2856 const char *config_path = NULL;
d309c1c3 2857 char **i;
0ec0deaa 2858 int r;
d309c1c3
LP
2859
2860 assert(scope >= 0);
2861 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 2862 assert(mode < _UNIT_FILE_PRESET_MAX);
d309c1c3 2863
4943d143 2864 r = lookup_paths_init(&paths, scope, 0, root_dir);
d309c1c3
LP
2865 if (r < 0)
2866 return r;
2867
e1c5c2b0 2868 config_path = runtime ? paths.runtime_config : paths.persistent_config;
d309c1c3 2869
8965d9f8
AC
2870 r = read_presets(scope, root_dir, &presets);
2871 if (r < 0)
2872 return r;
2873
a3c4eb07 2874 STRV_FOREACH(i, paths.search_path) {
d309c1c3 2875 _cleanup_closedir_ DIR *d = NULL;
d25e100b 2876 struct dirent *de;
d309c1c3 2877
401017e0 2878 d = opendir(*i);
d309c1c3
LP
2879 if (!d) {
2880 if (errno == ENOENT)
2881 continue;
2882
2883 return -errno;
2884 }
2885
d25e100b 2886 FOREACH_DIRENT(de, d, return -errno) {
d309c1c3 2887
7410616c 2888 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
d309c1c3
LP
2889 continue;
2890
2891 dirent_ensure_type(d, de);
2892
0ec0deaa 2893 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
d309c1c3
LP
2894 continue;
2895
af3d8113 2896 /* we don't pass changes[] in, because we want to handle errors on our own */
ff56349d 2897 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
9a0a413a
ZJS
2898 if (r == -ERFKILL)
2899 r = unit_file_changes_add(changes, n_changes,
2900 UNIT_FILE_IS_MASKED, de->d_name, NULL);
893275df
ZJS
2901 else if (r == -ENOLINK)
2902 r = unit_file_changes_add(changes, n_changes,
2903 UNIT_FILE_IS_DANGLING, de->d_name, NULL);
d309c1c3
LP
2904 if (r < 0)
2905 return r;
2906 }
2907 }
2908
e4bb56c7 2909 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes);
83096483
LP
2910}
2911
59ccf93d
LP
2912static void unit_file_list_free_one(UnitFileList *f) {
2913 if (!f)
d9e5e694
ZJS
2914 return;
2915
59ccf93d
LP
2916 free(f->path);
2917 free(f);
d9e5e694 2918}
59ccf93d 2919
0ec0deaa
LP
2920Hashmap* unit_file_list_free(Hashmap *h) {
2921 UnitFileList *i;
2922
2923 while ((i = hashmap_steal_first(h)))
2924 unit_file_list_free_one(i);
2925
2926 return hashmap_free(h);
2927}
2928
59ccf93d 2929DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
d9e5e694 2930
83096483
LP
2931int unit_file_get_list(
2932 UnitFileScope scope,
2933 const char *root_dir,
313fe66f 2934 Hashmap *h,
2935 char **states,
2936 char **patterns) {
83096483 2937
7fd1b19b 2938 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 2939 char **i;
83096483
LP
2940 int r;
2941
2942 assert(scope >= 0);
2943 assert(scope < _UNIT_FILE_SCOPE_MAX);
2944 assert(h);
2945
4943d143 2946 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2947 if (r < 0)
2948 return r;
2949
a3c4eb07 2950 STRV_FOREACH(i, paths.search_path) {
da39f6a6 2951 _cleanup_closedir_ DIR *d = NULL;
d25e100b 2952 struct dirent *de;
83096483 2953
401017e0 2954 d = opendir(*i);
83096483
LP
2955 if (!d) {
2956 if (errno == ENOENT)
2957 continue;
a1feacf7
ZJS
2958 if (IN_SET(errno, ENOTDIR, EACCES)) {
2959 log_debug("Failed to open \"%s\": %m", *i);
2960 continue;
2961 }
83096483 2962
d9e5e694 2963 return -errno;
83096483
LP
2964 }
2965
d25e100b 2966 FOREACH_DIRENT(de, d, return -errno) {
59ccf93d 2967 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
83096483 2968
7410616c 2969 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
83096483
LP
2970 continue;
2971
313fe66f 2972 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
2973 continue;
2974
83096483
LP
2975 if (hashmap_get(h, de->d_name))
2976 continue;
2977
da39f6a6 2978 dirent_ensure_type(d, de);
83096483 2979
da39f6a6 2980 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
83096483
LP
2981 continue;
2982
2983 f = new0(UnitFileList, 1);
d9e5e694
ZJS
2984 if (!f)
2985 return -ENOMEM;
83096483 2986
401017e0 2987 f->path = path_make_absolute(de->d_name, *i);
d9e5e694
ZJS
2988 if (!f->path)
2989 return -ENOMEM;
83096483 2990
401017e0 2991 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
d9e5e694 2992 if (r < 0)
0ec0deaa 2993 f->state = UNIT_FILE_BAD;
81fc054d 2994
313fe66f 2995 if (!strv_isempty(states) &&
2996 !strv_contains(states, unit_file_state_to_string(f->state)))
2997 continue;
2998
2b6bf07d 2999 r = hashmap_put(h, basename(f->path), f);
d9e5e694
ZJS
3000 if (r < 0)
3001 return r;
0ec0deaa 3002
d9e5e694 3003 f = NULL; /* prevent cleanup */
83096483
LP
3004 }
3005 }
3006
77cd2c87 3007 return 0;
83096483
LP
3008}
3009
3010static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
3011 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 3012 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
3013 [UNIT_FILE_LINKED] = "linked",
3014 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
3015 [UNIT_FILE_MASKED] = "masked",
3016 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
3017 [UNIT_FILE_STATIC] = "static",
b5b46d59 3018 [UNIT_FILE_DISABLED] = "disabled",
aedd4012 3019 [UNIT_FILE_INDIRECT] = "indirect",
f4139308 3020 [UNIT_FILE_GENERATED] = "generated",
e4fca67f 3021 [UNIT_FILE_TRANSIENT] = "transient",
0ec0deaa 3022 [UNIT_FILE_BAD] = "bad",
83096483
LP
3023};
3024
3025DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
3026
3027static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
3028 [UNIT_FILE_SYMLINK] = "symlink",
3029 [UNIT_FILE_UNLINK] = "unlink",
9a0a413a 3030 [UNIT_FILE_IS_MASKED] = "masked",
893275df 3031 [UNIT_FILE_IS_DANGLING] = "dangling",
c0576cd6
LP
3032};
3033
3034DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
d309c1c3 3035
86bbe5bf 3036static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
d309c1c3
LP
3037 [UNIT_FILE_PRESET_FULL] = "full",
3038 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
3039 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
3040};
3041
3042DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);