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_lookup_paths_free_ \
48 __attribute__((cleanup(lookup_paths_free)))
49 #define _cleanup_install_context_done_ \
50 __attribute__((cleanup(install_context_done)))
52 static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) {
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,
65 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
70 assert(scope < _UNIT_FILE_SCOPE_MAX);
75 case UNIT_FILE_SYSTEM:
77 if (root_dir && runtime)
78 asprintf(&p, "%s/run/systemd/system", root_dir);
80 p = strdup("/run/systemd/system");
82 asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH);
84 p = strdup(SYSTEM_CONFIG_UNIT_PATH);
88 case UNIT_FILE_GLOBAL:
94 p = strdup("/run/systemd/user");
96 p = strdup(USER_CONFIG_UNIT_PATH);
101 if (root_dir || runtime)
104 r = user_config_home(&p);
106 return r < 0 ? r : -ENOENT;
111 assert_not_reached("Bad scope");
121 static int add_file_change(
122 UnitFileChange **changes,
124 UnitFileChangeType type,
126 const char *source) {
132 assert(!changes == !n_changes);
137 c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
145 c[i].path = strdup(path);
150 c[i].source = strdup(source);
162 static int mark_symlink_for_removal(
163 Set **remove_symlinks_to,
171 r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func);
179 path_kill_slashes(n);
181 r = set_put(*remove_symlinks_to, n);
184 return r == -EEXIST ? 0 : r;
190 static int remove_marked_symlinks_fd(
191 Set *remove_symlinks_to,
194 const char *config_path,
196 UnitFileChange **changes,
201 DIR _cleanup_closedir_ *d = NULL;
203 assert(remove_symlinks_to);
211 close_nointr_nofail(fd);
219 union dirent_storage buf;
222 k = readdir_r(d, &buf.de, &de);
231 if (ignore_file(de->d_name))
234 dirent_ensure_type(d, de);
236 if (de->d_type == DT_DIR) {
238 char _cleanup_free_ *p = NULL;
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);
256 /* This will close nfd, regardless whether it succeeds or not */
257 q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files);
262 } else if (de->d_type == DT_LNK) {
263 char _cleanup_free_ *p = NULL, *dest = NULL;
267 p = path_make_absolute(de->d_name, path);
271 q = readlink_and_canonicalize(p, &dest);
282 set_get(remove_symlinks_to, dest) ||
283 set_get(remove_symlinks_to, path_get_file_name(dest));
285 if (unit_name_is_instance(p))
286 found = found && strv_contains(files, path_get_file_name(p));
290 if (unlink(p) < 0 && errno != ENOENT) {
295 rmdir_parents(p, config_path);
296 path_kill_slashes(p);
298 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
300 if (!set_get(remove_symlinks_to, p)) {
302 q = mark_symlink_for_removal(&remove_symlinks_to, p);
317 static int remove_marked_symlinks(
318 Set *remove_symlinks_to,
319 const char *config_path,
320 UnitFileChange **changes,
329 if (set_size(remove_symlinks_to) <= 0)
332 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
346 /* This takes possession of cfd and closes it */
347 q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files);
352 close_nointr_nofail(fd);
357 static int find_symlinks_fd(
361 const char *config_path,
362 bool *same_name_link) {
365 DIR _cleanup_closedir_ *d = NULL;
371 assert(same_name_link);
375 close_nointr_nofail(fd);
382 union dirent_storage buf;
384 k = readdir_r(d, &buf.de, &de);
391 if (ignore_file(de->d_name))
394 dirent_ensure_type(d, de);
396 if (de->d_type == DT_DIR) {
398 char _cleanup_free_ *p = NULL;
400 nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
410 p = path_make_absolute(de->d_name, path);
412 close_nointr_nofail(nfd);
416 /* This will close nfd, regardless whether it succeeds or not */
417 q = find_symlinks_fd(name, nfd, p, config_path, same_name_link);
425 } else if (de->d_type == DT_LNK) {
426 char _cleanup_free_ *p = NULL, *dest = NULL;
427 bool found_path, found_dest, b = false;
430 /* Acquire symlink name */
431 p = path_make_absolute(de->d_name, path);
435 /* Acquire symlink destination */
436 q = readlink_and_canonicalize(p, &dest);
446 /* Check if the symlink itself matches what we
448 if (path_is_absolute(name))
449 found_path = path_equal(p, name);
451 found_path = streq(de->d_name, name);
453 /* Check if what the symlink points to
454 * matches what we are looking for */
455 if (path_is_absolute(name))
456 found_dest = path_equal(dest, name);
458 found_dest = streq(path_get_file_name(dest), name);
460 if (found_path && found_dest) {
461 char _cleanup_free_ *t = NULL;
463 /* Filter out same name links in the main
465 t = path_make_absolute(name, config_path);
469 b = path_equal(t, p);
473 *same_name_link = true;
474 else if (found_path || found_dest)
482 static int find_symlinks(
484 const char *config_path,
485 bool *same_name_link) {
491 assert(same_name_link);
493 fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
500 /* This takes possession of fd and closes it */
501 return find_symlinks_fd(name, fd, config_path, config_path, same_name_link);
504 static int find_symlinks_in_scope(
506 const char *root_dir,
508 UnitFileState *state) {
511 char _cleanup_free_ *path = NULL;
512 bool same_name_link_runtime = false, same_name_link = false;
515 assert(scope < _UNIT_FILE_SCOPE_MAX);
518 if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) {
520 /* First look in runtime config path */
521 r = get_config_path(scope, true, root_dir, &path);
525 r = find_symlinks(name, path, &same_name_link_runtime);
529 *state = UNIT_FILE_ENABLED_RUNTIME;
534 /* Then look in the normal config path */
535 r = get_config_path(scope, false, root_dir, &path);
539 r = find_symlinks(name, path, &same_name_link);
543 *state = UNIT_FILE_ENABLED;
547 /* Hmm, we didn't find it, but maybe we found the same name
549 if (same_name_link_runtime) {
550 *state = UNIT_FILE_LINKED_RUNTIME;
552 } else if (same_name_link) {
553 *state = UNIT_FILE_LINKED;
563 const char *root_dir,
566 UnitFileChange **changes,
567 unsigned *n_changes) {
570 char _cleanup_free_ *prefix;
574 assert(scope < _UNIT_FILE_SCOPE_MAX);
576 r = get_config_path(scope, runtime, root_dir, &prefix);
580 STRV_FOREACH(i, files) {
581 char _cleanup_free_ *path = NULL;
583 if (!unit_name_is_valid(*i, true)) {
589 path = path_make_absolute(*i, prefix);
595 if (symlink("/dev/null", path) >= 0) {
596 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
601 if (errno == EEXIST) {
603 if (null_or_empty_path(path) > 0)
609 if (symlink("/dev/null", path) >= 0) {
611 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
612 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
629 int unit_file_unmask(
632 const char *root_dir,
634 UnitFileChange **changes,
635 unsigned *n_changes) {
637 char **i, *config_path = NULL;
639 Set *remove_symlinks_to = NULL;
642 assert(scope < _UNIT_FILE_SCOPE_MAX);
644 r = get_config_path(scope, runtime, root_dir, &config_path);
648 STRV_FOREACH(i, files) {
651 if (!unit_name_is_valid(*i, true)) {
657 path = path_make_absolute(*i, config_path);
663 q = null_or_empty_path(path);
665 if (unlink(path) >= 0) {
666 mark_symlink_for_removal(&remove_symlinks_to, path);
667 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
676 if (q != -ENOENT && r == 0)
684 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
688 set_free_free(remove_symlinks_to);
697 const char *root_dir,
700 UnitFileChange **changes,
701 unsigned *n_changes) {
703 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
705 char _cleanup_free_ *config_path = NULL;
709 assert(scope < _UNIT_FILE_SCOPE_MAX);
711 r = lookup_paths_init_from_scope(&paths, scope);
715 r = get_config_path(scope, runtime, root_dir, &config_path);
719 STRV_FOREACH(i, files) {
720 char _cleanup_free_ *path = NULL;
724 fn = path_get_file_name(*i);
726 if (!path_is_absolute(*i) ||
727 !unit_name_is_valid(fn, true)) {
733 if (lstat(*i, &st) < 0) {
739 if (!S_ISREG(st.st_mode)) {
744 q = in_search_path(*i, paths.unit_path);
751 path = path_make_absolute(fn, config_path);
755 if (symlink(*i, path) >= 0) {
756 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
760 if (errno == EEXIST) {
761 char _cleanup_free_ *dest = NULL;
763 q = readlink_and_make_absolute(path, &dest);
765 if (q < 0 && errno != ENOENT) {
771 if (q >= 0 && path_equal(dest, *i))
777 if (symlink(*i, path) >= 0) {
779 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
780 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
797 void unit_file_list_free(Hashmap *h) {
800 while ((i = hashmap_steal_first(h))) {
808 void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
811 assert(changes || n_changes == 0);
816 for (i = 0; i < n_changes; i++) {
817 free(changes[i].path);
818 free(changes[i].source);
824 static void install_info_free(InstallInfo *i) {
829 strv_free(i->aliases);
830 strv_free(i->wanted_by);
831 strv_free(i->required_by);
835 static void install_info_hashmap_free(Hashmap *m) {
841 while ((i = hashmap_steal_first(m)))
842 install_info_free(i);
847 static void install_context_done(InstallContext *c) {
850 install_info_hashmap_free(c->will_install);
851 install_info_hashmap_free(c->have_installed);
853 c->will_install = c->have_installed = NULL;
856 static int install_info_add(
860 InstallInfo *i = NULL;
864 assert(name || path);
867 name = path_get_file_name(path);
869 if (!unit_name_is_valid(name, true))
872 if (hashmap_get(c->have_installed, name) ||
873 hashmap_get(c->will_install, name))
876 r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func);
880 i = new0(InstallInfo, 1);
884 i->name = strdup(name);
891 i->path = strdup(path);
898 r = hashmap_put(c->will_install, i->name, i);
906 install_info_free(i);
911 static int install_info_add_auto(
913 const char *name_or_path) {
916 assert(name_or_path);
918 if (path_is_absolute(name_or_path))
919 return install_info_add(c, NULL, name_or_path);
921 return install_info_add(c, name_or_path, NULL);
924 static int config_parse_also(
925 const char *filename,
937 InstallContext *c = data;
943 FOREACH_WORD_QUOTED(w, l, rvalue, state) {
944 char _cleanup_free_ *n;
951 r = install_info_add(c, n, NULL);
959 static int unit_file_load(
963 bool allow_symlink) {
965 const ConfigTableItem items[] = {
966 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
967 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
968 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
969 { "Install", "Also", config_parse_also, 0, c },
970 { NULL, NULL, NULL, 0, NULL }
974 FILE _cleanup_fclose_ *f = NULL;
981 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
985 f = fdopen(fd, "re");
987 close_nointr_nofail(fd);
991 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
996 strv_length(info->aliases) +
997 strv_length(info->wanted_by) +
998 strv_length(info->required_by);
1001 static int unit_file_search(
1005 const char *root_dir,
1006 bool allow_symlink) {
1016 return unit_file_load(c, info, info->path, allow_symlink);
1020 STRV_FOREACH(p, paths->unit_path) {
1023 if (isempty(root_dir))
1024 asprintf(&path, "%s/%s", *p, info->name);
1026 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1031 r = unit_file_load(c, info, path, allow_symlink);
1036 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1037 /* unit file doesn't exist, however instance enablement was request */
1038 /* we will check if it is possible to load template unit file */
1039 char *template = NULL,
1040 *template_path = NULL,
1041 *template_dir = NULL;
1043 template = unit_name_template(info->name);
1049 /* we will reuse path variable since we don't need it anymore */
1050 template_dir = path;
1051 *(strrchr(path, '/') + 1) = '\0';
1053 template_path = strjoin(template_dir, template, NULL);
1054 if (!template_path) {
1060 /* let's try to load template unit */
1061 r = unit_file_load(c, info, template_path, allow_symlink);
1063 info->path = strdup(template_path);
1067 free(template_path);
1073 free(template_path);
1078 if (r != -ENOENT && r != -ELOOP)
1085 static int unit_file_can_install(
1087 const char *root_dir,
1089 bool allow_symlink) {
1091 InstallContext _cleanup_install_context_done_ c = {NULL};
1098 r = install_info_add_auto(&c, name);
1102 assert_se(i = hashmap_first(c.will_install));
1104 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1108 strv_length(i->aliases) +
1109 strv_length(i->wanted_by) +
1110 strv_length(i->required_by);
1115 static int create_symlink(
1116 const char *old_path,
1117 const char *new_path,
1119 UnitFileChange **changes,
1120 unsigned *n_changes) {
1122 char _cleanup_free_ *dest = NULL;
1128 mkdir_parents_label(new_path, 0755);
1130 if (symlink(old_path, new_path) >= 0) {
1131 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1135 if (errno != EEXIST)
1138 r = readlink_and_make_absolute(new_path, &dest);
1142 if (path_equal(dest, old_path))
1150 if (symlink(old_path, new_path) >= 0) {
1151 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1152 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1159 static int install_info_symlink_alias(
1161 const char *config_path,
1163 UnitFileChange **changes,
1164 unsigned *n_changes) {
1170 assert(config_path);
1172 STRV_FOREACH(s, i->aliases) {
1173 char _cleanup_free_ *alias_path = NULL, *dst = NULL;
1175 dst = install_full_printf(i, *s);
1179 alias_path = path_make_absolute(dst, config_path);
1183 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1191 static int install_info_symlink_wants(
1193 const char *config_path,
1195 UnitFileChange **changes,
1196 unsigned *n_changes) {
1202 assert(config_path);
1204 STRV_FOREACH(s, i->wanted_by) {
1205 char _cleanup_free_ *path = NULL, *dst = NULL;
1207 dst = install_full_printf(i, *s);
1211 if (!unit_name_is_valid(dst, true)) {
1216 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
1219 q = create_symlink(i->path, path, force, changes, n_changes);
1228 static int install_info_symlink_requires(
1230 const char *config_path,
1232 UnitFileChange **changes,
1233 unsigned *n_changes) {
1239 assert(config_path);
1241 STRV_FOREACH(s, i->required_by) {
1242 char _cleanup_free_ *path = NULL, *dst = NULL;
1244 dst = install_full_printf(i, *s);
1248 if (!unit_name_is_valid(dst, true)) {
1253 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
1256 q = create_symlink(i->path, path, force, changes, n_changes);
1265 static int install_info_symlink_link(
1268 const char *config_path,
1270 UnitFileChange **changes,
1271 unsigned *n_changes) {
1274 char _cleanup_free_ *path = NULL;
1278 assert(config_path);
1281 r = in_search_path(i->path, paths->unit_path);
1285 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1288 r = create_symlink(i->path, path, force, changes, n_changes);
1292 static int install_info_apply(
1295 const char *config_path,
1297 UnitFileChange **changes,
1298 unsigned *n_changes) {
1304 assert(config_path);
1306 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1308 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1312 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1316 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1323 static int install_context_apply(
1326 const char *config_path,
1327 const char *root_dir,
1329 UnitFileChange **changes,
1330 unsigned *n_changes) {
1337 assert(config_path);
1339 while ((i = hashmap_first(c->will_install))) {
1341 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1345 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1347 q = unit_file_search(c, i, paths, root_dir, false);
1356 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1357 if (r >= 0 && q < 0)
1364 static int install_context_mark_for_removal(
1367 Set **remove_symlinks_to,
1368 const char *config_path,
1369 const char *root_dir) {
1376 assert(config_path);
1378 /* Marks all items for removal */
1380 while ((i = hashmap_first(c->will_install))) {
1382 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1386 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1388 q = unit_file_search(c, i, paths, root_dir, false);
1397 if (unit_name_is_instance(i->name)) {
1398 char *unit_file = NULL;
1400 unit_file = path_get_file_name(i->path);
1402 if (unit_name_is_instance(unit_file))
1403 /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1404 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1406 /* does not exist, thus we will mark for removal symlinks to template unit file */
1407 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1409 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1411 if (r >= 0 && q < 0)
1418 int unit_file_enable(
1419 UnitFileScope scope,
1421 const char *root_dir,
1424 UnitFileChange **changes,
1425 unsigned *n_changes) {
1427 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1428 InstallContext _cleanup_install_context_done_ c = {NULL};
1430 char _cleanup_free_ *config_path = NULL;
1434 assert(scope < _UNIT_FILE_SCOPE_MAX);
1436 r = lookup_paths_init_from_scope(&paths, scope);
1440 r = get_config_path(scope, runtime, root_dir, &config_path);
1444 STRV_FOREACH(i, files) {
1445 r = install_info_add_auto(&c, *i);
1450 /* This will return the number of symlink rules that were
1451 supposed to be created, not the ones actually created. This is
1452 useful to determine whether the passed files had any
1453 installation data at all. */
1454 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1458 int unit_file_disable(
1459 UnitFileScope scope,
1461 const char *root_dir,
1463 UnitFileChange **changes,
1464 unsigned *n_changes) {
1466 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1467 InstallContext _cleanup_install_context_done_ c = {NULL};
1469 char _cleanup_free_ *config_path = NULL;
1470 Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
1474 assert(scope < _UNIT_FILE_SCOPE_MAX);
1476 r = lookup_paths_init_from_scope(&paths, scope);
1480 r = get_config_path(scope, runtime, root_dir, &config_path);
1484 STRV_FOREACH(i, files) {
1485 r = install_info_add_auto(&c, *i);
1490 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1492 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1499 int unit_file_reenable(
1500 UnitFileScope scope,
1502 const char *root_dir,
1505 UnitFileChange **changes,
1506 unsigned *n_changes) {
1508 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1509 InstallContext _cleanup_install_context_done_ c = {NULL};
1511 char _cleanup_free_ *config_path = NULL;
1512 Set _cleanup_set_free_free_ *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 = mark_symlink_for_removal(&remove_symlinks_to, *i);
1531 r = install_info_add_auto(&c, *i);
1536 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1538 /* Returns number of symlinks that where supposed to be installed. */
1539 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1546 UnitFileState unit_file_get_state(
1547 UnitFileScope scope,
1548 const char *root_dir,
1551 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1552 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1554 char _cleanup_free_ *path = NULL;
1558 assert(scope < _UNIT_FILE_SCOPE_MAX);
1561 if (root_dir && scope != UNIT_FILE_SYSTEM)
1564 if (!unit_name_is_valid(name, true))
1567 r = lookup_paths_init_from_scope(&paths, scope);
1571 STRV_FOREACH(i, paths.unit_path) {
1578 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1580 asprintf(&path, "%s/%s", *i, name);
1585 if (lstat(path, &st) < 0) {
1587 if (errno == ENOENT)
1593 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1596 r = null_or_empty_path(path);
1597 if (r < 0 && r != -ENOENT)
1600 state = path_startswith(*i, "/run") ?
1601 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1605 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1611 r = unit_file_can_install(&paths, root_dir, path, true);
1612 if (r < 0 && errno != -ENOENT)
1615 return UNIT_FILE_DISABLED;
1617 return UNIT_FILE_STATIC;
1620 return r < 0 ? r : state;
1623 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1624 char _cleanup_strv_free_ **files = NULL;
1629 assert(scope < _UNIT_FILE_SCOPE_MAX);
1632 if (scope == UNIT_FILE_SYSTEM)
1633 r = conf_files_list(&files, ".preset",
1634 "/etc/systemd/system-preset",
1635 "/usr/local/lib/systemd/system-preset",
1636 "/usr/lib/systemd/system-preset",
1637 #ifdef HAVE_SPLIT_USR
1638 "/lib/systemd/system-preset",
1641 else if (scope == UNIT_FILE_GLOBAL)
1642 r = conf_files_list(&files, ".preset",
1643 "/etc/systemd/user-preset",
1644 "/usr/local/lib/systemd/user-preset",
1645 "/usr/lib/systemd/user-preset",
1653 STRV_FOREACH(i, files) {
1654 FILE _cleanup_fclose_ *f;
1656 f = fopen(*i, "re");
1658 if (errno == ENOENT)
1665 char line[LINE_MAX], *l;
1667 if (!fgets(line, sizeof(line), f))
1674 if (strchr(COMMENTS, *l))
1677 if (first_word(l, "enable")) {
1679 l += strspn(l, WHITESPACE);
1681 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1684 } else if (first_word(l, "disable")) {
1686 l += strspn(l, WHITESPACE);
1688 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1692 log_debug("Couldn't parse line '%s'", l);
1696 /* Default is "enable" */
1700 int unit_file_preset(
1701 UnitFileScope scope,
1703 const char *root_dir,
1706 UnitFileChange **changes,
1707 unsigned *n_changes) {
1709 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1710 InstallContext _cleanup_install_context_done_ plus = {NULL}, minus = {NULL};
1712 char _cleanup_free_ *config_path = NULL;
1713 Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
1717 assert(scope < _UNIT_FILE_SCOPE_MAX);
1719 r = lookup_paths_init_from_scope(&paths, scope);
1723 r = get_config_path(scope, runtime, root_dir, &config_path);
1727 STRV_FOREACH(i, files) {
1729 if (!unit_name_is_valid(*i, true))
1732 r = unit_file_query_preset(scope, *i);
1737 r = install_info_add_auto(&plus, *i);
1739 r = install_info_add_auto(&minus, *i);
1745 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1746 config_path, root_dir);
1748 q = remove_marked_symlinks(remove_symlinks_to, config_path,
1749 changes, n_changes, files);
1753 /* Returns number of symlinks that where supposed to be installed. */
1754 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1755 changes, n_changes);
1762 static void unitfilelist_free(UnitFileList **f) {
1770 int unit_file_get_list(
1771 UnitFileScope scope,
1772 const char *root_dir,
1775 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1777 char _cleanup_free_ *buf = NULL;
1778 DIR _cleanup_closedir_ *d = NULL;
1782 assert(scope < _UNIT_FILE_SCOPE_MAX);
1785 if (root_dir && scope != UNIT_FILE_SYSTEM)
1788 r = lookup_paths_init_from_scope(&paths, scope);
1792 STRV_FOREACH(i, paths.unit_path) {
1793 const char *units_dir;
1799 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1809 d = opendir(units_dir);
1811 if (errno == ENOENT)
1819 union dirent_storage buffer;
1820 UnitFileList __attribute__((cleanup(unitfilelist_free)))
1823 r = readdir_r(d, &buffer.de, &de);
1830 if (ignore_file(de->d_name))
1833 if (!unit_name_is_valid(de->d_name, true))
1836 if (hashmap_get(h, de->d_name))
1839 r = dirent_ensure_type(d, de);
1847 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1850 f = new0(UnitFileList, 1);
1854 f->path = path_make_absolute(de->d_name, units_dir);
1858 r = null_or_empty_path(f->path);
1859 if (r < 0 && r != -ENOENT)
1863 path_startswith(*i, "/run") ?
1864 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1868 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1872 f->state = UNIT_FILE_ENABLED;
1876 r = unit_file_can_install(&paths, root_dir, f->path, true);
1877 if (r == -EINVAL || /* Invalid setting? */
1878 r == -EBADMSG || /* Invalid format? */
1879 r == -ENOENT /* Included file not found? */)
1880 f->state = UNIT_FILE_INVALID;
1884 f->state = UNIT_FILE_DISABLED;
1886 f->state = UNIT_FILE_STATIC;
1889 r = hashmap_put(h, path_get_file_name(f->path), f);
1892 f = NULL; /* prevent cleanup */
1899 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1900 [UNIT_FILE_ENABLED] = "enabled",
1901 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1902 [UNIT_FILE_LINKED] = "linked",
1903 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1904 [UNIT_FILE_MASKED] = "masked",
1905 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1906 [UNIT_FILE_STATIC] = "static",
1907 [UNIT_FILE_DISABLED] = "disabled",
1908 [UNIT_FILE_INVALID] = "invalid",
1911 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1913 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1914 [UNIT_FILE_SYMLINK] = "symlink",
1915 [UNIT_FILE_UNLINK] = "unlink",
1918 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);