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"
50 Hashmap *will_install;
51 Hashmap *have_installed;
54 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
57 assert(scope < _UNIT_FILE_SCOPE_MAX);
61 return lookup_paths_init(paths,
62 scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
63 scope == UNIT_FILE_USER);
66 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
71 assert(scope < _UNIT_FILE_SCOPE_MAX);
76 case UNIT_FILE_SYSTEM:
78 if (root_dir && runtime)
79 asprintf(&p, "%s/run/systemd/system", root_dir);
81 p = strdup("/run/systemd/system");
83 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
85 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
89 case UNIT_FILE_GLOBAL:
95 p = strdup("/run/systemd/user");
97 p = strdup(USER_CONFIG_UNIT_PATH);
102 if (root_dir || runtime)
105 r = user_config_home(&p);
107 return r < 0 ? r : -ENOENT;
112 assert_not_reached("Bad scope");
122 static int add_file_change(
123 UnitFileChange **changes,
125 UnitFileChangeType type,
127 const char *source) {
133 assert(!changes == !n_changes);
138 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
146 c[i].path = strdup(path);
151 c[i].source = strdup(source);
163 static int mark_symlink_for_removal(
164 Set **remove_symlinks_to,
172 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
180 path_kill_slashes(n);
182 r = set_put(*remove_symlinks_to, n);
185 return r == -EEXIST ? 0 : r;
191 static int remove_marked_symlinks_fd(
192 Set *remove_symlinks_to,
195 const char *config_path,
197 UnitFileChange **changes,
198 unsigned *n_changes) {
202 struct dirent buffer, *de;
204 assert(remove_symlinks_to);
212 close_nointr_nofail(fd);
221 k = readdir_r(d, &buffer, &de);
230 if (ignore_file(de->d_name))
233 dirent_ensure_type(d, de);
235 if (de->d_type == DT_DIR) {
239 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
249 p = path_make_absolute(de->d_name, path);
251 close_nointr_nofail(nfd);
256 /* This will close nfd, regardless whether it succeeds or not */
257 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
263 } else if (de->d_type == DT_LNK) {
268 p = path_make_absolute(de->d_name, path);
274 q = readlink_and_canonicalize(p, &dest);
287 set_get(remove_symlinks_to, dest) ||
288 set_get(remove_symlinks_to, path_get_file_name(dest));
292 if (unlink(p) < 0 && errno != ENOENT) {
297 rmdir_parents(p, config_path);
298 path_kill_slashes(p);
300 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
302 if (!set_get(remove_symlinks_to, p)) {
304 q = mark_symlink_for_removal(&remove_symlinks_to, p);
324 static int remove_marked_symlinks(
325 Set *remove_symlinks_to,
326 const char *config_path,
327 UnitFileChange **changes,
328 unsigned *n_changes) {
335 if (set_size(remove_symlinks_to) <= 0)
338 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
352 /* This takes possession of cfd and closes it */
353 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
358 close_nointr_nofail(fd);
363 static int find_symlinks_fd(
367 const char *config_path,
368 bool *same_name_link) {
372 struct dirent buffer, *de;
378 assert(same_name_link);
382 close_nointr_nofail(fd);
389 k = readdir_r(d, &buffer, &de);
398 if (ignore_file(de->d_name))
401 dirent_ensure_type(d, de);
403 if (de->d_type == DT_DIR) {
407 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
417 p = path_make_absolute(de->d_name, path);
419 close_nointr_nofail(nfd);
424 /* This will close nfd, regardless whether it succeeds or not */
425 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
436 } else if (de->d_type == DT_LNK) {
438 bool found_path, found_dest, b = false;
441 /* Acquire symlink name */
442 p = path_make_absolute(de->d_name, path);
448 /* Acquire symlink destination */
449 q = readlink_and_canonicalize(p, &dest);
461 /* Check if the symlink itself matches what we
463 if (path_is_absolute(name))
464 found_path = path_equal(p, name);
466 found_path = streq(de->d_name, name);
468 /* Check if what the symlink points to
469 * matches what we are looking for */
470 if (path_is_absolute(name))
471 found_dest = path_equal(dest, name);
473 found_dest = streq(path_get_file_name(dest), name);
477 if (found_path && found_dest) {
480 /* Filter out same name links in the main
482 t = path_make_absolute(name, config_path);
489 b = path_equal(t, p);
496 *same_name_link = true;
497 else if (found_path || found_dest) {
509 static int find_symlinks(
511 const char *config_path,
512 bool *same_name_link) {
518 assert(same_name_link);
520 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
524 /* This takes possession of fd and closes it */
525 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
528 static int find_symlinks_in_scope(
530 const char *root_dir,
532 UnitFileState *state) {
536 bool same_name_link_runtime = false, same_name_link = false;
539 assert(scope < _UNIT_FILE_SCOPE_MAX);
542 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
544 /* First look in runtime config path */
545 r = get_config_path(scope, true, root_dir, &path);
549 r = find_symlinks(name, path, &same_name_link_runtime);
555 *state = UNIT_FILE_ENABLED_RUNTIME;
560 /* Then look in the normal config path */
561 r = get_config_path(scope, false, root_dir, &path);
565 r = find_symlinks(name, path, &same_name_link);
571 *state = UNIT_FILE_ENABLED;
575 /* Hmm, we didn't find it, but maybe we found the same name
577 if (same_name_link_runtime) {
578 *state = UNIT_FILE_LINKED_RUNTIME;
580 } else if (same_name_link) {
581 *state = UNIT_FILE_LINKED;
591 const char *root_dir,
594 UnitFileChange **changes,
595 unsigned *n_changes) {
601 assert(scope < _UNIT_FILE_SCOPE_MAX);
603 r = get_config_path(scope, runtime, root_dir, &prefix);
607 STRV_FOREACH(i, files) {
610 if (!unit_name_is_valid_no_type(*i, true)) {
616 path = path_make_absolute(*i, prefix);
622 if (symlink("/dev/null", path) >= 0) {
623 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
629 if (errno == EEXIST) {
631 if (null_or_empty_path(path) > 0) {
639 if (symlink("/dev/null", path) >= 0) {
641 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
642 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
664 int unit_file_unmask(
667 const char *root_dir,
669 UnitFileChange **changes,
670 unsigned *n_changes) {
672 char **i, *config_path = NULL;
674 Set *remove_symlinks_to = NULL;
677 assert(scope < _UNIT_FILE_SCOPE_MAX);
679 r = get_config_path(scope, runtime, root_dir, &config_path);
683 STRV_FOREACH(i, files) {
686 if (!unit_name_is_valid_no_type(*i, true)) {
692 path = path_make_absolute(*i, config_path);
698 q = null_or_empty_path(path);
700 if (unlink(path) >= 0) {
701 mark_symlink_for_removal(&remove_symlinks_to, path);
702 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
711 if (q != -ENOENT && r == 0)
719 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
723 set_free_free(remove_symlinks_to);
732 const char *root_dir,
735 UnitFileChange **changes,
736 unsigned *n_changes) {
739 char **i, *config_path = NULL;
743 assert(scope < _UNIT_FILE_SCOPE_MAX);
747 r = lookup_paths_init_from_scope(&paths, scope);
751 r = get_config_path(scope, runtime, root_dir, &config_path);
755 STRV_FOREACH(i, files) {
759 fn = path_get_file_name(*i);
761 if (!path_is_absolute(*i) ||
762 !unit_name_is_valid_no_type(fn, true)) {
768 if (lstat(*i, &st) < 0) {
774 if (!S_ISREG(st.st_mode)) {
779 q = in_search_path(*i, paths.unit_path);
788 path = path_make_absolute(fn, config_path);
794 if (symlink(*i, path) >= 0) {
795 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
801 if (errno == EEXIST) {
804 q = readlink_and_make_absolute(path, &dest);
806 if (q < 0 && errno != ENOENT) {
815 if (q >= 0 && path_equal(dest, *i)) {
826 if (symlink(*i, path) >= 0) {
828 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
829 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
847 lookup_paths_free(&paths);
853 void unit_file_list_free(Hashmap *h) {
856 while ((i = hashmap_steal_first(h))) {
864 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
867 assert(changes || n_changes == 0);
872 for (i = 0; i < n_changes; i++) {
873 free(changes[i].path);
874 free(changes[i].source);
880 static void install_info_free(InstallInfo *i) {
885 strv_free(i->aliases);
886 strv_free(i->wanted_by);
887 strv_free(i->required_by);
891 static void install_info_hashmap_free(Hashmap *m) {
897 while ((i = hashmap_steal_first(m)))
898 install_info_free(i);
903 static void install_context_done(InstallContext *c) {
906 install_info_hashmap_free(c->will_install);
907 install_info_hashmap_free(c->have_installed);
909 c->will_install = c->have_installed = NULL;
912 static int install_info_add(
916 InstallInfo *i = NULL;
920 assert(name || path);
923 name = path_get_file_name(path);
925 if (!unit_name_is_valid_no_type(name, true))
928 if (hashmap_get(c->have_installed, name) ||
929 hashmap_get(c->will_install, name))
932 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
936 i = new0(InstallInfo, 1);
940 i->name = strdup(name);
947 i->path = strdup(path);
954 r = hashmap_put(c->will_install, i->name, i);
962 install_info_free(i);
967 static int install_info_add_auto(
969 const char *name_or_path) {
972 assert(name_or_path);
974 if (path_is_absolute(name_or_path))
975 return install_info_add(c, NULL, name_or_path);
977 return install_info_add(c, name_or_path, NULL);
980 static int config_parse_also(
981 const char *filename,
993 InstallContext *c = data;
999 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1007 r = install_info_add(c, n, NULL);
1019 static int unit_file_load(
1023 bool allow_symlink) {
1025 const ConfigTableItem items[] = {
1026 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1027 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1028 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1029 { "Install", "Also", config_parse_also, 0, c },
1030 { NULL, NULL, NULL, 0, NULL }
1041 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1045 f = fdopen(fd, "re");
1047 close_nointr_nofail(fd);
1051 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1057 strv_length(info->aliases) +
1058 strv_length(info->wanted_by) +
1059 strv_length(info->required_by);
1062 static int unit_file_search(
1066 const char *root_dir,
1067 bool allow_symlink) {
1077 return unit_file_load(c, info, info->path, allow_symlink);
1081 STRV_FOREACH(p, paths->unit_path) {
1084 if (isempty(root_dir))
1085 asprintf(&path, "%s/%s", *p, info->name);
1087 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1092 r = unit_file_load(c, info, path, allow_symlink);
1099 if (r != -ENOENT && r != -ELOOP)
1106 static int unit_file_can_install(
1108 const char *root_dir,
1110 bool allow_symlink) {
1121 r = install_info_add_auto(&c, name);
1125 assert_se(i = hashmap_first(c.will_install));
1127 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1131 strv_length(i->aliases) +
1132 strv_length(i->wanted_by) +
1133 strv_length(i->required_by);
1135 install_context_done(&c);
1140 static int create_symlink(
1141 const char *old_path,
1142 const char *new_path,
1144 UnitFileChange **changes,
1145 unsigned *n_changes) {
1153 mkdir_parents(new_path, 0755);
1155 if (symlink(old_path, new_path) >= 0) {
1156 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1160 if (errno != EEXIST)
1163 r = readlink_and_make_absolute(new_path, &dest);
1167 if (path_equal(dest, old_path)) {
1179 if (symlink(old_path, new_path) >= 0) {
1180 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1181 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1188 static int install_info_symlink_alias(
1190 const char *config_path,
1192 UnitFileChange **changes,
1193 unsigned *n_changes) {
1199 assert(config_path);
1201 STRV_FOREACH(s, i->aliases) {
1204 alias_path = path_make_absolute(*s, config_path);
1209 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1219 static int install_info_symlink_wants(
1221 const char *config_path,
1223 UnitFileChange **changes,
1224 unsigned *n_changes) {
1230 assert(config_path);
1232 STRV_FOREACH(s, i->wanted_by) {
1235 if (!unit_name_is_valid_no_type(*s, true)) {
1240 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1243 q = create_symlink(i->path, path, force, changes, n_changes);
1253 static int install_info_symlink_requires(
1255 const char *config_path,
1257 UnitFileChange **changes,
1258 unsigned *n_changes) {
1264 assert(config_path);
1266 STRV_FOREACH(s, i->required_by) {
1269 if (!unit_name_is_valid_no_type(*s, true)) {
1274 if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0)
1277 q = create_symlink(i->path, path, force, changes, n_changes);
1287 static int install_info_symlink_link(
1290 const char *config_path,
1292 UnitFileChange **changes,
1293 unsigned *n_changes) {
1300 assert(config_path);
1303 r = in_search_path(i->path, paths->unit_path);
1307 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1310 r = create_symlink(i->path, path, force, changes, n_changes);
1316 static int install_info_apply(
1319 const char *config_path,
1321 UnitFileChange **changes,
1322 unsigned *n_changes) {
1328 assert(config_path);
1330 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1332 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1336 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1340 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1347 static int install_context_apply(
1350 const char *config_path,
1351 const char *root_dir,
1353 UnitFileChange **changes,
1354 unsigned *n_changes) {
1361 assert(config_path);
1363 while ((i = hashmap_first(c->will_install))) {
1365 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1369 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1371 q = unit_file_search(c, i, paths, root_dir, false);
1380 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1381 if (r >= 0 && q < 0)
1388 static int install_context_mark_for_removal(
1391 Set **remove_symlinks_to,
1392 const char *config_path,
1393 const char *root_dir) {
1400 assert(config_path);
1402 /* Marks all items for removal */
1404 while ((i = hashmap_first(c->will_install))) {
1406 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1410 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1412 q = unit_file_search(c, i, paths, root_dir, false);
1421 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1422 if (r >= 0 && q < 0)
1429 int unit_file_enable(
1430 UnitFileScope scope,
1432 const char *root_dir,
1435 UnitFileChange **changes,
1436 unsigned *n_changes) {
1440 char **i, *config_path = 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 /* This will return the number of symlink rules that were
1464 supposed to be created, not the ones actually created. This is
1465 useful to determine whether the passed files hat any
1466 installation data at all. */
1467 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1470 install_context_done(&c);
1471 lookup_paths_free(&paths);
1477 int unit_file_disable(
1478 UnitFileScope scope,
1480 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 = install_info_add_auto(&c, *i);
1511 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1513 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1518 install_context_done(&c);
1519 lookup_paths_free(&paths);
1520 set_free_free(remove_symlinks_to);
1526 int unit_file_reenable(
1527 UnitFileScope scope,
1529 const char *root_dir,
1532 UnitFileChange **changes,
1533 unsigned *n_changes) {
1537 char **i, *config_path = NULL;
1538 Set *remove_symlinks_to = NULL;
1542 assert(scope < _UNIT_FILE_SCOPE_MAX);
1547 r = lookup_paths_init_from_scope(&paths, scope);
1551 r = get_config_path(scope, runtime, root_dir, &config_path);
1555 STRV_FOREACH(i, files) {
1556 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1560 r = install_info_add_auto(&c, *i);
1565 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1567 /* Returns number of symlinks that where supposed to be installed. */
1568 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1573 lookup_paths_free(&paths);
1574 install_context_done(&c);
1575 set_free_free(remove_symlinks_to);
1581 UnitFileState unit_file_get_state(
1582 UnitFileScope scope,
1583 const char *root_dir,
1587 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1588 char **i, *path = NULL;
1592 assert(scope < _UNIT_FILE_SCOPE_MAX);
1597 if (root_dir && scope != UNIT_FILE_SYSTEM)
1600 if (!unit_name_is_valid_no_type(name, true))
1603 r = lookup_paths_init_from_scope(&paths, scope);
1607 STRV_FOREACH(i, paths.unit_path) {
1614 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1616 asprintf(&path, "%s/%s", *i, name);
1623 if (lstat(path, &st) < 0) {
1625 if (errno == ENOENT)
1631 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1636 r = null_or_empty_path(path);
1637 if (r < 0 && r != -ENOENT)
1640 state = path_startswith(*i, "/run") ?
1641 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1646 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1654 r = unit_file_can_install(&paths, root_dir, path, true);
1655 if (r < 0 && errno != -ENOENT)
1658 state = UNIT_FILE_DISABLED;
1661 } else if (r == 0) {
1662 state = UNIT_FILE_STATIC;
1669 lookup_paths_free(&paths);
1672 return r < 0 ? r : state;
1675 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1680 assert(scope < _UNIT_FILE_SCOPE_MAX);
1683 if (scope == UNIT_FILE_SYSTEM)
1684 r = conf_files_list(&files, ".preset",
1685 "/etc/systemd/system.preset",
1686 "/usr/local/lib/systemd/system.preset",
1687 "/usr/lib/systemd/system.preset",
1688 "/lib/systemd/system.preset",
1690 else if (scope == UNIT_FILE_GLOBAL)
1691 r = conf_files_list(&files, ".preset",
1692 "/etc/systemd/user.preset",
1693 "/usr/local/lib/systemd/user.preset",
1694 "/usr/lib/systemd/user.preset",
1702 STRV_FOREACH(i, files) {
1705 f = fopen(*i, "re");
1707 if (errno == ENOENT)
1715 char line[LINE_MAX], *l;
1717 if (!fgets(line, sizeof(line), f))
1724 if (strchr(COMMENTS, *l))
1727 if (first_word(l, "enable")) {
1729 l += strspn(l, WHITESPACE);
1731 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1736 } else if (first_word(l, "disable")) {
1738 l += strspn(l, WHITESPACE);
1740 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1746 log_debug("Couldn't parse line '%s'", l);
1752 /* Default is "enable" */
1761 int unit_file_preset(
1762 UnitFileScope scope,
1764 const char *root_dir,
1767 UnitFileChange **changes,
1768 unsigned *n_changes) {
1771 InstallContext plus, minus;
1772 char **i, *config_path = NULL;
1773 Set *remove_symlinks_to = NULL;
1777 assert(scope < _UNIT_FILE_SCOPE_MAX);
1783 r = lookup_paths_init_from_scope(&paths, scope);
1787 r = get_config_path(scope, runtime, root_dir, &config_path);
1791 STRV_FOREACH(i, files) {
1793 if (!unit_name_is_valid_no_type(*i, true)) {
1798 r = unit_file_query_preset(scope, *i);
1803 r = install_info_add_auto(&plus, *i);
1805 r = install_info_add_auto(&minus, *i);
1811 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1813 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1817 /* Returns number of symlinks that where supposed to be installed. */
1818 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1823 lookup_paths_free(&paths);
1824 install_context_done(&plus);
1825 install_context_done(&minus);
1826 set_free_free(remove_symlinks_to);
1832 int unit_file_get_list(
1833 UnitFileScope scope,
1834 const char *root_dir,
1838 char **i, *buf = NULL;
1843 assert(scope < _UNIT_FILE_SCOPE_MAX);
1848 if (root_dir && scope != UNIT_FILE_SYSTEM)
1851 r = lookup_paths_init_from_scope(&paths, scope);
1855 STRV_FOREACH(i, paths.unit_path) {
1856 struct dirent buffer, *de;
1857 const char *units_dir;
1863 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1874 d = opendir(units_dir);
1876 if (errno == ENOENT)
1886 r = readdir_r(d, &buffer, &de);
1895 if (ignore_file(de->d_name))
1898 if (!unit_name_is_valid_no_type(de->d_name, true))
1901 if (hashmap_get(h, de->d_name))
1904 r = dirent_ensure_type(d, de);
1912 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1915 f = new0(UnitFileList, 1);
1921 f->path = path_make_absolute(de->d_name, units_dir);
1928 r = null_or_empty_path(f->path);
1929 if (r < 0 && r != -ENOENT) {
1935 path_startswith(*i, "/run") ?
1936 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1940 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1948 r = unit_file_can_install(&paths, root_dir, f->path, true);
1954 f->state = UNIT_FILE_DISABLED;
1957 f->state = UNIT_FILE_STATIC;
1966 r = hashmap_put(h, path_get_file_name(f->path), f);
1976 lookup_paths_free(&paths);
1985 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1986 [UNIT_FILE_ENABLED] = "enabled",
1987 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1988 [UNIT_FILE_LINKED] = "linked",
1989 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1990 [UNIT_FILE_MASKED] = "masked",
1991 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1992 [UNIT_FILE_STATIC] = "static",
1993 [UNIT_FILE_DISABLED] = "disabled"
1996 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1998 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1999 [UNIT_FILE_SYMLINK] = "symlink",
2000 [UNIT_FILE_UNLINK] = "unlink",
2003 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);