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 config_parse_user(
960 const char *filename,
969 InstallInfo *i = data;
976 printed = install_full_printf(i, rvalue);
986 static int unit_file_load(
990 bool allow_symlink) {
992 const ConfigTableItem items[] = {
993 { "Install", "Alias", config_parse_strv, 0, &info->aliases },
994 { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
995 { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
996 { "Install", "Also", config_parse_also, 0, c },
997 { "Exec", "User", config_parse_user, 0, info },
998 { NULL, NULL, NULL, 0, NULL }
1002 FILE _cleanup_fclose_ *f = NULL;
1009 fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW));
1013 f = fdopen(fd, "re");
1015 close_nointr_nofail(fd);
1019 r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info);
1024 strv_length(info->aliases) +
1025 strv_length(info->wanted_by) +
1026 strv_length(info->required_by);
1029 static int unit_file_search(
1033 const char *root_dir,
1034 bool allow_symlink) {
1044 return unit_file_load(c, info, info->path, allow_symlink);
1048 STRV_FOREACH(p, paths->unit_path) {
1051 if (isempty(root_dir))
1052 asprintf(&path, "%s/%s", *p, info->name);
1054 asprintf(&path, "%s/%s/%s", root_dir, *p, info->name);
1059 r = unit_file_load(c, info, path, allow_symlink);
1064 if (r == -ENOENT && unit_name_is_instance(info->name)) {
1065 /* unit file doesn't exist, however instance enablement was request */
1066 /* we will check if it is possible to load template unit file */
1067 char *template = NULL,
1068 *template_path = NULL,
1069 *template_dir = NULL;
1071 template = unit_name_template(info->name);
1077 /* we will reuse path variable since we don't need it anymore */
1078 template_dir = path;
1079 *(strrchr(path, '/') + 1) = '\0';
1081 template_path = strjoin(template_dir, template, NULL);
1082 if (!template_path) {
1088 /* let's try to load template unit */
1089 r = unit_file_load(c, info, template_path, allow_symlink);
1091 info->path = strdup(template_path);
1095 free(template_path);
1101 free(template_path);
1106 if (r != -ENOENT && r != -ELOOP)
1113 static int unit_file_can_install(
1115 const char *root_dir,
1117 bool allow_symlink) {
1119 InstallContext _cleanup_install_context_done_ c = {NULL};
1126 r = install_info_add_auto(&c, name);
1130 assert_se(i = hashmap_first(c.will_install));
1132 r = unit_file_search(&c, i, paths, root_dir, allow_symlink);
1136 strv_length(i->aliases) +
1137 strv_length(i->wanted_by) +
1138 strv_length(i->required_by);
1143 static int create_symlink(
1144 const char *old_path,
1145 const char *new_path,
1147 UnitFileChange **changes,
1148 unsigned *n_changes) {
1150 char _cleanup_free_ *dest = NULL;
1156 mkdir_parents_label(new_path, 0755);
1158 if (symlink(old_path, new_path) >= 0) {
1159 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1163 if (errno != EEXIST)
1166 r = readlink_and_make_absolute(new_path, &dest);
1170 if (path_equal(dest, old_path))
1178 if (symlink(old_path, new_path) >= 0) {
1179 add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
1180 add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
1187 static int install_info_symlink_alias(
1189 const char *config_path,
1191 UnitFileChange **changes,
1192 unsigned *n_changes) {
1198 assert(config_path);
1200 STRV_FOREACH(s, i->aliases) {
1201 char _cleanup_free_ *alias_path = NULL, *dst = NULL;
1203 dst = install_full_printf(i, *s);
1207 alias_path = path_make_absolute(dst, config_path);
1211 q = create_symlink(i->path, alias_path, force, changes, n_changes);
1219 static int install_info_symlink_wants(
1221 const char *config_path,
1223 UnitFileChange **changes,
1224 unsigned *n_changes) {
1230 assert(config_path);
1232 STRV_FOREACH(s, i->wanted_by) {
1233 char _cleanup_free_ *path = NULL, *dst = NULL;
1235 dst = install_full_printf(i, *s);
1239 if (!unit_name_is_valid(dst, true)) {
1244 if (asprintf(&path, "%s/%s.wants/%s", config_path, dst, i->name) < 0)
1247 q = create_symlink(i->path, path, force, changes, n_changes);
1256 static int install_info_symlink_requires(
1258 const char *config_path,
1260 UnitFileChange **changes,
1261 unsigned *n_changes) {
1267 assert(config_path);
1269 STRV_FOREACH(s, i->required_by) {
1270 char _cleanup_free_ *path = NULL, *dst = NULL;
1272 dst = install_full_printf(i, *s);
1276 if (!unit_name_is_valid(dst, true)) {
1281 if (asprintf(&path, "%s/%s.requires/%s", config_path, dst, i->name) < 0)
1284 q = create_symlink(i->path, path, force, changes, n_changes);
1293 static int install_info_symlink_link(
1296 const char *config_path,
1298 UnitFileChange **changes,
1299 unsigned *n_changes) {
1302 char _cleanup_free_ *path = NULL;
1306 assert(config_path);
1309 r = in_search_path(i->path, paths->unit_path);
1313 if (asprintf(&path, "%s/%s", config_path, i->name) < 0)
1316 r = create_symlink(i->path, path, force, changes, n_changes);
1320 static int install_info_apply(
1323 const char *config_path,
1325 UnitFileChange **changes,
1326 unsigned *n_changes) {
1332 assert(config_path);
1334 r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
1336 q = install_info_symlink_wants(i, config_path, force, changes, n_changes);
1340 q = install_info_symlink_requires(i, config_path, force, changes, n_changes);
1344 q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
1351 static int install_context_apply(
1354 const char *config_path,
1355 const char *root_dir,
1357 UnitFileChange **changes,
1358 unsigned *n_changes) {
1365 assert(config_path);
1367 while ((i = hashmap_first(c->will_install))) {
1369 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1373 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1375 q = unit_file_search(c, i, paths, root_dir, false);
1384 q = install_info_apply(i, paths, config_path, force, changes, n_changes);
1385 if (r >= 0 && q < 0)
1392 static int install_context_mark_for_removal(
1395 Set **remove_symlinks_to,
1396 const char *config_path,
1397 const char *root_dir) {
1404 assert(config_path);
1406 /* Marks all items for removal */
1408 while ((i = hashmap_first(c->will_install))) {
1410 q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func);
1414 assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0);
1416 q = unit_file_search(c, i, paths, root_dir, false);
1425 if (unit_name_is_instance(i->name)) {
1426 char *unit_file = NULL;
1428 unit_file = path_get_file_name(i->path);
1430 if (unit_name_is_instance(unit_file))
1431 /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */
1432 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1434 /* does not exist, thus we will mark for removal symlinks to template unit file */
1435 q = mark_symlink_for_removal(remove_symlinks_to, unit_file);
1437 q = mark_symlink_for_removal(remove_symlinks_to, i->name);
1439 if (r >= 0 && q < 0)
1446 int unit_file_enable(
1447 UnitFileScope scope,
1449 const char *root_dir,
1452 UnitFileChange **changes,
1453 unsigned *n_changes) {
1455 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1456 InstallContext _cleanup_install_context_done_ c = {NULL};
1458 char _cleanup_free_ *config_path = NULL;
1462 assert(scope < _UNIT_FILE_SCOPE_MAX);
1464 r = lookup_paths_init_from_scope(&paths, scope);
1468 r = get_config_path(scope, runtime, root_dir, &config_path);
1472 STRV_FOREACH(i, files) {
1473 r = install_info_add_auto(&c, *i);
1478 /* This will return the number of symlink rules that were
1479 supposed to be created, not the ones actually created. This is
1480 useful to determine whether the passed files had any
1481 installation data at all. */
1482 r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1486 int unit_file_disable(
1487 UnitFileScope scope,
1489 const char *root_dir,
1491 UnitFileChange **changes,
1492 unsigned *n_changes) {
1494 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1495 InstallContext _cleanup_install_context_done_ c = {NULL};
1497 char _cleanup_free_ *config_path = NULL;
1498 Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
1502 assert(scope < _UNIT_FILE_SCOPE_MAX);
1504 r = lookup_paths_init_from_scope(&paths, scope);
1508 r = get_config_path(scope, runtime, root_dir, &config_path);
1512 STRV_FOREACH(i, files) {
1513 r = install_info_add_auto(&c, *i);
1518 r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir);
1520 q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1527 int unit_file_reenable(
1528 UnitFileScope scope,
1530 const char *root_dir,
1533 UnitFileChange **changes,
1534 unsigned *n_changes) {
1536 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1537 InstallContext _cleanup_install_context_done_ c = {NULL};
1539 char _cleanup_free_ *config_path = NULL;
1540 Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
1544 assert(scope < _UNIT_FILE_SCOPE_MAX);
1546 r = lookup_paths_init_from_scope(&paths, scope);
1550 r = get_config_path(scope, runtime, root_dir, &config_path);
1554 STRV_FOREACH(i, files) {
1555 r = mark_symlink_for_removal(&remove_symlinks_to, *i);
1559 r = install_info_add_auto(&c, *i);
1564 r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files);
1566 /* Returns number of symlinks that where supposed to be installed. */
1567 q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes);
1574 UnitFileState unit_file_get_state(
1575 UnitFileScope scope,
1576 const char *root_dir,
1579 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1580 UnitFileState state = _UNIT_FILE_STATE_INVALID;
1582 char _cleanup_free_ *path = NULL;
1586 assert(scope < _UNIT_FILE_SCOPE_MAX);
1589 if (root_dir && scope != UNIT_FILE_SYSTEM)
1592 if (!unit_name_is_valid(name, true))
1595 r = lookup_paths_init_from_scope(&paths, scope);
1599 STRV_FOREACH(i, paths.unit_path) {
1606 asprintf(&path, "%s/%s/%s", root_dir, *i, name);
1608 asprintf(&path, "%s/%s", *i, name);
1613 if (lstat(path, &st) < 0) {
1615 if (errno == ENOENT)
1621 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
1624 r = null_or_empty_path(path);
1625 if (r < 0 && r != -ENOENT)
1628 state = path_startswith(*i, "/run") ?
1629 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1633 r = find_symlinks_in_scope(scope, root_dir, name, &state);
1639 r = unit_file_can_install(&paths, root_dir, path, true);
1640 if (r < 0 && errno != -ENOENT)
1643 return UNIT_FILE_DISABLED;
1645 return UNIT_FILE_STATIC;
1648 return r < 0 ? r : state;
1651 int unit_file_query_preset(UnitFileScope scope, const char *name) {
1652 char _cleanup_strv_free_ **files = NULL;
1657 assert(scope < _UNIT_FILE_SCOPE_MAX);
1660 if (scope == UNIT_FILE_SYSTEM)
1661 r = conf_files_list(&files, ".preset", NULL,
1662 "/etc/systemd/system-preset",
1663 "/usr/local/lib/systemd/system-preset",
1664 "/usr/lib/systemd/system-preset",
1665 #ifdef HAVE_SPLIT_USR
1666 "/lib/systemd/system-preset",
1669 else if (scope == UNIT_FILE_GLOBAL)
1670 r = conf_files_list(&files, ".preset", NULL,
1671 "/etc/systemd/user-preset",
1672 "/usr/local/lib/systemd/user-preset",
1673 "/usr/lib/systemd/user-preset",
1681 STRV_FOREACH(i, files) {
1682 FILE _cleanup_fclose_ *f;
1684 f = fopen(*i, "re");
1686 if (errno == ENOENT)
1693 char line[LINE_MAX], *l;
1695 if (!fgets(line, sizeof(line), f))
1702 if (strchr(COMMENTS, *l))
1705 if (first_word(l, "enable")) {
1707 l += strspn(l, WHITESPACE);
1709 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1712 } else if (first_word(l, "disable")) {
1714 l += strspn(l, WHITESPACE);
1716 if (fnmatch(l, name, FNM_NOESCAPE) == 0)
1720 log_debug("Couldn't parse line '%s'", l);
1724 /* Default is "enable" */
1728 int unit_file_preset(
1729 UnitFileScope scope,
1731 const char *root_dir,
1734 UnitFileChange **changes,
1735 unsigned *n_changes) {
1737 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1738 InstallContext _cleanup_install_context_done_ plus = {NULL}, minus = {NULL};
1740 char _cleanup_free_ *config_path = NULL;
1741 Set _cleanup_set_free_free_ *remove_symlinks_to = NULL;
1745 assert(scope < _UNIT_FILE_SCOPE_MAX);
1747 r = lookup_paths_init_from_scope(&paths, scope);
1751 r = get_config_path(scope, runtime, root_dir, &config_path);
1755 STRV_FOREACH(i, files) {
1757 if (!unit_name_is_valid(*i, true))
1760 r = unit_file_query_preset(scope, *i);
1765 r = install_info_add_auto(&plus, *i);
1767 r = install_info_add_auto(&minus, *i);
1773 r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to,
1774 config_path, root_dir);
1776 q = remove_marked_symlinks(remove_symlinks_to, config_path,
1777 changes, n_changes, files);
1781 /* Returns number of symlinks that where supposed to be installed. */
1782 q = install_context_apply(&plus, &paths, config_path, root_dir, force,
1783 changes, n_changes);
1790 static void unitfilelist_free(UnitFileList **f) {
1798 int unit_file_get_list(
1799 UnitFileScope scope,
1800 const char *root_dir,
1803 LookupPaths _cleanup_lookup_paths_free_ paths = {NULL};
1805 char _cleanup_free_ *buf = NULL;
1806 DIR _cleanup_closedir_ *d = NULL;
1810 assert(scope < _UNIT_FILE_SCOPE_MAX);
1813 if (root_dir && scope != UNIT_FILE_SYSTEM)
1816 r = lookup_paths_init_from_scope(&paths, scope);
1820 STRV_FOREACH(i, paths.unit_path) {
1821 const char *units_dir;
1827 if (asprintf(&buf, "%s/%s", root_dir, *i) < 0)
1837 d = opendir(units_dir);
1839 if (errno == ENOENT)
1847 union dirent_storage buffer;
1848 UnitFileList __attribute__((cleanup(unitfilelist_free)))
1851 r = readdir_r(d, &buffer.de, &de);
1858 if (ignore_file(de->d_name))
1861 if (!unit_name_is_valid(de->d_name, true))
1864 if (hashmap_get(h, de->d_name))
1867 r = dirent_ensure_type(d, de);
1875 if (de->d_type != DT_LNK && de->d_type != DT_REG)
1878 f = new0(UnitFileList, 1);
1882 f->path = path_make_absolute(de->d_name, units_dir);
1886 r = null_or_empty_path(f->path);
1887 if (r < 0 && r != -ENOENT)
1891 path_startswith(*i, "/run") ?
1892 UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
1896 r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state);
1900 f->state = UNIT_FILE_ENABLED;
1904 r = unit_file_can_install(&paths, root_dir, f->path, true);
1905 if (r == -EINVAL || /* Invalid setting? */
1906 r == -EBADMSG || /* Invalid format? */
1907 r == -ENOENT /* Included file not found? */)
1908 f->state = UNIT_FILE_INVALID;
1912 f->state = UNIT_FILE_DISABLED;
1914 f->state = UNIT_FILE_STATIC;
1917 r = hashmap_put(h, path_get_file_name(f->path), f);
1920 f = NULL; /* prevent cleanup */
1927 static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
1928 [UNIT_FILE_ENABLED] = "enabled",
1929 [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime",
1930 [UNIT_FILE_LINKED] = "linked",
1931 [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime",
1932 [UNIT_FILE_MASKED] = "masked",
1933 [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime",
1934 [UNIT_FILE_STATIC] = "static",
1935 [UNIT_FILE_DISABLED] = "disabled",
1936 [UNIT_FILE_INVALID] = "invalid",
1939 DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
1941 static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
1942 [UNIT_FILE_SYMLINK] = "symlink",
1943 [UNIT_FILE_UNLINK] = "unlink",
1946 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);