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,
67 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
72 assert(scope < _UNIT_FILE_SCOPE_MAX);
77 case UNIT_FILE_SYSTEM:
79 if (root_dir && runtime)
80 asprintf(&p, "%s/run/systemd/system", root_dir);
82 p = strdup("/run/systemd/system");
84 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
86 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
90 case UNIT_FILE_GLOBAL:
96 p = strdup("/run/systemd/user");
98 p = strdup(USER_CONFIG_UNIT_PATH);
103 if (root_dir || runtime)
106 r = user_config_home(&p);
108 return r < 0 ? r : -ENOENT;
113 assert_not_reached("Bad scope");
123 static int add_file_change(
124 UnitFileChange **changes,
126 UnitFileChangeType type,
128 const char *source) {
134 assert(!changes == !n_changes);
139 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
147 c[i].path = strdup(path);
152 c[i].source = strdup(source);
164 static int mark_symlink_for_removal(
165 Set **remove_symlinks_to,
173 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
181 path_kill_slashes(n);
183 r = set_put(*remove_symlinks_to, n);
186 return r == -EEXIST ? 0 : r;
192 static int remove_marked_symlinks_fd(
193 Set *remove_symlinks_to,
196 const char *config_path,
198 UnitFileChange **changes,
199 unsigned *n_changes) {
203 struct dirent buffer, *de;
205 assert(remove_symlinks_to);
213 close_nointr_nofail(fd);
222 k = readdir_r(d, &buffer, &de);
231 if (ignore_file(de->d_name))
234 dirent_ensure_type(d, de);
236 if (de->d_type == DT_DIR) {
240 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
250 p = path_make_absolute(de->d_name, path);
252 close_nointr_nofail(nfd);
257 /* This will close nfd, regardless whether it succeeds or not */
258 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes);
264 } else if (de->d_type == DT_LNK) {
269 p = path_make_absolute(de->d_name, path);
275 q = readlink_and_canonicalize(p, &dest);
288 set_get(remove_symlinks_to, dest) ||
289 set_get(remove_symlinks_to, path_get_file_name(dest));
293 if (unlink(p) < 0 && errno != ENOENT) {
298 rmdir_parents(p, config_path);
299 path_kill_slashes(p);
301 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
303 if (!set_get(remove_symlinks_to, p)) {
305 q = mark_symlink_for_removal(&remove_symlinks_to, p);
325 static int remove_marked_symlinks(
326 Set *remove_symlinks_to,
327 const char *config_path,
328 UnitFileChange **changes,
329 unsigned *n_changes) {
336 if (set_size(remove_symlinks_to) <= 0)
339 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
353 /* This takes possession of cfd and closes it */
354 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes);
359 close_nointr_nofail(fd);
364 static int find_symlinks_fd(
368 const char *config_path,
369 bool *same_name_link) {
373 struct dirent buffer, *de;
379 assert(same_name_link);
383 close_nointr_nofail(fd);
390 k = readdir_r(d, &buffer, &de);
399 if (ignore_file(de->d_name))
402 dirent_ensure_type(d, de);
404 if (de->d_type == DT_DIR) {
408 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
418 p = path_make_absolute(de->d_name, path);
420 close_nointr_nofail(nfd);
425 /* This will close nfd, regardless whether it succeeds or not */
426 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
437 } else if (de->d_type == DT_LNK) {
439 bool found_path, found_dest, b = false;
442 /* Acquire symlink name */
443 p = path_make_absolute(de->d_name, path);
449 /* Acquire symlink destination */
450 q = readlink_and_canonicalize(p, &dest);
462 /* Check if the symlink itself matches what we
464 if (path_is_absolute(name))
465 found_path = path_equal(p, name);
467 found_path = streq(de->d_name, name);
469 /* Check if what the symlink points to
470 * matches what we are looking for */
471 if (path_is_absolute(name))
472 found_dest = path_equal(dest, name);
474 found_dest = streq(path_get_file_name(dest), name);
478 if (found_path && found_dest) {
481 /* Filter out same name links in the main
483 t = path_make_absolute(name, config_path);
490 b = path_equal(t, p);
497 *same_name_link = true;
498 else if (found_path || found_dest) {
510 static int find_symlinks(
512 const char *config_path,
513 bool *same_name_link) {
519 assert(same_name_link);
521 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
525 /* This takes possession of fd and closes it */
526 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
529 static int find_symlinks_in_scope(
531 const char *root_dir,
533 UnitFileState *state) {
537 bool same_name_link_runtime = false, same_name_link = false;
540 assert(scope < _UNIT_FILE_SCOPE_MAX);
543 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
545 /* First look in runtime config path */
546 r = get_config_path(scope, true, root_dir, &path);
550 r = find_symlinks(name, path, &same_name_link_runtime);
556 *state = UNIT_FILE_ENABLED_RUNTIME;
561 /* Then look in the normal config path */
562 r = get_config_path(scope, false, root_dir, &path);
566 r = find_symlinks(name, path, &same_name_link);
572 *state = UNIT_FILE_ENABLED;
576 /* Hmm, we didn't find it, but maybe we found the same name
578 if (same_name_link_runtime) {
579 *state = UNIT_FILE_LINKED_RUNTIME;
581 } else if (same_name_link) {
582 *state = UNIT_FILE_LINKED;
592 const char *root_dir,
595 UnitFileChange **changes,
596 unsigned *n_changes) {
602 assert(scope < _UNIT_FILE_SCOPE_MAX);
604 r = get_config_path(scope, runtime, root_dir, &prefix);
608 STRV_FOREACH(i, files) {
611 if (!unit_name_is_valid_no_type(*i, true)) {
617 path = path_make_absolute(*i, prefix);
623 if (symlink("/dev/null", path) >= 0) {
624 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
630 if (errno == EEXIST) {
632 if (null_or_empty_path(path) > 0) {
640 if (symlink("/dev/null", path) >= 0) {
642 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
643 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
665 int unit_file_unmask(
668 const char *root_dir,
670 UnitFileChange **changes,
671 unsigned *n_changes) {
673 char **i, *config_path = NULL;
675 Set *remove_symlinks_to = NULL;
678 assert(scope < _UNIT_FILE_SCOPE_MAX);
680 r = get_config_path(scope, runtime, root_dir, &config_path);
684 STRV_FOREACH(i, files) {
687 if (!unit_name_is_valid_no_type(*i, true)) {
693 path = path_make_absolute(*i, config_path);
699 q = null_or_empty_path(path);
701 if (unlink(path) >= 0) {
702 mark_symlink_for_removal(&remove_symlinks_to, path);
703 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
712 if (q != -ENOENT && r == 0)
720 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
724 set_free_free(remove_symlinks_to);
733 const char *root_dir,
736 UnitFileChange **changes,
737 unsigned *n_changes) {
740 char **i, *config_path = NULL;
744 assert(scope < _UNIT_FILE_SCOPE_MAX);
748 r = lookup_paths_init_from_scope(&paths, scope);
752 r = get_config_path(scope, runtime, root_dir, &config_path);
756 STRV_FOREACH(i, files) {
760 fn = path_get_file_name(*i);
762 if (!path_is_absolute(*i) ||
763 !unit_name_is_valid_no_type(fn, true)) {
769 if (lstat(*i, &st) < 0) {
775 if (!S_ISREG(st.st_mode)) {
780 q = in_search_path(*i, paths.unit_path);
789 path = path_make_absolute(fn, config_path);
795 if (symlink(*i, path) >= 0) {
796 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
802 if (errno == EEXIST) {
805 q = readlink_and_make_absolute(path, &dest);
807 if (q < 0 && errno != ENOENT) {
816 if (q >= 0 && path_equal(dest, *i)) {
827 if (symlink(*i, path) >= 0) {
829 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
830 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
848 lookup_paths_free(&paths);
854 void unit_file_list_free(Hashmap *h) {
857 while ((i = hashmap_steal_first(h))) {
865 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
868 assert(changes || n_changes == 0);
873 for (i = 0; i < n_changes; i++) {
874 free(changes[i].path);
875 free(changes[i].source);
881 static void install_info_free(InstallInfo *i) {
886 strv_free(i->aliases);
887 strv_free(i->wanted_by);
888 strv_free(i->required_by);
892 static void install_info_hashmap_free(Hashmap *m) {
898 while ((i = hashmap_steal_first(m)))
899 install_info_free(i);
904 static void install_context_done(InstallContext *c) {
907 install_info_hashmap_free(c->will_install);
908 install_info_hashmap_free(c->have_installed);
910 c->will_install = c->have_installed = NULL;
913 static int install_info_add(
917 InstallInfo *i = NULL;
921 assert(name || path);
924 name = path_get_file_name(path);
926 if (!unit_name_is_valid_no_type(name, true))
929 if (hashmap_get(c->have_installed, name) ||
930 hashmap_get(c->will_install, name))
933 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
937 i = new0(InstallInfo, 1);
941 i->name = strdup(name);
948 i->path = strdup(path);
955 r = hashmap_put(c->will_install, i->name, i);
963 install_info_free(i);
968 static int install_info_add_auto(
970 const char *name_or_path) {
973 assert(name_or_path);
975 if (path_is_absolute(name_or_path))
976 return install_info_add(c, NULL, name_or_path);
978 return install_info_add(c, name_or_path, NULL);
981 static int config_parse_also(
982 const char *filename,
994 InstallContext *c = data;
1000 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1008 r = install_info_add(c, n, NULL);
1020 static int unit_file_load(
1024 bool allow_symlink) {
1026 const ConfigTableItem items[] = {
1027 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1028 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1029 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1030 { "Install", "Also", config_parse_also, 0, c },
1031 { NULL, NULL, NULL, 0, NULL }
1042 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1046 f = fdopen(fd, "re");
1048 close_nointr_nofail(fd);
1052 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1058 strv_length(info->aliases) +
1059 strv_length(info->wanted_by) +
1060 strv_length(info->required_by);
1063 static int unit_file_search(
1067 const char *root_dir,
1068 bool allow_symlink) {
1078 return unit_file_load(c, info, info->path, allow_symlink);
1082 STRV_FOREACH(p, paths->unit_path) {
1085 if (isempty(root_dir))
1086 asprintf(&path, "%s/%s", *p, info->name);
1088 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1093 r = unit_file_load(c, info, path, allow_symlink);
1100 if (r != -ENOENT && r != -ELOOP)
1107 static int unit_file_can_install(
1109 const char *root_dir,
1111 bool allow_symlink) {
1122 r = install_info_add_auto(&c, name);
1126 assert_se(i = hashmap_first(c.will_install));
1128 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1132 strv_length(i->aliases) +
1133 strv_length(i->wanted_by) +
1134 strv_length(i->required_by);
1136 install_context_done(&c);
1141 static int create_symlink(
1142 const char *old_path,
1143 const char *new_path,
1145 UnitFileChange **changes,
1146 unsigned *n_changes) {
1154 mkdir_parents(new_path, 0755);
1156 if (symlink(old_path, new_path) >= 0) {
1157 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1161 if (errno != EEXIST)
1164 r = readlink_and_make_absolute(new_path, &dest);
1168 if (path_equal(dest, old_path)) {
1180 if (symlink(old_path, new_path) >= 0) {
1181 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1182 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1189 static int install_info_symlink_alias(
1191 const char *config_path,
1193 UnitFileChange **changes,
1194 unsigned *n_changes) {
1200 assert(config_path);
1202 STRV_FOREACH(s, i->aliases) {
1205 alias_path = path_make_absolute(*s, config_path);
1210 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1220 static int install_info_symlink_wants(
1222 const char *config_path,
1224 UnitFileChange **changes,
1225 unsigned *n_changes) {
1231 assert(config_path);
1233 STRV_FOREACH(s, i->wanted_by) {
1236 if (!unit_name_is_valid_no_type(*s, true)) {
1241 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1244 q = create_symlink(i->path, path, force, changes, n_changes);
1254 static int install_info_symlink_requires(
1256 const char *config_path,
1258 UnitFileChange **changes,
1259 unsigned *n_changes) {
1265 assert(config_path);
1267 STRV_FOREACH(s, i->required_by) {
1270 if (!unit_name_is_valid_no_type(*s, true)) {
1275 if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0)
1278 q = create_symlink(i->path, path, force, changes, n_changes);
1288 static int install_info_symlink_link(
1291 const char *config_path,
1293 UnitFileChange **changes,
1294 unsigned *n_changes) {
1301 assert(config_path);
1304 r = in_search_path(i->path, paths->unit_path);
1308 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1311 r = create_symlink(i->path, path, force, changes, n_changes);
1317 static int install_info_apply(
1320 const char *config_path,
1322 UnitFileChange **changes,
1323 unsigned *n_changes) {
1329 assert(config_path);
1331 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1333 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1337 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1341 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1348 static int install_context_apply(
1351 const char *config_path,
1352 const char *root_dir,
1354 UnitFileChange **changes,
1355 unsigned *n_changes) {
1362 assert(config_path);
1364 while ((i = hashmap_first(c->will_install))) {
1366 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1370 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1372 q = unit_file_search(c, i, paths, root_dir, false);
1381 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1382 if (r >= 0 && q < 0)
1389 static int install_context_mark_for_removal(
1392 Set **remove_symlinks_to,
1393 const char *config_path,
1394 const char *root_dir) {
1401 assert(config_path);
1403 /* Marks all items for removal */
1405 while ((i = hashmap_first(c->will_install))) {
1407 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1411 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1413 q = unit_file_search(c, i, paths, root_dir, false);
1422 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1423 if (r >= 0 && q < 0)
1430 int unit_file_enable(
1431 UnitFileScope scope,
1433 const char *root_dir,
1436 UnitFileChange **changes,
1437 unsigned *n_changes) {
1441 char **i, *config_path = 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 /* This will return the number of symlink rules that were
1465 supposed to be created, not the ones actually created. This is
1466 useful to determine whether the passed files hat any
1467 installation data at all. */
1468 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1471 install_context_done(&c);
1472 lookup_paths_free(&paths);
1478 int unit_file_disable(
1479 UnitFileScope scope,
1481 const char *root_dir,
1483 UnitFileChange **changes,
1484 unsigned *n_changes) {
1488 char **i, *config_path = NULL;
1489 Set *remove_symlinks_to = NULL;
1493 assert(scope < _UNIT_FILE_SCOPE_MAX);
1498 r = lookup_paths_init_from_scope(&paths, scope);
1502 r = get_config_path(scope, runtime, root_dir, &config_path);
1506 STRV_FOREACH(i, files) {
1507 r = install_info_add_auto(&c, *i);
1512 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1514 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1519 install_context_done(&c);
1520 lookup_paths_free(&paths);
1521 set_free_free(remove_symlinks_to);
1527 int unit_file_reenable(
1528 UnitFileScope scope,
1530 const char *root_dir,
1533 UnitFileChange **changes,
1534 unsigned *n_changes) {
1538 char **i, *config_path = NULL;
1539 Set *remove_symlinks_to = NULL;
1543 assert(scope < _UNIT_FILE_SCOPE_MAX);
1548 r = lookup_paths_init_from_scope(&paths, scope);
1552 r = get_config_path(scope, runtime, root_dir, &config_path);
1556 STRV_FOREACH(i, files) {
1557 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1561 r = install_info_add_auto(&c, *i);
1566 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1568 /* Returns number of symlinks that where supposed to be installed. */
1569 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1574 lookup_paths_free(&paths);
1575 install_context_done(&c);
1576 set_free_free(remove_symlinks_to);
1582 UnitFileState unit_file_get_state(
1583 UnitFileScope scope,
1584 const char *root_dir,
1588 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1589 char **i, *path = NULL;
1593 assert(scope < _UNIT_FILE_SCOPE_MAX);
1598 if (root_dir && scope != UNIT_FILE_SYSTEM)
1601 if (!unit_name_is_valid_no_type(name, true))
1604 r = lookup_paths_init_from_scope(&paths, scope);
1608 STRV_FOREACH(i, paths.unit_path) {
1615 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1617 asprintf(&path, "%s/%s", *i, name);
1624 if (lstat(path, &st) < 0) {
1626 if (errno == ENOENT)
1632 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1637 r = null_or_empty_path(path);
1638 if (r < 0 && r != -ENOENT)
1641 state = path_startswith(*i, "/run") ?
1642 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1647 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1655 r = unit_file_can_install(&paths, root_dir, path, true);
1656 if (r < 0 && errno != -ENOENT)
1659 state = UNIT_FILE_DISABLED;
1662 } else if (r == 0) {
1663 state = UNIT_FILE_STATIC;
1670 lookup_paths_free(&paths);
1673 return r < 0 ? r : state;
1676 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1681 assert(scope < _UNIT_FILE_SCOPE_MAX);
1684 if (scope == UNIT_FILE_SYSTEM)
1685 r = conf_files_list(&files, ".preset",
1686 "/etc/systemd/system.preset",
1687 "/usr/local/lib/systemd/system.preset",
1688 "/usr/lib/systemd/system.preset",
1689 "/lib/systemd/system.preset",
1691 else if (scope == UNIT_FILE_GLOBAL)
1692 r = conf_files_list(&files, ".preset",
1693 "/etc/systemd/user.preset",
1694 "/usr/local/lib/systemd/user.preset",
1695 "/usr/lib/systemd/user.preset",
1703 STRV_FOREACH(i, files) {
1706 f = fopen(*i, "re");
1708 if (errno == ENOENT)
1716 char line[LINE_MAX], *l;
1718 if (!fgets(line, sizeof(line), f))
1725 if (strchr(COMMENTS, *l))
1728 if (first_word(l, "enable")) {
1730 l += strspn(l, WHITESPACE);
1732 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1737 } else if (first_word(l, "disable")) {
1739 l += strspn(l, WHITESPACE);
1741 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1747 log_debug("Couldn't parse line '%s'", l);
1753 /* Default is "enable" */
1762 int unit_file_preset(
1763 UnitFileScope scope,
1765 const char *root_dir,
1768 UnitFileChange **changes,
1769 unsigned *n_changes) {
1772 InstallContext plus, minus;
1773 char **i, *config_path = NULL;
1774 Set *remove_symlinks_to = NULL;
1778 assert(scope < _UNIT_FILE_SCOPE_MAX);
1784 r = lookup_paths_init_from_scope(&paths, scope);
1788 r = get_config_path(scope, runtime, root_dir, &config_path);
1792 STRV_FOREACH(i, files) {
1794 if (!unit_name_is_valid_no_type(*i, true)) {
1799 r = unit_file_query_preset(scope, *i);
1804 r = install_info_add_auto(&plus, *i);
1806 r = install_info_add_auto(&minus, *i);
1812 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1814 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
1818 /* Returns number of symlinks that where supposed to be installed. */
1819 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1824 lookup_paths_free(&paths);
1825 install_context_done(&plus);
1826 install_context_done(&minus);
1827 set_free_free(remove_symlinks_to);
1833 int unit_file_get_list(
1834 UnitFileScope scope,
1835 const char *root_dir,
1839 char **i, *buf = NULL;
1844 assert(scope < _UNIT_FILE_SCOPE_MAX);
1849 if (root_dir && scope != UNIT_FILE_SYSTEM)
1852 r = lookup_paths_init_from_scope(&paths, scope);
1856 STRV_FOREACH(i, paths.unit_path) {
1857 struct dirent buffer, *de;
1858 const char *units_dir;
1864 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1875 d = opendir(units_dir);
1877 if (errno == ENOENT)
1887 r = readdir_r(d, &buffer, &de);
1896 if (ignore_file(de->d_name))
1899 if (!unit_name_is_valid_no_type(de->d_name, true))
1902 if (hashmap_get(h, de->d_name))
1905 r = dirent_ensure_type(d, de);
1913 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1916 f = new0(UnitFileList, 1);
1922 f->path = path_make_absolute(de->d_name, units_dir);
1929 r = null_or_empty_path(f->path);
1930 if (r < 0 && r != -ENOENT) {
1936 path_startswith(*i, "/run") ?
1937 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1941 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1949 r = unit_file_can_install(&paths, root_dir, f->path, true);
1955 f->state = UNIT_FILE_DISABLED;
1958 f->state = UNIT_FILE_STATIC;
1967 r = hashmap_put(h, path_get_file_name(f->path), f);
1977 lookup_paths_free(&paths);
1986 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1987 [UNIT_FILE_ENABLED] = "enabled",
1988 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1989 [UNIT_FILE_LINKED] = "linked",
1990 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1991 [UNIT_FILE_MASKED] = "masked",
1992 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1993 [UNIT_FILE_STATIC] = "static",
1994 [UNIT_FILE_DISABLED] = "disabled"
1997 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1999 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2000 [UNIT_FILE_SYMLINK] = "symlink",
2001 [UNIT_FILE_UNLINK] = "unlink",
2004 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);