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