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