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)
78 p = strdup("/run/systemd/system");
80 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
82 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
86 case UNIT_FILE_GLOBAL:
92 p = strdup("/run/systemd/user");
94 p = strdup(USER_CONFIG_UNIT_PATH);
99 if (root_dir || runtime)
102 r = user_config_home(&p);
104 return r < 0 ? r : -ENOENT;
109 assert_not_reached("Bad scope");
119 static int add_file_change(
120 UnitFileChange **changes,
122 UnitFileChangeType type,
124 const char *source) {
130 assert(!changes == !n_changes);
135 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
143 c[i].path = strdup(path);
148 c[i].source = strdup(source);
160 static int mark_symlink_for_removal(
161 Set **remove_symlinks_to,
169 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
177 path_kill_slashes(n);
179 r = set_put(*remove_symlinks_to, n);
182 return r == -EEXIST ? 0 : r;
188 static int remove_marked_symlinks_fd(
189 Set *remove_symlinks_to,
192 const char *config_path,
194 UnitFileChange **changes,
195 unsigned *n_changes) {
199 struct dirent buffer, *de;
201 assert(remove_symlinks_to);
209 close_nointr_nofail(fd);
218 k = readdir_r(d, &buffer, &de);
227 if (ignore_file(de->d_name))
230 dirent_ensure_type(d, de);
232 if (de->d_type == DT_DIR) {
236 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
246 p = path_make_absolute(de->d_name, path);
248 close_nointr_nofail(nfd);
253 /* This will close nfd, regardless whether it succeeds or not */
254 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
260 } else if (de->d_type == DT_LNK) {
265 p = path_make_absolute(de->d_name, path);
271 q = readlink_and_canonicalize(p, &dest);
284 set_get(remove_symlinks_to, dest) ||
285 set_get(remove_symlinks_to, file_name_from_path(dest));
289 if (unlink(p) < 0 && errno != ENOENT) {
294 rmdir_parents(p, config_path);
295 path_kill_slashes(p);
297 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
299 if (!set_get(remove_symlinks_to, p)) {
301 q = mark_symlink_for_removal(&remove_symlinks_to, p);
321 static int remove_marked_symlinks(
322 Set *remove_symlinks_to,
323 const char *config_path,
324 UnitFileChange **changes,
325 unsigned *n_changes) {
332 if (set_size(remove_symlinks_to) <= 0)
335 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
349 /* This takes possession of cfd and closes it */
350 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
355 close_nointr_nofail(fd);
360 static int find_symlinks_fd(
364 const char *config_path,
365 bool *same_name_link) {
369 struct dirent buffer, *de;
375 assert(same_name_link);
379 close_nointr_nofail(fd);
386 k = readdir_r(d, &buffer, &de);
395 if (ignore_file(de->d_name))
398 dirent_ensure_type(d, de);
400 if (de->d_type == DT_DIR) {
404 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
414 p = path_make_absolute(de->d_name, path);
416 close_nointr_nofail(nfd);
421 /* This will close nfd, regardless whether it succeeds or not */
422 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
433 } else if (de->d_type == DT_LNK) {
435 bool found_path, found_dest, b = false;
438 /* Acquire symlink name */
439 p = path_make_absolute(de->d_name, path);
445 /* Acquire symlink destination */
446 q = readlink_and_canonicalize(p, &dest);
458 /* Check if the symlink itself matches what we
460 if (path_is_absolute(name))
461 found_path = path_equal(p, name);
463 found_path = streq(de->d_name, name);
465 /* Check if what the symlink points to
466 * matches what we are looking for */
467 if (path_is_absolute(name))
468 found_dest = path_equal(dest, name);
470 found_dest = streq(file_name_from_path(dest), name);
474 if (found_path && found_dest) {
477 /* Filter out same name links in the main
479 t = path_make_absolute(name, config_path);
487 b = path_equal(t, p);
494 *same_name_link = true;
495 else if (found_path || found_dest) {
507 static int find_symlinks(
509 const char *config_path,
510 bool *same_name_link) {
516 assert(same_name_link);
518 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
522 /* This takes possession of fd and closes it */
523 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
526 static int find_symlinks_in_scope(
528 const char *root_dir,
530 UnitFileState *state) {
534 bool same_name_link_runtime = false, same_name_link = false;
537 assert(scope < _UNIT_FILE_SCOPE_MAX);
540 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
542 /* First look in runtime config path */
543 r = get_config_path(scope, true, root_dir, &path);
547 r = find_symlinks(name, path, &same_name_link_runtime);
553 *state = UNIT_FILE_ENABLED_RUNTIME;
558 /* Then look in the normal config path */
559 r = get_config_path(scope, false, root_dir, &path);
563 r = find_symlinks(name, path, &same_name_link);
569 *state = UNIT_FILE_ENABLED;
573 /* Hmm, we didn't find it, but maybe we found the same name
575 if (same_name_link_runtime) {
576 *state = UNIT_FILE_LINKED_RUNTIME;
578 } else if (same_name_link) {
579 *state = UNIT_FILE_LINKED;
589 const char *root_dir,
592 UnitFileChange **changes,
593 unsigned *n_changes) {
599 assert(scope < _UNIT_FILE_SCOPE_MAX);
601 r = get_config_path(scope, runtime, root_dir, &prefix);
605 STRV_FOREACH(i, files) {
608 if (!unit_name_is_valid_no_type(*i, true)) {
614 path = path_make_absolute(*i, prefix);
620 if (symlink("/dev/null", path) >= 0) {
621 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
627 if (errno == EEXIST) {
629 if (null_or_empty_path(path) > 0) {
637 if (symlink("/dev/null", path) >= 0) {
639 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
640 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
662 int unit_file_unmask(
665 const char *root_dir,
667 UnitFileChange **changes,
668 unsigned *n_changes) {
670 char **i, *config_path = NULL;
672 Set *remove_symlinks_to = NULL;
675 assert(scope < _UNIT_FILE_SCOPE_MAX);
677 r = get_config_path(scope, runtime, root_dir, &config_path);
681 STRV_FOREACH(i, files) {
684 if (!unit_name_is_valid_no_type(*i, true)) {
690 path = path_make_absolute(*i, config_path);
696 q = null_or_empty_path(path);
698 if (unlink(path) >= 0) {
699 mark_symlink_for_removal(&remove_symlinks_to, path);
700 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
709 if (q != -ENOENT && r == 0)
717 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
721 set_free_free(remove_symlinks_to);
730 const char *root_dir,
733 UnitFileChange **changes,
734 unsigned *n_changes) {
737 char **i, *config_path = NULL;
741 assert(scope < _UNIT_FILE_SCOPE_MAX);
745 r = lookup_paths_init_from_scope(&paths, scope);
749 r = get_config_path(scope, runtime, root_dir, &config_path);
753 STRV_FOREACH(i, files) {
757 fn = file_name_from_path(*i);
759 if (!path_is_absolute(*i) ||
760 !unit_name_is_valid_no_type(fn, true)) {
766 if (lstat(*i, &st) < 0) {
772 if (!S_ISREG(st.st_mode)) {
777 q = in_search_path(*i, paths.unit_path);
786 path = path_make_absolute(fn, config_path);
792 if (symlink(*i, path) >= 0) {
793 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
799 if (errno == EEXIST) {
802 q = readlink_and_make_absolute(path, &dest);
804 if (q < 0 && errno != ENOENT) {
813 if (q >= 0 && path_equal(dest, *i)) {
824 if (symlink(*i, path) >= 0) {
826 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
827 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
845 lookup_paths_free(&paths);
851 void unit_file_list_free(Hashmap *h) {
854 while ((i = hashmap_steal_first(h))) {
862 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
865 assert(changes || n_changes == 0);
870 for (i = 0; i < n_changes; i++) {
871 free(changes[i].path);
872 free(changes[i].source);
878 static void install_info_free(InstallInfo *i) {
883 strv_free(i->aliases);
884 strv_free(i->wanted_by);
888 static void install_info_hashmap_free(Hashmap *m) {
894 while ((i = hashmap_steal_first(m)))
895 install_info_free(i);
900 static void install_context_done(InstallContext *c) {
903 install_info_hashmap_free(c->will_install);
904 install_info_hashmap_free(c->have_installed);
906 c->will_install = c->have_installed = NULL;
909 static int install_info_add(
913 InstallInfo *i = NULL;
917 assert(name || path);
920 name = file_name_from_path(path);
922 if (!unit_name_is_valid_no_type(name, true))
925 if (hashmap_get(c->have_installed, name) ||
926 hashmap_get(c->will_install, name))
929 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
933 i = new0(InstallInfo, 1);
937 i->name = strdup(name);
944 i->path = strdup(path);
951 r = hashmap_put(c->will_install, i->name, i);
959 install_info_free(i);
964 static int install_info_add_auto(
966 const char *name_or_path) {
969 assert(name_or_path);
971 if (path_is_absolute(name_or_path))
972 return install_info_add(c, NULL, name_or_path);
974 return install_info_add(c, name_or_path, NULL);
977 static int config_parse_also(
978 const char *filename,
990 InstallContext *c = data;
996 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1004 r = install_info_add(c, n, NULL);
1016 static int unit_file_load(
1020 bool allow_symlink) {
1022 const ConfigTableItem items[] = {
1023 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1024 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1025 { "Install", "Also", config_parse_also, 0, c },
1026 { NULL, NULL, NULL, 0, NULL }
1037 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1041 f = fdopen(fd, "re");
1043 close_nointr_nofail(fd);
1047 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1052 return strv_length(info->aliases) + strv_length(info->wanted_by);
1055 static int unit_file_search(
1059 const char *root_dir,
1060 bool allow_symlink) {
1070 return unit_file_load(c, info, info->path, allow_symlink);
1074 STRV_FOREACH(p, paths->unit_path) {
1077 if (isempty(root_dir))
1078 asprintf(&path, "%s/%s", *p, info->name);
1080 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1085 r = unit_file_load(c, info, path, allow_symlink);
1092 if (r != -ENOENT && r != -ELOOP)
1099 static int unit_file_can_install(
1101 const char *root_dir,
1103 bool allow_symlink) {
1114 r = install_info_add_auto(&c, name);
1118 assert_se(i = hashmap_first(c.will_install));
1120 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1123 r = strv_length(i->aliases) + strv_length(i->wanted_by);
1125 install_context_done(&c);
1130 static int create_symlink(
1131 const char *old_path,
1132 const char *new_path,
1134 UnitFileChange **changes,
1135 unsigned *n_changes) {
1143 mkdir_parents(new_path, 0755);
1145 if (symlink(old_path, new_path) >= 0) {
1146 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1150 if (errno != EEXIST)
1153 r = readlink_and_make_absolute(new_path, &dest);
1157 if (path_equal(dest, old_path)) {
1169 if (symlink(old_path, new_path) >= 0) {
1170 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1171 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1178 static int install_info_symlink_alias(
1180 const char *config_path,
1182 UnitFileChange **changes,
1183 unsigned *n_changes) {
1189 assert(config_path);
1191 STRV_FOREACH(s, i->aliases) {
1194 alias_path = path_make_absolute(*s, config_path);
1199 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1209 static int install_info_symlink_wants(
1211 const char *config_path,
1213 UnitFileChange **changes,
1214 unsigned *n_changes) {
1220 assert(config_path);
1222 STRV_FOREACH(s, i->wanted_by) {
1225 if (!unit_name_is_valid_no_type(*s, true)) {
1230 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1233 q = create_symlink(i->path, path, force, changes, n_changes);
1243 static int install_info_symlink_link(
1246 const char *config_path,
1248 UnitFileChange **changes,
1249 unsigned *n_changes) {
1256 assert(config_path);
1259 r = in_search_path(i->path, paths->unit_path);
1263 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1266 r = create_symlink(i->path, path, force, changes, n_changes);
1272 static int install_info_apply(
1275 const char *config_path,
1277 UnitFileChange **changes,
1278 unsigned *n_changes) {
1284 assert(config_path);
1286 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1288 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1292 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1299 static int install_context_apply(
1302 const char *config_path,
1303 const char *root_dir,
1305 UnitFileChange **changes,
1306 unsigned *n_changes) {
1313 assert(config_path);
1315 while ((i = hashmap_first(c->will_install))) {
1317 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1321 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1323 q = unit_file_search(c, i, paths, root_dir, false);
1332 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1333 if (r >= 0 && q < 0)
1340 static int install_context_mark_for_removal(
1343 Set **remove_symlinks_to,
1344 const char *config_path,
1345 const char *root_dir) {
1352 assert(config_path);
1354 /* Marks all items for removal */
1356 while ((i = hashmap_first(c->will_install))) {
1358 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1362 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1364 q = unit_file_search(c, i, paths, root_dir, false);
1373 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1374 if (r >= 0 && q < 0)
1381 int unit_file_enable(
1382 UnitFileScope scope,
1384 const char *root_dir,
1387 UnitFileChange **changes,
1388 unsigned *n_changes) {
1392 char **i, *config_path = NULL;
1396 assert(scope < _UNIT_FILE_SCOPE_MAX);
1401 r = lookup_paths_init_from_scope(&paths, scope);
1405 r = get_config_path(scope, runtime, root_dir, &config_path);
1409 STRV_FOREACH(i, files) {
1410 r = install_info_add_auto(&c, *i);
1415 /* This will return the number of symlink rules that were
1416 supposed to be created, not the ones actually created. This is
1417 useful to determine whether the passed files hat any
1418 installation data at all. */
1419 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1422 install_context_done(&c);
1423 lookup_paths_free(&paths);
1429 int unit_file_disable(
1430 UnitFileScope scope,
1432 const char *root_dir,
1434 UnitFileChange **changes,
1435 unsigned *n_changes) {
1439 char **i, *config_path = NULL;
1440 Set *remove_symlinks_to = NULL;
1444 assert(scope < _UNIT_FILE_SCOPE_MAX);
1449 r = lookup_paths_init_from_scope(&paths, scope);
1453 r = get_config_path(scope, runtime, root_dir, &config_path);
1457 STRV_FOREACH(i, files) {
1458 r = install_info_add_auto(&c, *i);
1463 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1465 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1470 install_context_done(&c);
1471 lookup_paths_free(&paths);
1472 set_free_free(remove_symlinks_to);
1478 int unit_file_reenable(
1479 UnitFileScope scope,
1481 const char *root_dir,
1484 UnitFileChange **changes,
1485 unsigned *n_changes) {
1489 char **i, *config_path = NULL;
1490 Set *remove_symlinks_to = NULL;
1494 assert(scope < _UNIT_FILE_SCOPE_MAX);
1499 r = lookup_paths_init_from_scope(&paths, scope);
1503 r = get_config_path(scope, runtime, root_dir, &config_path);
1507 STRV_FOREACH(i, files) {
1508 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1512 r = install_info_add_auto(&c, *i);
1517 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1519 /* Returns number of symlinks that where supposed to be installed. */
1520 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1525 lookup_paths_free(&paths);
1526 install_context_done(&c);
1527 set_free_free(remove_symlinks_to);
1533 UnitFileState unit_file_get_state(
1534 UnitFileScope scope,
1535 const char *root_dir,
1539 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1540 char **i, *path = NULL;
1544 assert(scope < _UNIT_FILE_SCOPE_MAX);
1549 if (root_dir && scope != UNIT_FILE_SYSTEM)
1552 if (!unit_name_is_valid_no_type(name, true))
1555 r = lookup_paths_init_from_scope(&paths, scope);
1559 STRV_FOREACH(i, paths.unit_path) {
1566 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1568 asprintf(&path, "%s/%s", *i, name);
1575 if (lstat(path, &st) < 0) {
1576 if (errno == ENOENT)
1583 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1588 r = null_or_empty_path(path);
1589 if (r < 0 && r != -ENOENT)
1592 state = path_startswith(*i, "/run") ?
1593 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1598 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1606 r = unit_file_can_install(&paths, root_dir, path, true);
1607 if (r < 0 && errno != -ENOENT)
1610 state = UNIT_FILE_DISABLED;
1613 } else if (r == 0) {
1614 state = UNIT_FILE_STATIC;
1621 lookup_paths_free(&paths);
1624 return r < 0 ? r : state;
1627 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1632 assert(scope < _UNIT_FILE_SCOPE_MAX);
1635 if (scope == UNIT_FILE_SYSTEM)
1636 r = conf_files_list(&files, ".preset",
1637 "/etc/systemd/system.preset",
1638 "/usr/local/lib/systemd/system.preset",
1639 "/usr/lib/systemd/system.preset",
1640 "/lib/systemd/system.preset",
1642 else if (scope == UNIT_FILE_GLOBAL)
1643 r = conf_files_list(&files, ".preset",
1644 "/etc/systemd/user.preset",
1645 "/usr/local/lib/systemd/user.preset",
1646 "/usr/lib/systemd/user.preset",
1654 STRV_FOREACH(i, files) {
1657 f = fopen(*i, "re");
1659 if (errno == ENOENT)
1667 char line[LINE_MAX], *l;
1669 if (!fgets(line, sizeof(line), f))
1676 if (strchr(COMMENTS, *l))
1679 if (first_word(l, "enable")) {
1681 l += strspn(l, WHITESPACE);
1683 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1688 } else if (first_word(l, "disable")) {
1690 l += strspn(l, WHITESPACE);
1692 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1698 log_debug("Couldn't parse line '%s'", l);
1704 /* Default is "enable" */
1713 int unit_file_preset(
1714 UnitFileScope scope,
1716 const char *root_dir,
1719 UnitFileChange **changes,
1720 unsigned *n_changes) {
1723 InstallContext plus, minus;
1724 char **i, *config_path = NULL;
1725 Set *remove_symlinks_to = NULL;
1729 assert(scope < _UNIT_FILE_SCOPE_MAX);
1735 r = lookup_paths_init_from_scope(&paths, scope);
1739 r = get_config_path(scope, runtime, root_dir, &config_path);
1743 STRV_FOREACH(i, files) {
1745 if (!unit_name_is_valid_no_type(*i, true)) {
1750 r = unit_file_query_preset(scope, *i);
1755 r = install_info_add_auto(&plus, *i);
1757 r = install_info_add_auto(&minus, *i);
1763 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1765 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1769 /* Returns number of symlinks that where supposed to be installed. */
1770 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1775 lookup_paths_free(&paths);
1776 install_context_done(&plus);
1777 install_context_done(&minus);
1778 set_free_free(remove_symlinks_to);
1784 int unit_file_get_list(
1785 UnitFileScope scope,
1786 const char *root_dir,
1790 char **i, *buf = NULL;
1795 assert(scope < _UNIT_FILE_SCOPE_MAX);
1800 if (root_dir && scope != UNIT_FILE_SYSTEM)
1803 r = lookup_paths_init_from_scope(&paths, scope);
1807 STRV_FOREACH(i, paths.unit_path) {
1808 struct dirent buffer, *de;
1809 const char *units_dir;
1815 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1826 d = opendir(units_dir);
1828 if (errno == ENOENT)
1838 r = readdir_r(d, &buffer, &de);
1847 if (ignore_file(de->d_name))
1850 if (!unit_name_is_valid_no_type(de->d_name, true))
1853 if (hashmap_get(h, de->d_name))
1856 r = dirent_ensure_type(d, de);
1858 if (errno == ENOENT)
1864 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1867 f = new0(UnitFileList, 1);
1873 f->path = path_make_absolute(de->d_name, units_dir);
1880 r = null_or_empty_path(f->path);
1881 if (r < 0 && r != -ENOENT) {
1887 path_startswith(*i, "/run") ?
1888 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1892 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1900 r = unit_file_can_install(&paths, root_dir, f->path, true);
1906 f->state = UNIT_FILE_DISABLED;
1908 } else if (r == 0) {
1909 f->state = UNIT_FILE_STATIC;
1918 r = hashmap_put(h, file_name_from_path(f->path), f);
1928 lookup_paths_free(&paths);
1937 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1938 [UNIT_FILE_ENABLED] = "enabled",
1939 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtie",
1940 [UNIT_FILE_LINKED] = "linked",
1941 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1942 [UNIT_FILE_MASKED] = "masked",
1943 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1944 [UNIT_FILE_STATIC] = "static",
1945 [UNIT_FILE_DISABLED] = "disabled"
1948 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1950 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1951 [UNIT_FILE_SYMLINK] = "symlink",
1952 [UNIT_FILE_UNLINK] = "unlink",
1955 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);