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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
31 #include "path-lookup.h"
33 #include "unit-name.h"
35 #include "conf-parser.h"
46 Hashmap
*will_install
;
47 Hashmap
*have_installed
;
50 static int lookup_paths_init_from_scope(LookupPaths
*paths
, UnitFileScope scope
) {
53 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
57 return lookup_paths_init(paths
,
58 scope
== UNIT_FILE_SYSTEM
? MANAGER_SYSTEM
: MANAGER_USER
,
59 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
)
78 p
= strdup("/run/systemd/system");
80 asprintf(&p
, "%s/%s", root_dir
, SYSTEM_CONFIG_UNIT_PATH
);
82 p
= strdup(SYSTEM_CONFIG_UNIT_PATH
);
86 case UNIT_FILE_GLOBAL
:
92 p
= strdup("/run/systemd/user");
94 p
= strdup(USER_CONFIG_UNIT_PATH
);
99 if (root_dir
|| runtime
)
102 r
= user_config_home(&p
);
104 return r
< 0 ? r
: -ENOENT
;
109 assert_not_reached("Bad scope");
119 static int add_file_change(
120 UnitFileChange
**changes
,
122 UnitFileChangeType type
,
124 const char *source
) {
130 assert(type
< _UNIT_FILE_CHANGE_TYPE_MAX
);
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
,
197 unsigned *n_changes
) {
201 struct dirent buffer
, *de
;
203 assert(remove_symlinks_to
);
211 close_nointr_nofail(fd
);
220 k
= readdir_r(d
, &buffer
, &de
);
229 if (ignore_file(de
->d_name
))
232 dirent_ensure_type(d
, de
);
234 if (de
->d_type
== DT_DIR
) {
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
);
250 close_nointr_nofail(nfd
);
255 /* This will close nfd, regardless whether it succeeds or not */
256 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, deleted
, changes
, n_changes
);
262 } else if (de
->d_type
== DT_LNK
) {
267 p
= path_make_absolute(de
->d_name
, path
);
273 q
= readlink_and_canonicalize(p
, &dest
);
286 set_get(remove_symlinks_to
, dest
) ||
287 set_get(remove_symlinks_to
, file_name_from_path(dest
));
291 if (unlink(p
) < 0 && errno
!= ENOENT
) {
296 rmdir_parents(p
, config_path
);
297 path_kill_slashes(p
);
299 add_file_change(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
301 if (!set_get(remove_symlinks_to
, p
)) {
303 q
= mark_symlink_for_removal(&remove_symlinks_to
, p
);
323 static int remove_marked_symlinks(
324 Set
*remove_symlinks_to
,
325 const char *config_path
,
326 UnitFileChange
**changes
,
327 unsigned *n_changes
) {
334 if (set_size(remove_symlinks_to
) <= 0)
337 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
351 /* This takes possession of cfd and closes it */
352 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, &deleted
, changes
, n_changes
);
357 close_nointr_nofail(fd
);
362 static int find_symlinks_fd(
366 const char *config_path
,
367 bool *same_name_link
) {
371 struct dirent buffer
, *de
;
377 assert(same_name_link
);
381 close_nointr_nofail(fd
);
388 k
= readdir_r(d
, &buffer
, &de
);
397 if (ignore_file(de
->d_name
))
400 dirent_ensure_type(d
, de
);
402 if (de
->d_type
== DT_DIR
) {
406 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
416 p
= path_make_absolute(de
->d_name
, path
);
418 close_nointr_nofail(nfd
);
423 /* This will close nfd, regardless whether it succeeds or not */
424 q
= find_symlinks_fd(name
, nfd
, p
, config_path
, same_name_link
);
435 } else if (de
->d_type
== DT_LNK
) {
437 bool found_path
, found_dest
, b
= false;
440 /* Acquire symlink name */
441 p
= path_make_absolute(de
->d_name
, path
);
447 /* Acquire symlink destination */
448 q
= readlink_and_canonicalize(p
, &dest
);
460 /* Check if the symlink itself matches what we
462 if (path_is_absolute(name
))
463 found_path
= path_equal(p
, name
);
465 found_path
= streq(de
->d_name
, name
);
467 /* Check if what the symlink points to
468 * matches what we are looking for */
469 if (path_is_absolute(name
))
470 found_dest
= path_equal(dest
, name
);
472 found_dest
= streq(file_name_from_path(dest
), name
);
476 if (found_path
&& found_dest
) {
479 /* Filter out same name links in the main
481 t
= path_make_absolute(name
, config_path
);
489 b
= path_equal(t
, p
);
496 *same_name_link
= true;
497 else if (found_path
|| found_dest
) {
509 static int find_symlinks(
511 const char *config_path
,
512 bool *same_name_link
) {
518 assert(same_name_link
);
520 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
524 /* This takes possession of fd and closes it */
525 return find_symlinks_fd(name
, fd
, config_path
, config_path
, same_name_link
);
528 static int find_symlinks_in_scope(
530 const char *root_dir
,
532 UnitFileState
*state
) {
536 bool same_name_link_runtime
= false, same_name_link
= false;
539 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
542 if (scope
== UNIT_FILE_SYSTEM
|| scope
== UNIT_FILE_GLOBAL
) {
544 /* First look in runtime config path */
545 r
= get_config_path(scope
, true, root_dir
, &path
);
549 r
= find_symlinks(name
, path
, &same_name_link_runtime
);
555 *state
= UNIT_FILE_ENABLED_RUNTIME
;
560 /* Then look in the normal config path */
561 r
= get_config_path(scope
, false, root_dir
, &path
);
565 r
= find_symlinks(name
, path
, &same_name_link
);
571 *state
= UNIT_FILE_ENABLED
;
575 /* Hmm, we didn't find it, but maybe we found the same name
577 if (same_name_link_runtime
) {
578 *state
= UNIT_FILE_LINKED_RUNTIME
;
580 } else if (same_name_link
) {
581 *state
= UNIT_FILE_LINKED
;
591 const char *root_dir
,
594 UnitFileChange
**changes
,
595 unsigned *n_changes
) {
601 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
603 r
= get_config_path(scope
, runtime
, root_dir
, &prefix
);
607 STRV_FOREACH(i
, files
) {
610 if (!unit_name_is_valid_no_type(*i
, true)) {
616 path
= path_make_absolute(*i
, prefix
);
622 if (symlink("/dev/null", path
) >= 0) {
623 add_file_change(changes
, n_changes
, UNIT_FILE_SYMLINK
, path
, "/dev/null");
629 if (errno
== EEXIST
) {
631 if (null_or_empty_path(path
) > 0) {
639 if (symlink("/dev/null", path
) >= 0) {
641 add_file_change(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
642 add_file_change(changes
, n_changes
, UNIT_FILE_SYMLINK
, path
, "/dev/null");
664 int unit_file_unmask(
667 const char *root_dir
,
669 UnitFileChange
**changes
,
670 unsigned *n_changes
) {
672 char **i
, *config_path
= NULL
;
674 Set
*remove_symlinks_to
= NULL
;
677 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
679 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
683 STRV_FOREACH(i
, files
) {
686 if (!unit_name_is_valid_no_type(*i
, true)) {
692 path
= path_make_absolute(*i
, config_path
);
698 q
= null_or_empty_path(path
);
700 if (unlink(path
) >= 0) {
701 mark_symlink_for_removal(&remove_symlinks_to
, path
);
702 add_file_change(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
711 if (q
!= -ENOENT
&& r
== 0)
719 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
723 set_free_free(remove_symlinks_to
);
732 const char *root_dir
,
735 UnitFileChange
**changes
,
736 unsigned *n_changes
) {
739 char **i
, *config_path
= NULL
;
743 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
747 r
= lookup_paths_init_from_scope(&paths
, scope
);
751 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
755 STRV_FOREACH(i
, files
) {
759 fn
= file_name_from_path(*i
);
761 if (!path_is_absolute(*i
) ||
762 !unit_name_is_valid_no_type(fn
, true)) {
768 if (lstat(*i
, &st
) < 0) {
774 if (!S_ISREG(st
.st_mode
)) {
779 q
= in_search_path(*i
, paths
.unit_path
);
788 path
= path_make_absolute(fn
, config_path
);
794 if (symlink(*i
, path
) >= 0) {
795 add_file_change(changes
, n_changes
, UNIT_FILE_SYMLINK
, path
, *i
);
801 if (errno
== EEXIST
) {
804 q
= readlink_and_make_absolute(path
, &dest
);
806 if (q
< 0 && errno
!= ENOENT
) {
815 if (q
>= 0 && path_equal(dest
, *i
)) {
826 if (symlink(*i
, path
) >= 0) {
828 add_file_change(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
829 add_file_change(changes
, n_changes
, UNIT_FILE_SYMLINK
, path
, *i
);
847 lookup_paths_free(&paths
);
853 void unit_file_list_free(Hashmap
*h
) {
856 while ((i
= hashmap_steal_first(h
))) {
864 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
867 assert(changes
|| n_changes
== 0);
872 for (i
= 0; i
< n_changes
; i
++) {
873 free(changes
[i
].path
);
874 free(changes
[i
].source
);
880 static void install_info_free(InstallInfo
*i
) {
885 strv_free(i
->aliases
);
886 strv_free(i
->wanted_by
);
890 static void install_info_hashmap_free(Hashmap
*m
) {
896 while ((i
= hashmap_steal_first(m
)))
897 install_info_free(i
);
902 static void install_context_done(InstallContext
*c
) {
905 install_info_hashmap_free(c
->will_install
);
906 install_info_hashmap_free(c
->have_installed
);
908 c
->will_install
= c
->have_installed
= NULL
;
911 static int install_info_add(
915 InstallInfo
*i
= NULL
;
919 assert(name
|| path
);
922 name
= file_name_from_path(path
);
924 if (!unit_name_is_valid_no_type(name
, true))
927 if (hashmap_get(c
->have_installed
, name
) ||
928 hashmap_get(c
->will_install
, name
))
931 r
= hashmap_ensure_allocated(&c
->will_install
, string_hash_func
, string_compare_func
);
935 i
= new0(InstallInfo
, 1);
939 i
->name
= strdup(name
);
946 i
->path
= strdup(path
);
953 r
= hashmap_put(c
->will_install
, i
->name
, i
);
961 install_info_free(i
);
966 static int install_info_add_auto(
968 const char *name_or_path
) {
971 assert(name_or_path
);
973 if (path_is_absolute(name_or_path
))
974 return install_info_add(c
, NULL
, name_or_path
);
976 return install_info_add(c
, name_or_path
, NULL
);
979 static int config_parse_also(
980 const char *filename
,
992 InstallContext
*c
= data
;
998 FOREACH_WORD_QUOTED(w
, l
, rvalue
, state
) {
1006 r
= install_info_add(c
, n
, NULL
);
1018 static int unit_file_load(
1022 bool allow_symlink
) {
1024 const ConfigItem items
[] = {
1025 { "Alias", config_parse_strv
, 0, &info
->aliases
, "Install" },
1026 { "WantedBy", config_parse_strv
, 0, &info
->wanted_by
, "Install" },
1027 { "Also", config_parse_also
, 0, c
, "Install" },
1028 { NULL
, NULL
, 0, NULL
, NULL
}
1039 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|(allow_symlink
? 0 : O_NOFOLLOW
));
1043 f
= fdopen(fd
, "re");
1045 close_nointr_nofail(fd
);
1049 r
= config_parse(path
, f
, NULL
, items
, true, info
);
1054 return strv_length(info
->aliases
) + strv_length(info
->wanted_by
);
1057 static int unit_file_search(
1061 const char *root_dir
,
1062 bool allow_symlink
) {
1072 return unit_file_load(c
, info
, info
->path
, allow_symlink
);
1076 STRV_FOREACH(p
, paths
->unit_path
) {
1079 if (isempty(root_dir
))
1080 asprintf(&path
, "%s/%s", *p
, info
->name
);
1082 asprintf(&path
, "%s/%s/%s", root_dir
, *p
, info
->name
);
1087 r
= unit_file_load(c
, info
, path
, allow_symlink
);
1094 if (r
!= -ENOENT
&& r
!= -ELOOP
)
1101 static int unit_file_can_install(
1103 const char *root_dir
,
1105 bool allow_symlink
) {
1116 r
= install_info_add_auto(&c
, name
);
1120 assert_se(i
= hashmap_first(c
.will_install
));
1122 r
= unit_file_search(&c
, i
, paths
, root_dir
, allow_symlink
);
1125 r
= strv_length(i
->aliases
) + strv_length(i
->wanted_by
);
1127 install_context_done(&c
);
1132 static int create_symlink(
1133 const char *old_path
,
1134 const char *new_path
,
1136 UnitFileChange
**changes
,
1137 unsigned *n_changes
) {
1145 mkdir_parents(new_path
, 0755);
1147 if (symlink(old_path
, new_path
) >= 0) {
1148 add_file_change(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
1152 if (errno
!= EEXIST
)
1155 r
= readlink_and_make_absolute(new_path
, &dest
);
1159 if (path_equal(dest
, old_path
)) {
1171 if (symlink(old_path
, new_path
) >= 0) {
1172 add_file_change(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
1173 add_file_change(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
1180 static int install_info_symlink_alias(
1182 const char *config_path
,
1184 UnitFileChange
**changes
,
1185 unsigned *n_changes
) {
1191 assert(config_path
);
1193 STRV_FOREACH(s
, i
->aliases
) {
1196 alias_path
= path_make_absolute(*s
, config_path
);
1201 q
= create_symlink(i
->path
, alias_path
, force
, changes
, n_changes
);
1211 static int install_info_symlink_wants(
1213 const char *config_path
,
1215 UnitFileChange
**changes
,
1216 unsigned *n_changes
) {
1222 assert(config_path
);
1224 STRV_FOREACH(s
, i
->wanted_by
) {
1227 if (!unit_name_is_valid_no_type(*s
, true)) {
1232 if (asprintf(&path
, "%s/%s.wants/%s", config_path
, *s
, i
->name
) < 0)
1235 q
= create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1245 static int install_info_symlink_link(
1248 const char *config_path
,
1250 UnitFileChange
**changes
,
1251 unsigned *n_changes
) {
1258 assert(config_path
);
1261 r
= in_search_path(i
->path
, paths
->unit_path
);
1265 if (asprintf(&path
, "%s/%s", config_path
, i
->name
) < 0)
1268 r
= create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1274 static int install_info_apply(
1277 const char *config_path
,
1279 UnitFileChange
**changes
,
1280 unsigned *n_changes
) {
1286 assert(config_path
);
1288 r
= install_info_symlink_alias(i
, config_path
, force
, changes
, n_changes
);
1290 q
= install_info_symlink_wants(i
, config_path
, force
, changes
, n_changes
);
1294 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1301 static int install_context_apply(
1304 const char *config_path
,
1305 const char *root_dir
,
1307 UnitFileChange
**changes
,
1308 unsigned *n_changes
) {
1315 assert(config_path
);
1317 while ((i
= hashmap_first(c
->will_install
))) {
1319 q
= hashmap_ensure_allocated(&c
->have_installed
, string_hash_func
, string_compare_func
);
1323 assert_se(hashmap_move_one(c
->have_installed
, c
->will_install
, i
->name
) == 0);
1325 q
= unit_file_search(c
, i
, paths
, root_dir
, false);
1334 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1335 if (r
>= 0 && q
< 0)
1342 static int install_context_mark_for_removal(
1345 Set
**remove_symlinks_to
,
1346 const char *config_path
,
1347 const char *root_dir
) {
1354 assert(config_path
);
1356 /* Marks all items for removal */
1358 while ((i
= hashmap_first(c
->will_install
))) {
1360 q
= hashmap_ensure_allocated(&c
->have_installed
, string_hash_func
, string_compare_func
);
1364 assert_se(hashmap_move_one(c
->have_installed
, c
->will_install
, i
->name
) == 0);
1366 q
= unit_file_search(c
, i
, paths
, root_dir
, false);
1375 q
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1376 if (r
>= 0 && q
< 0)
1383 int unit_file_enable(
1384 UnitFileScope scope
,
1386 const char *root_dir
,
1389 UnitFileChange
**changes
,
1390 unsigned *n_changes
) {
1394 char **i
, *config_path
= NULL
;
1398 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1403 r
= lookup_paths_init_from_scope(&paths
, scope
);
1407 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1411 STRV_FOREACH(i
, files
) {
1412 r
= install_info_add_auto(&c
, *i
);
1417 r
= install_context_apply(&c
, &paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1420 install_context_done(&c
);
1421 lookup_paths_free(&paths
);
1427 int unit_file_disable(
1428 UnitFileScope scope
,
1430 const char *root_dir
,
1432 UnitFileChange
**changes
,
1433 unsigned *n_changes
) {
1437 char **i
, *config_path
= NULL
;
1438 Set
*remove_symlinks_to
= NULL
;
1442 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1447 r
= lookup_paths_init_from_scope(&paths
, scope
);
1451 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1455 STRV_FOREACH(i
, files
) {
1456 r
= install_info_add_auto(&c
, *i
);
1461 r
= install_context_mark_for_removal(&c
, &paths
, &remove_symlinks_to
, config_path
, root_dir
);
1463 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1468 install_context_done(&c
);
1469 lookup_paths_free(&paths
);
1470 set_free_free(remove_symlinks_to
);
1476 int unit_file_reenable(
1477 UnitFileScope scope
,
1479 const char *root_dir
,
1482 UnitFileChange
**changes
,
1483 unsigned *n_changes
) {
1487 char **i
, *config_path
= NULL
;
1488 Set
*remove_symlinks_to
= NULL
;
1492 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1497 r
= lookup_paths_init_from_scope(&paths
, scope
);
1501 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1505 STRV_FOREACH(i
, files
) {
1506 r
= mark_symlink_for_removal(&remove_symlinks_to
, *i
);
1510 r
= install_info_add_auto(&c
, *i
);
1515 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1517 q
= install_context_apply(&c
, &paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1522 lookup_paths_free(&paths
);
1523 install_context_done(&c
);
1524 set_free_free(remove_symlinks_to
);
1530 UnitFileState
unit_file_get_state(
1531 UnitFileScope scope
,
1532 const char *root_dir
,
1536 UnitFileState state
= _UNIT_FILE_STATE_INVALID
;
1537 char **i
, *path
= NULL
;
1541 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1546 if (root_dir
&& scope
!= UNIT_FILE_SYSTEM
)
1549 if (!unit_name_is_valid_no_type(name
, true))
1552 r
= lookup_paths_init_from_scope(&paths
, scope
);
1556 STRV_FOREACH(i
, paths
.unit_path
) {
1563 asprintf(&path
, "%s/%s/%s", root_dir
, *i
, name
);
1565 asprintf(&path
, "%s/%s", *i
, name
);
1572 if (lstat(path
, &st
) < 0) {
1573 if (errno
== ENOENT
)
1580 if (!S_ISREG(st
.st_mode
) && !S_ISLNK(st
.st_mode
)) {
1585 r
= null_or_empty_path(path
);
1586 if (r
< 0 && r
!= -ENOENT
)
1589 state
= path_startswith(*i
, "/run") ?
1590 UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
1595 r
= find_symlinks_in_scope(scope
, root_dir
, name
, &state
);
1603 r
= unit_file_can_install(&paths
, root_dir
, path
, true);
1604 if (r
< 0 && errno
!= -ENOENT
)
1607 state
= UNIT_FILE_DISABLED
;
1610 } else if (r
== 0) {
1611 state
= UNIT_FILE_STATIC
;
1618 lookup_paths_free(&paths
);
1621 return r
< 0 ? r
: state
;
1624 int unit_file_query_preset(UnitFileScope scope
, const char *name
) {
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 "/lib/systemd/system.preset",
1639 else if (scope
== UNIT_FILE_GLOBAL
)
1640 r
= conf_files_list(&files
, ".preset",
1641 "/etc/systemd/user.preset",
1642 "/usr/local/lib/systemd/user.preset",
1643 "/usr/lib/systemd/user.preset",
1651 STRV_FOREACH(i
, files
) {
1654 f
= fopen(*i
, "re");
1656 if (errno
== ENOENT
)
1664 char line
[LINE_MAX
], *l
;
1666 if (!fgets(line
, sizeof(line
), f
))
1673 if (strchr(COMMENTS
, *l
))
1676 if (first_word(l
, "enable")) {
1678 l
+= strspn(l
, WHITESPACE
);
1680 if (fnmatch(l
, name
, FNM_NOESCAPE
) == 0) {
1685 } else if (first_word(l
, "disable")) {
1687 l
+= strspn(l
, WHITESPACE
);
1689 if (fnmatch(l
, name
, FNM_NOESCAPE
) == 0) {
1695 log_debug("Couldn't parse line '%s'", l
);
1701 /* Default is "enable" */
1710 int unit_file_preset(
1711 UnitFileScope scope
,
1713 const char *root_dir
,
1716 UnitFileChange
**changes
,
1717 unsigned *n_changes
) {
1720 InstallContext plus
, minus
;
1721 char **i
, *config_path
= NULL
;
1722 Set
*remove_symlinks_to
= NULL
;
1726 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1732 r
= lookup_paths_init_from_scope(&paths
, scope
);
1736 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1740 STRV_FOREACH(i
, files
) {
1742 if (!unit_name_is_valid_no_type(*i
, true)) {
1747 r
= unit_file_query_preset(scope
, *i
);
1752 r
= install_info_add_auto(&plus
, *i
);
1754 r
= install_info_add_auto(&minus
, *i
);
1760 r
= install_context_mark_for_removal(&minus
, &paths
, &remove_symlinks_to
, config_path
, root_dir
);
1762 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1766 q
= install_context_apply(&plus
, &paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1771 lookup_paths_free(&paths
);
1772 install_context_done(&plus
);
1773 install_context_done(&minus
);
1774 set_free_free(remove_symlinks_to
);
1780 int unit_file_get_list(
1781 UnitFileScope scope
,
1782 const char *root_dir
,
1786 char **i
, *buf
= NULL
;
1791 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1796 if (root_dir
&& scope
!= UNIT_FILE_SYSTEM
)
1799 r
= lookup_paths_init_from_scope(&paths
, scope
);
1803 STRV_FOREACH(i
, paths
.unit_path
) {
1804 struct dirent buffer
, *de
;
1805 const char *units_dir
;
1811 if (asprintf(&buf
, "%s/%s", root_dir
, *i
) < 0) {
1822 d
= opendir(units_dir
);
1824 if (errno
== ENOENT
)
1834 r
= readdir_r(d
, &buffer
, &de
);
1843 if (ignore_file(de
->d_name
))
1846 if (!unit_name_is_valid_no_type(de
->d_name
, true))
1849 if (hashmap_get(h
, de
->d_name
))
1852 r
= dirent_ensure_type(d
, de
);
1854 if (errno
== ENOENT
)
1860 if (de
->d_type
!= DT_LNK
&& de
->d_type
!= DT_REG
)
1863 f
= new0(UnitFileList
, 1);
1869 f
->path
= path_make_absolute(de
->d_name
, units_dir
);
1876 r
= null_or_empty_path(f
->path
);
1877 if (r
< 0 && r
!= -ENOENT
) {
1883 path_startswith(*i
, "/run") ?
1884 UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
1888 r
= find_symlinks_in_scope(scope
, root_dir
, de
->d_name
, &f
->state
);
1896 r
= unit_file_can_install(&paths
, root_dir
, f
->path
, true);
1902 f
->state
= UNIT_FILE_DISABLED
;
1904 } else if (r
== 0) {
1905 f
->state
= UNIT_FILE_STATIC
;
1914 r
= hashmap_put(h
, file_name_from_path(f
->path
), f
);
1924 lookup_paths_free(&paths
);
1933 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
1934 [UNIT_FILE_ENABLED
] = "enabled",
1935 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtie",
1936 [UNIT_FILE_LINKED
] = "linked",
1937 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
1938 [UNIT_FILE_MASKED
] = "masked",
1939 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
1940 [UNIT_FILE_STATIC
] = "static",
1941 [UNIT_FILE_DISABLED
] = "disabled"
1944 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
1946 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
1947 [UNIT_FILE_SYMLINK
] = "symlink",
1948 [UNIT_FILE_UNLINK
] = "unlink",
1951 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);