2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty <of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
32 #include "alloc-util.h"
33 #include "conf-files.h"
34 #include "conf-parser.h"
35 #include "dirent-util.h"
36 #include "extract-word.h"
41 #include "install-printf.h"
46 #include "path-lookup.h"
47 #include "path-util.h"
50 #include "stat-util.h"
51 #include "string-table.h"
52 #include "string-util.h"
54 #include "unit-name.h"
56 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
58 typedef enum SearchFlags
{
60 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 2,
64 OrderedHashmap
*will_process
;
65 OrderedHashmap
*have_processed
;
68 static int in_search_path(const LookupPaths
*p
, const char *path
) {
69 _cleanup_free_
char *parent
= NULL
;
74 parent
= dirname_malloc(path
);
78 STRV_FOREACH(i
, p
->search_path
)
79 if (path_equal(parent
, *i
))
85 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
89 e
= path_startswith(path
, p
->root_dir
);
93 /* Make sure the returned path starts with a slash */
95 if (e
== path
|| e
[-1] != '/')
107 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
108 _cleanup_free_
char *parent
= NULL
;
113 parent
= dirname_malloc(path
);
117 return path_equal(p
->generator
, parent
) ||
118 path_equal(p
->generator_early
, parent
) ||
119 path_equal(p
->generator_late
, parent
);
122 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
123 _cleanup_free_
char *parent
= NULL
;
128 parent
= dirname_malloc(path
);
132 return path_equal(p
->transient
, parent
);
135 static int path_is_config(const LookupPaths
*p
, const char *path
) {
136 _cleanup_free_
char *parent
= NULL
;
142 /* Checks whether the specified path is intended for configuration or is outside of it. We check both the
143 * top-level directory and the one actually configured. The latter is particularly relevant for cases where we
144 * operate on a root directory. */
146 rpath
= skip_root(p
, path
);
147 if (rpath
&& (path_startswith(rpath
, "/etc") || path_startswith(rpath
, "/run")))
150 parent
= dirname_malloc(path
);
154 return path_equal(parent
, p
->persistent_config
) ||
155 path_equal(parent
, p
->runtime_config
);
158 static int path_is_runtime(const LookupPaths
*p
, const char *path
) {
159 _cleanup_free_
char *parent
= NULL
;
165 rpath
= skip_root(p
, path
);
166 if (rpath
&& path_startswith(rpath
, "/run"))
169 parent
= dirname_malloc(path
);
173 return path_equal(parent
, p
->runtime_config
);
176 int unit_file_changes_add(
177 UnitFileChange
**changes
,
179 UnitFileChangeType type
,
181 const char *source
) {
187 assert(!changes
== !n_changes
);
192 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
200 c
[i
].path
= strdup(path
);
204 path_kill_slashes(c
[i
].path
);
207 c
[i
].source
= strdup(source
);
213 path_kill_slashes(c
[i
].path
);
221 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
224 assert(changes
|| n_changes
== 0);
229 for (i
= 0; i
< n_changes
; i
++) {
230 free(changes
[i
].path
);
231 free(changes
[i
].source
);
237 static int create_symlink(
238 const char *old_path
,
239 const char *new_path
,
241 UnitFileChange
**changes
,
242 unsigned *n_changes
) {
244 _cleanup_free_
char *dest
= NULL
;
250 /* Actually create a symlink, and remember that we did. Is
251 * smart enough to check if there's already a valid symlink in
254 mkdir_parents_label(new_path
, 0755);
256 if (symlink(old_path
, new_path
) >= 0) {
257 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
264 r
= readlink_malloc(new_path
, &dest
);
268 if (path_equal(dest
, old_path
))
274 r
= symlink_atomic(old_path
, new_path
);
278 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
279 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
284 static int mark_symlink_for_removal(
285 Set
**remove_symlinks_to
,
293 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
301 path_kill_slashes(n
);
303 r
= set_consume(*remove_symlinks_to
, n
);
312 static int remove_marked_symlinks_fd(
313 Set
*remove_symlinks_to
,
316 const char *config_path
,
317 const LookupPaths
*lp
,
319 UnitFileChange
**changes
,
320 unsigned *n_changes
) {
322 _cleanup_closedir_
DIR *d
= NULL
;
326 assert(remove_symlinks_to
);
341 FOREACH_DIRENT(de
, d
, return -errno
) {
343 dirent_ensure_type(d
, de
);
345 if (de
->d_type
== DT_DIR
) {
346 _cleanup_free_
char *p
= NULL
;
349 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
359 p
= path_make_absolute(de
->d_name
, path
);
365 /* This will close nfd, regardless whether it succeeds or not */
366 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, restart
, changes
, n_changes
);
370 } else if (de
->d_type
== DT_LNK
) {
371 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
376 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
379 p
= path_make_absolute(de
->d_name
, path
);
383 q
= readlink_malloc(p
, &dest
);
392 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
393 * the same name as a file that is marked. */
396 set_contains(remove_symlinks_to
, dest
) ||
397 set_contains(remove_symlinks_to
, basename(dest
)) ||
398 set_contains(remove_symlinks_to
, de
->d_name
);
403 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
409 path_kill_slashes(p
);
410 (void) rmdir_parents(p
, config_path
);
412 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
414 /* Now, remember the full path (but with the root prefix removed) of the symlink we just
415 * removed, and remove any symlinks to it, too */
417 rp
= skip_root(lp
, p
);
418 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
429 static int remove_marked_symlinks(
430 Set
*remove_symlinks_to
,
431 const char *config_path
,
432 const LookupPaths
*lp
,
433 UnitFileChange
**changes
,
434 unsigned *n_changes
) {
436 _cleanup_close_
int fd
= -1;
443 if (set_size(remove_symlinks_to
) <= 0)
446 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
454 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
458 /* This takes possession of cfd and closes it */
459 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, &restart
, changes
, n_changes
);
467 static int find_symlinks_fd(
468 const char *root_dir
,
472 const char *config_path
,
473 const LookupPaths
*lp
,
474 bool *same_name_link
) {
476 _cleanup_closedir_
DIR *d
= NULL
;
485 assert(same_name_link
);
493 FOREACH_DIRENT(de
, d
, return -errno
) {
495 dirent_ensure_type(d
, de
);
497 if (de
->d_type
== DT_DIR
) {
498 _cleanup_free_
char *p
= NULL
;
501 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
511 p
= path_make_absolute(de
->d_name
, path
);
517 /* This will close nfd, regardless whether it succeeds or not */
518 q
= find_symlinks_fd(root_dir
, name
, nfd
, p
, config_path
, lp
, same_name_link
);
524 } else if (de
->d_type
== DT_LNK
) {
525 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
526 bool found_path
, found_dest
, b
= false;
529 /* Acquire symlink name */
530 p
= path_make_absolute(de
->d_name
, path
);
534 /* Acquire symlink destination */
535 q
= readlink_malloc(p
, &dest
);
545 if (!path_is_absolute(dest
)) {
548 x
= prefix_root(root_dir
, dest
);
556 /* Check if the symlink itself matches what we
558 if (path_is_absolute(name
))
559 found_path
= path_equal(p
, name
);
561 found_path
= streq(de
->d_name
, name
);
563 /* Check if what the symlink points to
564 * matches what we are looking for */
565 if (path_is_absolute(name
))
566 found_dest
= path_equal(dest
, name
);
568 found_dest
= streq(basename(dest
), name
);
570 if (found_path
&& found_dest
) {
571 _cleanup_free_
char *t
= NULL
;
573 /* Filter out same name links in the main
575 t
= path_make_absolute(name
, config_path
);
579 b
= path_equal(t
, p
);
583 *same_name_link
= true;
584 else if (found_path
|| found_dest
)
592 static int find_symlinks(
593 const char *root_dir
,
595 const char *config_path
,
596 const LookupPaths
*lp
,
597 bool *same_name_link
) {
603 assert(same_name_link
);
605 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
612 /* This takes possession of fd and closes it */
613 return find_symlinks_fd(root_dir
, name
, fd
, config_path
, config_path
, lp
, same_name_link
);
616 static int find_symlinks_in_scope(
618 const LookupPaths
*paths
,
620 UnitFileState
*state
) {
622 bool same_name_link_runtime
= false, same_name_link
= false;
626 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
630 /* First look in the persistent config path */
631 r
= find_symlinks(paths
->root_dir
, name
, paths
->persistent_config
, paths
, &same_name_link
);
635 *state
= UNIT_FILE_ENABLED
;
639 /* Then look in runtime config path */
640 r
= find_symlinks(paths
->root_dir
, name
, paths
->runtime_config
, paths
, &same_name_link_runtime
);
644 *state
= UNIT_FILE_ENABLED_RUNTIME
;
648 /* Hmm, we didn't find it, but maybe we found the same name
650 if (same_name_link
) {
651 *state
= UNIT_FILE_LINKED
;
654 if (same_name_link_runtime
) {
655 *state
= UNIT_FILE_LINKED_RUNTIME
;
662 static void install_info_free(UnitFileInstallInfo
*i
) {
669 strv_free(i
->aliases
);
670 strv_free(i
->wanted_by
);
671 strv_free(i
->required_by
);
673 free(i
->default_instance
);
674 free(i
->symlink_target
);
678 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
679 UnitFileInstallInfo
*i
;
684 while ((i
= ordered_hashmap_steal_first(m
)))
685 install_info_free(i
);
687 return ordered_hashmap_free(m
);
690 static void install_context_done(InstallContext
*c
) {
693 c
->will_process
= install_info_hashmap_free(c
->will_process
);
694 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
697 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
698 UnitFileInstallInfo
*i
;
700 i
= ordered_hashmap_get(c
->have_processed
, name
);
704 return ordered_hashmap_get(c
->will_process
, name
);
707 static int install_info_add(
711 UnitFileInstallInfo
**ret
) {
713 UnitFileInstallInfo
*i
= NULL
;
717 assert(name
|| path
);
720 name
= basename(path
);
722 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
725 i
= install_info_find(c
, name
);
732 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
736 i
= new0(UnitFileInstallInfo
, 1);
739 i
->type
= _UNIT_FILE_TYPE_INVALID
;
741 i
->name
= strdup(name
);
748 i
->path
= strdup(path
);
755 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
765 install_info_free(i
);
769 static int config_parse_also(
771 const char *filename
,
774 unsigned section_line
,
781 UnitFileInstallInfo
*i
= userdata
;
782 InstallContext
*c
= data
;
790 _cleanup_free_
char *word
= NULL
;
792 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
798 r
= install_info_add(c
, word
, NULL
, NULL
);
802 r
= strv_push(&i
->also
, word
);
812 static int config_parse_default_instance(
814 const char *filename
,
817 unsigned section_line
,
824 UnitFileInstallInfo
*i
= data
;
832 r
= install_full_printf(i
, rvalue
, &printed
);
836 if (!unit_instance_is_valid(printed
)) {
841 free(i
->default_instance
);
842 i
->default_instance
= printed
;
847 static int unit_file_load(
849 UnitFileInstallInfo
*info
,
853 const ConfigTableItem items
[] = {
854 { "Install", "Alias", config_parse_strv
, 0, &info
->aliases
},
855 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
856 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
857 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
858 { "Install", "Also", config_parse_also
, 0, c
},
862 _cleanup_fclose_
FILE *f
= NULL
;
863 _cleanup_close_
int fd
= -1;
871 if (!(flags
& SEARCH_LOAD
)) {
872 r
= lstat(path
, &st
);
876 if (null_or_empty(&st
))
877 info
->type
= UNIT_FILE_TYPE_MASKED
;
878 else if (S_ISREG(st
.st_mode
))
879 info
->type
= UNIT_FILE_TYPE_REGULAR
;
880 else if (S_ISLNK(st
.st_mode
))
882 else if (S_ISDIR(st
.st_mode
))
890 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
893 if (fstat(fd
, &st
) < 0)
895 if (null_or_empty(&st
)) {
896 info
->type
= UNIT_FILE_TYPE_MASKED
;
899 if (S_ISDIR(st
.st_mode
))
901 if (!S_ISREG(st
.st_mode
))
904 f
= fdopen(fd
, "re");
909 r
= config_parse(NULL
, path
, f
,
911 config_item_table_lookup
, items
,
912 true, true, false, info
);
916 info
->type
= UNIT_FILE_TYPE_REGULAR
;
919 (int) strv_length(info
->aliases
) +
920 (int) strv_length(info
->wanted_by
) +
921 (int) strv_length(info
->required_by
);
924 static int unit_file_load_or_readlink(
926 UnitFileInstallInfo
*info
,
928 const char *root_dir
,
931 _cleanup_free_
char *target
= NULL
;
934 r
= unit_file_load(c
, info
, path
, flags
);
938 /* This is a symlink, let's read it. */
940 r
= readlink_malloc(path
, &target
);
944 if (path_equal(target
, "/dev/null"))
945 info
->type
= UNIT_FILE_TYPE_MASKED
;
950 bn
= basename(target
);
952 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
954 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
957 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
959 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
962 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
964 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
969 /* Enforce that the symlink destination does not
970 * change the unit file type. */
972 a
= unit_name_to_type(info
->name
);
973 b
= unit_name_to_type(bn
);
974 if (a
< 0 || b
< 0 || a
!= b
)
977 if (path_is_absolute(target
))
978 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
979 info
->symlink_target
= prefix_root(root_dir
, target
);
981 /* This is a relative path, take it relative to the dir the symlink is located in. */
982 info
->symlink_target
= file_in_same_dir(path
, target
);
983 if (!info
->symlink_target
)
986 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
992 static int unit_file_search(
994 UnitFileInstallInfo
*info
,
995 const LookupPaths
*paths
,
1005 /* Was this unit already loaded? */
1006 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1010 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1014 STRV_FOREACH(p
, paths
->search_path
) {
1015 _cleanup_free_
char *path
= NULL
;
1017 path
= strjoin(*p
, "/", info
->name
, NULL
);
1021 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1032 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1034 /* Unit file doesn't exist, however instance
1035 * enablement was requested. We will check if it is
1036 * possible to load template unit file. */
1038 _cleanup_free_
char *template = NULL
;
1040 r
= unit_name_template(info
->name
, &template);
1044 STRV_FOREACH(p
, paths
->search_path
) {
1045 _cleanup_free_
char *path
= NULL
;
1047 path
= strjoin(*p
, "/", template, NULL
);
1051 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1066 static int install_info_follow(
1068 UnitFileInstallInfo
*i
,
1069 const char *root_dir
,
1070 SearchFlags flags
) {
1075 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1077 if (!i
->symlink_target
)
1080 /* If the basename doesn't match, the caller should add a
1081 * complete new entry for this. */
1083 if (!streq(basename(i
->symlink_target
), i
->name
))
1087 i
->path
= i
->symlink_target
;
1088 i
->symlink_target
= NULL
;
1089 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1091 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1094 static int install_info_traverse(
1095 UnitFileScope scope
,
1097 const LookupPaths
*paths
,
1098 UnitFileInstallInfo
*start
,
1100 UnitFileInstallInfo
**ret
) {
1102 UnitFileInstallInfo
*i
;
1110 r
= unit_file_search(c
, start
, paths
, flags
);
1115 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1116 /* Follow the symlink */
1118 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1121 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1122 r
= path_is_config(paths
, i
->path
);
1129 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
);
1131 _cleanup_free_
char *buffer
= NULL
;
1137 /* Target has a different name, create a new
1138 * install info object for that, and continue
1141 bn
= basename(i
->symlink_target
);
1143 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1144 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1146 _cleanup_free_
char *instance
= NULL
;
1148 r
= unit_name_to_instance(i
->name
, &instance
);
1152 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1159 r
= install_info_add(c
, bn
, NULL
, &i
);
1163 r
= unit_file_search(c
, i
, paths
, flags
);
1168 /* Try again, with the new target we found. */
1177 static int install_info_add_auto(
1179 const LookupPaths
*paths
,
1180 const char *name_or_path
,
1181 UnitFileInstallInfo
**ret
) {
1184 assert(name_or_path
);
1186 if (path_is_absolute(name_or_path
)) {
1189 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1191 return install_info_add(c
, NULL
, pp
, ret
);
1193 return install_info_add(c
, name_or_path
, NULL
, ret
);
1196 static int install_info_discover(
1197 UnitFileScope scope
,
1199 const LookupPaths
*paths
,
1202 UnitFileInstallInfo
**ret
) {
1204 UnitFileInstallInfo
*i
;
1211 r
= install_info_add_auto(c
, paths
, name
, &i
);
1215 return install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1218 static int install_info_symlink_alias(
1219 UnitFileInstallInfo
*i
,
1220 const LookupPaths
*paths
,
1221 const char *config_path
,
1223 UnitFileChange
**changes
,
1224 unsigned *n_changes
) {
1231 assert(config_path
);
1233 STRV_FOREACH(s
, i
->aliases
) {
1234 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1237 q
= install_full_printf(i
, *s
, &dst
);
1241 alias_path
= path_make_absolute(dst
, config_path
);
1245 rp
= skip_root(paths
, i
->path
);
1247 q
= create_symlink(rp
?: i
->path
, alias_path
, force
, changes
, n_changes
);
1255 static int install_info_symlink_wants(
1256 UnitFileInstallInfo
*i
,
1257 const LookupPaths
*paths
,
1258 const char *config_path
,
1262 UnitFileChange
**changes
,
1263 unsigned *n_changes
) {
1265 _cleanup_free_
char *buf
= NULL
;
1272 assert(config_path
);
1274 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1276 /* Don't install any symlink if there's no default
1277 * instance configured */
1279 if (!i
->default_instance
)
1282 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1290 STRV_FOREACH(s
, list
) {
1291 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1294 q
= install_full_printf(i
, *s
, &dst
);
1298 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1303 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1307 rp
= skip_root(paths
, i
->path
);
1309 q
= create_symlink(rp
?: i
->path
, path
, force
, changes
, n_changes
);
1317 static int install_info_symlink_link(
1318 UnitFileInstallInfo
*i
,
1319 const LookupPaths
*paths
,
1320 const char *config_path
,
1322 UnitFileChange
**changes
,
1323 unsigned *n_changes
) {
1325 _cleanup_free_
char *path
= NULL
;
1331 assert(config_path
);
1334 r
= in_search_path(paths
, i
->path
);
1338 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1342 rp
= skip_root(paths
, i
->path
);
1344 return create_symlink(rp
?: i
->path
, path
, force
, changes
, n_changes
);
1347 static int install_info_apply(
1348 UnitFileInstallInfo
*i
,
1349 const LookupPaths
*paths
,
1350 const char *config_path
,
1352 UnitFileChange
**changes
,
1353 unsigned *n_changes
) {
1359 assert(config_path
);
1361 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1364 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1366 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", force
, changes
, n_changes
);
1370 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", force
, changes
, n_changes
);
1374 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1381 static int install_context_apply(
1382 UnitFileScope scope
,
1384 const LookupPaths
*paths
,
1385 const char *config_path
,
1388 UnitFileChange
**changes
,
1389 unsigned *n_changes
) {
1391 UnitFileInstallInfo
*i
;
1396 assert(config_path
);
1398 if (ordered_hashmap_isempty(c
->will_process
))
1401 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1406 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1409 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1413 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1417 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1420 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1432 static int install_context_mark_for_removal(
1433 UnitFileScope scope
,
1435 const LookupPaths
*paths
,
1436 Set
**remove_symlinks_to
,
1437 const char *config_path
) {
1439 UnitFileInstallInfo
*i
;
1444 assert(config_path
);
1446 /* Marks all items for removal */
1448 if (ordered_hashmap_isempty(c
->will_process
))
1451 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1455 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1457 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1461 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1465 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1468 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1477 UnitFileScope scope
,
1479 const char *root_dir
,
1482 UnitFileChange
**changes
,
1483 unsigned *n_changes
) {
1485 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1486 const char *config_path
;
1491 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1493 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1497 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1499 STRV_FOREACH(i
, files
) {
1500 _cleanup_free_
char *path
= NULL
;
1503 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1509 path
= path_make_absolute(*i
, config_path
);
1513 q
= create_symlink("/dev/null", path
, force
, changes
, n_changes
);
1514 if (q
< 0 && r
>= 0)
1521 int unit_file_unmask(
1522 UnitFileScope scope
,
1524 const char *root_dir
,
1526 UnitFileChange
**changes
,
1527 unsigned *n_changes
) {
1529 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1530 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1531 _cleanup_free_
char **todo
= NULL
;
1532 size_t n_todo
= 0, n_allocated
= 0;
1533 const char *config_path
;
1538 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1540 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1544 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1546 STRV_FOREACH(i
, files
) {
1547 _cleanup_free_
char *path
= NULL
;
1549 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1552 path
= path_make_absolute(*i
, config_path
);
1556 r
= null_or_empty_path(path
);
1564 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1567 todo
[n_todo
++] = *i
;
1573 STRV_FOREACH(i
, todo
) {
1574 _cleanup_free_
char *path
= NULL
;
1577 path
= path_make_absolute(*i
, config_path
);
1581 if (unlink(path
) < 0) {
1582 if (errno
!= -ENOENT
&& r
>= 0)
1588 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1590 rp
= skip_root(&paths
, path
);
1591 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
1596 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, changes
, n_changes
);
1604 UnitFileScope scope
,
1606 const char *root_dir
,
1609 UnitFileChange
**changes
,
1610 unsigned *n_changes
) {
1612 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1613 _cleanup_free_
char **todo
= NULL
;
1614 size_t n_todo
= 0, n_allocated
= 0;
1615 const char *config_path
;
1620 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1622 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1626 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1628 STRV_FOREACH(i
, files
) {
1629 _cleanup_free_
char *full
= NULL
;
1633 if (!path_is_absolute(*i
))
1637 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1640 full
= prefix_root(paths
.root_dir
, *i
);
1644 if (lstat(full
, &st
) < 0)
1646 if (S_ISLNK(st
.st_mode
))
1648 if (S_ISDIR(st
.st_mode
))
1650 if (!S_ISREG(st
.st_mode
))
1653 q
= in_search_path(&paths
, *i
);
1659 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1662 todo
[n_todo
++] = *i
;
1668 STRV_FOREACH(i
, todo
) {
1669 _cleanup_free_
char *new_path
= NULL
;
1670 const char *old_path
;
1672 old_path
= skip_root(&paths
, *i
);
1673 new_path
= path_make_absolute(basename(*i
), config_path
);
1677 q
= create_symlink(old_path
?: *i
, new_path
, force
, changes
, n_changes
);
1678 if (q
< 0 && r
>= 0)
1685 int unit_file_add_dependency(
1686 UnitFileScope scope
,
1688 const char *root_dir
,
1693 UnitFileChange
**changes
,
1694 unsigned *n_changes
) {
1696 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1697 _cleanup_(install_context_done
) InstallContext c
= {};
1698 UnitFileInstallInfo
*i
, *target_info
;
1699 const char *config_path
;
1704 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1707 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
1710 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
1713 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1717 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1719 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
1722 if (target_info
->type
== UNIT_FILE_TYPE_MASKED
)
1724 if (path_is_generator(&paths
, target_info
->path
))
1725 return -EADDRNOTAVAIL
;
1726 if (path_is_transient(&paths
, target_info
->path
))
1727 return -EADDRNOTAVAIL
;
1729 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
1731 STRV_FOREACH(f
, files
) {
1734 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1737 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1739 if (path_is_generator(&paths
, i
->path
))
1740 return -EADDRNOTAVAIL
;
1741 if (path_is_transient(&paths
, i
->path
))
1742 return -EADDRNOTAVAIL
;
1744 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1746 /* We didn't actually load anything from the unit
1747 * file, but instead just add in our new symlink to
1750 if (dep
== UNIT_WANTS
)
1753 l
= &i
->required_by
;
1756 *l
= strv_new(target_info
->name
, NULL
);
1761 return install_context_apply(scope
, &c
, &paths
, config_path
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
1764 int unit_file_enable(
1765 UnitFileScope scope
,
1767 const char *root_dir
,
1770 UnitFileChange
**changes
,
1771 unsigned *n_changes
) {
1773 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1774 _cleanup_(install_context_done
) InstallContext c
= {};
1775 const char *config_path
;
1776 UnitFileInstallInfo
*i
;
1781 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1783 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1787 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1789 STRV_FOREACH(f
, files
) {
1790 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
, &i
);
1793 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1795 if (path_is_generator(&paths
, i
->path
))
1796 return -EADDRNOTAVAIL
;
1797 if (path_is_transient(&paths
, i
->path
))
1798 return -EADDRNOTAVAIL
;
1800 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1803 /* This will return the number of symlink rules that were
1804 supposed to be created, not the ones actually created. This
1805 is useful to determine whether the passed files had any
1806 installation data at all. */
1808 return install_context_apply(scope
, &c
, &paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
1811 int unit_file_disable(
1812 UnitFileScope scope
,
1814 const char *root_dir
,
1816 UnitFileChange
**changes
,
1817 unsigned *n_changes
) {
1819 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1820 _cleanup_(install_context_done
) InstallContext c
= {};
1821 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1822 const char *config_path
;
1827 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1829 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1833 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1835 STRV_FOREACH(i
, files
) {
1836 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1839 r
= install_info_add(&c
, *i
, NULL
, NULL
);
1844 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
);
1848 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, changes
, n_changes
);
1851 int unit_file_reenable(
1852 UnitFileScope scope
,
1854 const char *root_dir
,
1857 UnitFileChange
**changes
,
1858 unsigned *n_changes
) {
1864 /* First, we invoke the disable command with only the basename... */
1865 l
= strv_length(files
);
1866 n
= newa(char*, l
+1);
1867 for (i
= 0; i
< l
; i
++)
1868 n
[i
] = basename(files
[i
]);
1871 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
1875 /* But the enable command with the full name */
1876 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
1879 int unit_file_set_default(
1880 UnitFileScope scope
,
1881 const char *root_dir
,
1884 UnitFileChange
**changes
,
1885 unsigned *n_changes
) {
1887 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1888 _cleanup_(install_context_done
) InstallContext c
= {};
1889 UnitFileInstallInfo
*i
;
1890 const char *new_path
, *old_path
;
1894 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1897 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
1899 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
1902 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1906 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
);
1909 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1911 if (path_is_generator(&paths
, i
->path
))
1912 return -EADDRNOTAVAIL
;
1913 if (path_is_transient(&paths
, i
->path
))
1914 return -EADDRNOTAVAIL
;
1916 old_path
= skip_root(&paths
, i
->path
);
1917 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
1919 return create_symlink(old_path
?: i
->path
, new_path
, force
, changes
, n_changes
);
1922 int unit_file_get_default(
1923 UnitFileScope scope
,
1924 const char *root_dir
,
1927 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1928 _cleanup_(install_context_done
) InstallContext c
= {};
1929 UnitFileInstallInfo
*i
;
1934 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1937 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1941 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1944 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1947 n
= strdup(i
->name
);
1955 int unit_file_lookup_state(
1956 UnitFileScope scope
,
1957 const LookupPaths
*paths
,
1959 UnitFileState
*ret
) {
1961 _cleanup_(install_context_done
) InstallContext c
= {};
1962 UnitFileInstallInfo
*i
;
1963 UnitFileState state
;
1969 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1972 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1976 /* Shortcut things, if the caller just wants to know if this unit exists. */
1982 case UNIT_FILE_TYPE_MASKED
:
1983 r
= path_is_runtime(paths
, i
->path
);
1987 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
1990 case UNIT_FILE_TYPE_REGULAR
:
1991 r
= path_is_generator(paths
, i
->path
);
1995 state
= UNIT_FILE_GENERATED
;
1999 r
= path_is_transient(paths
, i
->path
);
2003 state
= UNIT_FILE_TRANSIENT
;
2007 r
= find_symlinks_in_scope(scope
, paths
, i
->name
, &state
);
2011 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
2012 state
= UNIT_FILE_DISABLED
;
2013 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
2014 state
= UNIT_FILE_INDIRECT
;
2016 state
= UNIT_FILE_STATIC
;
2022 assert_not_reached("Unexpect unit file type.");
2029 int unit_file_get_state(
2030 UnitFileScope scope
,
2031 const char *root_dir
,
2033 UnitFileState
*ret
) {
2035 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2039 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2042 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2046 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2049 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2050 _cleanup_strv_free_
char **files
= NULL
;
2055 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2058 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2061 if (scope
== UNIT_FILE_SYSTEM
)
2062 r
= conf_files_list(&files
, ".preset", root_dir
,
2063 "/etc/systemd/system-preset",
2064 "/usr/local/lib/systemd/system-preset",
2065 "/usr/lib/systemd/system-preset",
2066 #ifdef HAVE_SPLIT_USR
2067 "/lib/systemd/system-preset",
2070 else if (scope
== UNIT_FILE_GLOBAL
)
2071 r
= conf_files_list(&files
, ".preset", root_dir
,
2072 "/etc/systemd/user-preset",
2073 "/usr/local/lib/systemd/user-preset",
2074 "/usr/lib/systemd/user-preset",
2077 return 1; /* Default is "enable" */
2082 STRV_FOREACH(p
, files
) {
2083 _cleanup_fclose_
FILE *f
;
2084 char line
[LINE_MAX
];
2086 f
= fopen(*p
, "re");
2088 if (errno
== ENOENT
)
2094 FOREACH_LINE(line
, f
, return -errno
) {
2095 const char *parameter
;
2102 if (strchr(COMMENTS
, *l
))
2105 parameter
= first_word(l
, "enable");
2107 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2108 log_debug("Preset file says enable %s.", name
);
2115 parameter
= first_word(l
, "disable");
2117 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2118 log_debug("Preset file says disable %s.", name
);
2125 log_debug("Couldn't parse line '%s'", l
);
2129 /* Default is "enable" */
2130 log_debug("Preset file doesn't say anything about %s, enabling.", name
);
2134 static int execute_preset(
2135 UnitFileScope scope
,
2136 InstallContext
*plus
,
2137 InstallContext
*minus
,
2138 const LookupPaths
*paths
,
2139 const char *config_path
,
2141 UnitFilePresetMode mode
,
2143 UnitFileChange
**changes
,
2144 unsigned *n_changes
) {
2151 assert(config_path
);
2153 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2154 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2156 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
);
2160 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, changes
, n_changes
);
2164 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2167 /* Returns number of symlinks that where supposed to be installed. */
2168 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2180 static int preset_prepare_one(
2181 UnitFileScope scope
,
2182 InstallContext
*plus
,
2183 InstallContext
*minus
,
2185 UnitFilePresetMode mode
,
2188 UnitFileInstallInfo
*i
;
2191 if (install_info_find(plus
, name
) ||
2192 install_info_find(minus
, name
))
2195 r
= unit_file_query_preset(scope
, paths
->root_dir
, name
);
2200 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2204 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
2206 if (path_is_generator(paths
, i
->path
))
2207 return -EADDRNOTAVAIL
;
2208 if (path_is_transient(paths
, i
->path
))
2209 return -EADDRNOTAVAIL
;
2211 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2216 int unit_file_preset(
2217 UnitFileScope scope
,
2219 const char *root_dir
,
2221 UnitFilePresetMode mode
,
2223 UnitFileChange
**changes
,
2224 unsigned *n_changes
) {
2226 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2227 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2228 const char *config_path
;
2233 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2234 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2236 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2240 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2242 STRV_FOREACH(i
, files
) {
2243 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2246 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, mode
, *i
);
2251 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, force
, changes
, n_changes
);
2254 int unit_file_preset_all(
2255 UnitFileScope scope
,
2257 const char *root_dir
,
2258 UnitFilePresetMode mode
,
2260 UnitFileChange
**changes
,
2261 unsigned *n_changes
) {
2263 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2264 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2265 const char *config_path
= NULL
;
2270 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2271 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2273 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2277 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2279 STRV_FOREACH(i
, paths
.search_path
) {
2280 _cleanup_closedir_
DIR *d
= NULL
;
2285 if (errno
== ENOENT
)
2291 FOREACH_DIRENT(de
, d
, return -errno
) {
2293 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2296 dirent_ensure_type(d
, de
);
2298 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2301 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, mode
, de
->d_name
);
2307 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, force
, changes
, n_changes
);
2310 static void unit_file_list_free_one(UnitFileList
*f
) {
2318 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2321 while ((i
= hashmap_steal_first(h
)))
2322 unit_file_list_free_one(i
);
2324 return hashmap_free(h
);
2327 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2329 int unit_file_get_list(
2330 UnitFileScope scope
,
2331 const char *root_dir
,
2334 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2339 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2342 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2346 STRV_FOREACH(i
, paths
.search_path
) {
2347 _cleanup_closedir_
DIR *d
= NULL
;
2352 if (errno
== ENOENT
)
2358 FOREACH_DIRENT(de
, d
, return -errno
) {
2359 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2361 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2364 if (hashmap_get(h
, de
->d_name
))
2367 dirent_ensure_type(d
, de
);
2369 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2372 f
= new0(UnitFileList
, 1);
2376 f
->path
= path_make_absolute(de
->d_name
, *i
);
2380 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
2382 f
->state
= UNIT_FILE_BAD
;
2384 r
= hashmap_put(h
, basename(f
->path
), f
);
2388 f
= NULL
; /* prevent cleanup */
2395 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2396 [UNIT_FILE_ENABLED
] = "enabled",
2397 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2398 [UNIT_FILE_LINKED
] = "linked",
2399 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
2400 [UNIT_FILE_MASKED
] = "masked",
2401 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
2402 [UNIT_FILE_STATIC
] = "static",
2403 [UNIT_FILE_DISABLED
] = "disabled",
2404 [UNIT_FILE_INDIRECT
] = "indirect",
2405 [UNIT_FILE_GENERATED
] = "generated",
2406 [UNIT_FILE_TRANSIENT
] = "transient",
2407 [UNIT_FILE_BAD
] = "bad",
2410 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
2412 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
2413 [UNIT_FILE_SYMLINK
] = "symlink",
2414 [UNIT_FILE_UNLINK
] = "unlink",
2417 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
2419 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
2420 [UNIT_FILE_PRESET_FULL
] = "full",
2421 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
2422 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
2425 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);