1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
32 #include "path-util.h"
33 #include "path-lookup.h"
35 #include "unit-name.h"
37 #include "conf-parser.h"
38 #include "conf-files.h"
49 Hashmap *will_install;
50 Hashmap *have_installed;
53 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
56 assert(scope < _UNIT_FILE_SCOPE_MAX);
60 return lookup_paths_init(paths,
61 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
62 scope == UNIT_FILE_USER);
65 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
70 assert(scope < _UNIT_FILE_SCOPE_MAX);
75 case UNIT_FILE_SYSTEM:
77 if (root_dir && runtime)
78 asprintf(&p, "%s/run/systemd/system", root_dir);
80 p = strdup("/run/systemd/system");
82 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
84 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
88 case UNIT_FILE_GLOBAL:
94 p = strdup("/run/systemd/user");
96 p = strdup(USER_CONFIG_UNIT_PATH);
101 if (root_dir || runtime)
104 r = user_config_home(&p);
106 return r < 0 ? r : -ENOENT;
111 assert_not_reached("Bad scope");
121 static int add_file_change(
122 UnitFileChange **changes,
124 UnitFileChangeType type,
126 const char *source) {
132 assert(!changes == !n_changes);
137 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
145 c[i].path = strdup(path);
150 c[i].source = strdup(source);
162 static int mark_symlink_for_removal(
163 Set **remove_symlinks_to,
171 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
179 path_kill_slashes(n);
181 r = set_put(*remove_symlinks_to, n);
184 return r == -EEXIST ? 0 : r;
190 static int remove_marked_symlinks_fd(
191 Set *remove_symlinks_to,
194 const char *config_path,
196 UnitFileChange **changes,
197 unsigned *n_changes) {
201 struct dirent buffer, *de;
203 assert(remove_symlinks_to);
211 close_nointr_nofail(fd);
220 k = readdir_r(d, &buffer, &de);
229 if (ignore_file(de->d_name))
232 dirent_ensure_type(d, de);
234 if (de->d_type == DT_DIR) {
238 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
248 p = path_make_absolute(de->d_name, path);
250 close_nointr_nofail(nfd);
255 /* This will close nfd, regardless whether it succeeds or not */
256 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
262 } else if (de->d_type == DT_LNK) {
267 p = path_make_absolute(de->d_name, path);
273 q = readlink_and_canonicalize(p, &dest);
286 set_get(remove_symlinks_to, dest) ||
287 set_get(remove_symlinks_to, path_get_file_name(dest));
291 if (unlink(p) < 0 && errno != ENOENT) {
296 rmdir_parents(p, config_path);
297 path_kill_slashes(p);
299 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
301 if (!set_get(remove_symlinks_to, p)) {
303 q = mark_symlink_for_removal(&remove_symlinks_to, p);
323 static int remove_marked_symlinks(
324 Set *remove_symlinks_to,
325 const char *config_path,
326 UnitFileChange **changes,
327 unsigned *n_changes) {
334 if (set_size(remove_symlinks_to) <= 0)
337 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
351 /* This takes possession of cfd and closes it */
352 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
357 close_nointr_nofail(fd);
362 static int find_symlinks_fd(
366 const char *config_path,
367 bool *same_name_link) {
371 struct dirent buffer, *de;
377 assert(same_name_link);
381 close_nointr_nofail(fd);
388 k = readdir_r(d, &buffer, &de);
397 if (ignore_file(de->d_name))
400 dirent_ensure_type(d, de);
402 if (de->d_type == DT_DIR) {
406 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
416 p = path_make_absolute(de->d_name, path);
418 close_nointr_nofail(nfd);
423 /* This will close nfd, regardless whether it succeeds or not */
424 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
435 } else if (de->d_type == DT_LNK) {
437 bool found_path, found_dest, b = false;
440 /* Acquire symlink name */
441 p = path_make_absolute(de->d_name, path);
447 /* Acquire symlink destination */
448 q = readlink_and_canonicalize(p, &dest);
460 /* Check if the symlink itself matches what we
462 if (path_is_absolute(name))
463 found_path = path_equal(p, name);
465 found_path = streq(de->d_name, name);
467 /* Check if what the symlink points to
468 * matches what we are looking for */
469 if (path_is_absolute(name))
470 found_dest = path_equal(dest, name);
472 found_dest = streq(path_get_file_name(dest), name);
476 if (found_path && found_dest) {
479 /* Filter out same name links in the main
481 t = path_make_absolute(name, config_path);
488 b = path_equal(t, p);
495 *same_name_link = true;
496 else if (found_path || found_dest) {
508 static int find_symlinks(
510 const char *config_path,
511 bool *same_name_link) {
517 assert(same_name_link);
519 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
523 /* This takes possession of fd and closes it */
524 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
527 static int find_symlinks_in_scope(
529 const char *root_dir,
531 UnitFileState *state) {
535 bool same_name_link_runtime = false, same_name_link = false;
538 assert(scope < _UNIT_FILE_SCOPE_MAX);
541 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
543 /* First look in runtime config path */
544 r = get_config_path(scope, true, root_dir, &path);
548 r = find_symlinks(name, path, &same_name_link_runtime);
554 *state = UNIT_FILE_ENABLED_RUNTIME;
559 /* Then look in the normal config path */
560 r = get_config_path(scope, false, root_dir, &path);
564 r = find_symlinks(name, path, &same_name_link);
570 *state = UNIT_FILE_ENABLED;
574 /* Hmm, we didn't find it, but maybe we found the same name
576 if (same_name_link_runtime) {
577 *state = UNIT_FILE_LINKED_RUNTIME;
579 } else if (same_name_link) {
580 *state = UNIT_FILE_LINKED;
590 const char *root_dir,
593 UnitFileChange **changes,
594 unsigned *n_changes) {
600 assert(scope < _UNIT_FILE_SCOPE_MAX);
602 r = get_config_path(scope, runtime, root_dir, &prefix);
606 STRV_FOREACH(i, files) {
609 if (!unit_name_is_valid_no_type(*i, true)) {
615 path = path_make_absolute(*i, prefix);
621 if (symlink("/dev/null", path) >= 0) {
622 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
628 if (errno == EEXIST) {
630 if (null_or_empty_path(path) > 0) {
638 if (symlink("/dev/null", path) >= 0) {
640 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
641 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
663 int unit_file_unmask(
666 const char *root_dir,
668 UnitFileChange **changes,
669 unsigned *n_changes) {
671 char **i, *config_path = NULL;
673 Set *remove_symlinks_to = NULL;
676 assert(scope < _UNIT_FILE_SCOPE_MAX);
678 r = get_config_path(scope, runtime, root_dir, &config_path);
682 STRV_FOREACH(i, files) {
685 if (!unit_name_is_valid_no_type(*i, true)) {
691 path = path_make_absolute(*i, config_path);
697 q = null_or_empty_path(path);
699 if (unlink(path) >= 0) {
700 mark_symlink_for_removal(&remove_symlinks_to, path);
701 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
710 if (q != -ENOENT && r == 0)
718 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
722 set_free_free(remove_symlinks_to);
731 const char *root_dir,
734 UnitFileChange **changes,
735 unsigned *n_changes) {
738 char **i, *config_path = NULL;
742 assert(scope < _UNIT_FILE_SCOPE_MAX);
746 r = lookup_paths_init_from_scope(&paths, scope);
750 r = get_config_path(scope, runtime, root_dir, &config_path);
754 STRV_FOREACH(i, files) {
758 fn = path_get_file_name(*i);
760 if (!path_is_absolute(*i) ||
761 !unit_name_is_valid_no_type(fn, true)) {
767 if (lstat(*i, &st) < 0) {
773 if (!S_ISREG(st.st_mode)) {
778 q = in_search_path(*i, paths.unit_path);
787 path = path_make_absolute(fn, config_path);
793 if (symlink(*i, path) >= 0) {
794 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
800 if (errno == EEXIST) {
803 q = readlink_and_make_absolute(path, &dest);
805 if (q < 0 && errno != ENOENT) {
814 if (q >= 0 && path_equal(dest, *i)) {
825 if (symlink(*i, path) >= 0) {
827 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
828 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
846 lookup_paths_free(&paths);
852 void unit_file_list_free(Hashmap *h) {
855 while ((i = hashmap_steal_first(h))) {
863 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
866 assert(changes || n_changes == 0);
871 for (i = 0; i < n_changes; i++) {
872 free(changes[i].path);
873 free(changes[i].source);
879 static void install_info_free(InstallInfo *i) {
884 strv_free(i->aliases);
885 strv_free(i->wanted_by);
889 static void install_info_hashmap_free(Hashmap *m) {
895 while ((i = hashmap_steal_first(m)))
896 install_info_free(i);
901 static void install_context_done(InstallContext *c) {
904 install_info_hashmap_free(c->will_install);
905 install_info_hashmap_free(c->have_installed);
907 c->will_install = c->have_installed = NULL;
910 static int install_info_add(
914 InstallInfo *i = NULL;
918 assert(name || path);
921 name = path_get_file_name(path);
923 if (!unit_name_is_valid_no_type(name, true))
926 if (hashmap_get(c->have_installed, name) ||
927 hashmap_get(c->will_install, name))
930 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
934 i = new0(InstallInfo, 1);
938 i->name = strdup(name);
945 i->path = strdup(path);
952 r = hashmap_put(c->will_install, i->name, i);
960 install_info_free(i);
965 static int install_info_add_auto(
967 const char *name_or_path) {
970 assert(name_or_path);
972 if (path_is_absolute(name_or_path))
973 return install_info_add(c, NULL, name_or_path);
975 return install_info_add(c, name_or_path, NULL);
978 static int config_parse_also(
979 const char *filename,
991 InstallContext *c = data;
997 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1005 r = install_info_add(c, n, NULL);
1017 static int unit_file_load(
1021 bool allow_symlink) {
1023 const ConfigTableItem items[] = {
1024 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1025 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1026 { "Install", "Also", config_parse_also, 0, c },
1027 { NULL, NULL, NULL, 0, NULL }
1038 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1042 f = fdopen(fd, "re");
1044 close_nointr_nofail(fd);
1048 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1053 return strv_length(info->aliases) + strv_length(info->wanted_by);
1056 static int unit_file_search(
1060 const char *root_dir,
1061 bool allow_symlink) {
1071 return unit_file_load(c, info, info->path, allow_symlink);
1075 STRV_FOREACH(p, paths->unit_path) {
1078 if (isempty(root_dir))
1079 asprintf(&path, "%s/%s", *p, info->name);
1081 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1086 r = unit_file_load(c, info, path, allow_symlink);
1093 if (r != -ENOENT && r != -ELOOP)
1100 static int unit_file_can_install(
1102 const char *root_dir,
1104 bool allow_symlink) {
1115 r = install_info_add_auto(&c, name);
1119 assert_se(i = hashmap_first(c.will_install));
1121 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1124 r = strv_length(i->aliases) + strv_length(i->wanted_by);
1126 install_context_done(&c);
1131 static int create_symlink(
1132 const char *old_path,
1133 const char *new_path,
1135 UnitFileChange **changes,
1136 unsigned *n_changes) {
1144 mkdir_parents(new_path, 0755);
1146 if (symlink(old_path, new_path) >= 0) {
1147 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1151 if (errno != EEXIST)
1154 r = readlink_and_make_absolute(new_path, &dest);
1158 if (path_equal(dest, old_path)) {
1170 if (symlink(old_path, new_path) >= 0) {
1171 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1172 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1179 static int install_info_symlink_alias(
1181 const char *config_path,
1183 UnitFileChange **changes,
1184 unsigned *n_changes) {
1190 assert(config_path);
1192 STRV_FOREACH(s, i->aliases) {
1195 alias_path = path_make_absolute(*s, config_path);
1200 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1210 static int install_info_symlink_wants(
1212 const char *config_path,
1214 UnitFileChange **changes,
1215 unsigned *n_changes) {
1221 assert(config_path);
1223 STRV_FOREACH(s, i->wanted_by) {
1226 if (!unit_name_is_valid_no_type(*s, true)) {
1231 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1234 q = create_symlink(i->path, path, force, changes, n_changes);
1244 static int install_info_symlink_link(
1247 const char *config_path,
1249 UnitFileChange **changes,
1250 unsigned *n_changes) {
1257 assert(config_path);
1260 r = in_search_path(i->path, paths->unit_path);
1264 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1267 r = create_symlink(i->path, path, force, changes, n_changes);
1273 static int install_info_apply(
1276 const char *config_path,
1278 UnitFileChange **changes,
1279 unsigned *n_changes) {
1285 assert(config_path);
1287 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1289 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1293 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1300 static int install_context_apply(
1303 const char *config_path,
1304 const char *root_dir,
1306 UnitFileChange **changes,
1307 unsigned *n_changes) {
1314 assert(config_path);
1316 while ((i = hashmap_first(c->will_install))) {
1318 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1322 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1324 q = unit_file_search(c, i, paths, root_dir, false);
1333 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1334 if (r >= 0 && q < 0)
1341 static int install_context_mark_for_removal(
1344 Set **remove_symlinks_to,
1345 const char *config_path,
1346 const char *root_dir) {
1353 assert(config_path);
1355 /* Marks all items for removal */
1357 while ((i = hashmap_first(c->will_install))) {
1359 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1363 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1365 q = unit_file_search(c, i, paths, root_dir, false);
1374 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1375 if (r >= 0 && q < 0)
1382 int unit_file_enable(
1383 UnitFileScope scope,
1385 const char *root_dir,
1388 UnitFileChange **changes,
1389 unsigned *n_changes) {
1393 char **i, *config_path = NULL;
1397 assert(scope < _UNIT_FILE_SCOPE_MAX);
1402 r = lookup_paths_init_from_scope(&paths, scope);
1406 r = get_config_path(scope, runtime, root_dir, &config_path);
1410 STRV_FOREACH(i, files) {
1411 r = install_info_add_auto(&c, *i);
1416 /* This will return the number of symlink rules that were
1417 supposed to be created, not the ones actually created. This is
1418 useful to determine whether the passed files hat any
1419 installation data at all. */
1420 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1423 install_context_done(&c);
1424 lookup_paths_free(&paths);
1430 int unit_file_disable(
1431 UnitFileScope scope,
1433 const char *root_dir,
1435 UnitFileChange **changes,
1436 unsigned *n_changes) {
1440 char **i, *config_path = NULL;
1441 Set *remove_symlinks_to = NULL;
1445 assert(scope < _UNIT_FILE_SCOPE_MAX);
1450 r = lookup_paths_init_from_scope(&paths, scope);
1454 r = get_config_path(scope, runtime, root_dir, &config_path);
1458 STRV_FOREACH(i, files) {
1459 r = install_info_add_auto(&c, *i);
1464 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1466 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1471 install_context_done(&c);
1472 lookup_paths_free(&paths);
1473 set_free_free(remove_symlinks_to);
1479 int unit_file_reenable(
1480 UnitFileScope scope,
1482 const char *root_dir,
1485 UnitFileChange **changes,
1486 unsigned *n_changes) {
1490 char **i, *config_path = NULL;
1491 Set *remove_symlinks_to = NULL;
1495 assert(scope < _UNIT_FILE_SCOPE_MAX);
1500 r = lookup_paths_init_from_scope(&paths, scope);
1504 r = get_config_path(scope, runtime, root_dir, &config_path);
1508 STRV_FOREACH(i, files) {
1509 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1513 r = install_info_add_auto(&c, *i);
1518 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1520 /* Returns number of symlinks that where supposed to be installed. */
1521 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1526 lookup_paths_free(&paths);
1527 install_context_done(&c);
1528 set_free_free(remove_symlinks_to);
1534 UnitFileState unit_file_get_state(
1535 UnitFileScope scope,
1536 const char *root_dir,
1540 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1541 char **i, *path = NULL;
1545 assert(scope < _UNIT_FILE_SCOPE_MAX);
1550 if (root_dir && scope != UNIT_FILE_SYSTEM)
1553 if (!unit_name_is_valid_no_type(name, true))
1556 r = lookup_paths_init_from_scope(&paths, scope);
1560 STRV_FOREACH(i, paths.unit_path) {
1567 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1569 asprintf(&path, "%s/%s", *i, name);
1576 if (lstat(path, &st) < 0) {
1578 if (errno == ENOENT)
1584 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1589 r = null_or_empty_path(path);
1590 if (r < 0 && r != -ENOENT)
1593 state = path_startswith(*i, "/run") ?
1594 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1599 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1607 r = unit_file_can_install(&paths, root_dir, path, true);
1608 if (r < 0 && errno != -ENOENT)
1611 state = UNIT_FILE_DISABLED;
1614 } else if (r == 0) {
1615 state = UNIT_FILE_STATIC;
1622 lookup_paths_free(&paths);
1625 return r < 0 ? r : state;
1628 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1633 assert(scope < _UNIT_FILE_SCOPE_MAX);
1636 if (scope == UNIT_FILE_SYSTEM)
1637 r = conf_files_list(&files, ".preset",
1638 "/etc/systemd/system.preset",
1639 "/usr/local/lib/systemd/system.preset",
1640 "/usr/lib/systemd/system.preset",
1641 "/lib/systemd/system.preset",
1643 else if (scope == UNIT_FILE_GLOBAL)
1644 r = conf_files_list(&files, ".preset",
1645 "/etc/systemd/user.preset",
1646 "/usr/local/lib/systemd/user.preset",
1647 "/usr/lib/systemd/user.preset",
1655 STRV_FOREACH(i, files) {
1658 f = fopen(*i, "re");
1660 if (errno == ENOENT)
1668 char line[LINE_MAX], *l;
1670 if (!fgets(line, sizeof(line), f))
1677 if (strchr(COMMENTS, *l))
1680 if (first_word(l, "enable")) {
1682 l += strspn(l, WHITESPACE);
1684 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1689 } else if (first_word(l, "disable")) {
1691 l += strspn(l, WHITESPACE);
1693 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1699 log_debug("Couldn't parse line '%s'", l);
1705 /* Default is "enable" */
1714 int unit_file_preset(
1715 UnitFileScope scope,
1717 const char *root_dir,
1720 UnitFileChange **changes,
1721 unsigned *n_changes) {
1724 InstallContext plus, minus;
1725 char **i, *config_path = NULL;
1726 Set *remove_symlinks_to = NULL;
1730 assert(scope < _UNIT_FILE_SCOPE_MAX);
1736 r = lookup_paths_init_from_scope(&paths, scope);
1740 r = get_config_path(scope, runtime, root_dir, &config_path);
1744 STRV_FOREACH(i, files) {
1746 if (!unit_name_is_valid_no_type(*i, true)) {
1751 r = unit_file_query_preset(scope, *i);
1756 r = install_info_add_auto(&plus, *i);
1758 r = install_info_add_auto(&minus, *i);
1764 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1766 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1770 /* Returns number of symlinks that where supposed to be installed. */
1771 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1776 lookup_paths_free(&paths);
1777 install_context_done(&plus);
1778 install_context_done(&minus);
1779 set_free_free(remove_symlinks_to);
1785 int unit_file_get_list(
1786 UnitFileScope scope,
1787 const char *root_dir,
1791 char **i, *buf = NULL;
1796 assert(scope < _UNIT_FILE_SCOPE_MAX);
1801 if (root_dir && scope != UNIT_FILE_SYSTEM)
1804 r = lookup_paths_init_from_scope(&paths, scope);
1808 STRV_FOREACH(i, paths.unit_path) {
1809 struct dirent buffer, *de;
1810 const char *units_dir;
1816 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1827 d = opendir(units_dir);
1829 if (errno == ENOENT)
1839 r = readdir_r(d, &buffer, &de);
1848 if (ignore_file(de->d_name))
1851 if (!unit_name_is_valid_no_type(de->d_name, true))
1854 if (hashmap_get(h, de->d_name))
1857 r = dirent_ensure_type(d, de);
1865 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1868 f = new0(UnitFileList, 1);
1874 f->path = path_make_absolute(de->d_name, units_dir);
1881 r = null_or_empty_path(f->path);
1882 if (r < 0 && r != -ENOENT) {
1888 path_startswith(*i, "/run") ?
1889 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1893 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1901 r = unit_file_can_install(&paths, root_dir, f->path, true);
1907 f->state = UNIT_FILE_DISABLED;
1910 f->state = UNIT_FILE_STATIC;
1919 r = hashmap_put(h, path_get_file_name(f->path), f);
1929 lookup_paths_free(&paths);
1938 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1939 [UNIT_FILE_ENABLED] = "enabled",
1940 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1941 [UNIT_FILE_LINKED] = "linked",
1942 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1943 [UNIT_FILE_MASKED] = "masked",
1944 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1945 [UNIT_FILE_STATIC] = "static",
1946 [UNIT_FILE_DISABLED] = "disabled"
1949 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1951 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1952 [UNIT_FILE_SYMLINK] = "symlink",
1953 [UNIT_FILE_UNLINK] = "unlink",
1956 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);