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_may_process(UnitFileInstallInfo
*i
, const LookupPaths
*paths
) {
711 /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
712 * not subject to enable/disable operations. */
714 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
716 if (path_is_generator(paths
, i
->path
))
717 return -EADDRNOTAVAIL
;
718 if (path_is_transient(paths
, i
->path
))
719 return -EADDRNOTAVAIL
;
724 static int install_info_add(
728 UnitFileInstallInfo
**ret
) {
730 UnitFileInstallInfo
*i
= NULL
;
734 assert(name
|| path
);
737 name
= basename(path
);
739 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
742 i
= install_info_find(c
, name
);
749 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
753 i
= new0(UnitFileInstallInfo
, 1);
756 i
->type
= _UNIT_FILE_TYPE_INVALID
;
758 i
->name
= strdup(name
);
765 i
->path
= strdup(path
);
772 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
782 install_info_free(i
);
786 static int config_parse_also(
788 const char *filename
,
791 unsigned section_line
,
798 UnitFileInstallInfo
*i
= userdata
;
799 InstallContext
*c
= data
;
807 _cleanup_free_
char *word
= NULL
;
809 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
815 r
= install_info_add(c
, word
, NULL
, NULL
);
819 r
= strv_push(&i
->also
, word
);
829 static int config_parse_default_instance(
831 const char *filename
,
834 unsigned section_line
,
841 UnitFileInstallInfo
*i
= data
;
849 r
= install_full_printf(i
, rvalue
, &printed
);
853 if (!unit_instance_is_valid(printed
)) {
858 free(i
->default_instance
);
859 i
->default_instance
= printed
;
864 static int unit_file_load(
866 UnitFileInstallInfo
*info
,
870 const ConfigTableItem items
[] = {
871 { "Install", "Alias", config_parse_strv
, 0, &info
->aliases
},
872 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
873 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
874 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
875 { "Install", "Also", config_parse_also
, 0, c
},
879 _cleanup_fclose_
FILE *f
= NULL
;
880 _cleanup_close_
int fd
= -1;
888 if (!(flags
& SEARCH_LOAD
)) {
889 r
= lstat(path
, &st
);
893 if (null_or_empty(&st
))
894 info
->type
= UNIT_FILE_TYPE_MASKED
;
895 else if (S_ISREG(st
.st_mode
))
896 info
->type
= UNIT_FILE_TYPE_REGULAR
;
897 else if (S_ISLNK(st
.st_mode
))
899 else if (S_ISDIR(st
.st_mode
))
907 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
910 if (fstat(fd
, &st
) < 0)
912 if (null_or_empty(&st
)) {
913 info
->type
= UNIT_FILE_TYPE_MASKED
;
916 if (S_ISDIR(st
.st_mode
))
918 if (!S_ISREG(st
.st_mode
))
921 f
= fdopen(fd
, "re");
926 r
= config_parse(NULL
, path
, f
,
928 config_item_table_lookup
, items
,
929 true, true, false, info
);
933 info
->type
= UNIT_FILE_TYPE_REGULAR
;
936 (int) strv_length(info
->aliases
) +
937 (int) strv_length(info
->wanted_by
) +
938 (int) strv_length(info
->required_by
);
941 static int unit_file_load_or_readlink(
943 UnitFileInstallInfo
*info
,
945 const char *root_dir
,
948 _cleanup_free_
char *target
= NULL
;
951 r
= unit_file_load(c
, info
, path
, flags
);
955 /* This is a symlink, let's read it. */
957 r
= readlink_malloc(path
, &target
);
961 if (path_equal(target
, "/dev/null"))
962 info
->type
= UNIT_FILE_TYPE_MASKED
;
967 bn
= basename(target
);
969 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
971 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
974 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
976 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
979 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
981 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
986 /* Enforce that the symlink destination does not
987 * change the unit file type. */
989 a
= unit_name_to_type(info
->name
);
990 b
= unit_name_to_type(bn
);
991 if (a
< 0 || b
< 0 || a
!= b
)
994 if (path_is_absolute(target
))
995 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
996 info
->symlink_target
= prefix_root(root_dir
, target
);
998 /* This is a relative path, take it relative to the dir the symlink is located in. */
999 info
->symlink_target
= file_in_same_dir(path
, target
);
1000 if (!info
->symlink_target
)
1003 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1009 static int unit_file_search(
1011 UnitFileInstallInfo
*info
,
1012 const LookupPaths
*paths
,
1013 SearchFlags flags
) {
1022 /* Was this unit already loaded? */
1023 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1027 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1031 STRV_FOREACH(p
, paths
->search_path
) {
1032 _cleanup_free_
char *path
= NULL
;
1034 path
= strjoin(*p
, "/", info
->name
, NULL
);
1038 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1049 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1051 /* Unit file doesn't exist, however instance
1052 * enablement was requested. We will check if it is
1053 * possible to load template unit file. */
1055 _cleanup_free_
char *template = NULL
;
1057 r
= unit_name_template(info
->name
, &template);
1061 STRV_FOREACH(p
, paths
->search_path
) {
1062 _cleanup_free_
char *path
= NULL
;
1064 path
= strjoin(*p
, "/", template, NULL
);
1068 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1083 static int install_info_follow(
1085 UnitFileInstallInfo
*i
,
1086 const char *root_dir
,
1087 SearchFlags flags
) {
1092 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1094 if (!i
->symlink_target
)
1097 /* If the basename doesn't match, the caller should add a
1098 * complete new entry for this. */
1100 if (!streq(basename(i
->symlink_target
), i
->name
))
1104 i
->path
= i
->symlink_target
;
1105 i
->symlink_target
= NULL
;
1106 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1108 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1111 static int install_info_traverse(
1112 UnitFileScope scope
,
1114 const LookupPaths
*paths
,
1115 UnitFileInstallInfo
*start
,
1117 UnitFileInstallInfo
**ret
) {
1119 UnitFileInstallInfo
*i
;
1127 r
= unit_file_search(c
, start
, paths
, flags
);
1132 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1133 /* Follow the symlink */
1135 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1138 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1139 r
= path_is_config(paths
, i
->path
);
1146 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
);
1148 _cleanup_free_
char *buffer
= NULL
;
1154 /* Target has a different name, create a new
1155 * install info object for that, and continue
1158 bn
= basename(i
->symlink_target
);
1160 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1161 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1163 _cleanup_free_
char *instance
= NULL
;
1165 r
= unit_name_to_instance(i
->name
, &instance
);
1169 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1176 r
= install_info_add(c
, bn
, NULL
, &i
);
1180 r
= unit_file_search(c
, i
, paths
, flags
);
1185 /* Try again, with the new target we found. */
1194 static int install_info_add_auto(
1196 const LookupPaths
*paths
,
1197 const char *name_or_path
,
1198 UnitFileInstallInfo
**ret
) {
1201 assert(name_or_path
);
1203 if (path_is_absolute(name_or_path
)) {
1206 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1208 return install_info_add(c
, NULL
, pp
, ret
);
1210 return install_info_add(c
, name_or_path
, NULL
, ret
);
1213 static int install_info_discover(
1214 UnitFileScope scope
,
1216 const LookupPaths
*paths
,
1219 UnitFileInstallInfo
**ret
) {
1221 UnitFileInstallInfo
*i
;
1228 r
= install_info_add_auto(c
, paths
, name
, &i
);
1232 return install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1235 static int install_info_symlink_alias(
1236 UnitFileInstallInfo
*i
,
1237 const LookupPaths
*paths
,
1238 const char *config_path
,
1240 UnitFileChange
**changes
,
1241 unsigned *n_changes
) {
1248 assert(config_path
);
1250 STRV_FOREACH(s
, i
->aliases
) {
1251 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1254 q
= install_full_printf(i
, *s
, &dst
);
1258 alias_path
= path_make_absolute(dst
, config_path
);
1262 rp
= skip_root(paths
, i
->path
);
1264 q
= create_symlink(rp
?: i
->path
, alias_path
, force
, changes
, n_changes
);
1272 static int install_info_symlink_wants(
1273 UnitFileInstallInfo
*i
,
1274 const LookupPaths
*paths
,
1275 const char *config_path
,
1279 UnitFileChange
**changes
,
1280 unsigned *n_changes
) {
1282 _cleanup_free_
char *buf
= NULL
;
1289 assert(config_path
);
1291 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1293 /* Don't install any symlink if there's no default
1294 * instance configured */
1296 if (!i
->default_instance
)
1299 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1307 STRV_FOREACH(s
, list
) {
1308 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1311 q
= install_full_printf(i
, *s
, &dst
);
1315 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1320 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1324 rp
= skip_root(paths
, i
->path
);
1326 q
= create_symlink(rp
?: i
->path
, path
, force
, changes
, n_changes
);
1334 static int install_info_symlink_link(
1335 UnitFileInstallInfo
*i
,
1336 const LookupPaths
*paths
,
1337 const char *config_path
,
1339 UnitFileChange
**changes
,
1340 unsigned *n_changes
) {
1342 _cleanup_free_
char *path
= NULL
;
1348 assert(config_path
);
1351 r
= in_search_path(paths
, i
->path
);
1355 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1359 rp
= skip_root(paths
, i
->path
);
1361 return create_symlink(rp
?: i
->path
, path
, force
, changes
, n_changes
);
1364 static int install_info_apply(
1365 UnitFileInstallInfo
*i
,
1366 const LookupPaths
*paths
,
1367 const char *config_path
,
1369 UnitFileChange
**changes
,
1370 unsigned *n_changes
) {
1376 assert(config_path
);
1378 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1381 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1383 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", force
, changes
, n_changes
);
1387 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", force
, changes
, n_changes
);
1391 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1398 static int install_context_apply(
1399 UnitFileScope scope
,
1401 const LookupPaths
*paths
,
1402 const char *config_path
,
1405 UnitFileChange
**changes
,
1406 unsigned *n_changes
) {
1408 UnitFileInstallInfo
*i
;
1413 assert(config_path
);
1415 if (ordered_hashmap_isempty(c
->will_process
))
1418 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1423 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1426 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1430 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1434 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1437 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1449 static int install_context_mark_for_removal(
1450 UnitFileScope scope
,
1452 const LookupPaths
*paths
,
1453 Set
**remove_symlinks_to
,
1454 const char *config_path
) {
1456 UnitFileInstallInfo
*i
;
1461 assert(config_path
);
1463 /* Marks all items for removal */
1465 if (ordered_hashmap_isempty(c
->will_process
))
1468 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1472 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1474 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1478 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1482 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1485 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1494 UnitFileScope scope
,
1496 const char *root_dir
,
1499 UnitFileChange
**changes
,
1500 unsigned *n_changes
) {
1502 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1503 const char *config_path
;
1508 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1510 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1514 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1516 STRV_FOREACH(i
, files
) {
1517 _cleanup_free_
char *path
= NULL
;
1520 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1526 path
= path_make_absolute(*i
, config_path
);
1530 q
= create_symlink("/dev/null", path
, force
, changes
, n_changes
);
1531 if (q
< 0 && r
>= 0)
1538 int unit_file_unmask(
1539 UnitFileScope scope
,
1541 const char *root_dir
,
1543 UnitFileChange
**changes
,
1544 unsigned *n_changes
) {
1546 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1547 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1548 _cleanup_free_
char **todo
= NULL
;
1549 size_t n_todo
= 0, n_allocated
= 0;
1550 const char *config_path
;
1555 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1557 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1561 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1563 STRV_FOREACH(i
, files
) {
1564 _cleanup_free_
char *path
= NULL
;
1566 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1569 path
= path_make_absolute(*i
, config_path
);
1573 r
= null_or_empty_path(path
);
1581 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1584 todo
[n_todo
++] = *i
;
1590 STRV_FOREACH(i
, todo
) {
1591 _cleanup_free_
char *path
= NULL
;
1594 path
= path_make_absolute(*i
, config_path
);
1598 if (unlink(path
) < 0) {
1599 if (errno
!= -ENOENT
&& r
>= 0)
1605 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1607 rp
= skip_root(&paths
, path
);
1608 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
1613 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, changes
, n_changes
);
1621 UnitFileScope scope
,
1623 const char *root_dir
,
1626 UnitFileChange
**changes
,
1627 unsigned *n_changes
) {
1629 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1630 _cleanup_free_
char **todo
= NULL
;
1631 size_t n_todo
= 0, n_allocated
= 0;
1632 const char *config_path
;
1637 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1639 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1643 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1645 STRV_FOREACH(i
, files
) {
1646 _cleanup_free_
char *full
= NULL
;
1650 if (!path_is_absolute(*i
))
1654 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1657 full
= prefix_root(paths
.root_dir
, *i
);
1661 if (lstat(full
, &st
) < 0)
1663 if (S_ISLNK(st
.st_mode
))
1665 if (S_ISDIR(st
.st_mode
))
1667 if (!S_ISREG(st
.st_mode
))
1670 q
= in_search_path(&paths
, *i
);
1676 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1679 todo
[n_todo
++] = *i
;
1685 STRV_FOREACH(i
, todo
) {
1686 _cleanup_free_
char *new_path
= NULL
;
1687 const char *old_path
;
1689 old_path
= skip_root(&paths
, *i
);
1690 new_path
= path_make_absolute(basename(*i
), config_path
);
1694 q
= create_symlink(old_path
?: *i
, new_path
, force
, changes
, n_changes
);
1695 if (q
< 0 && r
>= 0)
1702 int unit_file_add_dependency(
1703 UnitFileScope scope
,
1705 const char *root_dir
,
1710 UnitFileChange
**changes
,
1711 unsigned *n_changes
) {
1713 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1714 _cleanup_(install_context_done
) InstallContext c
= {};
1715 UnitFileInstallInfo
*i
, *target_info
;
1716 const char *config_path
;
1721 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1724 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
1727 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
1730 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1734 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1736 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
1739 r
= install_info_may_process(target_info
, &paths
);
1743 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
1745 STRV_FOREACH(f
, files
) {
1748 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1751 r
= install_info_may_process(i
, &paths
);
1755 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1757 /* We didn't actually load anything from the unit
1758 * file, but instead just add in our new symlink to
1761 if (dep
== UNIT_WANTS
)
1764 l
= &i
->required_by
;
1767 *l
= strv_new(target_info
->name
, NULL
);
1772 return install_context_apply(scope
, &c
, &paths
, config_path
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
1775 int unit_file_enable(
1776 UnitFileScope scope
,
1778 const char *root_dir
,
1781 UnitFileChange
**changes
,
1782 unsigned *n_changes
) {
1784 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1785 _cleanup_(install_context_done
) InstallContext c
= {};
1786 const char *config_path
;
1787 UnitFileInstallInfo
*i
;
1792 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1794 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1798 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1800 STRV_FOREACH(f
, files
) {
1801 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
, &i
);
1804 r
= install_info_may_process(i
, &paths
);
1808 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1811 /* This will return the number of symlink rules that were
1812 supposed to be created, not the ones actually created. This
1813 is useful to determine whether the passed files had any
1814 installation data at all. */
1816 return install_context_apply(scope
, &c
, &paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
1819 int unit_file_disable(
1820 UnitFileScope scope
,
1822 const char *root_dir
,
1824 UnitFileChange
**changes
,
1825 unsigned *n_changes
) {
1827 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1828 _cleanup_(install_context_done
) InstallContext c
= {};
1829 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1830 const char *config_path
;
1835 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1837 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1841 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1843 STRV_FOREACH(i
, files
) {
1844 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1847 r
= install_info_add(&c
, *i
, NULL
, NULL
);
1852 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
);
1856 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, changes
, n_changes
);
1859 int unit_file_reenable(
1860 UnitFileScope scope
,
1862 const char *root_dir
,
1865 UnitFileChange
**changes
,
1866 unsigned *n_changes
) {
1872 /* First, we invoke the disable command with only the basename... */
1873 l
= strv_length(files
);
1874 n
= newa(char*, l
+1);
1875 for (i
= 0; i
< l
; i
++)
1876 n
[i
] = basename(files
[i
]);
1879 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
1883 /* But the enable command with the full name */
1884 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
1887 int unit_file_set_default(
1888 UnitFileScope scope
,
1889 const char *root_dir
,
1892 UnitFileChange
**changes
,
1893 unsigned *n_changes
) {
1895 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1896 _cleanup_(install_context_done
) InstallContext c
= {};
1897 UnitFileInstallInfo
*i
;
1898 const char *new_path
, *old_path
;
1902 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1905 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
1907 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
1910 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1914 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
);
1917 r
= install_info_may_process(i
, &paths
);
1921 old_path
= skip_root(&paths
, i
->path
);
1922 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
1924 return create_symlink(old_path
?: i
->path
, new_path
, force
, changes
, n_changes
);
1927 int unit_file_get_default(
1928 UnitFileScope scope
,
1929 const char *root_dir
,
1932 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1933 _cleanup_(install_context_done
) InstallContext c
= {};
1934 UnitFileInstallInfo
*i
;
1939 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1942 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1946 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1949 r
= install_info_may_process(i
, &paths
);
1953 n
= strdup(i
->name
);
1961 int unit_file_lookup_state(
1962 UnitFileScope scope
,
1963 const LookupPaths
*paths
,
1965 UnitFileState
*ret
) {
1967 _cleanup_(install_context_done
) InstallContext c
= {};
1968 UnitFileInstallInfo
*i
;
1969 UnitFileState state
;
1975 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1978 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1982 /* Shortcut things, if the caller just wants to know if this unit exists. */
1988 case UNIT_FILE_TYPE_MASKED
:
1989 r
= path_is_runtime(paths
, i
->path
);
1993 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
1996 case UNIT_FILE_TYPE_REGULAR
:
1997 r
= path_is_generator(paths
, i
->path
);
2001 state
= UNIT_FILE_GENERATED
;
2005 r
= path_is_transient(paths
, i
->path
);
2009 state
= UNIT_FILE_TRANSIENT
;
2013 r
= find_symlinks_in_scope(scope
, paths
, i
->name
, &state
);
2017 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
2018 state
= UNIT_FILE_DISABLED
;
2019 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
2020 state
= UNIT_FILE_INDIRECT
;
2022 state
= UNIT_FILE_STATIC
;
2028 assert_not_reached("Unexpect unit file type.");
2035 int unit_file_get_state(
2036 UnitFileScope scope
,
2037 const char *root_dir
,
2039 UnitFileState
*ret
) {
2041 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2045 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2048 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2052 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2055 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2056 _cleanup_strv_free_
char **files
= NULL
;
2061 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2064 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2067 if (scope
== UNIT_FILE_SYSTEM
)
2068 r
= conf_files_list(&files
, ".preset", root_dir
,
2069 "/etc/systemd/system-preset",
2070 "/usr/local/lib/systemd/system-preset",
2071 "/usr/lib/systemd/system-preset",
2072 #ifdef HAVE_SPLIT_USR
2073 "/lib/systemd/system-preset",
2076 else if (scope
== UNIT_FILE_GLOBAL
)
2077 r
= conf_files_list(&files
, ".preset", root_dir
,
2078 "/etc/systemd/user-preset",
2079 "/usr/local/lib/systemd/user-preset",
2080 "/usr/lib/systemd/user-preset",
2083 return 1; /* Default is "enable" */
2088 STRV_FOREACH(p
, files
) {
2089 _cleanup_fclose_
FILE *f
;
2090 char line
[LINE_MAX
];
2092 f
= fopen(*p
, "re");
2094 if (errno
== ENOENT
)
2100 FOREACH_LINE(line
, f
, return -errno
) {
2101 const char *parameter
;
2108 if (strchr(COMMENTS
, *l
))
2111 parameter
= first_word(l
, "enable");
2113 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2114 log_debug("Preset file says enable %s.", name
);
2121 parameter
= first_word(l
, "disable");
2123 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2124 log_debug("Preset file says disable %s.", name
);
2131 log_debug("Couldn't parse line '%s'", l
);
2135 /* Default is "enable" */
2136 log_debug("Preset file doesn't say anything about %s, enabling.", name
);
2140 static int execute_preset(
2141 UnitFileScope scope
,
2142 InstallContext
*plus
,
2143 InstallContext
*minus
,
2144 const LookupPaths
*paths
,
2145 const char *config_path
,
2147 UnitFilePresetMode mode
,
2149 UnitFileChange
**changes
,
2150 unsigned *n_changes
) {
2157 assert(config_path
);
2159 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2160 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2162 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
);
2166 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, changes
, n_changes
);
2170 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2173 /* Returns number of symlinks that where supposed to be installed. */
2174 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2186 static int preset_prepare_one(
2187 UnitFileScope scope
,
2188 InstallContext
*plus
,
2189 InstallContext
*minus
,
2191 UnitFilePresetMode mode
,
2194 UnitFileInstallInfo
*i
;
2197 if (install_info_find(plus
, name
) ||
2198 install_info_find(minus
, name
))
2201 r
= unit_file_query_preset(scope
, paths
->root_dir
, name
);
2206 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2210 r
= install_info_may_process(i
, paths
);
2214 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2219 int unit_file_preset(
2220 UnitFileScope scope
,
2222 const char *root_dir
,
2224 UnitFilePresetMode mode
,
2226 UnitFileChange
**changes
,
2227 unsigned *n_changes
) {
2229 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2230 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2231 const char *config_path
;
2236 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2237 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2239 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2243 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2245 STRV_FOREACH(i
, files
) {
2246 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2249 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, mode
, *i
);
2254 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, force
, changes
, n_changes
);
2257 int unit_file_preset_all(
2258 UnitFileScope scope
,
2260 const char *root_dir
,
2261 UnitFilePresetMode mode
,
2263 UnitFileChange
**changes
,
2264 unsigned *n_changes
) {
2266 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2267 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2268 const char *config_path
= NULL
;
2273 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2274 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2276 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2280 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2282 STRV_FOREACH(i
, paths
.search_path
) {
2283 _cleanup_closedir_
DIR *d
= NULL
;
2288 if (errno
== ENOENT
)
2294 FOREACH_DIRENT(de
, d
, return -errno
) {
2296 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2299 dirent_ensure_type(d
, de
);
2301 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2304 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, mode
, de
->d_name
);
2310 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, force
, changes
, n_changes
);
2313 static void unit_file_list_free_one(UnitFileList
*f
) {
2321 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2324 while ((i
= hashmap_steal_first(h
)))
2325 unit_file_list_free_one(i
);
2327 return hashmap_free(h
);
2330 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2332 int unit_file_get_list(
2333 UnitFileScope scope
,
2334 const char *root_dir
,
2337 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2342 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2345 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2349 STRV_FOREACH(i
, paths
.search_path
) {
2350 _cleanup_closedir_
DIR *d
= NULL
;
2355 if (errno
== ENOENT
)
2361 FOREACH_DIRENT(de
, d
, return -errno
) {
2362 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2364 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2367 if (hashmap_get(h
, de
->d_name
))
2370 dirent_ensure_type(d
, de
);
2372 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2375 f
= new0(UnitFileList
, 1);
2379 f
->path
= path_make_absolute(de
->d_name
, *i
);
2383 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
2385 f
->state
= UNIT_FILE_BAD
;
2387 r
= hashmap_put(h
, basename(f
->path
), f
);
2391 f
= NULL
; /* prevent cleanup */
2398 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2399 [UNIT_FILE_ENABLED
] = "enabled",
2400 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2401 [UNIT_FILE_LINKED
] = "linked",
2402 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
2403 [UNIT_FILE_MASKED
] = "masked",
2404 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
2405 [UNIT_FILE_STATIC
] = "static",
2406 [UNIT_FILE_DISABLED
] = "disabled",
2407 [UNIT_FILE_INDIRECT
] = "indirect",
2408 [UNIT_FILE_GENERATED
] = "generated",
2409 [UNIT_FILE_TRANSIENT
] = "transient",
2410 [UNIT_FILE_BAD
] = "bad",
2413 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
2415 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
2416 [UNIT_FILE_SYMLINK
] = "symlink",
2417 [UNIT_FILE_UNLINK
] = "unlink",
2420 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
2422 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
2423 [UNIT_FILE_PRESET_FULL
] = "full",
2424 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
2425 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
2428 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);