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