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"
43 Hashmap *will_install;
44 Hashmap *have_installed;
47 #define _cleanup_install_context_done_ _cleanup_(install_context_done)
49 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
52 assert(scope < _UNIT_FILE_SCOPE_MAX);
56 return lookup_paths_init(paths,
57 scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
58 scope == UNIT_FILE_USER,
62 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
67 assert(scope < _UNIT_FILE_SCOPE_MAX);
72 case UNIT_FILE_SYSTEM:
74 if (root_dir && runtime)
75 asprintf(&p, "%s/run/systemd/system", root_dir);
77 p = strdup("/run/systemd/system");
79 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
81 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
85 case UNIT_FILE_GLOBAL:
91 p = strdup("/run/systemd/user");
93 p = strdup(USER_CONFIG_UNIT_PATH);
98 if (root_dir || runtime)
101 r = user_config_home(&p);
103 return r < 0 ? r : -ENOENT;
108 assert_not_reached("Bad scope");
118 static int add_file_change(
119 UnitFileChange **changes,
121 UnitFileChangeType type,
123 const char *source) {
129 assert(!changes == !n_changes);
134 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
142 c[i].path = strdup(path);
147 c[i].source = strdup(source);
159 static int mark_symlink_for_removal(
160 Set **remove_symlinks_to,
168 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
176 path_kill_slashes(n);
178 r = set_consume(*remove_symlinks_to, n);
180 return r == -EEXIST ? 0 : r;
185 static int remove_marked_symlinks_fd(
186 Set *remove_symlinks_to,
189 const char *config_path,
191 UnitFileChange **changes,
196 _cleanup_closedir_ DIR *d = NULL;
198 assert(remove_symlinks_to);
206 close_nointr_nofail(fd);
214 union dirent_storage buf;
217 k = readdir_r(d, &buf.de, &de);
226 if (ignore_file(de->d_name))
229 dirent_ensure_type(d, de);
231 if (de->d_type == DT_DIR) {
233 _cleanup_free_ char *p = NULL;
235 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
245 p = path_make_absolute(de->d_name, path);
247 close_nointr_nofail(nfd);
251 /* This will close nfd, regardless whether it succeeds or not */
252 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
257 } else if (de->d_type == DT_LNK) {
258 _cleanup_free_ char *p = NULL, *dest = NULL;
262 p = path_make_absolute(de->d_name, path);
266 q = readlink_and_canonicalize(p, &dest);
277 set_get(remove_symlinks_to, dest) ||
278 set_get(remove_symlinks_to, path_get_file_name(dest));
280 if (unit_name_is_instance(p))
281 found = found && strv_contains(files, path_get_file_name(p));
285 if (unlink(p) < 0 && errno != ENOENT) {
290 rmdir_parents(p, config_path);
291 path_kill_slashes(p);
293 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
295 if (!set_get(remove_symlinks_to, p)) {
297 q = mark_symlink_for_removal(&remove_symlinks_to, p);
312 static int remove_marked_symlinks(
313 Set *remove_symlinks_to,
314 const char *config_path,
315 UnitFileChange **changes,
324 if (set_size(remove_symlinks_to) <= 0)
327 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
341 /* This takes possession of cfd and closes it */
342 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
347 close_nointr_nofail(fd);
352 static int find_symlinks_fd(
356 const char *config_path,
357 bool *same_name_link) {
360 _cleanup_closedir_ DIR *d = NULL;
366 assert(same_name_link);
370 close_nointr_nofail(fd);
377 union dirent_storage buf;
379 k = readdir_r(d, &buf.de, &de);
386 if (ignore_file(de->d_name))
389 dirent_ensure_type(d, de);
391 if (de->d_type == DT_DIR) {
393 _cleanup_free_ char *p = NULL;
395 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
405 p = path_make_absolute(de->d_name, path);
407 close_nointr_nofail(nfd);
411 /* This will close nfd, regardless whether it succeeds or not */
412 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
420 } else if (de->d_type == DT_LNK) {
421 _cleanup_free_ char *p = NULL, *dest = NULL;
422 bool found_path, found_dest, b = false;
425 /* Acquire symlink name */
426 p = path_make_absolute(de->d_name, path);
430 /* Acquire symlink destination */
431 q = readlink_and_canonicalize(p, &dest);
441 /* Check if the symlink itself matches what we
443 if (path_is_absolute(name))
444 found_path = path_equal(p, name);
446 found_path = streq(de->d_name, name);
448 /* Check if what the symlink points to
449 * matches what we are looking for */
450 if (path_is_absolute(name))
451 found_dest = path_equal(dest, name);
453 found_dest = streq(path_get_file_name(dest), name);
455 if (found_path && found_dest) {
456 _cleanup_free_ char *t = NULL;
458 /* Filter out same name links in the main
460 t = path_make_absolute(name, config_path);
464 b = path_equal(t, p);
468 *same_name_link = true;
469 else if (found_path || found_dest)
477 static int find_symlinks(
479 const char *config_path,
480 bool *same_name_link) {
486 assert(same_name_link);
488 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
495 /* This takes possession of fd and closes it */
496 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
499 static int find_symlinks_in_scope(
501 const char *root_dir,
503 UnitFileState *state) {
506 _cleanup_free_ char *path2 = NULL;
507 bool same_name_link_runtime = false, same_name_link = false;
510 assert(scope < _UNIT_FILE_SCOPE_MAX);
513 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
514 _cleanup_free_ char *path = NULL;
516 /* First look in runtime config path */
517 r = get_config_path(scope, true, root_dir, &path);
521 r = find_symlinks(name, path, &same_name_link_runtime);
525 *state = UNIT_FILE_ENABLED_RUNTIME;
530 /* Then look in the normal config path */
531 r = get_config_path(scope, false, root_dir, &path2);
535 r = find_symlinks(name, path2, &same_name_link);
539 *state = UNIT_FILE_ENABLED;
543 /* Hmm, we didn't find it, but maybe we found the same name
545 if (same_name_link_runtime) {
546 *state = UNIT_FILE_LINKED_RUNTIME;
548 } else if (same_name_link) {
549 *state = UNIT_FILE_LINKED;
559 const char *root_dir,
562 UnitFileChange **changes,
563 unsigned *n_changes) {
566 _cleanup_free_ char *prefix;
570 assert(scope < _UNIT_FILE_SCOPE_MAX);
572 r = get_config_path(scope, runtime, root_dir, &prefix);
576 STRV_FOREACH(i, files) {
577 _cleanup_free_ char *path = NULL;
579 if (!unit_name_is_valid(*i, true)) {
585 path = path_make_absolute(*i, prefix);
591 if (symlink("/dev/null", path) >= 0) {
592 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
597 if (errno == EEXIST) {
599 if (null_or_empty_path(path) > 0)
605 if (symlink("/dev/null", path) >= 0) {
607 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
608 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
625 int unit_file_unmask(
628 const char *root_dir,
630 UnitFileChange **changes,
631 unsigned *n_changes) {
633 char **i, *config_path = NULL;
635 Set *remove_symlinks_to = NULL;
638 assert(scope < _UNIT_FILE_SCOPE_MAX);
640 r = get_config_path(scope, runtime, root_dir, &config_path);
644 STRV_FOREACH(i, files) {
647 if (!unit_name_is_valid(*i, true)) {
653 path = path_make_absolute(*i, config_path);
659 q = null_or_empty_path(path);
661 if (unlink(path) >= 0) {
662 mark_symlink_for_removal(&remove_symlinks_to, path);
663 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
672 if (q != -ENOENT && r == 0)
680 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
684 set_free_free(remove_symlinks_to);
693 const char *root_dir,
696 UnitFileChange **changes,
697 unsigned *n_changes) {
699 _cleanup_lookup_paths_free_ LookupPaths paths = {};
701 _cleanup_free_ char *config_path = NULL;
705 assert(scope < _UNIT_FILE_SCOPE_MAX);
707 r = lookup_paths_init_from_scope(&paths, scope);
711 r = get_config_path(scope, runtime, root_dir, &config_path);
715 STRV_FOREACH(i, files) {
716 _cleanup_free_ char *path = NULL;
720 fn = path_get_file_name(*i);
722 if (!path_is_absolute(*i) ||
723 !unit_name_is_valid(fn, true)) {
729 if (lstat(*i, &st) < 0) {
735 if (!S_ISREG(st.st_mode)) {
740 q = in_search_path(*i, paths.unit_path);
747 path = path_make_absolute(fn, config_path);
751 if (symlink(*i, path) >= 0) {
752 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
756 if (errno == EEXIST) {
757 _cleanup_free_ char *dest = NULL;
759 q = readlink_and_make_absolute(path, &dest);
761 if (q < 0 && errno != ENOENT) {
767 if (q >= 0 && path_equal(dest, *i))
773 if (symlink(*i, path) >= 0) {
775 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
776 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
793 void unit_file_list_free(Hashmap *h) {
796 while ((i = hashmap_steal_first(h))) {
804 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
807 assert(changes || n_changes == 0);
812 for (i = 0; i < n_changes; i++) {
813 free(changes[i].path);
814 free(changes[i].source);
820 static void install_info_free(InstallInfo *i) {
825 strv_free(i->aliases);
826 strv_free(i->wanted_by);
827 strv_free(i->required_by);
831 static void install_info_hashmap_free(Hashmap *m) {
837 while ((i = hashmap_steal_first(m)))
838 install_info_free(i);
843 static void install_context_done(InstallContext *c) {
846 install_info_hashmap_free(c->will_install);
847 install_info_hashmap_free(c->have_installed);
849 c->will_install = c->have_installed = NULL;
852 static int install_info_add(
856 InstallInfo *i = NULL;
860 assert(name || path);
863 name = path_get_file_name(path);
865 if (!unit_name_is_valid(name, true))
868 if (hashmap_get(c->have_installed, name) ||
869 hashmap_get(c->will_install, name))
872 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
876 i = new0(InstallInfo, 1);
880 i->name = strdup(name);
887 i->path = strdup(path);
894 r = hashmap_put(c->will_install, i->name, i);
902 install_info_free(i);
907 static int install_info_add_auto(
909 const char *name_or_path) {
912 assert(name_or_path);
914 if (path_is_absolute(name_or_path))
915 return install_info_add(c, NULL, name_or_path);
917 return install_info_add(c, name_or_path, NULL);
920 static int config_parse_also(const char *unit,
921 const char *filename,
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,
965 InstallInfo *i = data;
973 r = install_full_printf(i, rvalue, &printed);
983 static int unit_file_load(
987 bool allow_symlink) {
989 const ConfigTableItem items[] = {
990 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
991 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
992 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
993 { "Install", "Also", config_parse_also, 0, c },
994 { "Exec", "User", config_parse_user, 0, info },
995 { NULL, NULL, NULL, 0, NULL }
999 _cleanup_fclose_ FILE *f = NULL;
1006 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1010 f = fdopen(fd, "re");
1012 close_nointr_nofail(fd);
1016 r = config_parse(NULL, path, f, NULL,
1017 config_item_table_lookup, (void*) items, true, true, info);
1022 strv_length(info->aliases) +
1023 strv_length(info->wanted_by) +
1024 strv_length(info->required_by);
1027 static int unit_file_search(
1031 const char *root_dir,
1032 bool allow_symlink) {
1042 return unit_file_load(c, info, info->path, allow_symlink);
1046 STRV_FOREACH(p, paths->unit_path) {
1049 if (isempty(root_dir))
1050 asprintf(&path, "%s/%s", *p, info->name);
1052 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1057 r = unit_file_load(c, info, path, allow_symlink);
1062 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1063 /* Unit file doesn't exist, however instance enablement was requested.
1064 * We will check if it is possible to load template unit file. */
1065 char *template = NULL,
1066 *template_path = NULL,
1067 *template_dir = NULL;
1069 template = unit_name_template(info->name);
1075 /* We will reuse path variable since we don't need it anymore. */
1076 template_dir = path;
1077 *(strrchr(path, '/') + 1) = '\0';
1079 template_path = strjoin(template_dir, template, NULL);
1080 if (!template_path) {
1086 /* Let's try to load template unit. */
1087 r = unit_file_load(c, info, template_path, allow_symlink);
1089 info->path = strdup(template_path);
1093 free(template_path);
1099 free(template_path);
1104 if (r != -ENOENT && r != -ELOOP)
1111 static int unit_file_can_install(
1113 const char *root_dir,
1115 bool allow_symlink) {
1117 _cleanup_install_context_done_ InstallContext c = {};
1124 r = install_info_add_auto(&c, name);
1128 assert_se(i = hashmap_first(c.will_install));
1130 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1134 strv_length(i->aliases) +
1135 strv_length(i->wanted_by) +
1136 strv_length(i->required_by);
1141 static int create_symlink(
1142 const char *old_path,
1143 const char *new_path,
1145 UnitFileChange **changes,
1146 unsigned *n_changes) {
1148 _cleanup_free_ char *dest = NULL;
1154 mkdir_parents_label(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))
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, true)) {
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, true)) {
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 = path_get_file_name(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);
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. */
1496 r = 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);
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,
1564 UnitFileChange **changes,
1565 unsigned *n_changes) {
1567 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1568 _cleanup_install_context_done_ InstallContext c = {};
1569 _cleanup_free_ char *config_path = NULL;
1572 InstallInfo *i = NULL;
1575 assert(scope < _UNIT_FILE_SCOPE_MAX);
1577 if (unit_name_to_type(file) != UNIT_TARGET)
1580 r = lookup_paths_init_from_scope(&paths, scope);
1584 r = get_config_path(scope, false, root_dir, &config_path);
1588 r = install_info_add_auto(&c, file);
1592 i = (InstallInfo*)hashmap_first(c.will_install);
1594 r = unit_file_search(&c, i, &paths, root_dir, false);
1598 path = strappenda(config_path, "/default.target");
1599 r = create_symlink(i->path, path, true, changes, n_changes);
1606 int unit_file_get_default(
1607 UnitFileScope scope,
1608 const char *root_dir,
1611 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1615 r = lookup_paths_init_from_scope(&paths, scope);
1619 STRV_FOREACH(p, paths.unit_path) {
1620 _cleanup_free_ char *path = NULL, *tmp = NULL;
1623 if (isempty(root_dir))
1624 path = strappend(*p, "/default.target");
1626 path = strjoin(root_dir, "/", *p, "/default.target", NULL);
1631 r = readlink_malloc(path, &tmp);
1637 n = strdup(path_get_file_name(tmp));
1648 UnitFileState unit_file_get_state(
1649 UnitFileScope scope,
1650 const char *root_dir,
1653 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1654 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1656 _cleanup_free_ char *path = NULL;
1660 assert(scope < _UNIT_FILE_SCOPE_MAX);
1663 if (root_dir && scope != UNIT_FILE_SYSTEM)
1666 if (!unit_name_is_valid(name, true))
1669 r = lookup_paths_init_from_scope(&paths, scope);
1673 STRV_FOREACH(i, paths.unit_path) {
1680 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1682 asprintf(&path, "%s/%s", *i, name);
1688 * Search for a unit file in our default paths, to
1689 * be sure, that there are no broken symlinks.
1691 if (lstat(path, &st) < 0) {
1693 if (errno != ENOENT)
1696 if (!unit_name_is_instance(name))
1699 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1702 r = null_or_empty_path(path);
1703 if (r < 0 && r != -ENOENT)
1706 state = path_startswith(*i, "/run") ?
1707 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1712 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1718 r = unit_file_can_install(&paths, root_dir, path, true);
1719 if (r < 0 && errno != ENOENT)
1722 return UNIT_FILE_DISABLED;
1724 return UNIT_FILE_STATIC;
1727 return r < 0 ? r : state;
1730 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1731 _cleanup_strv_free_ char **files = NULL;
1736 assert(scope < _UNIT_FILE_SCOPE_MAX);
1739 if (scope == UNIT_FILE_SYSTEM)
1740 r = conf_files_list(&files, ".preset", NULL,
1741 "/etc/systemd/system-preset",
1742 "/usr/local/lib/systemd/system-preset",
1743 "/usr/lib/systemd/system-preset",
1744 #ifdef HAVE_SPLIT_USR
1745 "/lib/systemd/system-preset",
1748 else if (scope == UNIT_FILE_GLOBAL)
1749 r = conf_files_list(&files, ".preset", NULL,
1750 "/etc/systemd/user-preset",
1751 "/usr/local/lib/systemd/user-preset",
1752 "/usr/lib/systemd/user-preset",
1760 STRV_FOREACH(i, files) {
1761 _cleanup_fclose_ FILE *f;
1763 f = fopen(*i, "re");
1765 if (errno == ENOENT)
1772 char line[LINE_MAX], *l;
1774 if (!fgets(line, sizeof(line), f))
1781 if (strchr(COMMENTS "\n", *l))
1784 if (first_word(l, "enable")) {
1786 l += strspn(l, WHITESPACE);
1788 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1791 } else if (first_word(l, "disable")) {
1793 l += strspn(l, WHITESPACE);
1795 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1799 log_debug("Couldn't parse line '%s'", l);
1803 /* Default is "enable" */
1807 int unit_file_preset(
1808 UnitFileScope scope,
1810 const char *root_dir,
1813 UnitFileChange **changes,
1814 unsigned *n_changes) {
1816 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1817 _cleanup_install_context_done_ InstallContext plus = {}, minus = {};
1819 _cleanup_free_ char *config_path = NULL;
1820 _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
1824 assert(scope < _UNIT_FILE_SCOPE_MAX);
1826 r = lookup_paths_init_from_scope(&paths, scope);
1830 r = get_config_path(scope, runtime, root_dir, &config_path);
1834 STRV_FOREACH(i, files) {
1836 if (!unit_name_is_valid(*i, true))
1839 r = unit_file_query_preset(scope, *i);
1844 r = install_info_add_auto(&plus, *i);
1846 r = install_info_add_auto(&minus, *i);
1852 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1853 config_path, root_dir);
1855 q = remove_marked_symlinks(remove_symlinks_to, config_path,
1856 changes, n_changes, files);
1860 /* Returns number of symlinks that where supposed to be installed. */
1861 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1862 changes, n_changes);
1869 static void unitfilelist_free(UnitFileList **f) {
1876 #define _cleanup_unitfilelist_free_ _cleanup_(unitfilelist_free)
1878 int unit_file_get_list(
1879 UnitFileScope scope,
1880 const char *root_dir,
1883 _cleanup_lookup_paths_free_ LookupPaths paths = {};
1885 _cleanup_free_ char *buf = NULL;
1886 _cleanup_closedir_ DIR *d = NULL;
1890 assert(scope < _UNIT_FILE_SCOPE_MAX);
1893 if (root_dir && scope != UNIT_FILE_SYSTEM)
1896 r = lookup_paths_init_from_scope(&paths, scope);
1900 STRV_FOREACH(i, paths.unit_path) {
1901 const char *units_dir;
1907 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1917 d = opendir(units_dir);
1919 if (errno == ENOENT)
1927 union dirent_storage buffer;
1928 _cleanup_unitfilelist_free_ UnitFileList *f = NULL;
1930 r = readdir_r(d, &buffer.de, &de);
1937 if (ignore_file(de->d_name))
1940 if (!unit_name_is_valid(de->d_name, true))
1943 if (hashmap_get(h, de->d_name))
1946 r = dirent_ensure_type(d, de);
1954 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1957 f = new0(UnitFileList, 1);
1961 f->path = path_make_absolute(de->d_name, units_dir);
1965 r = null_or_empty_path(f->path);
1966 if (r < 0 && r != -ENOENT)
1970 path_startswith(*i, "/run") ?
1971 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1975 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1979 f->state = UNIT_FILE_ENABLED;
1983 r = unit_file_can_install(&paths, root_dir, f->path, true);
1984 if (r == -EINVAL || /* Invalid setting? */
1985 r == -EBADMSG || /* Invalid format? */
1986 r == -ENOENT /* Included file not found? */)
1987 f->state = UNIT_FILE_INVALID;
1991 f->state = UNIT_FILE_DISABLED;
1993 f->state = UNIT_FILE_STATIC;
1996 r = hashmap_put(h, path_get_file_name(f->path), f);
1999 f = NULL; /* prevent cleanup */
2006 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
2007 [UNIT_FILE_ENABLED] = "enabled",
2008 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
2009 [UNIT_FILE_LINKED] = "linked",
2010 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
2011 [UNIT_FILE_MASKED] = "masked",
2012 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
2013 [UNIT_FILE_STATIC] = "static",
2014 [UNIT_FILE_DISABLED] = "disabled",
2015 [UNIT_FILE_INVALID] = "invalid",
2018 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
2020 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
2021 [UNIT_FILE_SYMLINK] = "symlink",
2022 [UNIT_FILE_UNLINK] = "unlink",
2025 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);