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 char *path
, char **search
) {
69 _cleanup_free_
char *parent
= NULL
;
74 parent
= dirname_malloc(path
);
78 STRV_FOREACH(i
, search
)
79 if (path_equal(parent
, *i
))
85 static int get_config_path(UnitFileScope scope
, bool runtime
, const char *root_dir
, char **ret
) {
90 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
93 /* This determines where we shall create or remove our
94 * installation ("configuration") symlinks */
98 case UNIT_FILE_SYSTEM
:
101 p
= path_join(root_dir
, "/run/systemd/system", NULL
);
103 p
= path_join(root_dir
, SYSTEM_CONFIG_UNIT_PATH
, NULL
);
106 case UNIT_FILE_GLOBAL
:
112 p
= strdup("/run/systemd/user");
114 p
= strdup(USER_CONFIG_UNIT_PATH
);
123 r
= user_runtime_dir(&p
);
125 r
= user_config_home(&p
);
134 assert_not_reached("Bad scope");
144 static bool is_config_path(UnitFileScope scope
, const char *path
) {
148 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
151 /* Checks whether the specified path is intended for
152 * configuration or is outside of it */
156 case UNIT_FILE_SYSTEM
:
157 case UNIT_FILE_GLOBAL
:
158 return path_startswith(path
, "/etc") ||
159 path_startswith(path
, SYSTEM_CONFIG_UNIT_PATH
) ||
160 path_startswith(path
, "/run");
163 case UNIT_FILE_USER
: {
164 _cleanup_free_
char *p
= NULL
;
166 r
= user_config_home(&p
);
169 if (r
> 0 && path_startswith(path
, p
))
174 r
= user_runtime_dir(&p
);
177 if (r
> 0 && path_startswith(path
, p
))
184 assert_not_reached("Bad scope");
189 static int verify_root_dir(UnitFileScope scope
, const char **root_dir
) {
194 /* Verifies that the specified root directory to operate on
195 * makes sense. Reset it to NULL if it is the root directory
198 if (isempty(*root_dir
) || path_equal(*root_dir
, "/")) {
203 if (scope
!= UNIT_FILE_SYSTEM
)
206 r
= is_dir(*root_dir
, true);
215 int unit_file_changes_add(
216 UnitFileChange
**changes
,
218 UnitFileChangeType type
,
220 const char *source
) {
226 assert(!changes
== !n_changes
);
231 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
239 c
[i
].path
= strdup(path
);
243 path_kill_slashes(c
[i
].path
);
246 c
[i
].source
= strdup(source
);
252 path_kill_slashes(c
[i
].path
);
260 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
263 assert(changes
|| n_changes
== 0);
268 for (i
= 0; i
< n_changes
; i
++) {
269 free(changes
[i
].path
);
270 free(changes
[i
].source
);
276 static int create_symlink(
277 const char *old_path
,
278 const char *new_path
,
280 UnitFileChange
**changes
,
281 unsigned *n_changes
) {
283 _cleanup_free_
char *dest
= NULL
;
289 /* Actually create a symlink, and remember that we did. Is
290 * smart enough to check if there's already a valid symlink in
293 mkdir_parents_label(new_path
, 0755);
295 if (symlink(old_path
, new_path
) >= 0) {
296 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
303 r
= readlink_malloc(new_path
, &dest
);
307 if (path_equal(dest
, old_path
))
313 r
= symlink_atomic(old_path
, new_path
);
317 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
318 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
323 static int mark_symlink_for_removal(
324 Set
**remove_symlinks_to
,
332 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
340 path_kill_slashes(n
);
342 r
= set_consume(*remove_symlinks_to
, n
);
351 static int remove_marked_symlinks_fd(
352 Set
*remove_symlinks_to
,
355 const char *config_path
,
357 UnitFileChange
**changes
,
358 unsigned *n_changes
) {
360 _cleanup_closedir_
DIR *d
= NULL
;
364 assert(remove_symlinks_to
);
378 FOREACH_DIRENT(de
, d
, return -errno
) {
380 dirent_ensure_type(d
, de
);
382 if (de
->d_type
== DT_DIR
) {
383 _cleanup_free_
char *p
= NULL
;
386 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
396 p
= path_make_absolute(de
->d_name
, path
);
402 /* This will close nfd, regardless whether it succeeds or not */
403 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, restart
, changes
, n_changes
);
407 } else if (de
->d_type
== DT_LNK
) {
408 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
412 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
415 p
= path_make_absolute(de
->d_name
, path
);
419 q
= readlink_malloc(p
, &dest
);
429 /* We remove all links pointing to a file or
430 * path that is marked, as well as all files
431 * sharing the same name as a file that is
435 set_contains(remove_symlinks_to
, dest
) ||
436 set_contains(remove_symlinks_to
, basename(dest
)) ||
437 set_contains(remove_symlinks_to
, de
->d_name
);
442 if (unlink(p
) < 0 && errno
!= ENOENT
) {
448 path_kill_slashes(p
);
449 (void) rmdir_parents(p
, config_path
);
451 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
453 q
= mark_symlink_for_removal(&remove_symlinks_to
, p
);
464 static int remove_marked_symlinks(
465 Set
*remove_symlinks_to
,
466 const char *config_path
,
467 UnitFileChange
**changes
,
468 unsigned *n_changes
) {
470 _cleanup_close_
int fd
= -1;
476 if (set_size(remove_symlinks_to
) <= 0)
479 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
487 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
491 /* This takes possession of cfd and closes it */
492 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, &restart
, changes
, n_changes
);
500 static int find_symlinks_fd(
501 const char *root_dir
,
505 const char *config_path
,
506 bool *same_name_link
) {
508 _cleanup_closedir_
DIR *d
= NULL
;
516 assert(same_name_link
);
524 FOREACH_DIRENT(de
, d
, return -errno
) {
526 dirent_ensure_type(d
, de
);
528 if (de
->d_type
== DT_DIR
) {
529 _cleanup_free_
char *p
= NULL
;
532 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
542 p
= path_make_absolute(de
->d_name
, path
);
548 /* This will close nfd, regardless whether it succeeds or not */
549 q
= find_symlinks_fd(root_dir
, name
, nfd
, p
, config_path
, same_name_link
);
555 } else if (de
->d_type
== DT_LNK
) {
556 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
557 bool found_path
, found_dest
, b
= false;
560 /* Acquire symlink name */
561 p
= path_make_absolute(de
->d_name
, path
);
565 /* Acquire symlink destination */
566 q
= readlink_malloc(p
, &dest
);
576 if (!path_is_absolute(dest
)) {
579 x
= prefix_root(root_dir
, dest
);
587 /* Check if the symlink itself matches what we
589 if (path_is_absolute(name
))
590 found_path
= path_equal(p
, name
);
592 found_path
= streq(de
->d_name
, name
);
594 /* Check if what the symlink points to
595 * matches what we are looking for */
596 if (path_is_absolute(name
))
597 found_dest
= path_equal(dest
, name
);
599 found_dest
= streq(basename(dest
), name
);
601 if (found_path
&& found_dest
) {
602 _cleanup_free_
char *t
= NULL
;
604 /* Filter out same name links in the main
606 t
= path_make_absolute(name
, config_path
);
610 b
= path_equal(t
, p
);
614 *same_name_link
= true;
615 else if (found_path
|| found_dest
)
623 static int find_symlinks(
624 const char *root_dir
,
626 const char *config_path
,
627 bool *same_name_link
) {
633 assert(same_name_link
);
635 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
642 /* This takes possession of fd and closes it */
643 return find_symlinks_fd(root_dir
, name
, fd
, config_path
, config_path
, same_name_link
);
646 static int find_symlinks_in_scope(
648 const char *root_dir
,
650 UnitFileState
*state
) {
652 _cleanup_free_
char *normal_path
= NULL
, *runtime_path
= NULL
;
653 bool same_name_link_runtime
= false, same_name_link
= false;
657 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
660 /* First look in the normal config path */
661 r
= get_config_path(scope
, false, root_dir
, &normal_path
);
665 r
= find_symlinks(root_dir
, name
, normal_path
, &same_name_link
);
669 *state
= UNIT_FILE_ENABLED
;
673 /* Then look in runtime config path */
674 r
= get_config_path(scope
, true, root_dir
, &runtime_path
);
678 r
= find_symlinks(root_dir
, name
, runtime_path
, &same_name_link_runtime
);
682 *state
= UNIT_FILE_ENABLED_RUNTIME
;
686 /* Hmm, we didn't find it, but maybe we found the same name
688 if (same_name_link
) {
689 *state
= UNIT_FILE_LINKED
;
692 if (same_name_link_runtime
) {
693 *state
= UNIT_FILE_LINKED_RUNTIME
;
700 static void install_info_free(UnitFileInstallInfo
*i
) {
707 strv_free(i
->aliases
);
708 strv_free(i
->wanted_by
);
709 strv_free(i
->required_by
);
711 free(i
->default_instance
);
712 free(i
->symlink_target
);
716 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
717 UnitFileInstallInfo
*i
;
722 while ((i
= ordered_hashmap_steal_first(m
)))
723 install_info_free(i
);
725 return ordered_hashmap_free(m
);
728 static void install_context_done(InstallContext
*c
) {
731 c
->will_process
= install_info_hashmap_free(c
->will_process
);
732 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
735 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
736 UnitFileInstallInfo
*i
;
738 i
= ordered_hashmap_get(c
->have_processed
, name
);
742 return ordered_hashmap_get(c
->will_process
, name
);
745 static int install_info_add(
749 UnitFileInstallInfo
**ret
) {
751 UnitFileInstallInfo
*i
= NULL
;
755 assert(name
|| path
);
758 name
= basename(path
);
760 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
763 i
= install_info_find(c
, name
);
770 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
774 i
= new0(UnitFileInstallInfo
, 1);
777 i
->type
= _UNIT_FILE_TYPE_INVALID
;
779 i
->name
= strdup(name
);
786 i
->path
= strdup(path
);
793 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
803 install_info_free(i
);
807 static int install_info_add_auto(
809 const char *name_or_path
,
810 UnitFileInstallInfo
**ret
) {
813 assert(name_or_path
);
815 if (path_is_absolute(name_or_path
))
816 return install_info_add(c
, NULL
, name_or_path
, ret
);
818 return install_info_add(c
, name_or_path
, NULL
, ret
);
821 static int config_parse_also(
823 const char *filename
,
826 unsigned section_line
,
833 UnitFileInstallInfo
*i
= userdata
;
834 InstallContext
*c
= data
;
842 _cleanup_free_
char *word
= NULL
;
844 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
850 r
= install_info_add(c
, word
, NULL
, NULL
);
854 r
= strv_push(&i
->also
, word
);
864 static int config_parse_default_instance(
866 const char *filename
,
869 unsigned section_line
,
876 UnitFileInstallInfo
*i
= data
;
884 r
= install_full_printf(i
, rvalue
, &printed
);
888 if (!unit_instance_is_valid(printed
)) {
893 free(i
->default_instance
);
894 i
->default_instance
= printed
;
899 static int unit_file_load(
901 UnitFileInstallInfo
*info
,
903 const char *root_dir
,
906 const ConfigTableItem items
[] = {
907 { "Install", "Alias", config_parse_strv
, 0, &info
->aliases
},
908 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
909 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
910 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
911 { "Install", "Also", config_parse_also
, 0, c
},
915 _cleanup_fclose_
FILE *f
= NULL
;
916 _cleanup_close_
int fd
= -1;
924 path
= prefix_roota(root_dir
, path
);
926 if (!(flags
& SEARCH_LOAD
)) {
927 r
= lstat(path
, &st
);
931 if (null_or_empty(&st
))
932 info
->type
= UNIT_FILE_TYPE_MASKED
;
933 else if (S_ISREG(st
.st_mode
))
934 info
->type
= UNIT_FILE_TYPE_REGULAR
;
935 else if (S_ISLNK(st
.st_mode
))
937 else if (S_ISDIR(st
.st_mode
))
945 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
948 if (fstat(fd
, &st
) < 0)
950 if (null_or_empty(&st
)) {
951 info
->type
= UNIT_FILE_TYPE_MASKED
;
954 if (S_ISDIR(st
.st_mode
))
956 if (!S_ISREG(st
.st_mode
))
959 f
= fdopen(fd
, "re");
964 r
= config_parse(NULL
, path
, f
,
966 config_item_table_lookup
, items
,
967 true, true, false, info
);
971 info
->type
= UNIT_FILE_TYPE_REGULAR
;
974 (int) strv_length(info
->aliases
) +
975 (int) strv_length(info
->wanted_by
) +
976 (int) strv_length(info
->required_by
);
979 static int unit_file_load_or_readlink(
981 UnitFileInstallInfo
*info
,
983 const char *root_dir
,
986 _cleanup_free_
char *np
= NULL
;
989 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
993 /* This is a symlink, let's read it. */
995 r
= readlink_and_make_absolute_root(root_dir
, path
, &np
);
999 if (path_equal(np
, "/dev/null"))
1000 info
->type
= UNIT_FILE_TYPE_MASKED
;
1007 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1009 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1012 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1014 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1017 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1019 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1024 /* Enforce that the symlink destination does not
1025 * change the unit file type. */
1027 a
= unit_name_to_type(info
->name
);
1028 b
= unit_name_to_type(bn
);
1029 if (a
< 0 || b
< 0 || a
!= b
)
1032 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1033 info
->symlink_target
= np
;
1040 static int unit_file_search(
1042 UnitFileInstallInfo
*info
,
1043 const LookupPaths
*paths
,
1044 const char *root_dir
,
1045 SearchFlags flags
) {
1054 /* Was this unit already loaded? */
1055 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1059 return unit_file_load_or_readlink(c
, info
, info
->path
, root_dir
, flags
);
1063 STRV_FOREACH(p
, paths
->unit_path
) {
1064 _cleanup_free_
char *path
= NULL
;
1066 path
= strjoin(*p
, "/", info
->name
, NULL
);
1070 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1081 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1083 /* Unit file doesn't exist, however instance
1084 * enablement was requested. We will check if it is
1085 * possible to load template unit file. */
1087 _cleanup_free_
char *template = NULL
;
1089 r
= unit_name_template(info
->name
, &template);
1093 STRV_FOREACH(p
, paths
->unit_path
) {
1094 _cleanup_free_
char *path
= NULL
;
1096 path
= strjoin(*p
, "/", template, NULL
);
1100 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1115 static int install_info_follow(
1117 UnitFileInstallInfo
*i
,
1118 const char *root_dir
,
1119 SearchFlags flags
) {
1124 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1126 if (!i
->symlink_target
)
1129 /* If the basename doesn't match, the caller should add a
1130 * complete new entry for this. */
1132 if (!streq(basename(i
->symlink_target
), i
->name
))
1136 i
->path
= i
->symlink_target
;
1137 i
->symlink_target
= NULL
;
1138 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1140 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1143 static int install_info_traverse(
1144 UnitFileScope scope
,
1146 const char *root_dir
,
1147 const LookupPaths
*paths
,
1148 UnitFileInstallInfo
*start
,
1150 UnitFileInstallInfo
**ret
) {
1152 UnitFileInstallInfo
*i
;
1160 r
= unit_file_search(c
, start
, paths
, root_dir
, flags
);
1165 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1166 /* Follow the symlink */
1168 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1171 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
) && is_config_path(scope
, i
->path
))
1174 r
= install_info_follow(c
, i
, root_dir
, flags
);
1176 _cleanup_free_
char *buffer
= NULL
;
1182 /* Target has a different name, create a new
1183 * install info object for that, and continue
1186 bn
= basename(i
->symlink_target
);
1188 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1189 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1191 _cleanup_free_
char *instance
= NULL
;
1193 r
= unit_name_to_instance(i
->name
, &instance
);
1197 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1204 r
= install_info_add(c
, bn
, NULL
, &i
);
1208 r
= unit_file_search(c
, i
, paths
, root_dir
, flags
);
1213 /* Try again, with the new target we found. */
1222 static int install_info_discover(
1223 UnitFileScope scope
,
1225 const char *root_dir
,
1226 const LookupPaths
*paths
,
1229 UnitFileInstallInfo
**ret
) {
1231 UnitFileInstallInfo
*i
;
1238 r
= install_info_add_auto(c
, name
, &i
);
1242 return install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, ret
);
1245 static int install_info_symlink_alias(
1246 UnitFileInstallInfo
*i
,
1247 const char *config_path
,
1249 UnitFileChange
**changes
,
1250 unsigned *n_changes
) {
1256 assert(config_path
);
1258 STRV_FOREACH(s
, i
->aliases
) {
1259 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1261 q
= install_full_printf(i
, *s
, &dst
);
1265 alias_path
= path_make_absolute(dst
, config_path
);
1269 q
= create_symlink(i
->path
, alias_path
, force
, changes
, n_changes
);
1277 static int install_info_symlink_wants(
1278 UnitFileInstallInfo
*i
,
1279 const char *config_path
,
1283 UnitFileChange
**changes
,
1284 unsigned *n_changes
) {
1286 _cleanup_free_
char *buf
= NULL
;
1292 assert(config_path
);
1294 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1296 /* Don't install any symlink if there's no default
1297 * instance configured */
1299 if (!i
->default_instance
)
1302 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1310 STRV_FOREACH(s
, list
) {
1311 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1313 q
= install_full_printf(i
, *s
, &dst
);
1317 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1322 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1326 q
= create_symlink(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
,
1338 const char *root_dir
,
1340 UnitFileChange
**changes
,
1341 unsigned *n_changes
) {
1343 _cleanup_free_
char *path
= NULL
;
1348 assert(config_path
);
1351 r
= in_search_path(i
->path
, paths
->unit_path
);
1355 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1359 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1362 static int install_info_apply(
1363 UnitFileInstallInfo
*i
,
1364 const LookupPaths
*paths
,
1365 const char *config_path
,
1366 const char *root_dir
,
1368 UnitFileChange
**changes
,
1369 unsigned *n_changes
) {
1375 assert(config_path
);
1377 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1380 r
= install_info_symlink_alias(i
, config_path
, force
, changes
, n_changes
);
1382 q
= install_info_symlink_wants(i
, config_path
, i
->wanted_by
, ".wants/", force
, changes
, n_changes
);
1386 q
= install_info_symlink_wants(i
, config_path
, i
->required_by
, ".requires/", force
, changes
, n_changes
);
1390 q
= install_info_symlink_link(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1397 static int install_context_apply(
1398 UnitFileScope scope
,
1400 const LookupPaths
*paths
,
1401 const char *config_path
,
1402 const char *root_dir
,
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
, root_dir
, paths
, i
, flags
, NULL
);
1434 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1437 q
= install_info_apply(i
, paths
, config_path
, root_dir
, 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
,
1455 const char *root_dir
) {
1457 UnitFileInstallInfo
*i
;
1462 assert(config_path
);
1464 /* Marks all items for removal */
1466 if (ordered_hashmap_isempty(c
->will_process
))
1469 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1473 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1475 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1479 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1483 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1486 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1495 UnitFileScope scope
,
1497 const char *root_dir
,
1500 UnitFileChange
**changes
,
1501 unsigned *n_changes
) {
1503 _cleanup_free_
char *prefix
= NULL
;
1508 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1510 r
= verify_root_dir(scope
, &root_dir
);
1514 r
= get_config_path(scope
, runtime
, root_dir
, &prefix
);
1518 STRV_FOREACH(i
, files
) {
1519 _cleanup_free_
char *path
= NULL
;
1522 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1528 path
= path_make_absolute(*i
, prefix
);
1532 q
= create_symlink("/dev/null", path
, force
, changes
, n_changes
);
1533 if (q
< 0 && r
>= 0)
1540 int unit_file_unmask(
1541 UnitFileScope scope
,
1543 const char *root_dir
,
1545 UnitFileChange
**changes
,
1546 unsigned *n_changes
) {
1548 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1549 _cleanup_free_
char *config_path
= NULL
;
1550 _cleanup_free_
char **todo
= NULL
;
1551 size_t n_todo
= 0, n_allocated
= 0;
1556 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1558 r
= verify_root_dir(scope
, &root_dir
);
1562 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1566 STRV_FOREACH(i
, files
) {
1567 _cleanup_free_
char *path
= NULL
;
1569 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1572 path
= path_make_absolute(*i
, config_path
);
1576 r
= null_or_empty_path(path
);
1584 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1587 todo
[n_todo
++] = *i
;
1593 STRV_FOREACH(i
, todo
) {
1594 _cleanup_free_
char *path
= NULL
;
1596 path
= path_make_absolute(*i
, config_path
);
1600 if (unlink(path
) < 0) {
1601 if (errno
!= -ENOENT
&& r
>= 0)
1604 q
= mark_symlink_for_removal(&remove_symlinks_to
, path
);
1608 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1612 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1620 UnitFileScope scope
,
1622 const char *root_dir
,
1625 UnitFileChange
**changes
,
1626 unsigned *n_changes
) {
1628 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1629 _cleanup_free_
char *config_path
= NULL
;
1630 _cleanup_free_
char **todo
= NULL
;
1631 size_t n_todo
= 0, n_allocated
= 0;
1636 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1638 r
= verify_root_dir(scope
, &root_dir
);
1642 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1646 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1650 STRV_FOREACH(i
, files
) {
1651 _cleanup_free_
char *full
= NULL
;
1655 if (!path_is_absolute(*i
))
1659 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1662 full
= prefix_root(root_dir
, *i
);
1666 if (lstat(full
, &st
) < 0)
1668 if (S_ISLNK(st
.st_mode
))
1670 if (S_ISDIR(st
.st_mode
))
1672 if (!S_ISREG(st
.st_mode
))
1675 q
= in_search_path(*i
, paths
.unit_path
);
1681 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1684 todo
[n_todo
++] = *i
;
1690 STRV_FOREACH(i
, todo
) {
1691 _cleanup_free_
char *path
= NULL
;
1693 path
= path_make_absolute(basename(*i
), config_path
);
1697 q
= create_symlink(*i
, path
, force
, changes
, n_changes
);
1698 if (q
< 0 && r
>= 0)
1705 int unit_file_add_dependency(
1706 UnitFileScope scope
,
1708 const char *root_dir
,
1713 UnitFileChange
**changes
,
1714 unsigned *n_changes
) {
1716 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1717 _cleanup_(install_context_done
) InstallContext c
= {};
1718 _cleanup_free_
char *config_path
= NULL
;
1719 UnitFileInstallInfo
*i
, *target_info
;
1724 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1727 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
1730 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
1733 r
= verify_root_dir(scope
, &root_dir
);
1737 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1741 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1745 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
1748 if (target_info
->type
== UNIT_FILE_TYPE_MASKED
)
1751 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
1753 STRV_FOREACH(f
, files
) {
1756 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1759 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1762 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1764 /* We didn't actually load anything from the unit
1765 * file, but instead just add in our new symlink to
1768 if (dep
== UNIT_WANTS
)
1771 l
= &i
->required_by
;
1774 *l
= strv_new(target_info
->name
, NULL
);
1779 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
1782 int unit_file_enable(
1783 UnitFileScope scope
,
1785 const char *root_dir
,
1788 UnitFileChange
**changes
,
1789 unsigned *n_changes
) {
1791 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1792 _cleanup_(install_context_done
) InstallContext c
= {};
1793 _cleanup_free_
char *config_path
= NULL
;
1794 UnitFileInstallInfo
*i
;
1799 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1801 r
= verify_root_dir(scope
, &root_dir
);
1805 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1809 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1813 STRV_FOREACH(f
, files
) {
1814 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_LOAD
, &i
);
1817 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1820 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1823 /* This will return the number of symlink rules that were
1824 supposed to be created, not the ones actually created. This
1825 is useful to determine whether the passed files had any
1826 installation data at all. */
1828 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
1831 int unit_file_disable(
1832 UnitFileScope scope
,
1834 const char *root_dir
,
1836 UnitFileChange
**changes
,
1837 unsigned *n_changes
) {
1839 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1840 _cleanup_(install_context_done
) InstallContext c
= {};
1841 _cleanup_free_
char *config_path
= NULL
;
1842 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1847 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1849 r
= verify_root_dir(scope
, &root_dir
);
1853 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1857 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1861 STRV_FOREACH(i
, files
) {
1862 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1865 r
= install_info_add(&c
, *i
, NULL
, NULL
);
1870 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, root_dir
);
1874 return remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1877 int unit_file_reenable(
1878 UnitFileScope scope
,
1880 const char *root_dir
,
1883 UnitFileChange
**changes
,
1884 unsigned *n_changes
) {
1890 /* First, we invoke the disable command with only the basename... */
1891 l
= strv_length(files
);
1892 n
= newa(char*, l
+1);
1893 for (i
= 0; i
< l
; i
++)
1894 n
[i
] = basename(files
[i
]);
1897 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
1901 /* But the enable command with the full name */
1902 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
1905 int unit_file_set_default(
1906 UnitFileScope scope
,
1907 const char *root_dir
,
1910 UnitFileChange
**changes
,
1911 unsigned *n_changes
) {
1913 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1914 _cleanup_(install_context_done
) InstallContext c
= {};
1915 _cleanup_free_
char *config_path
= NULL
;
1916 UnitFileInstallInfo
*i
;
1921 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1924 if (unit_name_to_type(name
) != UNIT_TARGET
)
1926 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
1929 r
= verify_root_dir(scope
, &root_dir
);
1933 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1937 r
= get_config_path(scope
, false, root_dir
, &config_path
);
1941 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, name
, 0, &i
);
1944 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1947 path
= strjoina(config_path
, "/" SPECIAL_DEFAULT_TARGET
);
1949 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1952 int unit_file_get_default(
1953 UnitFileScope scope
,
1954 const char *root_dir
,
1957 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1958 _cleanup_(install_context_done
) InstallContext c
= {};
1959 UnitFileInstallInfo
*i
;
1964 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1967 r
= verify_root_dir(scope
, &root_dir
);
1971 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1975 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1978 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1981 n
= strdup(i
->name
);
1989 int unit_file_lookup_state(
1990 UnitFileScope scope
,
1991 const char *root_dir
,
1992 const LookupPaths
*paths
,
1994 UnitFileState
*ret
) {
1996 _cleanup_(install_context_done
) InstallContext c
= {};
1997 UnitFileInstallInfo
*i
;
1998 UnitFileState state
;
2004 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2007 r
= verify_root_dir(scope
, &root_dir
);
2011 r
= install_info_discover(scope
, &c
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2015 /* Shortcut things, if the caller just wants to know if this unit exists. */
2021 case UNIT_FILE_TYPE_MASKED
:
2022 state
= path_startswith(i
->path
, "/run") ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2025 case UNIT_FILE_TYPE_REGULAR
:
2026 r
= find_symlinks_in_scope(scope
, root_dir
, i
->name
, &state
);
2030 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
2031 state
= UNIT_FILE_DISABLED
;
2032 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
2033 state
= UNIT_FILE_INDIRECT
;
2035 state
= UNIT_FILE_STATIC
;
2041 assert_not_reached("Unexpect unit file type.");
2048 int unit_file_get_state(
2049 UnitFileScope scope
,
2050 const char *root_dir
,
2052 UnitFileState
*ret
) {
2054 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2058 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2061 r
= verify_root_dir(scope
, &root_dir
);
2065 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2069 return unit_file_lookup_state(scope
, root_dir
, &paths
, name
, ret
);
2072 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2073 _cleanup_strv_free_
char **files
= NULL
;
2078 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2081 r
= verify_root_dir(scope
, &root_dir
);
2085 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2088 if (scope
== UNIT_FILE_SYSTEM
)
2089 r
= conf_files_list(&files
, ".preset", root_dir
,
2090 "/etc/systemd/system-preset",
2091 "/usr/local/lib/systemd/system-preset",
2092 "/usr/lib/systemd/system-preset",
2093 #ifdef HAVE_SPLIT_USR
2094 "/lib/systemd/system-preset",
2097 else if (scope
== UNIT_FILE_GLOBAL
)
2098 r
= conf_files_list(&files
, ".preset", root_dir
,
2099 "/etc/systemd/user-preset",
2100 "/usr/local/lib/systemd/user-preset",
2101 "/usr/lib/systemd/user-preset",
2104 return 1; /* Default is "enable" */
2109 STRV_FOREACH(p
, files
) {
2110 _cleanup_fclose_
FILE *f
;
2111 char line
[LINE_MAX
];
2113 f
= fopen(*p
, "re");
2115 if (errno
== ENOENT
)
2121 FOREACH_LINE(line
, f
, return -errno
) {
2122 const char *parameter
;
2129 if (strchr(COMMENTS
, *l
))
2132 parameter
= first_word(l
, "enable");
2134 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2135 log_debug("Preset file says enable %s.", name
);
2142 parameter
= first_word(l
, "disable");
2144 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2145 log_debug("Preset file says disable %s.", name
);
2152 log_debug("Couldn't parse line '%s'", l
);
2156 /* Default is "enable" */
2157 log_debug("Preset file doesn't say anything about %s, enabling.", name
);
2161 static int execute_preset(
2162 UnitFileScope scope
,
2163 InstallContext
*plus
,
2164 InstallContext
*minus
,
2165 const LookupPaths
*paths
,
2166 const char *config_path
,
2167 const char *root_dir
,
2169 UnitFilePresetMode mode
,
2171 UnitFileChange
**changes
,
2172 unsigned *n_changes
) {
2179 assert(config_path
);
2181 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2182 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2184 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, root_dir
);
2188 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
2192 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2195 /* Returns number of symlinks that where supposed to be installed. */
2196 q
= install_context_apply(scope
, plus
, paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
2208 static int preset_prepare_one(
2209 UnitFileScope scope
,
2210 InstallContext
*plus
,
2211 InstallContext
*minus
,
2213 const char *root_dir
,
2214 UnitFilePresetMode mode
,
2217 UnitFileInstallInfo
*i
;
2220 if (install_info_find(plus
, name
) ||
2221 install_info_find(minus
, name
))
2224 r
= unit_file_query_preset(scope
, root_dir
, name
);
2229 r
= install_info_discover(scope
, plus
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2233 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
2236 r
= install_info_discover(scope
, minus
, root_dir
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2241 int unit_file_preset(
2242 UnitFileScope scope
,
2244 const char *root_dir
,
2246 UnitFilePresetMode mode
,
2248 UnitFileChange
**changes
,
2249 unsigned *n_changes
) {
2251 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2252 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2253 _cleanup_free_
char *config_path
= NULL
;
2258 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2259 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2261 r
= verify_root_dir(scope
, &root_dir
);
2265 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2269 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
2273 STRV_FOREACH(i
, files
) {
2274 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2277 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, *i
);
2282 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, files
, mode
, force
, changes
, n_changes
);
2285 int unit_file_preset_all(
2286 UnitFileScope scope
,
2288 const char *root_dir
,
2289 UnitFilePresetMode mode
,
2291 UnitFileChange
**changes
,
2292 unsigned *n_changes
) {
2294 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2295 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2296 _cleanup_free_
char *config_path
= NULL
;
2301 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2302 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2304 r
= verify_root_dir(scope
, &root_dir
);
2308 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2312 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
2316 STRV_FOREACH(i
, paths
.unit_path
) {
2317 _cleanup_closedir_
DIR *d
= NULL
;
2318 _cleanup_free_
char *units_dir
;
2321 units_dir
= path_join(root_dir
, *i
, NULL
);
2325 d
= opendir(units_dir
);
2327 if (errno
== ENOENT
)
2333 FOREACH_DIRENT(de
, d
, return -errno
) {
2335 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2338 dirent_ensure_type(d
, de
);
2340 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2343 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, de
->d_name
);
2349 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, NULL
, mode
, force
, changes
, n_changes
);
2352 static void unit_file_list_free_one(UnitFileList
*f
) {
2360 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2363 while ((i
= hashmap_steal_first(h
)))
2364 unit_file_list_free_one(i
);
2366 return hashmap_free(h
);
2369 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2371 int unit_file_get_list(
2372 UnitFileScope scope
,
2373 const char *root_dir
,
2376 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2381 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2384 r
= verify_root_dir(scope
, &root_dir
);
2388 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2392 STRV_FOREACH(i
, paths
.unit_path
) {
2393 _cleanup_closedir_
DIR *d
= NULL
;
2394 _cleanup_free_
char *units_dir
;
2397 units_dir
= path_join(root_dir
, *i
, NULL
);
2401 d
= opendir(units_dir
);
2403 if (errno
== ENOENT
)
2409 FOREACH_DIRENT(de
, d
, return -errno
) {
2410 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2412 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2415 if (hashmap_get(h
, de
->d_name
))
2418 dirent_ensure_type(d
, de
);
2420 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2423 f
= new0(UnitFileList
, 1);
2427 f
->path
= path_make_absolute(de
->d_name
, units_dir
);
2431 r
= unit_file_lookup_state(scope
, root_dir
, &paths
, basename(f
->path
), &f
->state
);
2433 f
->state
= UNIT_FILE_BAD
;
2435 r
= hashmap_put(h
, basename(f
->path
), f
);
2439 f
= NULL
; /* prevent cleanup */
2446 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2447 [UNIT_FILE_ENABLED
] = "enabled",
2448 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2449 [UNIT_FILE_LINKED
] = "linked",
2450 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
2451 [UNIT_FILE_MASKED
] = "masked",
2452 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
2453 [UNIT_FILE_STATIC
] = "static",
2454 [UNIT_FILE_DISABLED
] = "disabled",
2455 [UNIT_FILE_INDIRECT
] = "indirect",
2456 [UNIT_FILE_BAD
] = "bad",
2459 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
2461 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
2462 [UNIT_FILE_SYMLINK
] = "symlink",
2463 [UNIT_FILE_UNLINK
] = "unlink",
2466 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
2468 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
2469 [UNIT_FILE_PRESET_FULL
] = "full",
2470 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
2471 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
2474 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);