1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty <of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "alloc-util.h"
29 #include "conf-files.h"
30 #include "conf-parser.h"
31 #include "dirent-util.h"
36 #include "install-printf.h"
39 #include "path-lookup.h"
40 #include "path-util.h"
43 #include "stat-util.h"
44 #include "string-table.h"
45 #include "string-util.h"
47 #include "unit-name.h"
50 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
52 typedef enum SearchFlags
{
54 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 2,
58 OrderedHashmap
*will_process
;
59 OrderedHashmap
*have_processed
;
62 static int in_search_path(const char *path
, char **search
) {
63 _cleanup_free_
char *parent
= NULL
;
68 parent
= dirname_malloc(path
);
72 STRV_FOREACH(i
, search
)
73 if (path_equal(parent
, *i
))
79 static int get_config_path(UnitFileScope scope
, bool runtime
, const char *root_dir
, char **ret
) {
84 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
87 /* This determines where we shall create or remove our
88 * installation ("configuration") symlinks */
92 case UNIT_FILE_SYSTEM
:
95 p
= path_join(root_dir
, "/run/systemd/system", NULL
);
97 p
= path_join(root_dir
, SYSTEM_CONFIG_UNIT_PATH
, NULL
);
100 case UNIT_FILE_GLOBAL
:
106 p
= strdup("/run/systemd/user");
108 p
= strdup(USER_CONFIG_UNIT_PATH
);
117 r
= user_runtime_dir(&p
);
119 r
= user_config_home(&p
);
128 assert_not_reached("Bad scope");
138 static bool is_config_path(UnitFileScope scope
, const char *path
) {
142 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
145 /* Checks whether the specified path is intended for
146 * configuration or is outside of it */
150 case UNIT_FILE_SYSTEM
:
151 case UNIT_FILE_GLOBAL
:
152 return path_startswith(path
, "/etc") ||
153 path_startswith(path
, SYSTEM_CONFIG_UNIT_PATH
) ||
154 path_startswith(path
, "/run");
157 case UNIT_FILE_USER
: {
158 _cleanup_free_
char *p
= NULL
;
160 r
= user_config_home(&p
);
163 if (r
> 0 && path_startswith(path
, p
))
168 r
= user_runtime_dir(&p
);
171 if (r
> 0 && path_startswith(path
, p
))
178 assert_not_reached("Bad scope");
183 static int verify_root_dir(UnitFileScope scope
, const char **root_dir
) {
188 /* Verifies that the specified root directory to operate on
189 * makes sense. Reset it to NULL if it is the root directory
192 if (isempty(*root_dir
) || path_equal(*root_dir
, "/")) {
197 if (scope
!= UNIT_FILE_SYSTEM
)
200 r
= is_dir(*root_dir
, true);
209 int unit_file_changes_add(
210 UnitFileChange
**changes
,
212 UnitFileChangeType type
,
214 const char *source
) {
220 assert(!changes
== !n_changes
);
225 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
233 c
[i
].path
= strdup(path
);
237 path_kill_slashes(c
[i
].path
);
240 c
[i
].source
= strdup(source
);
246 path_kill_slashes(c
[i
].path
);
254 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
257 assert(changes
|| n_changes
== 0);
262 for (i
= 0; i
< n_changes
; i
++) {
263 free(changes
[i
].path
);
264 free(changes
[i
].source
);
270 static int create_symlink(
271 const char *old_path
,
272 const char *new_path
,
274 UnitFileChange
**changes
,
275 unsigned *n_changes
) {
277 _cleanup_free_
char *dest
= NULL
;
283 /* Actually create a symlink, and remember that we did. Is
284 * smart enough to check if there's already a valid symlink in
287 mkdir_parents_label(new_path
, 0755);
289 if (symlink(old_path
, new_path
) >= 0) {
290 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
297 r
= readlink_malloc(new_path
, &dest
);
301 if (path_equal(dest
, old_path
))
307 r
= symlink_atomic(old_path
, new_path
);
311 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
312 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
317 static int mark_symlink_for_removal(
318 Set
**remove_symlinks_to
,
326 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
334 path_kill_slashes(n
);
336 r
= set_consume(*remove_symlinks_to
, n
);
345 static int remove_marked_symlinks_fd(
346 Set
*remove_symlinks_to
,
349 const char *config_path
,
351 UnitFileChange
**changes
,
352 unsigned *n_changes
) {
354 _cleanup_closedir_
DIR *d
= NULL
;
358 assert(remove_symlinks_to
);
372 FOREACH_DIRENT(de
, d
, return -errno
) {
374 dirent_ensure_type(d
, de
);
376 if (de
->d_type
== DT_DIR
) {
377 _cleanup_free_
char *p
= NULL
;
380 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
390 p
= path_make_absolute(de
->d_name
, path
);
396 /* This will close nfd, regardless whether it succeeds or not */
397 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, restart
, changes
, n_changes
);
401 } else if (de
->d_type
== DT_LNK
) {
402 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
406 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
409 p
= path_make_absolute(de
->d_name
, path
);
413 q
= readlink_malloc(p
, &dest
);
423 /* We remove all links pointing to a file or
424 * path that is marked, as well as all files
425 * sharing the same name as a file that is
429 set_contains(remove_symlinks_to
, dest
) ||
430 set_contains(remove_symlinks_to
, basename(dest
)) ||
431 set_contains(remove_symlinks_to
, de
->d_name
);
436 if (unlink(p
) < 0 && errno
!= ENOENT
) {
442 path_kill_slashes(p
);
443 (void) rmdir_parents(p
, config_path
);
445 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
447 q
= mark_symlink_for_removal(&remove_symlinks_to
, p
);
458 static int remove_marked_symlinks(
459 Set
*remove_symlinks_to
,
460 const char *config_path
,
461 UnitFileChange
**changes
,
462 unsigned *n_changes
) {
464 _cleanup_close_
int fd
= -1;
470 if (set_size(remove_symlinks_to
) <= 0)
473 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
481 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
485 /* This takes possession of cfd and closes it */
486 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, &restart
, changes
, n_changes
);
494 static int find_symlinks_fd(
495 const char *root_dir
,
499 const char *config_path
,
500 bool *same_name_link
) {
502 _cleanup_closedir_
DIR *d
= NULL
;
510 assert(same_name_link
);
518 FOREACH_DIRENT(de
, d
, return -errno
) {
520 dirent_ensure_type(d
, de
);
522 if (de
->d_type
== DT_DIR
) {
523 _cleanup_free_
char *p
= NULL
;
526 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
536 p
= path_make_absolute(de
->d_name
, path
);
542 /* This will close nfd, regardless whether it succeeds or not */
543 q
= find_symlinks_fd(root_dir
, name
, nfd
, p
, config_path
, same_name_link
);
549 } else if (de
->d_type
== DT_LNK
) {
550 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
551 bool found_path
, found_dest
, b
= false;
554 /* Acquire symlink name */
555 p
= path_make_absolute(de
->d_name
, path
);
559 /* Acquire symlink destination */
560 q
= readlink_malloc(p
, &dest
);
570 if (!path_is_absolute(dest
)) {
573 x
= prefix_root(root_dir
, dest
);
581 /* Check if the symlink itself matches what we
583 if (path_is_absolute(name
))
584 found_path
= path_equal(p
, name
);
586 found_path
= streq(de
->d_name
, name
);
588 /* Check if what the symlink points to
589 * matches what we are looking for */
590 if (path_is_absolute(name
))
591 found_dest
= path_equal(dest
, name
);
593 found_dest
= streq(basename(dest
), name
);
595 if (found_path
&& found_dest
) {
596 _cleanup_free_
char *t
= NULL
;
598 /* Filter out same name links in the main
600 t
= path_make_absolute(name
, config_path
);
604 b
= path_equal(t
, p
);
608 *same_name_link
= true;
609 else if (found_path
|| found_dest
)
617 static int find_symlinks(
618 const char *root_dir
,
620 const char *config_path
,
621 bool *same_name_link
) {
627 assert(same_name_link
);
629 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
636 /* This takes possession of fd and closes it */
637 return find_symlinks_fd(root_dir
, name
, fd
, config_path
, config_path
, same_name_link
);
640 static int find_symlinks_in_scope(
642 const char *root_dir
,
644 UnitFileState
*state
) {
646 _cleanup_free_
char *normal_path
= NULL
, *runtime_path
= NULL
;
647 bool same_name_link_runtime
= false, same_name_link
= false;
651 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
654 /* First look in the normal config path */
655 r
= get_config_path(scope
, false, root_dir
, &normal_path
);
659 r
= find_symlinks(root_dir
, name
, normal_path
, &same_name_link
);
663 *state
= UNIT_FILE_ENABLED
;
667 /* Then look in runtime config path */
668 r
= get_config_path(scope
, true, root_dir
, &runtime_path
);
672 r
= find_symlinks(root_dir
, name
, runtime_path
, &same_name_link_runtime
);
676 *state
= UNIT_FILE_ENABLED_RUNTIME
;
680 /* Hmm, we didn't find it, but maybe we found the same name
682 if (same_name_link
) {
683 *state
= UNIT_FILE_LINKED
;
686 if (same_name_link_runtime
) {
687 *state
= UNIT_FILE_LINKED_RUNTIME
;
694 static void install_info_free(UnitFileInstallInfo
*i
) {
701 strv_free(i
->aliases
);
702 strv_free(i
->wanted_by
);
703 strv_free(i
->required_by
);
705 free(i
->default_instance
);
706 free(i
->symlink_target
);
710 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
711 UnitFileInstallInfo
*i
;
716 while ((i
= ordered_hashmap_steal_first(m
)))
717 install_info_free(i
);
719 return ordered_hashmap_free(m
);
722 static void install_context_done(InstallContext
*c
) {
725 c
->will_process
= install_info_hashmap_free(c
->will_process
);
726 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
729 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
730 UnitFileInstallInfo
*i
;
732 i
= ordered_hashmap_get(c
->have_processed
, name
);
736 return ordered_hashmap_get(c
->will_process
, name
);
739 static int install_info_add(
743 UnitFileInstallInfo
**ret
) {
745 UnitFileInstallInfo
*i
= NULL
;
749 assert(name
|| path
);
752 name
= basename(path
);
754 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
757 i
= install_info_find(c
, name
);
764 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
768 i
= new0(UnitFileInstallInfo
, 1);
771 i
->type
= _UNIT_FILE_TYPE_INVALID
;
773 i
->name
= strdup(name
);
780 i
->path
= strdup(path
);
787 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
797 install_info_free(i
);
801 static int install_info_add_auto(
803 const char *name_or_path
,
804 UnitFileInstallInfo
**ret
) {
807 assert(name_or_path
);
809 if (path_is_absolute(name_or_path
))
810 return install_info_add(c
, NULL
, name_or_path
, ret
);
812 return install_info_add(c
, name_or_path
, NULL
, ret
);
815 static int config_parse_also(
817 const char *filename
,
820 unsigned section_line
,
827 UnitFileInstallInfo
*i
= userdata
;
828 InstallContext
*c
= data
;
836 _cleanup_free_
char *word
= NULL
;
838 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
844 r
= install_info_add(c
, word
, NULL
, NULL
);
848 r
= strv_push(&i
->also
, word
);
858 static int config_parse_default_instance(
860 const char *filename
,
863 unsigned section_line
,
870 UnitFileInstallInfo
*i
= data
;
878 r
= install_full_printf(i
, rvalue
, &printed
);
882 if (!unit_instance_is_valid(printed
)) {
887 free(i
->default_instance
);
888 i
->default_instance
= printed
;
893 static int unit_file_load(
895 UnitFileInstallInfo
*info
,
897 const char *root_dir
,
900 const ConfigTableItem items
[] = {
901 { "Install", "Alias", config_parse_strv
, 0, &info
->aliases
},
902 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
903 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
904 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
905 { "Install", "Also", config_parse_also
, 0, c
},
909 _cleanup_fclose_
FILE *f
= NULL
;
910 _cleanup_close_
int fd
= -1;
918 path
= prefix_roota(root_dir
, path
);
920 if (!(flags
& SEARCH_LOAD
)) {
921 r
= lstat(path
, &st
);
925 if (null_or_empty(&st
))
926 info
->type
= UNIT_FILE_TYPE_MASKED
;
927 else if (S_ISREG(st
.st_mode
))
928 info
->type
= UNIT_FILE_TYPE_REGULAR
;
929 else if (S_ISLNK(st
.st_mode
))
931 else if (S_ISDIR(st
.st_mode
))
939 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
942 if (fstat(fd
, &st
) < 0)
944 if (null_or_empty(&st
)) {
945 info
->type
= UNIT_FILE_TYPE_MASKED
;
948 if (S_ISDIR(st
.st_mode
))
950 if (!S_ISREG(st
.st_mode
))
953 f
= fdopen(fd
, "re");
958 r
= config_parse(NULL
, path
, f
,
960 config_item_table_lookup
, items
,
961 true, true, false, info
);
965 info
->type
= UNIT_FILE_TYPE_REGULAR
;
968 (int) strv_length(info
->aliases
) +
969 (int) strv_length(info
->wanted_by
) +
970 (int) strv_length(info
->required_by
);
973 static int unit_file_load_or_readlink(
975 UnitFileInstallInfo
*info
,
977 const char *root_dir
,
980 _cleanup_free_
char *np
= NULL
;
983 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
987 /* This is a symlink, let's read it. */
989 r
= readlink_and_make_absolute_root(root_dir
, path
, &np
);
993 if (path_equal(np
, "/dev/null"))
994 info
->type
= UNIT_FILE_TYPE_MASKED
;
1001 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1003 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1006 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1008 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1011 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1013 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1018 /* Enforce that the symlink destination does not
1019 * change the unit file type. */
1021 a
= unit_name_to_type(info
->name
);
1022 b
= unit_name_to_type(bn
);
1023 if (a
< 0 || b
< 0 || a
!= b
)
1026 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1027 info
->symlink_target
= np
;
1034 static int unit_file_search(
1036 UnitFileInstallInfo
*info
,
1037 const LookupPaths
*paths
,
1038 const char *root_dir
,
1039 SearchFlags flags
) {
1048 /* Was this unit already loaded? */
1049 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1053 return unit_file_load_or_readlink(c
, info
, info
->path
, root_dir
, flags
);
1057 STRV_FOREACH(p
, paths
->unit_path
) {
1058 _cleanup_free_
char *path
= NULL
;
1060 path
= strjoin(*p
, "/", info
->name
, NULL
);
1064 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1075 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1077 /* Unit file doesn't exist, however instance
1078 * enablement was requested. We will check if it is
1079 * possible to load template unit file. */
1081 _cleanup_free_
char *template = NULL
;
1083 r
= unit_name_template(info
->name
, &template);
1087 STRV_FOREACH(p
, paths
->unit_path
) {
1088 _cleanup_free_
char *path
= NULL
;
1090 path
= strjoin(*p
, "/", template, NULL
);
1094 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1109 static int install_info_follow(
1111 UnitFileInstallInfo
*i
,
1112 const char *root_dir
,
1113 SearchFlags flags
) {
1118 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1120 if (!i
->symlink_target
)
1123 /* If the basename doesn't match, the caller should add a
1124 * complete new entry for this. */
1126 if (!streq(basename(i
->symlink_target
), i
->name
))
1130 i
->path
= i
->symlink_target
;
1131 i
->symlink_target
= NULL
;
1132 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1134 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1137 static int install_info_traverse(
1138 UnitFileScope scope
,
1140 const char *root_dir
,
1141 const LookupPaths
*paths
,
1142 UnitFileInstallInfo
*start
,
1144 UnitFileInstallInfo
**ret
) {
1146 UnitFileInstallInfo
*i
;
1154 r
= unit_file_search(c
, start
, paths
, root_dir
, flags
);
1159 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1160 /* Follow the symlink */
1162 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1165 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
) && is_config_path(scope
, i
->path
))
1168 r
= install_info_follow(c
, i
, root_dir
, flags
);
1170 _cleanup_free_
char *buffer
= NULL
;
1176 /* Target has a different name, create a new
1177 * install info object for that, and continue
1180 bn
= basename(i
->symlink_target
);
1182 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1183 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1185 _cleanup_free_
char *instance
= NULL
;
1187 r
= unit_name_to_instance(i
->name
, &instance
);
1191 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1198 r
= install_info_add(c
, bn
, NULL
, &i
);
1202 r
= unit_file_search(c
, i
, paths
, root_dir
, flags
);
1207 /* Try again, with the new target we found. */
1216 static int install_info_discover(
1217 UnitFileScope scope
,
1219 const char *root_dir
,
1220 const LookupPaths
*paths
,
1223 UnitFileInstallInfo
**ret
) {
1225 UnitFileInstallInfo
*i
;
1232 r
= install_info_add_auto(c
, name
, &i
);
1236 return install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, ret
);
1239 static int install_info_symlink_alias(
1240 UnitFileInstallInfo
*i
,
1241 const char *config_path
,
1243 UnitFileChange
**changes
,
1244 unsigned *n_changes
) {
1250 assert(config_path
);
1252 STRV_FOREACH(s
, i
->aliases
) {
1253 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1255 q
= install_full_printf(i
, *s
, &dst
);
1259 alias_path
= path_make_absolute(dst
, config_path
);
1263 q
= create_symlink(i
->path
, alias_path
, force
, changes
, n_changes
);
1271 static int install_info_symlink_wants(
1272 UnitFileInstallInfo
*i
,
1273 const char *config_path
,
1277 UnitFileChange
**changes
,
1278 unsigned *n_changes
) {
1280 _cleanup_free_
char *buf
= NULL
;
1286 assert(config_path
);
1288 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1290 /* Don't install any symlink if there's no default
1291 * instance configured */
1293 if (!i
->default_instance
)
1296 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1304 STRV_FOREACH(s
, list
) {
1305 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1307 q
= install_full_printf(i
, *s
, &dst
);
1311 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1316 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1320 q
= create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1328 static int install_info_symlink_link(
1329 UnitFileInstallInfo
*i
,
1330 const LookupPaths
*paths
,
1331 const char *config_path
,
1332 const char *root_dir
,
1334 UnitFileChange
**changes
,
1335 unsigned *n_changes
) {
1337 _cleanup_free_
char *path
= NULL
;
1342 assert(config_path
);
1345 r
= in_search_path(i
->path
, paths
->unit_path
);
1349 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1353 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1356 static int install_info_apply(
1357 UnitFileInstallInfo
*i
,
1358 const LookupPaths
*paths
,
1359 const char *config_path
,
1360 const char *root_dir
,
1362 UnitFileChange
**changes
,
1363 unsigned *n_changes
) {
1369 assert(config_path
);
1371 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1374 r
= install_info_symlink_alias(i
, config_path
, force
, changes
, n_changes
);
1376 q
= install_info_symlink_wants(i
, config_path
, i
->wanted_by
, ".wants/", force
, changes
, n_changes
);
1380 q
= install_info_symlink_wants(i
, config_path
, i
->required_by
, ".requires/", force
, changes
, n_changes
);
1384 q
= install_info_symlink_link(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1391 static int install_context_apply(
1392 UnitFileScope scope
,
1394 const LookupPaths
*paths
,
1395 const char *config_path
,
1396 const char *root_dir
,
1399 UnitFileChange
**changes
,
1400 unsigned *n_changes
) {
1402 UnitFileInstallInfo
*i
;
1407 assert(config_path
);
1409 if (ordered_hashmap_isempty(c
->will_process
))
1412 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1417 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1420 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1424 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, NULL
);
1428 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1431 q
= install_info_apply(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1443 static int install_context_mark_for_removal(
1444 UnitFileScope scope
,
1446 const LookupPaths
*paths
,
1447 Set
**remove_symlinks_to
,
1448 const char *config_path
,
1449 const char *root_dir
) {
1451 UnitFileInstallInfo
*i
;
1456 assert(config_path
);
1458 /* Marks all items for removal */
1460 if (ordered_hashmap_isempty(c
->will_process
))
1463 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1467 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1469 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1473 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1477 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1480 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1489 UnitFileScope scope
,
1491 const char *root_dir
,
1494 UnitFileChange
**changes
,
1495 unsigned *n_changes
) {
1497 _cleanup_free_
char *prefix
= NULL
;
1502 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1504 r
= verify_root_dir(scope
, &root_dir
);
1508 r
= get_config_path(scope
, runtime
, root_dir
, &prefix
);
1512 STRV_FOREACH(i
, files
) {
1513 _cleanup_free_
char *path
= NULL
;
1516 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1522 path
= path_make_absolute(*i
, prefix
);
1526 q
= create_symlink("/dev/null", path
, force
, changes
, n_changes
);
1527 if (q
< 0 && r
>= 0)
1534 int unit_file_unmask(
1535 UnitFileScope scope
,
1537 const char *root_dir
,
1539 UnitFileChange
**changes
,
1540 unsigned *n_changes
) {
1542 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1543 _cleanup_free_
char *config_path
= NULL
;
1544 _cleanup_free_
char **todo
= NULL
;
1545 size_t n_todo
= 0, n_allocated
= 0;
1550 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1552 r
= verify_root_dir(scope
, &root_dir
);
1556 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1560 STRV_FOREACH(i
, files
) {
1561 _cleanup_free_
char *path
= NULL
;
1563 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1566 path
= path_make_absolute(*i
, config_path
);
1570 r
= null_or_empty_path(path
);
1578 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1581 todo
[n_todo
++] = *i
;
1587 STRV_FOREACH(i
, todo
) {
1588 _cleanup_free_
char *path
= NULL
;
1590 path
= path_make_absolute(*i
, config_path
);
1594 if (unlink(path
) < 0) {
1595 if (errno
!= -ENOENT
&& r
>= 0)
1598 q
= mark_symlink_for_removal(&remove_symlinks_to
, path
);
1602 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1606 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1614 UnitFileScope scope
,
1616 const char *root_dir
,
1619 UnitFileChange
**changes
,
1620 unsigned *n_changes
) {
1622 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1623 _cleanup_free_
char *config_path
= NULL
;
1624 _cleanup_free_
char **todo
= NULL
;
1625 size_t n_todo
= 0, n_allocated
= 0;
1630 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1632 r
= verify_root_dir(scope
, &root_dir
);
1636 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1640 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1644 STRV_FOREACH(i
, files
) {
1645 _cleanup_free_
char *full
= NULL
;
1649 if (!path_is_absolute(*i
))
1653 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1656 full
= prefix_root(root_dir
, *i
);
1660 if (lstat(full
, &st
) < 0)
1662 if (S_ISLNK(st
.st_mode
))
1664 if (S_ISDIR(st
.st_mode
))
1666 if (!S_ISREG(st
.st_mode
))
1669 q
= in_search_path(*i
, paths
.unit_path
);
1675 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1678 todo
[n_todo
++] = *i
;
1684 STRV_FOREACH(i
, todo
) {
1685 _cleanup_free_
char *path
= NULL
;
1687 path
= path_make_absolute(basename(*i
), config_path
);
1691 q
= create_symlink(*i
, path
, force
, changes
, n_changes
);
1692 if (q
< 0 && r
>= 0)
1699 int unit_file_add_dependency(
1700 UnitFileScope scope
,
1702 const char *root_dir
,
1707 UnitFileChange
**changes
,
1708 unsigned *n_changes
) {
1710 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1711 _cleanup_(install_context_done
) InstallContext c
= {};
1712 _cleanup_free_
char *config_path
= NULL
;
1713 UnitFileInstallInfo
*i
, *target_info
;
1718 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1721 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
1724 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
1727 r
= verify_root_dir(scope
, &root_dir
);
1731 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1735 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1739 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
1742 if (target_info
->type
== UNIT_FILE_TYPE_MASKED
)
1745 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
1747 STRV_FOREACH(f
, files
) {
1750 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1753 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1756 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1758 /* We didn't actually load anything from the unit
1759 * file, but instead just add in our new symlink to
1762 if (dep
== UNIT_WANTS
)
1765 l
= &i
->required_by
;
1768 *l
= strv_new(target_info
->name
, NULL
);
1773 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
1776 int unit_file_enable(
1777 UnitFileScope scope
,
1779 const char *root_dir
,
1782 UnitFileChange
**changes
,
1783 unsigned *n_changes
) {
1785 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1786 _cleanup_(install_context_done
) InstallContext c
= {};
1787 _cleanup_free_
char *config_path
= NULL
;
1788 UnitFileInstallInfo
*i
;
1793 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1795 r
= verify_root_dir(scope
, &root_dir
);
1799 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1803 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1807 STRV_FOREACH(f
, files
) {
1808 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_LOAD
, &i
);
1811 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1814 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1817 /* This will return the number of symlink rules that were
1818 supposed to be created, not the ones actually created. This
1819 is useful to determine whether the passed files had any
1820 installation data at all. */
1822 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
1825 int unit_file_disable(
1826 UnitFileScope scope
,
1828 const char *root_dir
,
1830 UnitFileChange
**changes
,
1831 unsigned *n_changes
) {
1833 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1834 _cleanup_(install_context_done
) InstallContext c
= {};
1835 _cleanup_free_
char *config_path
= NULL
;
1836 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1841 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1843 r
= verify_root_dir(scope
, &root_dir
);
1847 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1851 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1855 STRV_FOREACH(i
, files
) {
1856 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1859 r
= install_info_add(&c
, *i
, NULL
, NULL
);
1864 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, root_dir
);
1868 return remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1871 int unit_file_reenable(
1872 UnitFileScope scope
,
1874 const char *root_dir
,
1877 UnitFileChange
**changes
,
1878 unsigned *n_changes
) {
1884 /* First, we invoke the disable command with only the basename... */
1885 l
= strv_length(files
);
1886 n
= newa(char*, l
+1);
1887 for (i
= 0; i
< l
; i
++)
1888 n
[i
] = basename(files
[i
]);
1891 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
1895 /* But the enable command with the full name */
1896 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
1899 int unit_file_set_default(
1900 UnitFileScope scope
,
1901 const char *root_dir
,
1904 UnitFileChange
**changes
,
1905 unsigned *n_changes
) {
1907 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1908 _cleanup_(install_context_done
) InstallContext c
= {};
1909 _cleanup_free_
char *config_path
= NULL
;
1910 UnitFileInstallInfo
*i
;
1915 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1918 if (unit_name_to_type(name
) != UNIT_TARGET
)
1920 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
1923 r
= verify_root_dir(scope
, &root_dir
);
1927 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1931 r
= get_config_path(scope
, false, root_dir
, &config_path
);
1935 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, name
, 0, &i
);
1938 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1941 path
= strjoina(config_path
, "/" SPECIAL_DEFAULT_TARGET
);
1943 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1946 int unit_file_get_default(
1947 UnitFileScope scope
,
1948 const char *root_dir
,
1951 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1952 _cleanup_(install_context_done
) InstallContext c
= {};
1953 UnitFileInstallInfo
*i
;
1958 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1961 r
= verify_root_dir(scope
, &root_dir
);
1965 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1969 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1972 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1975 n
= strdup(i
->name
);
1983 int unit_file_lookup_state(
1984 UnitFileScope scope
,
1985 const char *root_dir
,
1986 const LookupPaths
*paths
,
1988 UnitFileState
*ret
) {
1990 _cleanup_(install_context_done
) InstallContext c
= {};
1991 UnitFileInstallInfo
*i
;
1992 UnitFileState state
;
1998 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2001 r
= verify_root_dir(scope
, &root_dir
);
2005 r
= install_info_discover(scope
, &c
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2009 /* Shortcut things, if the caller just wants to know if this unit exists. */
2015 case UNIT_FILE_TYPE_MASKED
:
2016 state
= path_startswith(i
->path
, "/run") ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2019 case UNIT_FILE_TYPE_REGULAR
:
2020 r
= find_symlinks_in_scope(scope
, root_dir
, i
->name
, &state
);
2024 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
2025 state
= UNIT_FILE_DISABLED
;
2026 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
2027 state
= UNIT_FILE_INDIRECT
;
2029 state
= UNIT_FILE_STATIC
;
2035 assert_not_reached("Unexpect unit file type.");
2042 int unit_file_get_state(
2043 UnitFileScope scope
,
2044 const char *root_dir
,
2046 UnitFileState
*ret
) {
2048 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2052 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2055 r
= verify_root_dir(scope
, &root_dir
);
2059 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2063 return unit_file_lookup_state(scope
, root_dir
, &paths
, name
, ret
);
2066 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2067 _cleanup_strv_free_
char **files
= NULL
;
2072 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2075 r
= verify_root_dir(scope
, &root_dir
);
2079 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2082 if (scope
== UNIT_FILE_SYSTEM
)
2083 r
= conf_files_list(&files
, ".preset", root_dir
,
2084 "/etc/systemd/system-preset",
2085 "/usr/local/lib/systemd/system-preset",
2086 "/usr/lib/systemd/system-preset",
2087 #ifdef HAVE_SPLIT_USR
2088 "/lib/systemd/system-preset",
2091 else if (scope
== UNIT_FILE_GLOBAL
)
2092 r
= conf_files_list(&files
, ".preset", root_dir
,
2093 "/etc/systemd/user-preset",
2094 "/usr/local/lib/systemd/user-preset",
2095 "/usr/lib/systemd/user-preset",
2098 return 1; /* Default is "enable" */
2103 STRV_FOREACH(p
, files
) {
2104 _cleanup_fclose_
FILE *f
;
2105 char line
[LINE_MAX
];
2107 f
= fopen(*p
, "re");
2109 if (errno
== ENOENT
)
2115 FOREACH_LINE(line
, f
, return -errno
) {
2116 const char *parameter
;
2123 if (strchr(COMMENTS
, *l
))
2126 parameter
= first_word(l
, "enable");
2128 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2129 log_debug("Preset file says enable %s.", name
);
2136 parameter
= first_word(l
, "disable");
2138 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2139 log_debug("Preset file says disable %s.", name
);
2146 log_debug("Couldn't parse line '%s'", l
);
2150 /* Default is "enable" */
2151 log_debug("Preset file doesn't say anything about %s, enabling.", name
);
2155 static int execute_preset(
2156 UnitFileScope scope
,
2157 InstallContext
*plus
,
2158 InstallContext
*minus
,
2159 const LookupPaths
*paths
,
2160 const char *config_path
,
2161 const char *root_dir
,
2163 UnitFilePresetMode mode
,
2165 UnitFileChange
**changes
,
2166 unsigned *n_changes
) {
2173 assert(config_path
);
2175 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2176 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2178 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, root_dir
);
2182 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
2186 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2189 /* Returns number of symlinks that where supposed to be installed. */
2190 q
= install_context_apply(scope
, plus
, paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
2202 static int preset_prepare_one(
2203 UnitFileScope scope
,
2204 InstallContext
*plus
,
2205 InstallContext
*minus
,
2207 const char *root_dir
,
2208 UnitFilePresetMode mode
,
2211 UnitFileInstallInfo
*i
;
2214 if (install_info_find(plus
, name
) ||
2215 install_info_find(minus
, name
))
2218 r
= unit_file_query_preset(scope
, root_dir
, name
);
2223 r
= install_info_discover(scope
, plus
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2227 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
2230 r
= install_info_discover(scope
, minus
, root_dir
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2235 int unit_file_preset(
2236 UnitFileScope scope
,
2238 const char *root_dir
,
2240 UnitFilePresetMode mode
,
2242 UnitFileChange
**changes
,
2243 unsigned *n_changes
) {
2245 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2246 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2247 _cleanup_free_
char *config_path
= NULL
;
2252 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2253 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2255 r
= verify_root_dir(scope
, &root_dir
);
2259 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2263 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
2267 STRV_FOREACH(i
, files
) {
2268 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2271 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, *i
);
2276 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, files
, mode
, force
, changes
, n_changes
);
2279 int unit_file_preset_all(
2280 UnitFileScope scope
,
2282 const char *root_dir
,
2283 UnitFilePresetMode mode
,
2285 UnitFileChange
**changes
,
2286 unsigned *n_changes
) {
2288 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2289 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2290 _cleanup_free_
char *config_path
= NULL
;
2295 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2296 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2298 r
= verify_root_dir(scope
, &root_dir
);
2302 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2306 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
2310 STRV_FOREACH(i
, paths
.unit_path
) {
2311 _cleanup_closedir_
DIR *d
= NULL
;
2312 _cleanup_free_
char *units_dir
;
2315 units_dir
= path_join(root_dir
, *i
, NULL
);
2319 d
= opendir(units_dir
);
2321 if (errno
== ENOENT
)
2327 FOREACH_DIRENT(de
, d
, return -errno
) {
2329 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2332 dirent_ensure_type(d
, de
);
2334 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2337 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, de
->d_name
);
2343 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, NULL
, mode
, force
, changes
, n_changes
);
2346 static void unit_file_list_free_one(UnitFileList
*f
) {
2354 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2357 while ((i
= hashmap_steal_first(h
)))
2358 unit_file_list_free_one(i
);
2360 return hashmap_free(h
);
2363 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2365 int unit_file_get_list(
2366 UnitFileScope scope
,
2367 const char *root_dir
,
2370 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2375 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2378 r
= verify_root_dir(scope
, &root_dir
);
2382 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2386 STRV_FOREACH(i
, paths
.unit_path
) {
2387 _cleanup_closedir_
DIR *d
= NULL
;
2388 _cleanup_free_
char *units_dir
;
2391 units_dir
= path_join(root_dir
, *i
, NULL
);
2395 d
= opendir(units_dir
);
2397 if (errno
== ENOENT
)
2403 FOREACH_DIRENT(de
, d
, return -errno
) {
2404 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2406 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2409 if (hashmap_get(h
, de
->d_name
))
2412 dirent_ensure_type(d
, de
);
2414 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2417 f
= new0(UnitFileList
, 1);
2421 f
->path
= path_make_absolute(de
->d_name
, units_dir
);
2425 r
= unit_file_lookup_state(scope
, root_dir
, &paths
, basename(f
->path
), &f
->state
);
2427 f
->state
= UNIT_FILE_BAD
;
2429 r
= hashmap_put(h
, basename(f
->path
), f
);
2433 f
= NULL
; /* prevent cleanup */
2440 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2441 [UNIT_FILE_ENABLED
] = "enabled",
2442 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2443 [UNIT_FILE_LINKED
] = "linked",
2444 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
2445 [UNIT_FILE_MASKED
] = "masked",
2446 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
2447 [UNIT_FILE_STATIC
] = "static",
2448 [UNIT_FILE_DISABLED
] = "disabled",
2449 [UNIT_FILE_INDIRECT
] = "indirect",
2450 [UNIT_FILE_BAD
] = "bad",
2453 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
2455 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
2456 [UNIT_FILE_SYMLINK
] = "symlink",
2457 [UNIT_FILE_UNLINK
] = "unlink",
2460 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
2462 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
2463 [UNIT_FILE_PRESET_FULL
] = "full",
2464 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
2465 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
2468 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);