]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/install.c
install: when disabling units, do so even if the unit is missing
[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);
425 return path_equal_or_files_same(a, b);
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;
e1c5c2b0 1896
0ec0deaa
LP
1897 STRV_FOREACH(i, files) {
1898 _cleanup_free_ char *path = NULL;
1899 int q;
1900
1901 if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) {
1902 if (r == 0)
1903 r = -EINVAL;
1904 continue;
1905 }
1906
e1c5c2b0 1907 path = path_make_absolute(*i, config_path);
0ec0deaa
LP
1908 if (!path)
1909 return -ENOMEM;
29283ea4 1910
b3796dd8 1911 q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
0ec0deaa 1912 if (q < 0 && r >= 0)
83096483
LP
1913 r = q;
1914 }
1915
1916 return r;
1917}
1918
0ec0deaa
LP
1919int unit_file_unmask(
1920 UnitFileScope scope,
b3796dd8 1921 UnitFileFlags flags,
0ec0deaa
LP
1922 const char *root_dir,
1923 char **files,
1924 UnitFileChange **changes,
1925 unsigned *n_changes) {
1926
e1c5c2b0 1927 _cleanup_lookup_paths_free_ LookupPaths paths = {};
0ec0deaa 1928 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
dc7dd61d 1929 _cleanup_strv_free_ char **todo = NULL;
0ec0deaa 1930 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 1931 const char *config_path;
0ec0deaa 1932 char **i;
3b3557c4 1933 bool dry_run;
0ec0deaa
LP
1934 int r, q;
1935
1936 assert(scope >= 0);
1937 assert(scope < _UNIT_FILE_SCOPE_MAX);
1938
4943d143 1939 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
1940 if (r < 0)
1941 return r;
1942
b3796dd8 1943 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
3b3557c4 1944 dry_run = !!(flags & UNIT_FILE_DRY_RUN);
e1c5c2b0 1945
0ec0deaa
LP
1946 STRV_FOREACH(i, files) {
1947 _cleanup_free_ char *path = NULL;
1948
1949 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
1950 return -EINVAL;
1951
1952 path = path_make_absolute(*i, config_path);
1953 if (!path)
1954 return -ENOMEM;
1955
1956 r = null_or_empty_path(path);
1957 if (r == -ENOENT)
1958 continue;
1959 if (r < 0)
1960 return r;
1961 if (r == 0)
1962 continue;
1963
1964 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
1965 return -ENOMEM;
1966
d054eae6
EV
1967 todo[n_todo] = strdup(*i);
1968 if (!todo[n_todo])
1969 return -ENOMEM;
1970
1971 n_todo++;
0ec0deaa
LP
1972 }
1973
1974 strv_uniq(todo);
1975
1976 r = 0;
1977 STRV_FOREACH(i, todo) {
1978 _cleanup_free_ char *path = NULL;
401017e0 1979 const char *rp;
0ec0deaa
LP
1980
1981 path = path_make_absolute(*i, config_path);
1982 if (!path)
1983 return -ENOMEM;
1984
3b3557c4 1985 if (!dry_run && unlink(path) < 0) {
af3d8113
ZJS
1986 if (errno != ENOENT) {
1987 if (r >= 0)
1988 r = -errno;
1989 unit_file_changes_add(changes, n_changes, -errno, path, NULL);
1990 }
0ec0deaa 1991
401017e0 1992 continue;
0ec0deaa 1993 }
401017e0
LP
1994
1995 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
1996
1997 rp = skip_root(&paths, path);
1998 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
1999 if (q < 0)
2000 return q;
0ec0deaa
LP
2001 }
2002
3b3557c4 2003 q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes);
0ec0deaa
LP
2004 if (r >= 0)
2005 r = q;
2006
2007 return r;
2008}
2009
2010int unit_file_link(
e94937df 2011 UnitFileScope scope,
b3796dd8 2012 UnitFileFlags flags,
e94937df
LN
2013 const char *root_dir,
2014 char **files,
e94937df
LN
2015 UnitFileChange **changes,
2016 unsigned *n_changes) {
2017
2018 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8af35ba6 2019 _cleanup_strv_free_ char **todo = NULL;
0ec0deaa 2020 size_t n_todo = 0, n_allocated = 0;
e1c5c2b0 2021 const char *config_path;
e94937df 2022 char **i;
0ec0deaa 2023 int r, q;
e94937df
LN
2024
2025 assert(scope >= 0);
2026 assert(scope < _UNIT_FILE_SCOPE_MAX);
2027
4943d143 2028 r = lookup_paths_init(&paths, scope, 0, root_dir);
e94937df
LN
2029 if (r < 0)
2030 return r;
2031
b3796dd8 2032 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
e94937df
LN
2033
2034 STRV_FOREACH(i, files) {
0ec0deaa
LP
2035 _cleanup_free_ char *full = NULL;
2036 struct stat st;
2037 char *fn;
e94937df 2038
0ec0deaa
LP
2039 if (!path_is_absolute(*i))
2040 return -EINVAL;
e94937df 2041
0ec0deaa
LP
2042 fn = basename(*i);
2043 if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
2044 return -EINVAL;
2045
e4bb56c7 2046 full = prefix_root(paths.root_dir, *i);
0ec0deaa
LP
2047 if (!full)
2048 return -ENOMEM;
2049
2050 if (lstat(full, &st) < 0)
2051 return -errno;
2052 if (S_ISLNK(st.st_mode))
2053 return -ELOOP;
2054 if (S_ISDIR(st.st_mode))
2055 return -EISDIR;
2056 if (!S_ISREG(st.st_mode))
2057 return -ENOTTY;
2058
32c0ed7b 2059 q = in_search_path(&paths, *i);
0ec0deaa
LP
2060 if (q < 0)
2061 return q;
2062 if (q > 0)
2063 continue;
2064
2065 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2066 return -ENOMEM;
2067
8af35ba6
EV
2068 todo[n_todo] = strdup(*i);
2069 if (!todo[n_todo])
2070 return -ENOMEM;
2071
2072 n_todo++;
e94937df
LN
2073 }
2074
0ec0deaa 2075 strv_uniq(todo);
e94937df 2076
0ec0deaa
LP
2077 r = 0;
2078 STRV_FOREACH(i, todo) {
401017e0 2079 _cleanup_free_ char *new_path = NULL;
0ec0deaa 2080
401017e0
LP
2081 new_path = path_make_absolute(basename(*i), config_path);
2082 if (!new_path)
0ec0deaa
LP
2083 return -ENOMEM;
2084
b3796dd8 2085 q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
0ec0deaa
LP
2086 if (q < 0 && r >= 0)
2087 r = q;
2d5c93c7
MS
2088 }
2089
0ec0deaa
LP
2090 return r;
2091}
2092
344ca755
LP
2093static int path_shall_revert(const LookupPaths *paths, const char *path) {
2094 int r;
2095
2096 assert(paths);
2097 assert(path);
2098
2099 /* Checks whether the path is one where the drop-in directories shall be removed. */
2100
dfead90d 2101 r = path_is_config(paths, path, true);
344ca755
LP
2102 if (r != 0)
2103 return r;
2104
2105 r = path_is_control(paths, path);
2106 if (r != 0)
2107 return r;
2108
2109 return path_is_transient(paths, path);
2110}
2111
2112int unit_file_revert(
2113 UnitFileScope scope,
2114 const char *root_dir,
2115 char **files,
2116 UnitFileChange **changes,
2117 unsigned *n_changes) {
2118
2119 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
344ca755
LP
2120 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2121 _cleanup_strv_free_ char **todo = NULL;
2122 size_t n_todo = 0, n_allocated = 0;
2123 char **i;
2124 int r, q;
2125
2126 /* Puts a unit file back into vendor state. This means:
2127 *
2128 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2129 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2130 *
2131 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2132 * "config", but not in "transient" or "control" or even "generated").
2133 *
4f25723c 2134 * We remove all that in both the runtime and the persistent directories, if that applies.
344ca755
LP
2135 */
2136
2137 r = lookup_paths_init(&paths, scope, 0, root_dir);
2138 if (r < 0)
2139 return r;
2140
2141 STRV_FOREACH(i, files) {
2142 bool has_vendor = false;
2143 char **p;
2144
2145 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2146 return -EINVAL;
2147
2148 STRV_FOREACH(p, paths.search_path) {
2149 _cleanup_free_ char *path = NULL, *dropin = NULL;
2150 struct stat st;
2151
2152 path = path_make_absolute(*i, *p);
2153 if (!path)
2154 return -ENOMEM;
2155
2156 r = lstat(path, &st);
2157 if (r < 0) {
2158 if (errno != ENOENT)
2159 return -errno;
2160 } else if (S_ISREG(st.st_mode)) {
2161 /* Check if there's a vendor version */
2162 r = path_is_vendor(&paths, path);
2163 if (r < 0)
2164 return r;
2165 if (r > 0)
2166 has_vendor = true;
2167 }
2168
2169 dropin = strappend(path, ".d");
2170 if (!dropin)
2171 return -ENOMEM;
2172
2173 r = lstat(dropin, &st);
2174 if (r < 0) {
2175 if (errno != ENOENT)
2176 return -errno;
2177 } else if (S_ISDIR(st.st_mode)) {
2178 /* Remove the drop-ins */
2179 r = path_shall_revert(&paths, dropin);
2180 if (r < 0)
2181 return r;
2182 if (r > 0) {
2183 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2184 return -ENOMEM;
2185
2186 todo[n_todo++] = dropin;
2187 dropin = NULL;
2188 }
2189 }
2190 }
2191
2192 if (!has_vendor)
2193 continue;
2194
2195 /* OK, there's a vendor version, hence drop all configuration versions */
2196 STRV_FOREACH(p, paths.search_path) {
2197 _cleanup_free_ char *path = NULL;
2198 struct stat st;
2199
2200 path = path_make_absolute(*i, *p);
2201 if (!path)
2202 return -ENOMEM;
2203
2204 r = lstat(path, &st);
2205 if (r < 0) {
2206 if (errno != ENOENT)
2207 return -errno;
2208 } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
dfead90d 2209 r = path_is_config(&paths, path, true);
344ca755
LP
2210 if (r < 0)
2211 return r;
2212 if (r > 0) {
2213 if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
2214 return -ENOMEM;
2215
2216 todo[n_todo++] = path;
2217 path = NULL;
2218 }
2219 }
2220 }
2221 }
2222
2223 strv_uniq(todo);
2224
2225 r = 0;
2226 STRV_FOREACH(i, todo) {
2227 _cleanup_strv_free_ char **fs = NULL;
2228 const char *rp;
2229 char **j;
2230
2231 (void) get_files_in_directory(*i, &fs);
2232
2233 q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
2234 if (q < 0 && q != -ENOENT && r >= 0) {
2235 r = q;
2236 continue;
2237 }
2238
2239 STRV_FOREACH(j, fs) {
2240 _cleanup_free_ char *t = NULL;
2241
605405c6 2242 t = strjoin(*i, "/", *j);
344ca755
LP
2243 if (!t)
2244 return -ENOMEM;
2245
2246 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
2247 }
2248
2249 unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
2250
2251 rp = skip_root(&paths, *i);
2252 q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
2253 if (q < 0)
2254 return q;
2255 }
2256
3b3557c4 2257 q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes);
344ca755
LP
2258 if (r >= 0)
2259 r = q;
2260
3b3557c4 2261 q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes);
344ca755
LP
2262 if (r >= 0)
2263 r = q;
2264
2265 return r;
2266}
2267
0ec0deaa
LP
2268int unit_file_add_dependency(
2269 UnitFileScope scope,
b3796dd8 2270 UnitFileFlags flags,
0ec0deaa
LP
2271 const char *root_dir,
2272 char **files,
2273 const char *target,
2274 UnitDependency dep,
0ec0deaa
LP
2275 UnitFileChange **changes,
2276 unsigned *n_changes) {
2277
2278 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2279 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2280 UnitFileInstallInfo *i, *target_info;
e1c5c2b0 2281 const char *config_path;
0ec0deaa
LP
2282 char **f;
2283 int r;
2284
2285 assert(scope >= 0);
2286 assert(scope < _UNIT_FILE_SCOPE_MAX);
2287 assert(target);
2288
2289 if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES))
2290 return -EINVAL;
2291
2292 if (!unit_name_is_valid(target, UNIT_NAME_ANY))
2293 return -EINVAL;
2294
4943d143 2295 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2296 if (r < 0)
2297 return r;
2298
b3796dd8 2299 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
0ec0deaa 2300
59108fbe
ZJS
2301 r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2302 &target_info, changes, n_changes);
0ec0deaa
LP
2303 if (r < 0)
2304 return r;
af3d8113 2305 r = install_info_may_process(target_info, &paths, changes, n_changes);
76adb5b8
LP
2306 if (r < 0)
2307 return r;
0ec0deaa
LP
2308
2309 assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
e94937df 2310
0ec0deaa
LP
2311 STRV_FOREACH(f, files) {
2312 char ***l;
2313
59108fbe
ZJS
2314 r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2315 &i, changes, n_changes);
e94937df
LN
2316 if (r < 0)
2317 return r;
af3d8113 2318 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2319 if (r < 0)
2320 return r;
0ec0deaa
LP
2321
2322 assert(i->type == UNIT_FILE_TYPE_REGULAR);
2323
2324 /* We didn't actually load anything from the unit
2325 * file, but instead just add in our new symlink to
2326 * create. */
e94937df
LN
2327
2328 if (dep == UNIT_WANTS)
0ec0deaa 2329 l = &i->wanted_by;
e94937df 2330 else
0ec0deaa 2331 l = &i->required_by;
e94937df 2332
0ec0deaa
LP
2333 strv_free(*l);
2334 *l = strv_new(target_info->name, NULL);
2335 if (!*l)
2336 return -ENOMEM;
e94937df
LN
2337 }
2338
b3796dd8 2339 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
e94937df
LN
2340}
2341
83096483
LP
2342int unit_file_enable(
2343 UnitFileScope scope,
b3796dd8 2344 UnitFileFlags flags,
83096483 2345 const char *root_dir,
7195aa42 2346 char **files,
83096483
LP
2347 UnitFileChange **changes,
2348 unsigned *n_changes) {
2349
7fd1b19b 2350 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2351 _cleanup_(install_context_done) InstallContext c = {};
e1c5c2b0 2352 const char *config_path;
0ec0deaa
LP
2353 UnitFileInstallInfo *i;
2354 char **f;
83096483
LP
2355 int r;
2356
2357 assert(scope >= 0);
2358 assert(scope < _UNIT_FILE_SCOPE_MAX);
2359
4943d143 2360 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2361 if (r < 0)
2362 return r;
2363
b3796dd8 2364 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
83096483 2365
0ec0deaa 2366 STRV_FOREACH(f, files) {
59108fbe
ZJS
2367 r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2368 &i, changes, n_changes);
83096483 2369 if (r < 0)
d9e5e694 2370 return r;
af3d8113 2371 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2372 if (r < 0)
2373 return r;
0ec0deaa
LP
2374
2375 assert(i->type == UNIT_FILE_TYPE_REGULAR);
83096483
LP
2376 }
2377
729e3769 2378 /* This will return the number of symlink rules that were
d25e100b
LP
2379 supposed to be created, not the ones actually created. This
2380 is useful to determine whether the passed files had any
2381 installation data at all. */
b91a3b02 2382
b3796dd8 2383 return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes);
83096483
LP
2384}
2385
2386int unit_file_disable(
2387 UnitFileScope scope,
b3796dd8 2388 UnitFileFlags flags,
83096483 2389 const char *root_dir,
7195aa42 2390 char **files,
83096483
LP
2391 UnitFileChange **changes,
2392 unsigned *n_changes) {
2393
7fd1b19b 2394 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2395 _cleanup_(install_context_done) InstallContext c = {};
7fd1b19b 2396 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
e1c5c2b0 2397 const char *config_path;
0ec0deaa
LP
2398 char **i;
2399 int r;
83096483
LP
2400
2401 assert(scope >= 0);
2402 assert(scope < _UNIT_FILE_SCOPE_MAX);
2403
4943d143 2404 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2405 if (r < 0)
2406 return r;
2407
b3796dd8 2408 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
83096483
LP
2409
2410 STRV_FOREACH(i, files) {
0ec0deaa
LP
2411 if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
2412 return -EINVAL;
2413
19539807 2414 r = install_info_add(&c, *i, NULL, false, NULL);
83096483 2415 if (r < 0)
d9e5e694 2416 return r;
83096483
LP
2417 }
2418
637d6e5b 2419 r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, changes, n_changes);
0ec0deaa
LP
2420 if (r < 0)
2421 return r;
83096483 2422
3b3557c4 2423 return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes);
83096483
LP
2424}
2425
2426int unit_file_reenable(
2427 UnitFileScope scope,
b3796dd8 2428 UnitFileFlags flags,
83096483 2429 const char *root_dir,
7195aa42 2430 char **files,
83096483
LP
2431 UnitFileChange **changes,
2432 unsigned *n_changes) {
0ec0deaa
LP
2433
2434 char **n;
92d430a9 2435 int r;
0ec0deaa 2436 size_t l, i;
83096483 2437
0ec0deaa
LP
2438 /* First, we invoke the disable command with only the basename... */
2439 l = strv_length(files);
2440 n = newa(char*, l+1);
2441 for (i = 0; i < l; i++)
2442 n[i] = basename(files[i]);
2443 n[i] = NULL;
2444
b3796dd8 2445 r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes);
83096483 2446 if (r < 0)
d9e5e694 2447 return r;
83096483 2448
0ec0deaa 2449 /* But the enable command with the full name */
b3796dd8 2450 return unit_file_enable(scope, flags, root_dir, files, changes, n_changes);
83096483
LP
2451}
2452
99504dd4
VP
2453int unit_file_set_default(
2454 UnitFileScope scope,
b3796dd8 2455 UnitFileFlags flags,
99504dd4 2456 const char *root_dir,
0ec0deaa 2457 const char *name,
99504dd4
VP
2458 UnitFileChange **changes,
2459 unsigned *n_changes) {
2460
2461 _cleanup_lookup_paths_free_ LookupPaths paths = {};
59ccf93d 2462 _cleanup_(install_context_done) InstallContext c = {};
0ec0deaa 2463 UnitFileInstallInfo *i;
60bec8e4 2464 const char *new_path;
99504dd4 2465 int r;
99504dd4
VP
2466
2467 assert(scope >= 0);
2468 assert(scope < _UNIT_FILE_SCOPE_MAX);
0ec0deaa 2469 assert(name);
99504dd4 2470
401017e0 2471 if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
0ec0deaa
LP
2472 return -EINVAL;
2473 if (streq(name, SPECIAL_DEFAULT_TARGET))
99504dd4
VP
2474 return -EINVAL;
2475
4943d143 2476 r = lookup_paths_init(&paths, scope, 0, root_dir);
99504dd4
VP
2477 if (r < 0)
2478 return r;
2479
59108fbe 2480 r = install_info_discover(scope, &c, &paths, name, 0, &i, changes, n_changes);
99504dd4
VP
2481 if (r < 0)
2482 return r;
af3d8113 2483 r = install_info_may_process(i, &paths, changes, n_changes);
76adb5b8
LP
2484 if (r < 0)
2485 return r;
99504dd4 2486
401017e0 2487 new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
b3796dd8 2488 return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
99504dd4
VP
2489}
2490
2491int unit_file_get_default(
2492 UnitFileScope scope,
2493 const char *root_dir,
2494 char **name) {
2495
2496 _cleanup_lookup_paths_free_ LookupPaths paths = {};
0ec0deaa
LP
2497 _cleanup_(install_context_done) InstallContext c = {};
2498 UnitFileInstallInfo *i;
2499 char *n;
99504dd4
VP
2500 int r;
2501
16ed0233
LP
2502 assert(scope >= 0);
2503 assert(scope < _UNIT_FILE_SCOPE_MAX);
2504 assert(name);
2505
4943d143 2506 r = lookup_paths_init(&paths, scope, 0, root_dir);
0ec0deaa
LP
2507 if (r < 0)
2508 return r;
99504dd4 2509
59108fbe
ZJS
2510 r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2511 &i, NULL, NULL);
0ec0deaa
LP
2512 if (r < 0)
2513 return r;
af3d8113 2514 r = install_info_may_process(i, &paths, NULL, 0);
76adb5b8
LP
2515 if (r < 0)
2516 return r;
99504dd4 2517
0ec0deaa
LP
2518 n = strdup(i->name);
2519 if (!n)
2520 return -ENOMEM;
99504dd4 2521
0ec0deaa
LP
2522 *name = n;
2523 return 0;
99504dd4
VP
2524}
2525
2c52204c 2526static int unit_file_lookup_state(
83096483 2527 UnitFileScope scope,
a8ffe6fb 2528 const LookupPaths *paths,
0ec0deaa
LP
2529 const char *name,
2530 UnitFileState *ret) {
83096483 2531
0ec0deaa
LP
2532 _cleanup_(install_context_done) InstallContext c = {};
2533 UnitFileInstallInfo *i;
2534 UnitFileState state;
2535 int r;
83096483 2536
a8ffe6fb 2537 assert(paths);
0ec0deaa 2538 assert(name);
83096483 2539
7410616c 2540 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
83096483
LP
2541 return -EINVAL;
2542
59108fbe
ZJS
2543 r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2544 &i, NULL, NULL);
0ec0deaa
LP
2545 if (r < 0)
2546 return r;
83096483 2547
0ec0deaa
LP
2548 /* Shortcut things, if the caller just wants to know if this unit exists. */
2549 if (!ret)
2550 return 0;
83096483 2551
0ec0deaa 2552 switch (i->type) {
67820a0c 2553
0ec0deaa 2554 case UNIT_FILE_TYPE_MASKED:
dfead90d 2555 r = path_is_runtime(paths, i->path, true);
385eb996
LP
2556 if (r < 0)
2557 return r;
2558
2559 state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
0ec0deaa 2560 break;
83096483 2561
0ec0deaa 2562 case UNIT_FILE_TYPE_REGULAR:
f4dc1e65 2563 r = path_is_generator(paths, i->path);
f4139308
LP
2564 if (r < 0)
2565 return r;
2566 if (r > 0) {
2567 state = UNIT_FILE_GENERATED;
2568 break;
2569 }
2570
e4fca67f
LP
2571 r = path_is_transient(paths, i->path);
2572 if (r < 0)
2573 return r;
2574 if (r > 0) {
2575 state = UNIT_FILE_TRANSIENT;
2576 break;
2577 }
2578
80cb9da3 2579 r = find_symlinks_in_scope(paths, i->name, &state);
d9e5e694
ZJS
2580 if (r < 0)
2581 return r;
0ec0deaa
LP
2582 if (r == 0) {
2583 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i))
2584 state = UNIT_FILE_DISABLED;
2585 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i))
2586 state = UNIT_FILE_INDIRECT;
2587 else
2588 state = UNIT_FILE_STATIC;
2589 }
83096483 2590
0ec0deaa
LP
2591 break;
2592
2593 default:
2594 assert_not_reached("Unexpect unit file type.");
83096483
LP
2595 }
2596
0ec0deaa
LP
2597 *ret = state;
2598 return 0;
83096483
LP
2599}
2600
0ec0deaa 2601int unit_file_get_state(
a8ffe6fb
ZJS
2602 UnitFileScope scope,
2603 const char *root_dir,
0ec0deaa
LP
2604 const char *name,
2605 UnitFileState *ret) {
a8ffe6fb
ZJS
2606
2607 _cleanup_lookup_paths_free_ LookupPaths paths = {};
2608 int r;
2609
2610 assert(scope >= 0);
2611 assert(scope < _UNIT_FILE_SCOPE_MAX);
2612 assert(name);
2613
4943d143 2614 r = lookup_paths_init(&paths, scope, 0, root_dir);
a8ffe6fb
ZJS
2615 if (r < 0)
2616 return r;
2617
e4bb56c7 2618 return unit_file_lookup_state(scope, &paths, name, ret);
a8ffe6fb
ZJS
2619}
2620
e735decc
LP
2621int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
2622 _cleanup_(install_context_done) InstallContext c = {};
2623 int r;
2624
2625 assert(paths);
2626 assert(name);
2627
2628 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2629 return -EINVAL;
2630
59108fbe 2631 r = install_info_discover(scope, &c, paths, name, 0, NULL, NULL, NULL);
e735decc
LP
2632 if (r == -ENOENT)
2633 return 0;
2634 if (r < 0)
2635 return r;
2636
2637 return 1;
2638}
2639
8965d9f8
AC
2640static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
2641 _cleanup_(presets_freep) Presets ps = {};
2642 size_t n_allocated = 0;
7fd1b19b 2643 _cleanup_strv_free_ char **files = NULL;
cba2ef02 2644 char **p;
83096483
LP
2645 int r;
2646
2647 assert(scope >= 0);
2648 assert(scope < _UNIT_FILE_SCOPE_MAX);
8965d9f8 2649 assert(presets);
0ec0deaa 2650
83096483 2651 if (scope == UNIT_FILE_SYSTEM)
c2a8d7b0 2652 r = conf_files_list(&files, ".preset", root_dir,
a7480dba
LP
2653 "/etc/systemd/system-preset",
2654 "/usr/local/lib/systemd/system-preset",
2655 "/usr/lib/systemd/system-preset",
b4bdfefa 2656#ifdef HAVE_SPLIT_USR
a7480dba 2657 "/lib/systemd/system-preset",
b4bdfefa 2658#endif
83096483
LP
2659 NULL);
2660 else if (scope == UNIT_FILE_GLOBAL)
c2a8d7b0 2661 r = conf_files_list(&files, ".preset", root_dir,
a7480dba
LP
2662 "/etc/systemd/user-preset",
2663 "/usr/local/lib/systemd/user-preset",
2664 "/usr/lib/systemd/user-preset",
83096483 2665 NULL);
8965d9f8
AC
2666 else {
2667 *presets = (Presets){};
2668
2669 return 0;
2670 }
83096483
LP
2671
2672 if (r < 0)
2673 return r;
2674
cba2ef02 2675 STRV_FOREACH(p, files) {
7fd1b19b 2676 _cleanup_fclose_ FILE *f;
0ec0deaa 2677 char line[LINE_MAX];
d544d1a4 2678 int n = 0;
83096483 2679
cba2ef02 2680 f = fopen(*p, "re");
83096483
LP
2681 if (!f) {
2682 if (errno == ENOENT)
2683 continue;
2684
d9e5e694 2685 return -errno;
83096483
LP
2686 }
2687
0ec0deaa 2688 FOREACH_LINE(line, f, return -errno) {
8965d9f8 2689 PresetRule rule = {};
0ec0deaa
LP
2690 const char *parameter;
2691 char *l;
83096483
LP
2692
2693 l = strstrip(line);
d544d1a4 2694 n++;
83096483 2695
0ec0deaa
LP
2696 if (isempty(l))
2697 continue;
2698 if (strchr(COMMENTS, *l))
83096483
LP
2699 continue;
2700
0ec0deaa
LP
2701 parameter = first_word(l, "enable");
2702 if (parameter) {
8965d9f8 2703 char *pattern;
d9e5e694 2704
8965d9f8
AC
2705 pattern = strdup(parameter);
2706 if (!pattern)
2707 return -ENOMEM;
2708
2709 rule = (PresetRule) {
2710 .pattern = pattern,
2711 .action = PRESET_ENABLE,
2712 };
0ec0deaa 2713 }
83096483 2714
0ec0deaa
LP
2715 parameter = first_word(l, "disable");
2716 if (parameter) {
8965d9f8 2717 char *pattern;
d9e5e694 2718
8965d9f8
AC
2719 pattern = strdup(parameter);
2720 if (!pattern)
2721 return -ENOMEM;
2722
2723 rule = (PresetRule) {
2724 .pattern = pattern,
2725 .action = PRESET_DISABLE,
2726 };
2727 }
2728
2729 if (rule.action) {
2730 if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
2731 return -ENOMEM;
2732
2733 ps.rules[ps.n_rules++] = rule;
0ec0deaa
LP
2734 continue;
2735 }
2736
d544d1a4 2737 log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
83096483 2738 }
83096483
LP
2739 }
2740
8965d9f8
AC
2741 *presets = ps;
2742 ps = (Presets){};
2743
2744 return 0;
2745}
2746
2747static int query_presets(const char *name, const Presets presets) {
2748 PresetAction action = PRESET_UNKNOWN;
2749 size_t i;
2750
2751 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
2752 return -EINVAL;
2753
2754 for (i = 0; i < presets.n_rules; i++)
2755 if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
2756 action = presets.rules[i].action;
2757 break;
2758 }
2759
2760 switch (action) {
2761 case PRESET_UNKNOWN:
2762 log_debug("Preset files don't specify rule for %s. Enabling.", name);
2763 return 1;
2764 case PRESET_ENABLE:
2765 log_debug("Preset files say enable %s.", name);
2766 return 1;
2767 case PRESET_DISABLE:
2768 log_debug("Preset files say disable %s.", name);
2769 return 0;
2770 default:
2771 assert_not_reached("invalid preset action");
2772 }
2773}
2774
2775int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
2776 _cleanup_(presets_freep) Presets presets = {};
2777 int r;
2778
2779 r = read_presets(scope, root_dir, &presets);
2780 if (r < 0)
2781 return r;
2782
2783 return query_presets(name, presets);
83096483
LP
2784}
2785
0ec0deaa
LP
2786static int execute_preset(
2787 UnitFileScope scope,
2788 InstallContext *plus,
2789 InstallContext *minus,
2790 const LookupPaths *paths,
2791 const char *config_path,
0ec0deaa
LP
2792 char **files,
2793 UnitFilePresetMode mode,
2794 bool force,
2795 UnitFileChange **changes,
2796 unsigned *n_changes) {
2797
2798 int r;
2799
2800 assert(plus);
2801 assert(minus);
2802 assert(paths);
2803 assert(config_path);
2804
2805 if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
2806 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
2807
637d6e5b 2808 r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, changes, n_changes);
0ec0deaa
LP
2809 if (r < 0)
2810 return r;
2811
3b3557c4 2812 r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes);
0ec0deaa
LP
2813 } else
2814 r = 0;
2815
2816 if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) {
2817 int q;
2818
2819 /* Returns number of symlinks that where supposed to be installed. */
e4bb56c7 2820 q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
0ec0deaa
LP
2821 if (r >= 0) {
2822 if (q < 0)
2823 r = q;
2824 else
596fc263 2825 r += q;
0ec0deaa
LP
2826 }
2827 }
2828
2829 return r;
2830}
2831
2832static int preset_prepare_one(
2833 UnitFileScope scope,
2834 InstallContext *plus,
2835 InstallContext *minus,
2836 LookupPaths *paths,
af3d8113 2837 const char *name,
8965d9f8 2838 Presets presets,
af3d8113
ZJS
2839 UnitFileChange **changes,
2840 unsigned *n_changes) {
0ec0deaa 2841
11e11fd5 2842 _cleanup_(install_context_done) InstallContext tmp = {};
0ec0deaa
LP
2843 UnitFileInstallInfo *i;
2844 int r;
2845
11e11fd5 2846 if (install_info_find(plus, name) || install_info_find(minus, name))
0ec0deaa
LP
2847 return 0;
2848
59108fbe
ZJS
2849 r = install_info_discover(scope, &tmp, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2850 &i, changes, n_changes);
11e11fd5
ZJS
2851 if (r < 0)
2852 return r;
2853 if (!streq(name, i->name)) {
2854 log_debug("Skipping %s because is an alias for %s", name, i->name);
2855 return 0;
2856 }
2857
8965d9f8 2858 r = query_presets(name, presets);
0ec0deaa
LP
2859 if (r < 0)
2860 return r;
2861
2862 if (r > 0) {
59108fbe
ZJS
2863 r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS,
2864 &i, changes, n_changes);
0ec0deaa
LP
2865 if (r < 0)
2866 return r;
2867
af3d8113 2868 r = install_info_may_process(i, paths, changes, n_changes);
76adb5b8
LP
2869 if (r < 0)
2870 return r;
0ec0deaa 2871 } else
59108fbe
ZJS
2872 r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS,
2873 &i, changes, n_changes);
0ec0deaa
LP
2874
2875 return r;
2876}
2877
83096483
LP
2878int unit_file_preset(
2879 UnitFileScope scope,
b3796dd8 2880 UnitFileFlags flags,
83096483 2881 const char *root_dir,
7195aa42 2882 char **files,
d309c1c3 2883 UnitFilePresetMode mode,
83096483
LP
2884 UnitFileChange **changes,
2885 unsigned *n_changes) {
2886
59ccf93d 2887 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
da39f6a6 2888 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8965d9f8 2889 _cleanup_(presets_freep) Presets presets = {};
e1c5c2b0 2890 const char *config_path;
da39f6a6 2891 char **i;
0ec0deaa 2892 int r;
83096483
LP
2893
2894 assert(scope >= 0);
2895 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 2896 assert(mode < _UNIT_FILE_PRESET_MAX);
83096483 2897
4943d143 2898 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
2899 if (r < 0)
2900 return r;
2901
b3796dd8 2902 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
83096483 2903
8965d9f8
AC
2904 r = read_presets(scope, root_dir, &presets);
2905 if (r < 0)
2906 return r;
83096483 2907
8965d9f8 2908 STRV_FOREACH(i, files) {
ff56349d 2909 r = preset_prepare_one(scope, &plus, &minus, &paths, *i, presets, changes, n_changes);
83096483 2910 if (r < 0)
d9e5e694 2911 return r;
83096483
LP
2912 }
2913
b3796dd8 2914 return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
d309c1c3
LP
2915}
2916
2917int unit_file_preset_all(
2918 UnitFileScope scope,
b3796dd8 2919 UnitFileFlags flags,
d309c1c3
LP
2920 const char *root_dir,
2921 UnitFilePresetMode mode,
d309c1c3
LP
2922 UnitFileChange **changes,
2923 unsigned *n_changes) {
2924
59ccf93d 2925 _cleanup_(install_context_done) InstallContext plus = {}, minus = {};
d309c1c3 2926 _cleanup_lookup_paths_free_ LookupPaths paths = {};
8965d9f8 2927 _cleanup_(presets_freep) Presets presets = {};
e1c5c2b0 2928 const char *config_path = NULL;
d309c1c3 2929 char **i;
0ec0deaa 2930 int r;
d309c1c3
LP
2931
2932 assert(scope >= 0);
2933 assert(scope < _UNIT_FILE_SCOPE_MAX);
86bbe5bf 2934 assert(mode < _UNIT_FILE_PRESET_MAX);
d309c1c3 2935
4943d143 2936 r = lookup_paths_init(&paths, scope, 0, root_dir);
d309c1c3
LP
2937 if (r < 0)
2938 return r;
2939
b3796dd8 2940 config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
d309c1c3 2941
8965d9f8
AC
2942 r = read_presets(scope, root_dir, &presets);
2943 if (r < 0)
2944 return r;
2945
a3c4eb07 2946 STRV_FOREACH(i, paths.search_path) {
d309c1c3 2947 _cleanup_closedir_ DIR *d = NULL;
d25e100b 2948 struct dirent *de;
d309c1c3 2949
401017e0 2950 d = opendir(*i);
d309c1c3
LP
2951 if (!d) {
2952 if (errno == ENOENT)
2953 continue;
2954
2955 return -errno;
2956 }
2957
d25e100b 2958 FOREACH_DIRENT(de, d, return -errno) {
d309c1c3 2959
7410616c 2960 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
d309c1c3
LP
2961 continue;
2962
2963 dirent_ensure_type(d, de);
2964
0ec0deaa 2965 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
d309c1c3
LP
2966 continue;
2967
af3d8113 2968 /* we don't pass changes[] in, because we want to handle errors on our own */
ff56349d 2969 r = preset_prepare_one(scope, &plus, &minus, &paths, de->d_name, presets, NULL, 0);
9a0a413a
ZJS
2970 if (r == -ERFKILL)
2971 r = unit_file_changes_add(changes, n_changes,
2972 UNIT_FILE_IS_MASKED, de->d_name, NULL);
893275df
ZJS
2973 else if (r == -ENOLINK)
2974 r = unit_file_changes_add(changes, n_changes,
2975 UNIT_FILE_IS_DANGLING, de->d_name, NULL);
d309c1c3
LP
2976 if (r < 0)
2977 return r;
2978 }
2979 }
2980
b3796dd8 2981 return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes);
83096483
LP
2982}
2983
59ccf93d
LP
2984static void unit_file_list_free_one(UnitFileList *f) {
2985 if (!f)
d9e5e694
ZJS
2986 return;
2987
59ccf93d
LP
2988 free(f->path);
2989 free(f);
d9e5e694 2990}
59ccf93d 2991
0ec0deaa
LP
2992Hashmap* unit_file_list_free(Hashmap *h) {
2993 UnitFileList *i;
2994
2995 while ((i = hashmap_steal_first(h)))
2996 unit_file_list_free_one(i);
2997
2998 return hashmap_free(h);
2999}
3000
59ccf93d 3001DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
d9e5e694 3002
83096483
LP
3003int unit_file_get_list(
3004 UnitFileScope scope,
3005 const char *root_dir,
313fe66f 3006 Hashmap *h,
3007 char **states,
3008 char **patterns) {
83096483 3009
7fd1b19b 3010 _cleanup_lookup_paths_free_ LookupPaths paths = {};
d9e5e694 3011 char **i;
83096483
LP
3012 int r;
3013
3014 assert(scope >= 0);
3015 assert(scope < _UNIT_FILE_SCOPE_MAX);
3016 assert(h);
3017
4943d143 3018 r = lookup_paths_init(&paths, scope, 0, root_dir);
83096483
LP
3019 if (r < 0)
3020 return r;
3021
a3c4eb07 3022 STRV_FOREACH(i, paths.search_path) {
da39f6a6 3023 _cleanup_closedir_ DIR *d = NULL;
d25e100b 3024 struct dirent *de;
83096483 3025
401017e0 3026 d = opendir(*i);
83096483
LP
3027 if (!d) {
3028 if (errno == ENOENT)
3029 continue;
a1feacf7
ZJS
3030 if (IN_SET(errno, ENOTDIR, EACCES)) {
3031 log_debug("Failed to open \"%s\": %m", *i);
3032 continue;
3033 }
83096483 3034
d9e5e694 3035 return -errno;
83096483
LP
3036 }
3037
d25e100b 3038 FOREACH_DIRENT(de, d, return -errno) {
59ccf93d 3039 _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL;
83096483 3040
7410616c 3041 if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
83096483
LP
3042 continue;
3043
313fe66f 3044 if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
3045 continue;
3046
83096483
LP
3047 if (hashmap_get(h, de->d_name))
3048 continue;
3049
da39f6a6 3050 dirent_ensure_type(d, de);
83096483 3051
da39f6a6 3052 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
83096483
LP
3053 continue;
3054
3055 f = new0(UnitFileList, 1);
d9e5e694
ZJS
3056 if (!f)
3057 return -ENOMEM;
83096483 3058
401017e0 3059 f->path = path_make_absolute(de->d_name, *i);
d9e5e694
ZJS
3060 if (!f->path)
3061 return -ENOMEM;
83096483 3062
401017e0 3063 r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
d9e5e694 3064 if (r < 0)
0ec0deaa 3065 f->state = UNIT_FILE_BAD;
81fc054d 3066
313fe66f 3067 if (!strv_isempty(states) &&
3068 !strv_contains(states, unit_file_state_to_string(f->state)))
3069 continue;
3070
2b6bf07d 3071 r = hashmap_put(h, basename(f->path), f);
d9e5e694
ZJS
3072 if (r < 0)
3073 return r;
0ec0deaa 3074
d9e5e694 3075 f = NULL; /* prevent cleanup */
83096483
LP
3076 }
3077 }
3078
77cd2c87 3079 return 0;
83096483
LP
3080}
3081
3082static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
3083 [UNIT_FILE_ENABLED] = "enabled",
771faa9a 3084 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
83096483
LP
3085 [UNIT_FILE_LINKED] = "linked",
3086 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
3087 [UNIT_FILE_MASKED] = "masked",
3088 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
3089 [UNIT_FILE_STATIC] = "static",
b5b46d59 3090 [UNIT_FILE_DISABLED] = "disabled",
aedd4012 3091 [UNIT_FILE_INDIRECT] = "indirect",
f4139308 3092 [UNIT_FILE_GENERATED] = "generated",
e4fca67f 3093 [UNIT_FILE_TRANSIENT] = "transient",
0ec0deaa 3094 [UNIT_FILE_BAD] = "bad",
83096483
LP
3095};
3096
3097DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
c0576cd6
LP
3098
3099static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
3100 [UNIT_FILE_SYMLINK] = "symlink",
3101 [UNIT_FILE_UNLINK] = "unlink",
9a0a413a 3102 [UNIT_FILE_IS_MASKED] = "masked",
893275df 3103 [UNIT_FILE_IS_DANGLING] = "dangling",
c0576cd6
LP
3104};
3105
3106DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
d309c1c3 3107
86bbe5bf 3108static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = {
d309c1c3
LP
3109 [UNIT_FILE_PRESET_FULL] = "full",
3110 [UNIT_FILE_PRESET_ENABLE_ONLY] = "enable-only",
3111 [UNIT_FILE_PRESET_DISABLE_ONLY] = "disable-only",
3112};
3113
3114DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode, UnitFilePresetMode);