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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include "path-lookup.h"
33 #include "unit-name.h"
35 #include "conf-parser.h"
46 Hashmap *will_install;
47 Hashmap *have_installed;
50 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
53 assert(scope < _UNIT_FILE_SCOPE_MAX);
57 return lookup_paths_init(paths,
58 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
59 scope == UNIT_FILE_USER);
62 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
67 assert(scope < _UNIT_FILE_SCOPE_MAX);
72 case UNIT_FILE_SYSTEM:
74 if (root_dir && runtime)
75 asprintf(&p, "%s/run/systemd/system", root_dir);
77 p = strdup("/run/systemd/system");
79 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
81 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
85 case UNIT_FILE_GLOBAL:
91 p = strdup("/run/systemd/user");
93 p = strdup(USER_CONFIG_UNIT_PATH);
98 if (root_dir || runtime)
101 r = user_config_home(&p);
103 return r < 0 ? r : -ENOENT;
108 assert_not_reached("Bad scope");
118 static int add_file_change(
119 UnitFileChange **changes,
121 UnitFileChangeType type,
123 const char *source) {
129 assert(!changes == !n_changes);
134 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
142 c[i].path = strdup(path);
147 c[i].source = strdup(source);
159 static int mark_symlink_for_removal(
160 Set **remove_symlinks_to,
168 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
176 path_kill_slashes(n);
178 r = set_put(*remove_symlinks_to, n);
181 return r == -EEXIST ? 0 : r;
187 static int remove_marked_symlinks_fd(
188 Set *remove_symlinks_to,
191 const char *config_path,
193 UnitFileChange **changes,
194 unsigned *n_changes) {
198 struct dirent buffer, *de;
200 assert(remove_symlinks_to);
208 close_nointr_nofail(fd);
217 k = readdir_r(d, &buffer, &de);
226 if (ignore_file(de->d_name))
229 dirent_ensure_type(d, de);
231 if (de->d_type == DT_DIR) {
235 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
245 p = path_make_absolute(de->d_name, path);
247 close_nointr_nofail(nfd);
252 /* This will close nfd, regardless whether it succeeds or not */
253 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
259 } else if (de->d_type == DT_LNK) {
264 p = path_make_absolute(de->d_name, path);
270 q = readlink_and_canonicalize(p, &dest);
283 set_get(remove_symlinks_to, dest) ||
284 set_get(remove_symlinks_to, file_name_from_path(dest));
288 if (unlink(p) < 0 && errno != ENOENT) {
293 rmdir_parents(p, config_path);
294 path_kill_slashes(p);
296 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
298 if (!set_get(remove_symlinks_to, p)) {
300 q = mark_symlink_for_removal(&remove_symlinks_to, p);
320 static int remove_marked_symlinks(
321 Set *remove_symlinks_to,
322 const char *config_path,
323 UnitFileChange **changes,
324 unsigned *n_changes) {
331 if (set_size(remove_symlinks_to) <= 0)
334 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
348 /* This takes possession of cfd and closes it */
349 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
354 close_nointr_nofail(fd);
359 static int find_symlinks_fd(
363 const char *config_path,
364 bool *same_name_link) {
368 struct dirent buffer, *de;
374 assert(same_name_link);
378 close_nointr_nofail(fd);
385 k = readdir_r(d, &buffer, &de);
394 if (ignore_file(de->d_name))
397 dirent_ensure_type(d, de);
399 if (de->d_type == DT_DIR) {
403 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
413 p = path_make_absolute(de->d_name, path);
415 close_nointr_nofail(nfd);
420 /* This will close nfd, regardless whether it succeeds or not */
421 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
432 } else if (de->d_type == DT_LNK) {
434 bool found_path, found_dest, b = false;
437 /* Acquire symlink name */
438 p = path_make_absolute(de->d_name, path);
444 /* Acquire symlink destination */
445 q = readlink_and_canonicalize(p, &dest);
457 /* Check if the symlink itself matches what we
459 if (path_is_absolute(name))
460 found_path = path_equal(p, name);
462 found_path = streq(de->d_name, name);
464 /* Check if what the symlink points to
465 * matches what we are looking for */
466 if (path_is_absolute(name))
467 found_dest = path_equal(dest, name);
469 found_dest = streq(file_name_from_path(dest), name);
473 if (found_path && found_dest) {
476 /* Filter out same name links in the main
478 t = path_make_absolute(name, config_path);
485 b = path_equal(t, p);
492 *same_name_link = true;
493 else if (found_path || found_dest) {
505 static int find_symlinks(
507 const char *config_path,
508 bool *same_name_link) {
514 assert(same_name_link);
516 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
520 /* This takes possession of fd and closes it */
521 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
524 static int find_symlinks_in_scope(
526 const char *root_dir,
528 UnitFileState *state) {
532 bool same_name_link_runtime = false, same_name_link = false;
535 assert(scope < _UNIT_FILE_SCOPE_MAX);
538 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
540 /* First look in runtime config path */
541 r = get_config_path(scope, true, root_dir, &path);
545 r = find_symlinks(name, path, &same_name_link_runtime);
551 *state = UNIT_FILE_ENABLED_RUNTIME;
556 /* Then look in the normal config path */
557 r = get_config_path(scope, false, root_dir, &path);
561 r = find_symlinks(name, path, &same_name_link);
567 *state = UNIT_FILE_ENABLED;
571 /* Hmm, we didn't find it, but maybe we found the same name
573 if (same_name_link_runtime) {
574 *state = UNIT_FILE_LINKED_RUNTIME;
576 } else if (same_name_link) {
577 *state = UNIT_FILE_LINKED;
587 const char *root_dir,
590 UnitFileChange **changes,
591 unsigned *n_changes) {
597 assert(scope < _UNIT_FILE_SCOPE_MAX);
599 r = get_config_path(scope, runtime, root_dir, &prefix);
603 STRV_FOREACH(i, files) {
606 if (!unit_name_is_valid_no_type(*i, true)) {
612 path = path_make_absolute(*i, prefix);
618 if (symlink("/dev/null", path) >= 0) {
619 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
625 if (errno == EEXIST) {
627 if (null_or_empty_path(path) > 0) {
635 if (symlink("/dev/null", path) >= 0) {
637 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
638 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
660 int unit_file_unmask(
663 const char *root_dir,
665 UnitFileChange **changes,
666 unsigned *n_changes) {
668 char **i, *config_path = NULL;
670 Set *remove_symlinks_to = NULL;
673 assert(scope < _UNIT_FILE_SCOPE_MAX);
675 r = get_config_path(scope, runtime, root_dir, &config_path);
679 STRV_FOREACH(i, files) {
682 if (!unit_name_is_valid_no_type(*i, true)) {
688 path = path_make_absolute(*i, config_path);
694 q = null_or_empty_path(path);
696 if (unlink(path) >= 0) {
697 mark_symlink_for_removal(&remove_symlinks_to, path);
698 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
707 if (q != -ENOENT && r == 0)
715 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
719 set_free_free(remove_symlinks_to);
728 const char *root_dir,
731 UnitFileChange **changes,
732 unsigned *n_changes) {
735 char **i, *config_path = NULL;
739 assert(scope < _UNIT_FILE_SCOPE_MAX);
743 r = lookup_paths_init_from_scope(&paths, scope);
747 r = get_config_path(scope, runtime, root_dir, &config_path);
751 STRV_FOREACH(i, files) {
755 fn = file_name_from_path(*i);
757 if (!path_is_absolute(*i) ||
758 !unit_name_is_valid_no_type(fn, true)) {
764 if (lstat(*i, &st) < 0) {
770 if (!S_ISREG(st.st_mode)) {
775 q = in_search_path(*i, paths.unit_path);
784 path = path_make_absolute(fn, config_path);
790 if (symlink(*i, path) >= 0) {
791 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
797 if (errno == EEXIST) {
800 q = readlink_and_make_absolute(path, &dest);
802 if (q < 0 && errno != ENOENT) {
811 if (q >= 0 && path_equal(dest, *i)) {
822 if (symlink(*i, path) >= 0) {
824 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
825 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
843 lookup_paths_free(&paths);
849 void unit_file_list_free(Hashmap *h) {
852 while ((i = hashmap_steal_first(h))) {
860 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
863 assert(changes || n_changes == 0);
868 for (i = 0; i < n_changes; i++) {
869 free(changes[i].path);
870 free(changes[i].source);
876 static void install_info_free(InstallInfo *i) {
881 strv_free(i->aliases);
882 strv_free(i->wanted_by);
886 static void install_info_hashmap_free(Hashmap *m) {
892 while ((i = hashmap_steal_first(m)))
893 install_info_free(i);
898 static void install_context_done(InstallContext *c) {
901 install_info_hashmap_free(c->will_install);
902 install_info_hashmap_free(c->have_installed);
904 c->will_install = c->have_installed = NULL;
907 static int install_info_add(
911 InstallInfo *i = NULL;
915 assert(name || path);
918 name = file_name_from_path(path);
920 if (!unit_name_is_valid_no_type(name, true))
923 if (hashmap_get(c->have_installed, name) ||
924 hashmap_get(c->will_install, name))
927 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
931 i = new0(InstallInfo, 1);
935 i->name = strdup(name);
942 i->path = strdup(path);
949 r = hashmap_put(c->will_install, i->name, i);
957 install_info_free(i);
962 static int install_info_add_auto(
964 const char *name_or_path) {
967 assert(name_or_path);
969 if (path_is_absolute(name_or_path))
970 return install_info_add(c, NULL, name_or_path);
972 return install_info_add(c, name_or_path, NULL);
975 static int config_parse_also(
976 const char *filename,
988 InstallContext *c = data;
994 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1002 r = install_info_add(c, n, NULL);
1014 static int unit_file_load(
1018 bool allow_symlink) {
1020 const ConfigTableItem items[] = {
1021 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1022 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1023 { "Install", "Also", config_parse_also, 0, c },
1024 { NULL, NULL, NULL, 0, NULL }
1035 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1039 f = fdopen(fd, "re");
1041 close_nointr_nofail(fd);
1045 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1050 return strv_length(info->aliases) + strv_length(info->wanted_by);
1053 static int unit_file_search(
1057 const char *root_dir,
1058 bool allow_symlink) {
1068 return unit_file_load(c, info, info->path, allow_symlink);
1072 STRV_FOREACH(p, paths->unit_path) {
1075 if (isempty(root_dir))
1076 asprintf(&path, "%s/%s", *p, info->name);
1078 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1083 r = unit_file_load(c, info, path, allow_symlink);
1090 if (r != -ENOENT && r != -ELOOP)
1097 static int unit_file_can_install(
1099 const char *root_dir,
1101 bool allow_symlink) {
1112 r = install_info_add_auto(&c, name);
1116 assert_se(i = hashmap_first(c.will_install));
1118 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1121 r = strv_length(i->aliases) + strv_length(i->wanted_by);
1123 install_context_done(&c);
1128 static int create_symlink(
1129 const char *old_path,
1130 const char *new_path,
1132 UnitFileChange **changes,
1133 unsigned *n_changes) {
1141 mkdir_parents(new_path, 0755);
1143 if (symlink(old_path, new_path) >= 0) {
1144 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1148 if (errno != EEXIST)
1151 r = readlink_and_make_absolute(new_path, &dest);
1155 if (path_equal(dest, old_path)) {
1167 if (symlink(old_path, new_path) >= 0) {
1168 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1169 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1176 static int install_info_symlink_alias(
1178 const char *config_path,
1180 UnitFileChange **changes,
1181 unsigned *n_changes) {
1187 assert(config_path);
1189 STRV_FOREACH(s, i->aliases) {
1192 alias_path = path_make_absolute(*s, config_path);
1197 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1207 static int install_info_symlink_wants(
1209 const char *config_path,
1211 UnitFileChange **changes,
1212 unsigned *n_changes) {
1218 assert(config_path);
1220 STRV_FOREACH(s, i->wanted_by) {
1223 if (!unit_name_is_valid_no_type(*s, true)) {
1228 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1231 q = create_symlink(i->path, path, force, changes, n_changes);
1241 static int install_info_symlink_link(
1244 const char *config_path,
1246 UnitFileChange **changes,
1247 unsigned *n_changes) {
1254 assert(config_path);
1257 r = in_search_path(i->path, paths->unit_path);
1261 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1264 r = create_symlink(i->path, path, force, changes, n_changes);
1270 static int install_info_apply(
1273 const char *config_path,
1275 UnitFileChange **changes,
1276 unsigned *n_changes) {
1282 assert(config_path);
1284 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1286 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1290 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1297 static int install_context_apply(
1300 const char *config_path,
1301 const char *root_dir,
1303 UnitFileChange **changes,
1304 unsigned *n_changes) {
1311 assert(config_path);
1313 while ((i = hashmap_first(c->will_install))) {
1315 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1319 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1321 q = unit_file_search(c, i, paths, root_dir, false);
1330 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1331 if (r >= 0 && q < 0)
1338 static int install_context_mark_for_removal(
1341 Set **remove_symlinks_to,
1342 const char *config_path,
1343 const char *root_dir) {
1350 assert(config_path);
1352 /* Marks all items for removal */
1354 while ((i = hashmap_first(c->will_install))) {
1356 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1360 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1362 q = unit_file_search(c, i, paths, root_dir, false);
1371 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1372 if (r >= 0 && q < 0)
1379 int unit_file_enable(
1380 UnitFileScope scope,
1382 const char *root_dir,
1385 UnitFileChange **changes,
1386 unsigned *n_changes) {
1390 char **i, *config_path = NULL;
1394 assert(scope < _UNIT_FILE_SCOPE_MAX);
1399 r = lookup_paths_init_from_scope(&paths, scope);
1403 r = get_config_path(scope, runtime, root_dir, &config_path);
1407 STRV_FOREACH(i, files) {
1408 r = install_info_add_auto(&c, *i);
1413 /* This will return the number of symlink rules that were
1414 supposed to be created, not the ones actually created. This is
1415 useful to determine whether the passed files hat any
1416 installation data at all. */
1417 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1420 install_context_done(&c);
1421 lookup_paths_free(&paths);
1427 int unit_file_disable(
1428 UnitFileScope scope,
1430 const char *root_dir,
1432 UnitFileChange **changes,
1433 unsigned *n_changes) {
1437 char **i, *config_path = NULL;
1438 Set *remove_symlinks_to = NULL;
1442 assert(scope < _UNIT_FILE_SCOPE_MAX);
1447 r = lookup_paths_init_from_scope(&paths, scope);
1451 r = get_config_path(scope, runtime, root_dir, &config_path);
1455 STRV_FOREACH(i, files) {
1456 r = install_info_add_auto(&c, *i);
1461 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1463 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1468 install_context_done(&c);
1469 lookup_paths_free(&paths);
1470 set_free_free(remove_symlinks_to);
1476 int unit_file_reenable(
1477 UnitFileScope scope,
1479 const char *root_dir,
1482 UnitFileChange **changes,
1483 unsigned *n_changes) {
1487 char **i, *config_path = NULL;
1488 Set *remove_symlinks_to = NULL;
1492 assert(scope < _UNIT_FILE_SCOPE_MAX);
1497 r = lookup_paths_init_from_scope(&paths, scope);
1501 r = get_config_path(scope, runtime, root_dir, &config_path);
1505 STRV_FOREACH(i, files) {
1506 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1510 r = install_info_add_auto(&c, *i);
1515 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1517 /* Returns number of symlinks that where supposed to be installed. */
1518 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1523 lookup_paths_free(&paths);
1524 install_context_done(&c);
1525 set_free_free(remove_symlinks_to);
1531 UnitFileState unit_file_get_state(
1532 UnitFileScope scope,
1533 const char *root_dir,
1537 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1538 char **i, *path = NULL;
1542 assert(scope < _UNIT_FILE_SCOPE_MAX);
1547 if (root_dir && scope != UNIT_FILE_SYSTEM)
1550 if (!unit_name_is_valid_no_type(name, true))
1553 r = lookup_paths_init_from_scope(&paths, scope);
1557 STRV_FOREACH(i, paths.unit_path) {
1564 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1566 asprintf(&path, "%s/%s", *i, name);
1573 if (lstat(path, &st) < 0) {
1574 if (errno == ENOENT)
1581 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1586 r = null_or_empty_path(path);
1587 if (r < 0 && r != -ENOENT)
1590 state = path_startswith(*i, "/run") ?
1591 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1596 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1604 r = unit_file_can_install(&paths, root_dir, path, true);
1605 if (r < 0 && errno != -ENOENT)
1608 state = UNIT_FILE_DISABLED;
1611 } else if (r == 0) {
1612 state = UNIT_FILE_STATIC;
1619 lookup_paths_free(&paths);
1622 return r < 0 ? r : state;
1625 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1630 assert(scope < _UNIT_FILE_SCOPE_MAX);
1633 if (scope == UNIT_FILE_SYSTEM)
1634 r = conf_files_list(&files, ".preset",
1635 "/etc/systemd/system.preset",
1636 "/usr/local/lib/systemd/system.preset",
1637 "/usr/lib/systemd/system.preset",
1638 "/lib/systemd/system.preset",
1640 else if (scope == UNIT_FILE_GLOBAL)
1641 r = conf_files_list(&files, ".preset",
1642 "/etc/systemd/user.preset",
1643 "/usr/local/lib/systemd/user.preset",
1644 "/usr/lib/systemd/user.preset",
1652 STRV_FOREACH(i, files) {
1655 f = fopen(*i, "re");
1657 if (errno == ENOENT)
1665 char line[LINE_MAX], *l;
1667 if (!fgets(line, sizeof(line), f))
1674 if (strchr(COMMENTS, *l))
1677 if (first_word(l, "enable")) {
1679 l += strspn(l, WHITESPACE);
1681 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1686 } else if (first_word(l, "disable")) {
1688 l += strspn(l, WHITESPACE);
1690 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1696 log_debug("Couldn't parse line '%s'", l);
1702 /* Default is "enable" */
1711 int unit_file_preset(
1712 UnitFileScope scope,
1714 const char *root_dir,
1717 UnitFileChange **changes,
1718 unsigned *n_changes) {
1721 InstallContext plus, minus;
1722 char **i, *config_path = NULL;
1723 Set *remove_symlinks_to = NULL;
1727 assert(scope < _UNIT_FILE_SCOPE_MAX);
1733 r = lookup_paths_init_from_scope(&paths, scope);
1737 r = get_config_path(scope, runtime, root_dir, &config_path);
1741 STRV_FOREACH(i, files) {
1743 if (!unit_name_is_valid_no_type(*i, true)) {
1748 r = unit_file_query_preset(scope, *i);
1753 r = install_info_add_auto(&plus, *i);
1755 r = install_info_add_auto(&minus, *i);
1761 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1763 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1767 /* Returns number of symlinks that where supposed to be installed. */
1768 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1773 lookup_paths_free(&paths);
1774 install_context_done(&plus);
1775 install_context_done(&minus);
1776 set_free_free(remove_symlinks_to);
1782 int unit_file_get_list(
1783 UnitFileScope scope,
1784 const char *root_dir,
1788 char **i, *buf = NULL;
1793 assert(scope < _UNIT_FILE_SCOPE_MAX);
1798 if (root_dir && scope != UNIT_FILE_SYSTEM)
1801 r = lookup_paths_init_from_scope(&paths, scope);
1805 STRV_FOREACH(i, paths.unit_path) {
1806 struct dirent buffer, *de;
1807 const char *units_dir;
1813 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1824 d = opendir(units_dir);
1826 if (errno == ENOENT)
1836 r = readdir_r(d, &buffer, &de);
1845 if (ignore_file(de->d_name))
1848 if (!unit_name_is_valid_no_type(de->d_name, true))
1851 if (hashmap_get(h, de->d_name))
1854 r = dirent_ensure_type(d, de);
1856 if (errno == ENOENT)
1862 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1865 f = new0(UnitFileList, 1);
1871 f->path = path_make_absolute(de->d_name, units_dir);
1878 r = null_or_empty_path(f->path);
1879 if (r < 0 && r != -ENOENT) {
1885 path_startswith(*i, "/run") ?
1886 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1890 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1898 r = unit_file_can_install(&paths, root_dir, f->path, true);
1904 f->state = UNIT_FILE_DISABLED;
1907 f->state = UNIT_FILE_STATIC;
1916 r = hashmap_put(h, file_name_from_path(f->path), f);
1926 lookup_paths_free(&paths);
1935 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1936 [UNIT_FILE_ENABLED] = "enabled",
1937 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtie",
1938 [UNIT_FILE_LINKED] = "linked",
1939 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1940 [UNIT_FILE_MASKED] = "masked",
1941 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1942 [UNIT_FILE_STATIC] = "static",
1943 [UNIT_FILE_DISABLED] = "disabled"
1946 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1948 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1949 [UNIT_FILE_SYMLINK] = "symlink",
1950 [UNIT_FILE_UNLINK] = "unlink",
1953 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);