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/>.
34 #include "alloc-util.h"
35 #include "conf-files.h"
36 #include "conf-parser.h"
37 #include "dirent-util.h"
38 #include "extract-word.h"
43 #include "install-printf.h"
48 #include "path-lookup.h"
49 #include "path-util.h"
52 #include "stat-util.h"
53 #include "string-table.h"
54 #include "string-util.h"
56 #include "unit-name.h"
58 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
60 typedef enum SearchFlags
{
62 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 2,
66 OrderedHashmap
*will_process
;
67 OrderedHashmap
*have_processed
;
70 static int in_search_path(const char *path
, char **search
) {
71 _cleanup_free_
char *parent
= NULL
;
76 parent
= dirname_malloc(path
);
80 STRV_FOREACH(i
, search
)
81 if (path_equal(parent
, *i
))
87 static int get_config_path(UnitFileScope scope
, bool runtime
, const char *root_dir
, char **ret
) {
92 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
95 /* This determines where we shall create or remove our
96 * installation ("configuration") symlinks */
100 case UNIT_FILE_SYSTEM
:
103 p
= path_join(root_dir
, "/run/systemd/system", NULL
);
105 p
= path_join(root_dir
, SYSTEM_CONFIG_UNIT_PATH
, NULL
);
108 case UNIT_FILE_GLOBAL
:
114 p
= strdup("/run/systemd/user");
116 p
= strdup(USER_CONFIG_UNIT_PATH
);
125 r
= user_runtime_dir(&p
);
127 r
= user_config_home(&p
);
136 assert_not_reached("Bad scope");
146 static bool is_config_path(UnitFileScope scope
, const char *path
) {
150 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
153 /* Checks whether the specified path is intended for
154 * configuration or is outside of it */
158 case UNIT_FILE_SYSTEM
:
159 case UNIT_FILE_GLOBAL
:
160 return path_startswith(path
, "/etc") ||
161 path_startswith(path
, SYSTEM_CONFIG_UNIT_PATH
) ||
162 path_startswith(path
, "/run");
165 case UNIT_FILE_USER
: {
166 _cleanup_free_
char *p
= NULL
;
168 r
= user_config_home(&p
);
171 if (r
> 0 && path_startswith(path
, p
))
176 r
= user_runtime_dir(&p
);
179 if (r
> 0 && path_startswith(path
, p
))
186 assert_not_reached("Bad scope");
191 static int verify_root_dir(UnitFileScope scope
, const char **root_dir
) {
196 /* Verifies that the specified root directory to operate on
197 * makes sense. Reset it to NULL if it is the root directory
200 if (isempty(*root_dir
) || path_equal(*root_dir
, "/")) {
205 if (scope
!= UNIT_FILE_SYSTEM
)
208 r
= is_dir(*root_dir
, true);
217 int unit_file_changes_add(
218 UnitFileChange
**changes
,
220 UnitFileChangeType type
,
222 const char *source
) {
228 assert(!changes
== !n_changes
);
233 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
241 c
[i
].path
= strdup(path
);
245 path_kill_slashes(c
[i
].path
);
248 c
[i
].source
= strdup(source
);
254 path_kill_slashes(c
[i
].path
);
262 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
265 assert(changes
|| n_changes
== 0);
270 for (i
= 0; i
< n_changes
; i
++) {
271 free(changes
[i
].path
);
272 free(changes
[i
].source
);
278 static int create_symlink(
279 const char *old_path
,
280 const char *new_path
,
282 UnitFileChange
**changes
,
283 unsigned *n_changes
) {
285 _cleanup_free_
char *dest
= NULL
;
291 /* Actually create a symlink, and remember that we did. Is
292 * smart enough to check if there's already a valid symlink in
295 mkdir_parents_label(new_path
, 0755);
297 if (symlink(old_path
, new_path
) >= 0) {
298 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
305 r
= readlink_malloc(new_path
, &dest
);
309 if (path_equal(dest
, old_path
))
315 r
= symlink_atomic(old_path
, new_path
);
319 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
320 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
325 static int mark_symlink_for_removal(
326 Set
**remove_symlinks_to
,
334 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
342 path_kill_slashes(n
);
344 r
= set_consume(*remove_symlinks_to
, n
);
353 static int remove_marked_symlinks_fd(
354 Set
*remove_symlinks_to
,
357 const char *config_path
,
359 UnitFileChange
**changes
,
360 unsigned *n_changes
) {
362 _cleanup_closedir_
DIR *d
= NULL
;
366 assert(remove_symlinks_to
);
380 FOREACH_DIRENT(de
, d
, return -errno
) {
382 dirent_ensure_type(d
, de
);
384 if (de
->d_type
== DT_DIR
) {
385 _cleanup_free_
char *p
= NULL
;
388 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
398 p
= path_make_absolute(de
->d_name
, path
);
404 /* This will close nfd, regardless whether it succeeds or not */
405 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, restart
, changes
, n_changes
);
409 } else if (de
->d_type
== DT_LNK
) {
410 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
414 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
417 p
= path_make_absolute(de
->d_name
, path
);
421 q
= readlink_malloc(p
, &dest
);
431 /* We remove all links pointing to a file or
432 * path that is marked, as well as all files
433 * sharing the same name as a file that is
437 set_contains(remove_symlinks_to
, dest
) ||
438 set_contains(remove_symlinks_to
, basename(dest
)) ||
439 set_contains(remove_symlinks_to
, de
->d_name
);
444 if (unlink(p
) < 0 && errno
!= ENOENT
) {
450 path_kill_slashes(p
);
451 (void) rmdir_parents(p
, config_path
);
453 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
455 q
= mark_symlink_for_removal(&remove_symlinks_to
, p
);
466 static int remove_marked_symlinks(
467 Set
*remove_symlinks_to
,
468 const char *config_path
,
469 UnitFileChange
**changes
,
470 unsigned *n_changes
) {
472 _cleanup_close_
int fd
= -1;
478 if (set_size(remove_symlinks_to
) <= 0)
481 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
489 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
493 /* This takes possession of cfd and closes it */
494 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, &restart
, changes
, n_changes
);
502 static int find_symlinks_fd(
503 const char *root_dir
,
507 const char *config_path
,
508 bool *same_name_link
) {
510 _cleanup_closedir_
DIR *d
= NULL
;
518 assert(same_name_link
);
526 FOREACH_DIRENT(de
, d
, return -errno
) {
528 dirent_ensure_type(d
, de
);
530 if (de
->d_type
== DT_DIR
) {
531 _cleanup_free_
char *p
= NULL
;
534 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
544 p
= path_make_absolute(de
->d_name
, path
);
550 /* This will close nfd, regardless whether it succeeds or not */
551 q
= find_symlinks_fd(root_dir
, name
, nfd
, p
, config_path
, same_name_link
);
557 } else if (de
->d_type
== DT_LNK
) {
558 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
559 bool found_path
, found_dest
, b
= false;
562 /* Acquire symlink name */
563 p
= path_make_absolute(de
->d_name
, path
);
567 /* Acquire symlink destination */
568 q
= readlink_malloc(p
, &dest
);
578 if (!path_is_absolute(dest
)) {
581 x
= prefix_root(root_dir
, dest
);
589 /* Check if the symlink itself matches what we
591 if (path_is_absolute(name
))
592 found_path
= path_equal(p
, name
);
594 found_path
= streq(de
->d_name
, name
);
596 /* Check if what the symlink points to
597 * matches what we are looking for */
598 if (path_is_absolute(name
))
599 found_dest
= path_equal(dest
, name
);
601 found_dest
= streq(basename(dest
), name
);
603 if (found_path
&& found_dest
) {
604 _cleanup_free_
char *t
= NULL
;
606 /* Filter out same name links in the main
608 t
= path_make_absolute(name
, config_path
);
612 b
= path_equal(t
, p
);
616 *same_name_link
= true;
617 else if (found_path
|| found_dest
)
625 static int find_symlinks(
626 const char *root_dir
,
628 const char *config_path
,
629 bool *same_name_link
) {
635 assert(same_name_link
);
637 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
644 /* This takes possession of fd and closes it */
645 return find_symlinks_fd(root_dir
, name
, fd
, config_path
, config_path
, same_name_link
);
648 static int find_symlinks_in_scope(
650 const char *root_dir
,
652 UnitFileState
*state
) {
654 _cleanup_free_
char *normal_path
= NULL
, *runtime_path
= NULL
;
655 bool same_name_link_runtime
= false, same_name_link
= false;
659 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
662 /* First look in the normal config path */
663 r
= get_config_path(scope
, false, root_dir
, &normal_path
);
667 r
= find_symlinks(root_dir
, name
, normal_path
, &same_name_link
);
671 *state
= UNIT_FILE_ENABLED
;
675 /* Then look in runtime config path */
676 r
= get_config_path(scope
, true, root_dir
, &runtime_path
);
680 r
= find_symlinks(root_dir
, name
, runtime_path
, &same_name_link_runtime
);
684 *state
= UNIT_FILE_ENABLED_RUNTIME
;
688 /* Hmm, we didn't find it, but maybe we found the same name
690 if (same_name_link
) {
691 *state
= UNIT_FILE_LINKED
;
694 if (same_name_link_runtime
) {
695 *state
= UNIT_FILE_LINKED_RUNTIME
;
702 static void install_info_free(UnitFileInstallInfo
*i
) {
709 strv_free(i
->aliases
);
710 strv_free(i
->wanted_by
);
711 strv_free(i
->required_by
);
713 free(i
->default_instance
);
714 free(i
->symlink_target
);
718 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
719 UnitFileInstallInfo
*i
;
724 while ((i
= ordered_hashmap_steal_first(m
)))
725 install_info_free(i
);
727 return ordered_hashmap_free(m
);
730 static void install_context_done(InstallContext
*c
) {
733 c
->will_process
= install_info_hashmap_free(c
->will_process
);
734 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
737 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
738 UnitFileInstallInfo
*i
;
740 i
= ordered_hashmap_get(c
->have_processed
, name
);
744 return ordered_hashmap_get(c
->will_process
, name
);
747 static int install_info_add(
751 UnitFileInstallInfo
**ret
) {
753 UnitFileInstallInfo
*i
= NULL
;
757 assert(name
|| path
);
760 name
= basename(path
);
762 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
765 i
= install_info_find(c
, name
);
772 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
776 i
= new0(UnitFileInstallInfo
, 1);
779 i
->type
= _UNIT_FILE_TYPE_INVALID
;
781 i
->name
= strdup(name
);
788 i
->path
= strdup(path
);
795 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
805 install_info_free(i
);
809 static int install_info_add_auto(
811 const char *name_or_path
,
812 UnitFileInstallInfo
**ret
) {
815 assert(name_or_path
);
817 if (path_is_absolute(name_or_path
))
818 return install_info_add(c
, NULL
, name_or_path
, ret
);
820 return install_info_add(c
, name_or_path
, NULL
, ret
);
823 static int config_parse_also(
825 const char *filename
,
828 unsigned section_line
,
835 UnitFileInstallInfo
*i
= userdata
;
836 InstallContext
*c
= data
;
844 _cleanup_free_
char *word
= NULL
;
846 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
852 r
= install_info_add(c
, word
, NULL
, NULL
);
856 r
= strv_push(&i
->also
, word
);
866 static int config_parse_default_instance(
868 const char *filename
,
871 unsigned section_line
,
878 UnitFileInstallInfo
*i
= data
;
886 r
= install_full_printf(i
, rvalue
, &printed
);
890 if (!unit_instance_is_valid(printed
)) {
895 free(i
->default_instance
);
896 i
->default_instance
= printed
;
901 static int unit_file_load(
903 UnitFileInstallInfo
*info
,
905 const char *root_dir
,
908 const ConfigTableItem items
[] = {
909 { "Install", "Alias", config_parse_strv
, 0, &info
->aliases
},
910 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
911 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
912 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
913 { "Install", "Also", config_parse_also
, 0, c
},
917 _cleanup_fclose_
FILE *f
= NULL
;
918 _cleanup_close_
int fd
= -1;
926 path
= prefix_roota(root_dir
, path
);
928 if (!(flags
& SEARCH_LOAD
)) {
929 r
= lstat(path
, &st
);
933 if (null_or_empty(&st
))
934 info
->type
= UNIT_FILE_TYPE_MASKED
;
935 else if (S_ISREG(st
.st_mode
))
936 info
->type
= UNIT_FILE_TYPE_REGULAR
;
937 else if (S_ISLNK(st
.st_mode
))
939 else if (S_ISDIR(st
.st_mode
))
947 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
950 if (fstat(fd
, &st
) < 0)
952 if (null_or_empty(&st
)) {
953 info
->type
= UNIT_FILE_TYPE_MASKED
;
956 if (S_ISDIR(st
.st_mode
))
958 if (!S_ISREG(st
.st_mode
))
961 f
= fdopen(fd
, "re");
966 r
= config_parse(NULL
, path
, f
,
968 config_item_table_lookup
, items
,
969 true, true, false, info
);
973 info
->type
= UNIT_FILE_TYPE_REGULAR
;
976 (int) strv_length(info
->aliases
) +
977 (int) strv_length(info
->wanted_by
) +
978 (int) strv_length(info
->required_by
);
981 static int unit_file_load_or_readlink(
983 UnitFileInstallInfo
*info
,
985 const char *root_dir
,
988 _cleanup_free_
char *np
= NULL
;
991 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
995 /* This is a symlink, let's read it. */
997 r
= readlink_and_make_absolute_root(root_dir
, path
, &np
);
1001 if (path_equal(np
, "/dev/null"))
1002 info
->type
= UNIT_FILE_TYPE_MASKED
;
1009 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1011 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1014 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1016 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1019 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1021 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1026 /* Enforce that the symlink destination does not
1027 * change the unit file type. */
1029 a
= unit_name_to_type(info
->name
);
1030 b
= unit_name_to_type(bn
);
1031 if (a
< 0 || b
< 0 || a
!= b
)
1034 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1035 info
->symlink_target
= np
;
1042 static int unit_file_search(
1044 UnitFileInstallInfo
*info
,
1045 const LookupPaths
*paths
,
1046 const char *root_dir
,
1047 SearchFlags flags
) {
1056 /* Was this unit already loaded? */
1057 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1061 return unit_file_load_or_readlink(c
, info
, info
->path
, root_dir
, flags
);
1065 STRV_FOREACH(p
, paths
->unit_path
) {
1066 _cleanup_free_
char *path
= NULL
;
1068 path
= strjoin(*p
, "/", info
->name
, NULL
);
1072 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1083 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1085 /* Unit file doesn't exist, however instance
1086 * enablement was requested. We will check if it is
1087 * possible to load template unit file. */
1089 _cleanup_free_
char *template = NULL
;
1091 r
= unit_name_template(info
->name
, &template);
1095 STRV_FOREACH(p
, paths
->unit_path
) {
1096 _cleanup_free_
char *path
= NULL
;
1098 path
= strjoin(*p
, "/", template, NULL
);
1102 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1117 static int install_info_follow(
1119 UnitFileInstallInfo
*i
,
1120 const char *root_dir
,
1121 SearchFlags flags
) {
1126 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1128 if (!i
->symlink_target
)
1131 /* If the basename doesn't match, the caller should add a
1132 * complete new entry for this. */
1134 if (!streq(basename(i
->symlink_target
), i
->name
))
1138 i
->path
= i
->symlink_target
;
1139 i
->symlink_target
= NULL
;
1140 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1142 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1145 static int install_info_traverse(
1146 UnitFileScope scope
,
1148 const char *root_dir
,
1149 const LookupPaths
*paths
,
1150 UnitFileInstallInfo
*start
,
1152 UnitFileInstallInfo
**ret
) {
1154 UnitFileInstallInfo
*i
;
1162 r
= unit_file_search(c
, start
, paths
, root_dir
, flags
);
1167 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1168 /* Follow the symlink */
1170 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1173 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
) && is_config_path(scope
, i
->path
))
1176 r
= install_info_follow(c
, i
, root_dir
, flags
);
1178 _cleanup_free_
char *buffer
= NULL
;
1184 /* Target has a different name, create a new
1185 * install info object for that, and continue
1188 bn
= basename(i
->symlink_target
);
1190 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1191 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1193 _cleanup_free_
char *instance
= NULL
;
1195 r
= unit_name_to_instance(i
->name
, &instance
);
1199 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1206 r
= install_info_add(c
, bn
, NULL
, &i
);
1210 r
= unit_file_search(c
, i
, paths
, root_dir
, flags
);
1215 /* Try again, with the new target we found. */
1224 static int install_info_discover(
1225 UnitFileScope scope
,
1227 const char *root_dir
,
1228 const LookupPaths
*paths
,
1231 UnitFileInstallInfo
**ret
) {
1233 UnitFileInstallInfo
*i
;
1240 r
= install_info_add_auto(c
, name
, &i
);
1244 return install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, ret
);
1247 static int install_info_symlink_alias(
1248 UnitFileInstallInfo
*i
,
1249 const char *config_path
,
1251 UnitFileChange
**changes
,
1252 unsigned *n_changes
) {
1258 assert(config_path
);
1260 STRV_FOREACH(s
, i
->aliases
) {
1261 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1263 q
= install_full_printf(i
, *s
, &dst
);
1267 alias_path
= path_make_absolute(dst
, config_path
);
1271 q
= create_symlink(i
->path
, alias_path
, force
, changes
, n_changes
);
1279 static int install_info_symlink_wants(
1280 UnitFileInstallInfo
*i
,
1281 const char *config_path
,
1285 UnitFileChange
**changes
,
1286 unsigned *n_changes
) {
1288 _cleanup_free_
char *buf
= NULL
;
1294 assert(config_path
);
1296 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1298 /* Don't install any symlink if there's no default
1299 * instance configured */
1301 if (!i
->default_instance
)
1304 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1312 STRV_FOREACH(s
, list
) {
1313 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1315 q
= install_full_printf(i
, *s
, &dst
);
1319 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1324 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1328 q
= create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1336 static int install_info_symlink_link(
1337 UnitFileInstallInfo
*i
,
1338 const LookupPaths
*paths
,
1339 const char *config_path
,
1340 const char *root_dir
,
1342 UnitFileChange
**changes
,
1343 unsigned *n_changes
) {
1345 _cleanup_free_
char *path
= NULL
;
1350 assert(config_path
);
1353 r
= in_search_path(i
->path
, paths
->unit_path
);
1357 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1361 return create_symlink(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
,
1368 const char *root_dir
,
1370 UnitFileChange
**changes
,
1371 unsigned *n_changes
) {
1377 assert(config_path
);
1379 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1382 r
= install_info_symlink_alias(i
, config_path
, force
, changes
, n_changes
);
1384 q
= install_info_symlink_wants(i
, config_path
, i
->wanted_by
, ".wants/", force
, changes
, n_changes
);
1388 q
= install_info_symlink_wants(i
, config_path
, i
->required_by
, ".requires/", force
, changes
, n_changes
);
1392 q
= install_info_symlink_link(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1399 static int install_context_apply(
1400 UnitFileScope scope
,
1402 const LookupPaths
*paths
,
1403 const char *config_path
,
1404 const char *root_dir
,
1407 UnitFileChange
**changes
,
1408 unsigned *n_changes
) {
1410 UnitFileInstallInfo
*i
;
1415 assert(config_path
);
1417 if (ordered_hashmap_isempty(c
->will_process
))
1420 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1425 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1428 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1432 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, NULL
);
1436 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1439 q
= install_info_apply(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1451 static int install_context_mark_for_removal(
1452 UnitFileScope scope
,
1454 const LookupPaths
*paths
,
1455 Set
**remove_symlinks_to
,
1456 const char *config_path
,
1457 const char *root_dir
) {
1459 UnitFileInstallInfo
*i
;
1464 assert(config_path
);
1466 /* Marks all items for removal */
1468 if (ordered_hashmap_isempty(c
->will_process
))
1471 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1475 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1477 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1481 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1485 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1488 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1497 UnitFileScope scope
,
1499 const char *root_dir
,
1502 UnitFileChange
**changes
,
1503 unsigned *n_changes
) {
1505 _cleanup_free_
char *prefix
= NULL
;
1510 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1512 r
= verify_root_dir(scope
, &root_dir
);
1516 r
= get_config_path(scope
, runtime
, root_dir
, &prefix
);
1520 STRV_FOREACH(i
, files
) {
1521 _cleanup_free_
char *path
= NULL
;
1524 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1530 path
= path_make_absolute(*i
, prefix
);
1534 q
= create_symlink("/dev/null", path
, force
, changes
, n_changes
);
1535 if (q
< 0 && r
>= 0)
1542 int unit_file_unmask(
1543 UnitFileScope scope
,
1545 const char *root_dir
,
1547 UnitFileChange
**changes
,
1548 unsigned *n_changes
) {
1550 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1551 _cleanup_free_
char *config_path
= NULL
;
1552 _cleanup_free_
char **todo
= NULL
;
1553 size_t n_todo
= 0, n_allocated
= 0;
1558 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1560 r
= verify_root_dir(scope
, &root_dir
);
1564 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1568 STRV_FOREACH(i
, files
) {
1569 _cleanup_free_
char *path
= NULL
;
1571 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1574 path
= path_make_absolute(*i
, config_path
);
1578 r
= null_or_empty_path(path
);
1586 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1589 todo
[n_todo
++] = *i
;
1595 STRV_FOREACH(i
, todo
) {
1596 _cleanup_free_
char *path
= NULL
;
1598 path
= path_make_absolute(*i
, config_path
);
1602 if (unlink(path
) < 0) {
1603 if (errno
!= -ENOENT
&& r
>= 0)
1606 q
= mark_symlink_for_removal(&remove_symlinks_to
, path
);
1610 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1614 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1622 UnitFileScope scope
,
1624 const char *root_dir
,
1627 UnitFileChange
**changes
,
1628 unsigned *n_changes
) {
1630 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1631 _cleanup_free_
char *config_path
= NULL
;
1632 _cleanup_free_
char **todo
= NULL
;
1633 size_t n_todo
= 0, n_allocated
= 0;
1638 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1640 r
= verify_root_dir(scope
, &root_dir
);
1644 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1648 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1652 STRV_FOREACH(i
, files
) {
1653 _cleanup_free_
char *full
= NULL
;
1657 if (!path_is_absolute(*i
))
1661 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1664 full
= prefix_root(root_dir
, *i
);
1668 if (lstat(full
, &st
) < 0)
1670 if (S_ISLNK(st
.st_mode
))
1672 if (S_ISDIR(st
.st_mode
))
1674 if (!S_ISREG(st
.st_mode
))
1677 q
= in_search_path(*i
, paths
.unit_path
);
1683 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1686 todo
[n_todo
++] = *i
;
1692 STRV_FOREACH(i
, todo
) {
1693 _cleanup_free_
char *path
= NULL
;
1695 path
= path_make_absolute(basename(*i
), config_path
);
1699 q
= create_symlink(*i
, path
, force
, changes
, n_changes
);
1700 if (q
< 0 && r
>= 0)
1707 int unit_file_add_dependency(
1708 UnitFileScope scope
,
1710 const char *root_dir
,
1715 UnitFileChange
**changes
,
1716 unsigned *n_changes
) {
1718 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1719 _cleanup_(install_context_done
) InstallContext c
= {};
1720 _cleanup_free_
char *config_path
= NULL
;
1721 UnitFileInstallInfo
*i
, *target_info
;
1726 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1729 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
1732 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
1735 r
= verify_root_dir(scope
, &root_dir
);
1739 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1743 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1747 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
1750 if (target_info
->type
== UNIT_FILE_TYPE_MASKED
)
1753 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
1755 STRV_FOREACH(f
, files
) {
1758 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1761 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1764 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1766 /* We didn't actually load anything from the unit
1767 * file, but instead just add in our new symlink to
1770 if (dep
== UNIT_WANTS
)
1773 l
= &i
->required_by
;
1776 *l
= strv_new(target_info
->name
, NULL
);
1781 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
1784 int unit_file_enable(
1785 UnitFileScope scope
,
1787 const char *root_dir
,
1790 UnitFileChange
**changes
,
1791 unsigned *n_changes
) {
1793 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1794 _cleanup_(install_context_done
) InstallContext c
= {};
1795 _cleanup_free_
char *config_path
= NULL
;
1796 UnitFileInstallInfo
*i
;
1801 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1803 r
= verify_root_dir(scope
, &root_dir
);
1807 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1811 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1815 STRV_FOREACH(f
, files
) {
1816 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_LOAD
, &i
);
1819 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1822 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1825 /* This will return the number of symlink rules that were
1826 supposed to be created, not the ones actually created. This
1827 is useful to determine whether the passed files had any
1828 installation data at all. */
1830 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
1833 int unit_file_disable(
1834 UnitFileScope scope
,
1836 const char *root_dir
,
1838 UnitFileChange
**changes
,
1839 unsigned *n_changes
) {
1841 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1842 _cleanup_(install_context_done
) InstallContext c
= {};
1843 _cleanup_free_
char *config_path
= NULL
;
1844 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1849 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1851 r
= verify_root_dir(scope
, &root_dir
);
1855 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1859 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
1863 STRV_FOREACH(i
, files
) {
1864 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1867 r
= install_info_add(&c
, *i
, NULL
, NULL
);
1872 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, root_dir
);
1876 return remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1879 int unit_file_reenable(
1880 UnitFileScope scope
,
1882 const char *root_dir
,
1885 UnitFileChange
**changes
,
1886 unsigned *n_changes
) {
1892 /* First, we invoke the disable command with only the basename... */
1893 l
= strv_length(files
);
1894 n
= newa(char*, l
+1);
1895 for (i
= 0; i
< l
; i
++)
1896 n
[i
] = basename(files
[i
]);
1899 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
1903 /* But the enable command with the full name */
1904 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
1907 int unit_file_set_default(
1908 UnitFileScope scope
,
1909 const char *root_dir
,
1912 UnitFileChange
**changes
,
1913 unsigned *n_changes
) {
1915 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1916 _cleanup_(install_context_done
) InstallContext c
= {};
1917 _cleanup_free_
char *config_path
= NULL
;
1918 UnitFileInstallInfo
*i
;
1923 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1926 if (unit_name_to_type(name
) != UNIT_TARGET
)
1928 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
1931 r
= verify_root_dir(scope
, &root_dir
);
1935 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1939 r
= get_config_path(scope
, false, root_dir
, &config_path
);
1943 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, name
, 0, &i
);
1946 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1949 path
= strjoina(config_path
, "/" SPECIAL_DEFAULT_TARGET
);
1951 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1954 int unit_file_get_default(
1955 UnitFileScope scope
,
1956 const char *root_dir
,
1959 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1960 _cleanup_(install_context_done
) InstallContext c
= {};
1961 UnitFileInstallInfo
*i
;
1966 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1969 r
= verify_root_dir(scope
, &root_dir
);
1973 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
1977 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1980 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1983 n
= strdup(i
->name
);
1991 int unit_file_lookup_state(
1992 UnitFileScope scope
,
1993 const char *root_dir
,
1994 const LookupPaths
*paths
,
1996 UnitFileState
*ret
) {
1998 _cleanup_(install_context_done
) InstallContext c
= {};
1999 UnitFileInstallInfo
*i
;
2000 UnitFileState state
;
2006 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2009 r
= verify_root_dir(scope
, &root_dir
);
2013 r
= install_info_discover(scope
, &c
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2017 /* Shortcut things, if the caller just wants to know if this unit exists. */
2023 case UNIT_FILE_TYPE_MASKED
:
2024 state
= path_startswith(i
->path
, "/run") ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2027 case UNIT_FILE_TYPE_REGULAR
:
2028 r
= find_symlinks_in_scope(scope
, root_dir
, i
->name
, &state
);
2032 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
2033 state
= UNIT_FILE_DISABLED
;
2034 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
2035 state
= UNIT_FILE_INDIRECT
;
2037 state
= UNIT_FILE_STATIC
;
2043 assert_not_reached("Unexpect unit file type.");
2050 int unit_file_get_state(
2051 UnitFileScope scope
,
2052 const char *root_dir
,
2054 UnitFileState
*ret
) {
2056 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2060 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2063 r
= verify_root_dir(scope
, &root_dir
);
2067 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2071 return unit_file_lookup_state(scope
, root_dir
, &paths
, name
, ret
);
2074 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2075 _cleanup_strv_free_
char **files
= NULL
;
2080 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2083 r
= verify_root_dir(scope
, &root_dir
);
2087 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2090 if (scope
== UNIT_FILE_SYSTEM
)
2091 r
= conf_files_list(&files
, ".preset", root_dir
,
2092 "/etc/systemd/system-preset",
2093 "/usr/local/lib/systemd/system-preset",
2094 "/usr/lib/systemd/system-preset",
2095 #ifdef HAVE_SPLIT_USR
2096 "/lib/systemd/system-preset",
2099 else if (scope
== UNIT_FILE_GLOBAL
)
2100 r
= conf_files_list(&files
, ".preset", root_dir
,
2101 "/etc/systemd/user-preset",
2102 "/usr/local/lib/systemd/user-preset",
2103 "/usr/lib/systemd/user-preset",
2106 return 1; /* Default is "enable" */
2111 STRV_FOREACH(p
, files
) {
2112 _cleanup_fclose_
FILE *f
;
2113 char line
[LINE_MAX
];
2115 f
= fopen(*p
, "re");
2117 if (errno
== ENOENT
)
2123 FOREACH_LINE(line
, f
, return -errno
) {
2124 const char *parameter
;
2131 if (strchr(COMMENTS
, *l
))
2134 parameter
= first_word(l
, "enable");
2136 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2137 log_debug("Preset file says enable %s.", name
);
2144 parameter
= first_word(l
, "disable");
2146 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2147 log_debug("Preset file says disable %s.", name
);
2154 log_debug("Couldn't parse line '%s'", l
);
2158 /* Default is "enable" */
2159 log_debug("Preset file doesn't say anything about %s, enabling.", name
);
2163 static int execute_preset(
2164 UnitFileScope scope
,
2165 InstallContext
*plus
,
2166 InstallContext
*minus
,
2167 const LookupPaths
*paths
,
2168 const char *config_path
,
2169 const char *root_dir
,
2171 UnitFilePresetMode mode
,
2173 UnitFileChange
**changes
,
2174 unsigned *n_changes
) {
2181 assert(config_path
);
2183 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2184 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2186 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, root_dir
);
2190 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
2194 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2197 /* Returns number of symlinks that where supposed to be installed. */
2198 q
= install_context_apply(scope
, plus
, paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
2210 static int preset_prepare_one(
2211 UnitFileScope scope
,
2212 InstallContext
*plus
,
2213 InstallContext
*minus
,
2215 const char *root_dir
,
2216 UnitFilePresetMode mode
,
2219 UnitFileInstallInfo
*i
;
2222 if (install_info_find(plus
, name
) ||
2223 install_info_find(minus
, name
))
2226 r
= unit_file_query_preset(scope
, root_dir
, name
);
2231 r
= install_info_discover(scope
, plus
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2235 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
2238 r
= install_info_discover(scope
, minus
, root_dir
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2243 int unit_file_preset(
2244 UnitFileScope scope
,
2246 const char *root_dir
,
2248 UnitFilePresetMode mode
,
2250 UnitFileChange
**changes
,
2251 unsigned *n_changes
) {
2253 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2254 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2255 _cleanup_free_
char *config_path
= NULL
;
2260 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2261 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2263 r
= verify_root_dir(scope
, &root_dir
);
2267 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2271 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
2275 STRV_FOREACH(i
, files
) {
2276 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2279 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, *i
);
2284 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, files
, mode
, force
, changes
, n_changes
);
2287 int unit_file_preset_all(
2288 UnitFileScope scope
,
2290 const char *root_dir
,
2291 UnitFilePresetMode mode
,
2293 UnitFileChange
**changes
,
2294 unsigned *n_changes
) {
2296 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2297 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2298 _cleanup_free_
char *config_path
= NULL
;
2303 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2304 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2306 r
= verify_root_dir(scope
, &root_dir
);
2310 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2314 r
= get_config_path(scope
, runtime
, root_dir
, &config_path
);
2318 STRV_FOREACH(i
, paths
.unit_path
) {
2319 _cleanup_closedir_
DIR *d
= NULL
;
2320 _cleanup_free_
char *units_dir
;
2323 units_dir
= path_join(root_dir
, *i
, NULL
);
2327 d
= opendir(units_dir
);
2329 if (errno
== ENOENT
)
2335 FOREACH_DIRENT(de
, d
, return -errno
) {
2337 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2340 dirent_ensure_type(d
, de
);
2342 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2345 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, de
->d_name
);
2351 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, NULL
, mode
, force
, changes
, n_changes
);
2354 static void unit_file_list_free_one(UnitFileList
*f
) {
2362 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2365 while ((i
= hashmap_steal_first(h
)))
2366 unit_file_list_free_one(i
);
2368 return hashmap_free(h
);
2371 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2373 int unit_file_get_list(
2374 UnitFileScope scope
,
2375 const char *root_dir
,
2378 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2383 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2386 r
= verify_root_dir(scope
, &root_dir
);
2390 r
= lookup_paths_init_from_scope(&paths
, scope
, root_dir
);
2394 STRV_FOREACH(i
, paths
.unit_path
) {
2395 _cleanup_closedir_
DIR *d
= NULL
;
2396 _cleanup_free_
char *units_dir
;
2399 units_dir
= path_join(root_dir
, *i
, NULL
);
2403 d
= opendir(units_dir
);
2405 if (errno
== ENOENT
)
2411 FOREACH_DIRENT(de
, d
, return -errno
) {
2412 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2414 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2417 if (hashmap_get(h
, de
->d_name
))
2420 dirent_ensure_type(d
, de
);
2422 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2425 f
= new0(UnitFileList
, 1);
2429 f
->path
= path_make_absolute(de
->d_name
, units_dir
);
2433 r
= unit_file_lookup_state(scope
, root_dir
, &paths
, basename(f
->path
), &f
->state
);
2435 f
->state
= UNIT_FILE_BAD
;
2437 r
= hashmap_put(h
, basename(f
->path
), f
);
2441 f
= NULL
; /* prevent cleanup */
2448 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2449 [UNIT_FILE_ENABLED
] = "enabled",
2450 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2451 [UNIT_FILE_LINKED
] = "linked",
2452 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
2453 [UNIT_FILE_MASKED
] = "masked",
2454 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
2455 [UNIT_FILE_STATIC
] = "static",
2456 [UNIT_FILE_DISABLED
] = "disabled",
2457 [UNIT_FILE_INDIRECT
] = "indirect",
2458 [UNIT_FILE_BAD
] = "bad",
2461 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
2463 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
2464 [UNIT_FILE_SYMLINK
] = "symlink",
2465 [UNIT_FILE_UNLINK
] = "unlink",
2468 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
2470 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
2471 [UNIT_FILE_PRESET_FULL
] = "full",
2472 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
2473 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
2476 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);