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"
39 #include "specifier.h"
40 #include "install-printf.h"
44 Hashmap *will_install;
45 Hashmap *have_installed;
48 #define _cleanup_install_context_done_ _cleanup_(install_context_done)
50 static int lookup_paths_init_from_scope(LookupPaths *paths,
52 const char *root_dir) {
55 assert(scope < _UNIT_FILE_SCOPE_MAX);
59 return lookup_paths_init(paths,
60 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
61 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_consume(*remove_symlinks_to, n);
184 return r == -EEXIST ? 0 : r;
189 static int remove_marked_symlinks_fd(
190 Set *remove_symlinks_to,
193 const char *config_path,
195 UnitFileChange **changes,
200 _cleanup_closedir_ DIR *d = NULL;
202 assert(remove_symlinks_to);
221 if (!de && errno != 0) {
229 if (ignore_file(de->d_name))
232 dirent_ensure_type(d, de);
234 if (de->d_type == DT_DIR) {
236 _cleanup_free_ char *p = NULL;
238 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
248 p = path_make_absolute(de->d_name, path);
254 /* This will close nfd, regardless whether it succeeds or not */
255 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
260 } else if (de->d_type == DT_LNK) {
261 _cleanup_free_ char *p = NULL, *dest = NULL;
265 p = path_make_absolute(de->d_name, path);
269 q = readlink_and_canonicalize(p, &dest);
280 set_get(remove_symlinks_to, dest) ||
281 set_get(remove_symlinks_to, basename(dest));
283 if (unit_name_is_instance(p))
284 found = found && strv_contains(files, basename(p));
288 if (unlink(p) < 0 && errno != ENOENT) {
293 rmdir_parents(p, config_path);
294 path_kill_slashes(p);
296 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
298 if (!set_get(remove_symlinks_to, p)) {
300 q = mark_symlink_for_removal(&remove_symlinks_to, p);
315 static int remove_marked_symlinks(
316 Set *remove_symlinks_to,
317 const char *config_path,
318 UnitFileChange **changes,
322 _cleanup_close_ int fd = -1;
328 if (set_size(remove_symlinks_to) <= 0)
331 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
339 cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
345 /* This takes possession of cfd and closes it */
346 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
354 static int find_symlinks_fd(
358 const char *config_path,
359 bool *same_name_link) {
362 _cleanup_closedir_ DIR *d = NULL;
368 assert(same_name_link);
381 if (!de && errno != 0)
387 if (ignore_file(de->d_name))
390 dirent_ensure_type(d, de);
392 if (de->d_type == DT_DIR) {
394 _cleanup_free_ char *p = NULL;
396 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
406 p = path_make_absolute(de->d_name, path);
412 /* This will close nfd, regardless whether it succeeds or not */
413 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
421 } else if (de->d_type == DT_LNK) {
422 _cleanup_free_ char *p = NULL, *dest = NULL;
423 bool found_path, found_dest, b = false;
426 /* Acquire symlink name */
427 p = path_make_absolute(de->d_name, path);
431 /* Acquire symlink destination */
432 q = readlink_and_canonicalize(p, &dest);
442 /* Check if the symlink itself matches what we
444 if (path_is_absolute(name))
445 found_path = path_equal(p, name);
447 found_path = streq(de->d_name, name);
449 /* Check if what the symlink points to
450 * matches what we are looking for */
451 if (path_is_absolute(name))
452 found_dest = path_equal(dest, name);
454 found_dest = streq(basename(dest), name);
456 if (found_path && found_dest) {
457 _cleanup_free_ char *t = NULL;
459 /* Filter out same name links in the main
461 t = path_make_absolute(name, config_path);
465 b = path_equal(t, p);
469 *same_name_link = true;
470 else if (found_path || found_dest)
476 static int find_symlinks(
478 const char *config_path,
479 bool *same_name_link) {
485 assert(same_name_link);
487 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
494 /* This takes possession of fd and closes it */
495 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
498 static int find_symlinks_in_scope(
500 const char *root_dir,
502 UnitFileState *state) {
505 _cleanup_free_ char *path2 = NULL;
506 bool same_name_link_runtime = false, same_name_link = false;
509 assert(scope < _UNIT_FILE_SCOPE_MAX);
512 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
513 _cleanup_free_ char *path = NULL;
515 /* First look in runtime config path */
516 r = get_config_path(scope, true, root_dir, &path);
520 r = find_symlinks(name, path, &same_name_link_runtime);
524 *state = UNIT_FILE_ENABLED_RUNTIME;
529 /* Then look in the normal config path */
530 r = get_config_path(scope, false, root_dir, &path2);
534 r = find_symlinks(name, path2, &same_name_link);
538 *state = UNIT_FILE_ENABLED;
542 /* Hmm, we didn't find it, but maybe we found the same name
544 if (same_name_link_runtime) {
545 *state = UNIT_FILE_LINKED_RUNTIME;
547 } else if (same_name_link) {
548 *state = UNIT_FILE_LINKED;
558 const char *root_dir,
561 UnitFileChange **changes,
562 unsigned *n_changes) {
565 _cleanup_free_ char *prefix = NULL;
569 assert(scope < _UNIT_FILE_SCOPE_MAX);
571 r = get_config_path(scope, runtime, root_dir, &prefix);
575 STRV_FOREACH(i, files) {
576 _cleanup_free_ char *path = NULL;
578 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
584 path = path_make_absolute(*i, prefix);
590 if (symlink("/dev/null", path) >= 0) {
591 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
596 if (errno == EEXIST) {
598 if (null_or_empty_path(path) > 0)
604 if (symlink("/dev/null", path) >= 0) {
606 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
607 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
624 int unit_file_unmask(
627 const char *root_dir,
629 UnitFileChange **changes,
630 unsigned *n_changes) {
632 char **i, *config_path = NULL;
634 Set *remove_symlinks_to = NULL;
637 assert(scope < _UNIT_FILE_SCOPE_MAX);
639 r = get_config_path(scope, runtime, root_dir, &config_path);
643 STRV_FOREACH(i, files) {
646 if (!unit_name_is_valid(*i, TEMPLATE_VALID)) {
652 path = path_make_absolute(*i, config_path);
658 q = null_or_empty_path(path);
660 if (unlink(path) >= 0) {
661 mark_symlink_for_removal(&remove_symlinks_to, path);
662 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
671 if (q != -ENOENT && r == 0)
679 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
683 set_free_free(remove_symlinks_to);
692 const char *root_dir,
695 UnitFileChange **changes,
696 unsigned *n_changes) {
698 _cleanup_lookup_paths_free_ LookupPaths paths = {};
700 _cleanup_free_ char *config_path = NULL;
704 assert(scope < _UNIT_FILE_SCOPE_MAX);
706 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
710 r = get_config_path(scope, runtime, root_dir, &config_path);
714 STRV_FOREACH(i, files) {
715 _cleanup_free_ char *path = NULL;
721 if (!path_is_absolute(*i) ||
722 !unit_name_is_valid(fn, TEMPLATE_VALID)) {
728 if (lstat(*i, &st) < 0) {
734 if (!S_ISREG(st.st_mode)) {
739 q = in_search_path(*i, paths.unit_path);
746 path = path_make_absolute(fn, config_path);
750 if (symlink(*i, path) >= 0) {
751 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
755 if (errno == EEXIST) {
756 _cleanup_free_ char *dest = NULL;
758 q = readlink_and_make_absolute(path, &dest);
760 if (q < 0 && errno != ENOENT) {
766 if (q >= 0 && path_equal(dest, *i))
772 if (symlink(*i, path) >= 0) {
774 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
775 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
792 void unit_file_list_free(Hashmap *h) {
795 while ((i = hashmap_steal_first(h))) {
803 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
806 assert(changes || n_changes == 0);
811 for (i = 0; i < n_changes; i++) {
812 free(changes[i].path);
813 free(changes[i].source);
819 static void install_info_free(InstallInfo *i) {
824 strv_free(i->aliases);
825 strv_free(i->wanted_by);
826 strv_free(i->required_by);
830 static void install_info_hashmap_free(Hashmap *m) {
836 while ((i = hashmap_steal_first(m)))
837 install_info_free(i);
842 static void install_context_done(InstallContext *c) {
845 install_info_hashmap_free(c->will_install);
846 install_info_hashmap_free(c->have_installed);
848 c->will_install = c->have_installed = NULL;
851 static int install_info_add(
855 InstallInfo *i = NULL;
859 assert(name || path);
862 name = basename(path);
864 if (!unit_name_is_valid(name, TEMPLATE_VALID))
867 if (hashmap_get(c->have_installed, name) ||
868 hashmap_get(c->will_install, name))
871 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
875 i = new0(InstallInfo, 1);
879 i->name = strdup(name);
886 i->path = strdup(path);
893 r = hashmap_put(c->will_install, i->name, i);
901 install_info_free(i);
906 static int install_info_add_auto(
908 const char *name_or_path) {
911 assert(name_or_path);
913 if (path_is_absolute(name_or_path))
914 return install_info_add(c, NULL, name_or_path);
916 return install_info_add(c, name_or_path, NULL);
919 static int config_parse_also(const char *unit,
920 const char *filename,
923 unsigned section_line,
933 InstallContext *c = data;
939 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
940 _cleanup_free_ char *n;
947 r = install_info_add(c, n, NULL);
955 static int config_parse_user(const char *unit,
956 const char *filename,
959 unsigned section_line,
966 InstallInfo *i = data;
974 r = install_full_printf(i, rvalue, &printed);
984 static int unit_file_load(
988 bool allow_symlink) {
990 const ConfigTableItem items[] = {
991 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
992 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
993 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
994 { "Install", "Also", config_parse_also, 0, c },
995 { "Exec", "User", config_parse_user, 0, info },
996 { NULL, NULL, NULL, 0, NULL }
1000 _cleanup_fclose_ FILE *f = NULL;
1007 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1011 f = fdopen(fd, "re");
1017 r = config_parse(NULL, path, f, NULL,
1018 config_item_table_lookup, (void*) items, true, true, info);
1023 (int) strv_length(info->aliases) +
1024 (int) strv_length(info->wanted_by) +
1025 (int) strv_length(info->required_by);
1028 static int unit_file_search(
1032 const char *root_dir,
1033 bool allow_symlink) {
1043 char *full_path = NULL;
1045 if (!isempty(root_dir))
1046 full_path = strappenda(root_dir, info->path);
1048 return unit_file_load(c, info, full_path ?: info->path, allow_symlink);
1053 STRV_FOREACH(p, paths->unit_path) {
1054 _cleanup_free_ char *path = NULL, *full_path = NULL;
1056 path = strjoin(*p, "/", info->name, NULL);
1060 if (!isempty(root_dir)) {
1061 full_path = strappend(root_dir, path);
1066 r = unit_file_load(c, info, full_path ?: path, allow_symlink);
1070 } else if (r == -ENOENT && unit_name_is_instance(info->name)) {
1071 /* Unit file doesn't exist, however instance enablement was requested.
1072 * We will check if it is possible to load template unit file. */
1073 _cleanup_free_ char *template = NULL, *template_dir = NULL;
1075 template = unit_name_template(info->name);
1079 /* We will reuse path variable since we don't need it anymore. */
1080 template_dir = path;
1081 *(strrchr(template_dir, '/') + 1) = '\0';
1083 path = strappend(template_dir, template);
1087 if (!isempty(root_dir)) {
1089 full_path = strappend(root_dir, path);
1094 /* Let's try to load template unit. */
1095 r = unit_file_load(c, info, full_path ?: path, allow_symlink);
1102 if (r != -ENOENT && r != -ELOOP)
1109 static int unit_file_can_install(
1111 const char *root_dir,
1113 bool allow_symlink) {
1115 _cleanup_install_context_done_ InstallContext c = {};
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 (int) strv_length(i->aliases) +
1133 (int) strv_length(i->wanted_by) +
1134 (int) strv_length(i->required_by);
1139 static int create_symlink(
1140 const char *old_path,
1141 const char *new_path,
1143 UnitFileChange **changes,
1144 unsigned *n_changes) {
1146 _cleanup_free_ char *dest = NULL;
1152 mkdir_parents_label(new_path, 0755);
1154 if (symlink(old_path, new_path) >= 0) {
1155 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1159 if (errno != EEXIST)
1162 r = readlink_and_make_absolute(new_path, &dest);
1166 if (path_equal(dest, old_path))
1172 r = unlink(new_path);
1173 if (r < 0 && errno != ENOENT)
1176 if (symlink(old_path, new_path) >= 0) {
1177 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1178 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1185 static int install_info_symlink_alias(
1187 const char *config_path,
1189 UnitFileChange **changes,
1190 unsigned *n_changes) {
1196 assert(config_path);
1198 STRV_FOREACH(s, i->aliases) {
1199 _cleanup_free_ char *alias_path = NULL, *dst = NULL;
1201 q = install_full_printf(i, *s, &dst);
1205 alias_path = path_make_absolute(dst, config_path);
1209 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1217 static int install_info_symlink_wants(
1219 const char *config_path,
1221 UnitFileChange **changes,
1222 unsigned *n_changes) {
1228 assert(config_path);
1230 STRV_FOREACH(s, i->wanted_by) {
1231 _cleanup_free_ char *path = NULL, *dst = NULL;
1233 q = install_full_printf(i, *s, &dst);
1237 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
1242 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
1245 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) {
1268 _cleanup_free_ char *path = NULL, *dst = NULL;
1270 q = install_full_printf(i, *s, &dst);
1274 if (!unit_name_is_valid(dst, TEMPLATE_VALID)) {
1279 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
1282 q = create_symlink(i->path, path, force, changes, n_changes);
1291 static int install_info_symlink_link(
1294 const char *config_path,
1296 UnitFileChange **changes,
1297 unsigned *n_changes) {
1300 _cleanup_free_ char *path = NULL;
1304 assert(config_path);
1307 r = in_search_path(i->path, paths->unit_path);
1311 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1314 r = create_symlink(i->path, path, force, changes, n_changes);
1318 static int install_info_apply(
1321 const char *config_path,
1323 UnitFileChange **changes,
1324 unsigned *n_changes) {
1330 assert(config_path);
1332 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1334 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1338 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1342 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1349 static int install_context_apply(
1352 const char *config_path,
1353 const char *root_dir,
1355 UnitFileChange **changes,
1356 unsigned *n_changes) {
1363 assert(config_path);
1365 while ((i = hashmap_first(c->will_install))) {
1367 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1371 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1373 q = unit_file_search(c, i, paths, root_dir, false);
1382 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1383 if (r >= 0 && q < 0)
1390 static int install_context_mark_for_removal(
1393 Set **remove_symlinks_to,
1394 const char *config_path,
1395 const char *root_dir) {
1402 assert(config_path);
1404 /* Marks all items for removal */
1406 while ((i = hashmap_first(c->will_install))) {
1408 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1412 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1414 q = unit_file_search(c, i, paths, root_dir, false);
1425 if (unit_name_is_instance(i->name)) {
1429 unit_file = basename(i->path);
1431 if (unit_name_is_instance(unit_file))
1432 /* unit file named as instance exists, thus all symlinks
1433 * pointing to it will be removed */
1434 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1436 /* does not exist, thus we will mark for removal symlinks
1437 * to template unit file */
1438 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1440 /* If i->path is not set, it means that we didn't actually find
1441 * the unit file. But we can still remove symlinks to the
1442 * nonexistent template. */
1443 unit_file = unit_name_template(i->name);
1447 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1451 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1453 if (r >= 0 && q < 0)
1460 int unit_file_enable(
1461 UnitFileScope scope,
1463 const char *root_dir,
1466 UnitFileChange **changes,
1467 unsigned *n_changes) {
1469 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1470 _cleanup_install_context_done_ InstallContext c = {};
1472 _cleanup_free_ char *config_path = NULL;
1476 assert(scope < _UNIT_FILE_SCOPE_MAX);
1478 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1482 r = get_config_path(scope, runtime, root_dir, &config_path);
1486 STRV_FOREACH(i, files) {
1487 r = install_info_add_auto(&c, *i);
1492 /* This will return the number of symlink rules that were
1493 supposed to be created, not the ones actually created. This is
1494 useful to determine whether the passed files had any
1495 installation data at all. */
1497 return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1500 int unit_file_disable(
1501 UnitFileScope scope,
1503 const char *root_dir,
1505 UnitFileChange **changes,
1506 unsigned *n_changes) {
1508 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1509 _cleanup_install_context_done_ InstallContext c = {};
1511 _cleanup_free_ char *config_path = NULL;
1512 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1516 assert(scope < _UNIT_FILE_SCOPE_MAX);
1518 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1522 r = get_config_path(scope, runtime, root_dir, &config_path);
1526 STRV_FOREACH(i, files) {
1527 r = install_info_add_auto(&c, *i);
1532 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1534 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1541 int unit_file_reenable(
1542 UnitFileScope scope,
1544 const char *root_dir,
1547 UnitFileChange **changes,
1548 unsigned *n_changes) {
1551 r = unit_file_disable(scope, runtime, root_dir, files,
1552 changes, n_changes);
1556 return unit_file_enable(scope, runtime, root_dir, files, force,
1557 changes, n_changes);
1560 int unit_file_set_default(
1561 UnitFileScope scope,
1562 const char *root_dir,
1565 UnitFileChange **changes,
1566 unsigned *n_changes) {
1568 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1569 _cleanup_install_context_done_ InstallContext c = {};
1570 _cleanup_free_ char *config_path = NULL;
1573 InstallInfo *i = NULL;
1576 assert(scope < _UNIT_FILE_SCOPE_MAX);
1579 if (unit_name_to_type(file) != UNIT_TARGET)
1582 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1586 r = get_config_path(scope, false, root_dir, &config_path);
1590 r = install_info_add_auto(&c, file);
1594 assert_se(i = hashmap_first(c.will_install));
1596 r = unit_file_search(&c, i, &paths, root_dir, false);
1600 path = strappenda(config_path, "/" SPECIAL_DEFAULT_TARGET);
1602 r = create_symlink(i->path, path, force, changes, n_changes);
1609 int unit_file_get_default(
1610 UnitFileScope scope,
1611 const char *root_dir,
1614 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1619 assert(scope < _UNIT_FILE_SCOPE_MAX);
1622 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1626 STRV_FOREACH(p, paths.unit_path) {
1627 _cleanup_free_ char *path = NULL, *tmp = NULL;
1630 if (isempty(root_dir))
1631 path = strappend(*p, "/" SPECIAL_DEFAULT_TARGET);
1633 path = strjoin(root_dir, "/", *p, "/" SPECIAL_DEFAULT_TARGET, NULL);
1638 r = readlink_malloc(path, &tmp);
1641 else if (r == -EINVAL)
1643 n = strdup(SPECIAL_DEFAULT_TARGET);
1647 n = strdup(basename(tmp));
1659 UnitFileState unit_file_get_state(
1660 UnitFileScope scope,
1661 const char *root_dir,
1664 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1665 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1667 _cleanup_free_ char *path = NULL;
1671 assert(scope < _UNIT_FILE_SCOPE_MAX);
1674 if (root_dir && scope != UNIT_FILE_SYSTEM)
1677 if (!unit_name_is_valid(name, TEMPLATE_VALID))
1680 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1684 STRV_FOREACH(i, paths.unit_path) {
1692 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1694 asprintf(&path, "%s/%s", *i, name);
1699 partial = path + strlen(root_dir) + 1;
1704 * Search for a unit file in our default paths, to
1705 * be sure, that there are no broken symlinks.
1707 if (lstat(path, &st) < 0) {
1709 if (errno != ENOENT)
1712 if (!unit_name_is_instance(name))
1715 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1718 r = null_or_empty_path(path);
1719 if (r < 0 && r != -ENOENT)
1722 state = path_startswith(*i, "/run") ?
1723 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1728 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1734 r = unit_file_can_install(&paths, root_dir, partial, true);
1735 if (r < 0 && errno != ENOENT)
1738 return UNIT_FILE_DISABLED;
1740 return UNIT_FILE_STATIC;
1743 return r < 0 ? r : state;
1746 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1747 _cleanup_strv_free_ char **files = NULL;
1752 assert(scope < _UNIT_FILE_SCOPE_MAX);
1755 if (scope == UNIT_FILE_SYSTEM)
1756 r = conf_files_list(&files, ".preset", NULL,
1757 "/etc/systemd/system-preset",
1758 "/usr/local/lib/systemd/system-preset",
1759 "/usr/lib/systemd/system-preset",
1760 #ifdef HAVE_SPLIT_USR
1761 "/lib/systemd/system-preset",
1764 else if (scope == UNIT_FILE_GLOBAL)
1765 r = conf_files_list(&files, ".preset", NULL,
1766 "/etc/systemd/user-preset",
1767 "/usr/local/lib/systemd/user-preset",
1768 "/usr/lib/systemd/user-preset",
1776 STRV_FOREACH(i, files) {
1777 _cleanup_fclose_ FILE *f;
1779 f = fopen(*i, "re");
1781 if (errno == ENOENT)
1788 char line[LINE_MAX], *l;
1790 if (!fgets(line, sizeof(line), f))
1797 if (strchr(COMMENTS "\n", *l))
1800 if (first_word(l, "enable")) {
1802 l += strspn(l, WHITESPACE);
1804 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1807 } else if (first_word(l, "disable")) {
1809 l += strspn(l, WHITESPACE);
1811 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1815 log_debug("Couldn't parse line '%s'", l);
1819 /* Default is "enable" */
1823 int unit_file_preset(
1824 UnitFileScope scope,
1826 const char *root_dir,
1829 UnitFileChange **changes,
1830 unsigned *n_changes) {
1832 _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
1833 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1834 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1835 _cleanup_free_ char *config_path = NULL;
1840 assert(scope < _UNIT_FILE_SCOPE_MAX);
1842 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1846 r = get_config_path(scope, runtime, root_dir, &config_path);
1850 STRV_FOREACH(i, files) {
1852 if (!unit_name_is_valid(*i, TEMPLATE_VALID))
1855 r = unit_file_query_preset(scope, *i);
1860 r = install_info_add_auto(&plus, *i);
1862 r = install_info_add_auto(&minus, *i);
1867 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir);
1869 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1873 /* Returns number of symlinks that where supposed to be installed. */
1874 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1875 changes, n_changes);
1882 static void unitfilelist_free(UnitFileList **f) {
1889 #define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
1891 int unit_file_get_list(
1892 UnitFileScope scope,
1893 const char *root_dir,
1896 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1901 assert(scope < _UNIT_FILE_SCOPE_MAX);
1904 if (root_dir && scope != UNIT_FILE_SYSTEM)
1907 r = lookup_paths_init_from_scope(&paths, scope, root_dir);
1911 STRV_FOREACH(i, paths.unit_path) {
1912 _cleanup_closedir_ DIR *d = NULL;
1913 _cleanup_free_ char *buf = NULL;
1914 const char *units_dir;
1916 if (!isempty(root_dir)) {
1917 buf = strjoin(root_dir, "/", *i, NULL);
1925 d = opendir(units_dir);
1927 if (errno == ENOENT)
1935 _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
1939 if (!de && errno != 0)
1945 if (ignore_file(de->d_name))
1948 if (!unit_name_is_valid(de->d_name, TEMPLATE_VALID))
1951 if (hashmap_get(h, de->d_name))
1954 dirent_ensure_type(d, de);
1956 if (!IN_SET(de->d_type, DT_LNK, DT_REG))
1959 f = new0(UnitFileList, 1);
1963 f->path = path_make_absolute(de->d_name, units_dir);
1967 r = null_or_empty_path(f->path);
1968 if (r < 0 && r != -ENOENT)
1972 path_startswith(*i, "/run") ?
1973 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1977 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1981 f->state = UNIT_FILE_ENABLED;
1985 r = unit_file_can_install(&paths, root_dir, f->path, true);
1986 if (r == -EINVAL || /* Invalid setting? */
1987 r == -EBADMSG || /* Invalid format? */
1988 r == -ENOENT /* Included file not found? */)
1989 f->state = UNIT_FILE_INVALID;
1993 f->state = UNIT_FILE_DISABLED;
1995 f->state = UNIT_FILE_STATIC;
1998 r = hashmap_put(h, basename(f->path), f);
2001 f = NULL; /* prevent cleanup */
2008 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2009 [UNIT_FILE_ENABLED] = "enabled",
2010 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
2011 [UNIT_FILE_LINKED] = "linked",
2012 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2013 [UNIT_FILE_MASKED] = "masked",
2014 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2015 [UNIT_FILE_STATIC] = "static",
2016 [UNIT_FILE_DISABLED] = "disabled",
2017 [UNIT_FILE_INVALID] = "invalid",
2020 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
2022 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2023 [UNIT_FILE_SYMLINK] = "symlink",
2024 [UNIT_FILE_UNLINK] = "unlink",
2027 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);