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