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,
204 struct dirent buffer, *de;
206 assert(remove_symlinks_to);
214 close_nointr_nofail(fd);
223 k = readdir_r(d, &buffer, &de);
232 if (ignore_file(de->d_name))
235 dirent_ensure_type(d, de);
237 if (de->d_type == DT_DIR) {
241 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
251 p = path_make_absolute(de->d_name, path);
253 close_nointr_nofail(nfd);
258 /* This will close nfd, regardless whether it succeeds or not */
259 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
265 } else if (de->d_type == DT_LNK) {
270 p = path_make_absolute(de->d_name, path);
276 q = readlink_and_canonicalize(p, &dest);
289 set_get(remove_symlinks_to, dest) ||
290 set_get(remove_symlinks_to, path_get_file_name(dest));
292 if (unit_name_is_instance(p))
293 found = found && strv_contains(files, path_get_file_name(p));
297 if (unlink(p) < 0 && errno != ENOENT) {
302 rmdir_parents(p, config_path);
303 path_kill_slashes(p);
305 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
307 if (!set_get(remove_symlinks_to, p)) {
309 q = mark_symlink_for_removal(&remove_symlinks_to, p);
329 static int remove_marked_symlinks(
330 Set *remove_symlinks_to,
331 const char *config_path,
332 UnitFileChange **changes,
341 if (set_size(remove_symlinks_to) <= 0)
344 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
358 /* This takes possession of cfd and closes it */
359 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
364 close_nointr_nofail(fd);
369 static int find_symlinks_fd(
373 const char *config_path,
374 bool *same_name_link) {
378 struct dirent buffer, *de;
384 assert(same_name_link);
388 close_nointr_nofail(fd);
395 k = readdir_r(d, &buffer, &de);
404 if (ignore_file(de->d_name))
407 dirent_ensure_type(d, de);
409 if (de->d_type == DT_DIR) {
413 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
423 p = path_make_absolute(de->d_name, path);
425 close_nointr_nofail(nfd);
430 /* This will close nfd, regardless whether it succeeds or not */
431 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
442 } else if (de->d_type == DT_LNK) {
444 bool found_path, found_dest, b = false;
447 /* Acquire symlink name */
448 p = path_make_absolute(de->d_name, path);
454 /* Acquire symlink destination */
455 q = readlink_and_canonicalize(p, &dest);
467 /* Check if the symlink itself matches what we
469 if (path_is_absolute(name))
470 found_path = path_equal(p, name);
472 found_path = streq(de->d_name, name);
474 /* Check if what the symlink points to
475 * matches what we are looking for */
476 if (path_is_absolute(name))
477 found_dest = path_equal(dest, name);
479 found_dest = streq(path_get_file_name(dest), name);
483 if (found_path && found_dest) {
486 /* Filter out same name links in the main
488 t = path_make_absolute(name, config_path);
495 b = path_equal(t, p);
502 *same_name_link = true;
503 else if (found_path || found_dest) {
515 static int find_symlinks(
517 const char *config_path,
518 bool *same_name_link) {
524 assert(same_name_link);
526 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
530 /* This takes possession of fd and closes it */
531 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
534 static int find_symlinks_in_scope(
536 const char *root_dir,
538 UnitFileState *state) {
542 bool same_name_link_runtime = false, same_name_link = false;
545 assert(scope < _UNIT_FILE_SCOPE_MAX);
548 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
550 /* First look in runtime config path */
551 r = get_config_path(scope, true, root_dir, &path);
555 r = find_symlinks(name, path, &same_name_link_runtime);
561 *state = UNIT_FILE_ENABLED_RUNTIME;
566 /* Then look in the normal config path */
567 r = get_config_path(scope, false, root_dir, &path);
571 r = find_symlinks(name, path, &same_name_link);
577 *state = UNIT_FILE_ENABLED;
581 /* Hmm, we didn't find it, but maybe we found the same name
583 if (same_name_link_runtime) {
584 *state = UNIT_FILE_LINKED_RUNTIME;
586 } else if (same_name_link) {
587 *state = UNIT_FILE_LINKED;
597 const char *root_dir,
600 UnitFileChange **changes,
601 unsigned *n_changes) {
607 assert(scope < _UNIT_FILE_SCOPE_MAX);
609 r = get_config_path(scope, runtime, root_dir, &prefix);
613 STRV_FOREACH(i, files) {
616 if (!unit_name_is_valid(*i, true)) {
622 path = path_make_absolute(*i, prefix);
628 if (symlink("/dev/null", path) >= 0) {
629 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
635 if (errno == EEXIST) {
637 if (null_or_empty_path(path) > 0) {
645 if (symlink("/dev/null", path) >= 0) {
647 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
648 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
670 int unit_file_unmask(
673 const char *root_dir,
675 UnitFileChange **changes,
676 unsigned *n_changes) {
678 char **i, *config_path = NULL;
680 Set *remove_symlinks_to = NULL;
683 assert(scope < _UNIT_FILE_SCOPE_MAX);
685 r = get_config_path(scope, runtime, root_dir, &config_path);
689 STRV_FOREACH(i, files) {
692 if (!unit_name_is_valid(*i, true)) {
698 path = path_make_absolute(*i, config_path);
704 q = null_or_empty_path(path);
706 if (unlink(path) >= 0) {
707 mark_symlink_for_removal(&remove_symlinks_to, path);
708 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
717 if (q != -ENOENT && r == 0)
725 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
729 set_free_free(remove_symlinks_to);
738 const char *root_dir,
741 UnitFileChange **changes,
742 unsigned *n_changes) {
745 char **i, *config_path = NULL;
749 assert(scope < _UNIT_FILE_SCOPE_MAX);
753 r = lookup_paths_init_from_scope(&paths, scope);
757 r = get_config_path(scope, runtime, root_dir, &config_path);
761 STRV_FOREACH(i, files) {
765 fn = path_get_file_name(*i);
767 if (!path_is_absolute(*i) ||
768 !unit_name_is_valid(fn, true)) {
774 if (lstat(*i, &st) < 0) {
780 if (!S_ISREG(st.st_mode)) {
785 q = in_search_path(*i, paths.unit_path);
794 path = path_make_absolute(fn, config_path);
800 if (symlink(*i, path) >= 0) {
801 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
807 if (errno == EEXIST) {
810 q = readlink_and_make_absolute(path, &dest);
812 if (q < 0 && errno != ENOENT) {
821 if (q >= 0 && path_equal(dest, *i)) {
832 if (symlink(*i, path) >= 0) {
834 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
835 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
853 lookup_paths_free(&paths);
859 void unit_file_list_free(Hashmap *h) {
862 while ((i = hashmap_steal_first(h))) {
870 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
873 assert(changes || n_changes == 0);
878 for (i = 0; i < n_changes; i++) {
879 free(changes[i].path);
880 free(changes[i].source);
886 static void install_info_free(InstallInfo *i) {
891 strv_free(i->aliases);
892 strv_free(i->wanted_by);
893 strv_free(i->required_by);
897 static void install_info_hashmap_free(Hashmap *m) {
903 while ((i = hashmap_steal_first(m)))
904 install_info_free(i);
909 static void install_context_done(InstallContext *c) {
912 install_info_hashmap_free(c->will_install);
913 install_info_hashmap_free(c->have_installed);
915 c->will_install = c->have_installed = NULL;
918 static int install_info_add(
922 InstallInfo *i = NULL;
926 assert(name || path);
929 name = path_get_file_name(path);
931 if (!unit_name_is_valid(name, true))
934 if (hashmap_get(c->have_installed, name) ||
935 hashmap_get(c->will_install, name))
938 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
942 i = new0(InstallInfo, 1);
946 i->name = strdup(name);
953 i->path = strdup(path);
960 r = hashmap_put(c->will_install, i->name, i);
968 install_info_free(i);
973 static int install_info_add_auto(
975 const char *name_or_path) {
978 assert(name_or_path);
980 if (path_is_absolute(name_or_path))
981 return install_info_add(c, NULL, name_or_path);
983 return install_info_add(c, name_or_path, NULL);
986 static int config_parse_also(
987 const char *filename,
999 InstallContext *c = data;
1005 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
1013 r = install_info_add(c, n, NULL);
1025 static int unit_file_load(
1029 bool allow_symlink) {
1031 const ConfigTableItem items[] = {
1032 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
1033 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
1034 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
1035 { "Install", "Also", config_parse_also, 0, c },
1036 { NULL, NULL, NULL, 0, NULL }
1047 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1051 f = fdopen(fd, "re");
1053 close_nointr_nofail(fd);
1057 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1063 strv_length(info->aliases) +
1064 strv_length(info->wanted_by) +
1065 strv_length(info->required_by);
1068 static int unit_file_search(
1072 const char *root_dir,
1073 bool allow_symlink) {
1083 return unit_file_load(c, info, info->path, allow_symlink);
1087 STRV_FOREACH(p, paths->unit_path) {
1090 if (isempty(root_dir))
1091 asprintf(&path, "%s/%s", *p, info->name);
1093 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1098 r = unit_file_load(c, info, path, allow_symlink);
1103 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1104 /* unit file doesn't exist, however instance enablement was request */
1105 /* we will check if it is possible to load template unit file */
1106 char *template = NULL,
1107 *template_path = NULL,
1108 *template_dir = NULL;
1110 template = unit_name_template(info->name);
1116 /* we will reuse path variable since we don't need it anymore */
1117 template_dir = path;
1118 *(strrchr(path, '/') + 1) = '\0';
1120 template_path = strjoin(template_dir, template, NULL);
1121 if (!template_path) {
1127 /* let's try to load template unit */
1128 r = unit_file_load(c, info, template_path, allow_symlink);
1130 info->path = strdup(template_path);
1134 free(template_path);
1140 free(template_path);
1145 if (r != -ENOENT && r != -ELOOP)
1152 static int unit_file_can_install(
1154 const char *root_dir,
1156 bool allow_symlink) {
1167 r = install_info_add_auto(&c, name);
1171 assert_se(i = hashmap_first(c.will_install));
1173 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1177 strv_length(i->aliases) +
1178 strv_length(i->wanted_by) +
1179 strv_length(i->required_by);
1181 install_context_done(&c);
1186 static int create_symlink(
1187 const char *old_path,
1188 const char *new_path,
1190 UnitFileChange **changes,
1191 unsigned *n_changes) {
1199 mkdir_parents_label(new_path, 0755);
1201 if (symlink(old_path, new_path) >= 0) {
1202 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1206 if (errno != EEXIST)
1209 r = readlink_and_make_absolute(new_path, &dest);
1213 if (path_equal(dest, old_path)) {
1225 if (symlink(old_path, new_path) >= 0) {
1226 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1227 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1234 static int install_info_symlink_alias(
1236 const char *config_path,
1238 UnitFileChange **changes,
1239 unsigned *n_changes) {
1245 assert(config_path);
1247 STRV_FOREACH(s, i->aliases) {
1250 alias_path = path_make_absolute(*s, config_path);
1255 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1265 static int install_info_symlink_wants(
1267 const char *config_path,
1269 UnitFileChange **changes,
1270 unsigned *n_changes) {
1276 assert(config_path);
1278 STRV_FOREACH(s, i->wanted_by) {
1281 if (!unit_name_is_valid(*s, true)) {
1286 if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0)
1289 q = create_symlink(i->path, path, force, changes, n_changes);
1299 static int install_info_symlink_requires(
1301 const char *config_path,
1303 UnitFileChange **changes,
1304 unsigned *n_changes) {
1310 assert(config_path);
1312 STRV_FOREACH(s, i->required_by) {
1315 if (!unit_name_is_valid(*s, true)) {
1320 if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0)
1323 q = create_symlink(i->path, path, force, changes, n_changes);
1333 static int install_info_symlink_link(
1336 const char *config_path,
1338 UnitFileChange **changes,
1339 unsigned *n_changes) {
1346 assert(config_path);
1349 r = in_search_path(i->path, paths->unit_path);
1353 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1356 r = create_symlink(i->path, path, force, changes, n_changes);
1362 static int install_info_apply(
1365 const char *config_path,
1367 UnitFileChange **changes,
1368 unsigned *n_changes) {
1374 assert(config_path);
1376 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1378 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1382 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1386 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1393 static int install_context_apply(
1396 const char *config_path,
1397 const char *root_dir,
1399 UnitFileChange **changes,
1400 unsigned *n_changes) {
1407 assert(config_path);
1409 while ((i = hashmap_first(c->will_install))) {
1411 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1415 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1417 q = unit_file_search(c, i, paths, root_dir, false);
1426 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1427 if (r >= 0 && q < 0)
1434 static int install_context_mark_for_removal(
1437 Set **remove_symlinks_to,
1438 const char *config_path,
1439 const char *root_dir) {
1446 assert(config_path);
1448 /* Marks all items for removal */
1450 while ((i = hashmap_first(c->will_install))) {
1452 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1456 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1458 q = unit_file_search(c, i, paths, root_dir, false);
1467 if (unit_name_is_instance(i->name)) {
1468 char *unit_file = NULL;
1470 unit_file = path_get_file_name(i->path);
1472 if (unit_name_is_instance(unit_file))
1473 /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1474 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1476 /* does not exist, thus we will mark for removal symlinks to template unit file */
1477 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1479 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1481 if (r >= 0 && q < 0)
1488 int unit_file_enable(
1489 UnitFileScope scope,
1491 const char *root_dir,
1494 UnitFileChange **changes,
1495 unsigned *n_changes) {
1499 char **i, *config_path = NULL;
1503 assert(scope < _UNIT_FILE_SCOPE_MAX);
1508 r = lookup_paths_init_from_scope(&paths, scope);
1512 r = get_config_path(scope, runtime, root_dir, &config_path);
1516 STRV_FOREACH(i, files) {
1517 r = install_info_add_auto(&c, *i);
1522 /* This will return the number of symlink rules that were
1523 supposed to be created, not the ones actually created. This is
1524 useful to determine whether the passed files hat any
1525 installation data at all. */
1526 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1529 install_context_done(&c);
1530 lookup_paths_free(&paths);
1536 int unit_file_disable(
1537 UnitFileScope scope,
1539 const char *root_dir,
1541 UnitFileChange **changes,
1542 unsigned *n_changes) {
1546 char **i, *config_path = NULL;
1547 Set *remove_symlinks_to = NULL;
1551 assert(scope < _UNIT_FILE_SCOPE_MAX);
1556 r = lookup_paths_init_from_scope(&paths, scope);
1560 r = get_config_path(scope, runtime, root_dir, &config_path);
1564 STRV_FOREACH(i, files) {
1565 r = install_info_add_auto(&c, *i);
1570 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1572 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1577 install_context_done(&c);
1578 lookup_paths_free(&paths);
1579 set_free_free(remove_symlinks_to);
1585 int unit_file_reenable(
1586 UnitFileScope scope,
1588 const char *root_dir,
1591 UnitFileChange **changes,
1592 unsigned *n_changes) {
1596 char **i, *config_path = NULL;
1597 Set *remove_symlinks_to = NULL;
1601 assert(scope < _UNIT_FILE_SCOPE_MAX);
1606 r = lookup_paths_init_from_scope(&paths, scope);
1610 r = get_config_path(scope, runtime, root_dir, &config_path);
1614 STRV_FOREACH(i, files) {
1615 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1619 r = install_info_add_auto(&c, *i);
1624 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1626 /* Returns number of symlinks that where supposed to be installed. */
1627 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1632 lookup_paths_free(&paths);
1633 install_context_done(&c);
1634 set_free_free(remove_symlinks_to);
1640 UnitFileState unit_file_get_state(
1641 UnitFileScope scope,
1642 const char *root_dir,
1646 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1647 char **i, *path = NULL;
1651 assert(scope < _UNIT_FILE_SCOPE_MAX);
1656 if (root_dir && scope != UNIT_FILE_SYSTEM)
1659 if (!unit_name_is_valid(name, true))
1662 r = lookup_paths_init_from_scope(&paths, scope);
1666 STRV_FOREACH(i, paths.unit_path) {
1673 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1675 asprintf(&path, "%s/%s", *i, name);
1682 if (lstat(path, &st) < 0) {
1684 if (errno == ENOENT)
1690 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
1695 r = null_or_empty_path(path);
1696 if (r < 0 && r != -ENOENT)
1699 state = path_startswith(*i, "/run") ?
1700 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1705 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1713 r = unit_file_can_install(&paths, root_dir, path, true);
1714 if (r < 0 && errno != -ENOENT)
1717 state = UNIT_FILE_DISABLED;
1720 } else if (r == 0) {
1721 state = UNIT_FILE_STATIC;
1728 lookup_paths_free(&paths);
1731 return r < 0 ? r : state;
1734 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1739 assert(scope < _UNIT_FILE_SCOPE_MAX);
1742 if (scope == UNIT_FILE_SYSTEM)
1743 r = conf_files_list(&files, ".preset",
1744 "/etc/systemd/system-preset",
1745 "/usr/local/lib/systemd/system-preset",
1746 "/usr/lib/systemd/system-preset",
1747 #ifdef HAVE_SPLIT_USR
1748 "/lib/systemd/system-preset",
1751 else if (scope == UNIT_FILE_GLOBAL)
1752 r = conf_files_list(&files, ".preset",
1753 "/etc/systemd/user-preset",
1754 "/usr/local/lib/systemd/user-preset",
1755 "/usr/lib/systemd/user-preset",
1763 STRV_FOREACH(i, files) {
1766 f = fopen(*i, "re");
1768 if (errno == ENOENT)
1776 char line[LINE_MAX], *l;
1778 if (!fgets(line, sizeof(line), f))
1785 if (strchr(COMMENTS, *l))
1788 if (first_word(l, "enable")) {
1790 l += strspn(l, WHITESPACE);
1792 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1797 } else if (first_word(l, "disable")) {
1799 l += strspn(l, WHITESPACE);
1801 if (fnmatch(l, name, FNM_NOESCAPE) == 0) {
1807 log_debug("Couldn't parse line '%s'", l);
1813 /* Default is "enable" */
1822 int unit_file_preset(
1823 UnitFileScope scope,
1825 const char *root_dir,
1828 UnitFileChange **changes,
1829 unsigned *n_changes) {
1832 InstallContext plus, minus;
1833 char **i, *config_path = NULL;
1834 Set *remove_symlinks_to = NULL;
1838 assert(scope < _UNIT_FILE_SCOPE_MAX);
1844 r = lookup_paths_init_from_scope(&paths, scope);
1848 r = get_config_path(scope, runtime, root_dir, &config_path);
1852 STRV_FOREACH(i, files) {
1854 if (!unit_name_is_valid(*i, true)) {
1859 r = unit_file_query_preset(scope, *i);
1864 r = install_info_add_auto(&plus, *i);
1866 r = install_info_add_auto(&minus, *i);
1872 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1874 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1878 /* Returns number of symlinks that where supposed to be installed. */
1879 q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes);
1884 lookup_paths_free(&paths);
1885 install_context_done(&plus);
1886 install_context_done(&minus);
1887 set_free_free(remove_symlinks_to);
1893 int unit_file_get_list(
1894 UnitFileScope scope,
1895 const char *root_dir,
1899 char **i, *buf = NULL;
1904 assert(scope < _UNIT_FILE_SCOPE_MAX);
1909 if (root_dir && scope != UNIT_FILE_SYSTEM)
1912 r = lookup_paths_init_from_scope(&paths, scope);
1916 STRV_FOREACH(i, paths.unit_path) {
1917 struct dirent buffer, *de;
1918 const char *units_dir;
1924 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) {
1935 d = opendir(units_dir);
1937 if (errno == ENOENT)
1947 r = readdir_r(d, &buffer, &de);
1956 if (ignore_file(de->d_name))
1959 if (!unit_name_is_valid(de->d_name, true))
1962 if (hashmap_get(h, de->d_name))
1965 r = dirent_ensure_type(d, de);
1973 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1976 f = new0(UnitFileList, 1);
1982 f->path = path_make_absolute(de->d_name, units_dir);
1989 r = null_or_empty_path(f->path);
1990 if (r < 0 && r != -ENOENT) {
1996 path_startswith(*i, "/run") ?
1997 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
2001 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
2009 r = unit_file_can_install(&paths, root_dir, f->path, true);
2015 f->state = UNIT_FILE_DISABLED;
2018 f->state = UNIT_FILE_STATIC;
2027 r = hashmap_put(h, path_get_file_name(f->path), f);
2037 lookup_paths_free(&paths);
2046 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2047 [UNIT_FILE_ENABLED] = "enabled",
2048 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
2049 [UNIT_FILE_LINKED] = "linked",
2050 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2051 [UNIT_FILE_MASKED] = "masked",
2052 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2053 [UNIT_FILE_STATIC] = "static",
2054 [UNIT_FILE_DISABLED] = "disabled"
2057 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
2059 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2060 [UNIT_FILE_SYMLINK] = "symlink",
2061 [UNIT_FILE_UNLINK] = "unlink",
2064 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);