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