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 unit_file_is_generated(const LookupPaths
*p
, const char *path
) {
86 _cleanup_free_
char *parent
= NULL
;
91 parent
= dirname_malloc(path
);
95 return path_equal(p
->generator
, parent
) ||
96 path_equal(p
->generator_early
, parent
) ||
97 path_equal(p
->generator_late
, parent
);
100 static int path_is_config(const LookupPaths
*p
, const char *path
) {
101 _cleanup_free_
char *parent
= NULL
;
106 /* Checks whether the specified path is intended for configuration or is outside of it. We check both the
107 * top-level directory and the one actually configured. The latter is particularly relevant for cases where we
108 * operate on a root directory. */
110 if (path_startswith(path
, "/etc") || path_startswith(path
, "/run"))
113 parent
= dirname_malloc(path
);
117 return path_equal(parent
, p
->persistent_config
) ||
118 path_equal(parent
, p
->runtime_config
);
121 static int path_is_runtime(const LookupPaths
*p
, const char *path
) {
122 _cleanup_free_
char *parent
= NULL
;
127 if (path_startswith(path
, "/run"))
130 parent
= dirname_malloc(path
);
134 return path_equal(parent
, p
->runtime_config
);
137 static int verify_root_dir(UnitFileScope scope
, const char **root_dir
) {
142 /* Verifies that the specified root directory to operate on
143 * makes sense. Reset it to NULL if it is the root directory
146 if (isempty(*root_dir
) || path_equal(*root_dir
, "/")) {
151 if (scope
!= UNIT_FILE_SYSTEM
)
154 r
= is_dir(*root_dir
, true);
163 int unit_file_changes_add(
164 UnitFileChange
**changes
,
166 UnitFileChangeType type
,
168 const char *source
) {
174 assert(!changes
== !n_changes
);
179 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
187 c
[i
].path
= strdup(path
);
191 path_kill_slashes(c
[i
].path
);
194 c
[i
].source
= strdup(source
);
200 path_kill_slashes(c
[i
].path
);
208 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
211 assert(changes
|| n_changes
== 0);
216 for (i
= 0; i
< n_changes
; i
++) {
217 free(changes
[i
].path
);
218 free(changes
[i
].source
);
224 static int create_symlink(
225 const char *old_path
,
226 const char *new_path
,
228 UnitFileChange
**changes
,
229 unsigned *n_changes
) {
231 _cleanup_free_
char *dest
= NULL
;
237 /* Actually create a symlink, and remember that we did. Is
238 * smart enough to check if there's already a valid symlink in
241 mkdir_parents_label(new_path
, 0755);
243 if (symlink(old_path
, new_path
) >= 0) {
244 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
251 r
= readlink_malloc(new_path
, &dest
);
255 if (path_equal(dest
, old_path
))
261 r
= symlink_atomic(old_path
, new_path
);
265 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
266 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
271 static int mark_symlink_for_removal(
272 Set
**remove_symlinks_to
,
280 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
288 path_kill_slashes(n
);
290 r
= set_consume(*remove_symlinks_to
, n
);
299 static int remove_marked_symlinks_fd(
300 Set
*remove_symlinks_to
,
303 const char *config_path
,
305 UnitFileChange
**changes
,
306 unsigned *n_changes
) {
308 _cleanup_closedir_
DIR *d
= NULL
;
312 assert(remove_symlinks_to
);
326 FOREACH_DIRENT(de
, d
, return -errno
) {
328 dirent_ensure_type(d
, de
);
330 if (de
->d_type
== DT_DIR
) {
331 _cleanup_free_
char *p
= NULL
;
334 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
344 p
= path_make_absolute(de
->d_name
, path
);
350 /* This will close nfd, regardless whether it succeeds or not */
351 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, restart
, changes
, n_changes
);
355 } else if (de
->d_type
== DT_LNK
) {
356 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
360 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
363 p
= path_make_absolute(de
->d_name
, path
);
367 q
= readlink_malloc(p
, &dest
);
377 /* We remove all links pointing to a file or
378 * path that is marked, as well as all files
379 * sharing the same name as a file that is
383 set_contains(remove_symlinks_to
, dest
) ||
384 set_contains(remove_symlinks_to
, basename(dest
)) ||
385 set_contains(remove_symlinks_to
, de
->d_name
);
390 if (unlink(p
) < 0 && errno
!= ENOENT
) {
396 path_kill_slashes(p
);
397 (void) rmdir_parents(p
, config_path
);
399 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
401 q
= mark_symlink_for_removal(&remove_symlinks_to
, p
);
412 static int remove_marked_symlinks(
413 Set
*remove_symlinks_to
,
414 const char *config_path
,
415 UnitFileChange
**changes
,
416 unsigned *n_changes
) {
418 _cleanup_close_
int fd
= -1;
424 if (set_size(remove_symlinks_to
) <= 0)
427 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
435 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
439 /* This takes possession of cfd and closes it */
440 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, &restart
, changes
, n_changes
);
448 static int find_symlinks_fd(
449 const char *root_dir
,
453 const char *config_path
,
454 bool *same_name_link
) {
456 _cleanup_closedir_
DIR *d
= NULL
;
464 assert(same_name_link
);
472 FOREACH_DIRENT(de
, d
, return -errno
) {
474 dirent_ensure_type(d
, de
);
476 if (de
->d_type
== DT_DIR
) {
477 _cleanup_free_
char *p
= NULL
;
480 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
490 p
= path_make_absolute(de
->d_name
, path
);
496 /* This will close nfd, regardless whether it succeeds or not */
497 q
= find_symlinks_fd(root_dir
, name
, nfd
, p
, config_path
, same_name_link
);
503 } else if (de
->d_type
== DT_LNK
) {
504 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
505 bool found_path
, found_dest
, b
= false;
508 /* Acquire symlink name */
509 p
= path_make_absolute(de
->d_name
, path
);
513 /* Acquire symlink destination */
514 q
= readlink_malloc(p
, &dest
);
524 if (!path_is_absolute(dest
)) {
527 x
= prefix_root(root_dir
, dest
);
535 /* Check if the symlink itself matches what we
537 if (path_is_absolute(name
))
538 found_path
= path_equal(p
, name
);
540 found_path
= streq(de
->d_name
, name
);
542 /* Check if what the symlink points to
543 * matches what we are looking for */
544 if (path_is_absolute(name
))
545 found_dest
= path_equal(dest
, name
);
547 found_dest
= streq(basename(dest
), name
);
549 if (found_path
&& found_dest
) {
550 _cleanup_free_
char *t
= NULL
;
552 /* Filter out same name links in the main
554 t
= path_make_absolute(name
, config_path
);
558 b
= path_equal(t
, p
);
562 *same_name_link
= true;
563 else if (found_path
|| found_dest
)
571 static int find_symlinks(
572 const char *root_dir
,
574 const char *config_path
,
575 bool *same_name_link
) {
581 assert(same_name_link
);
583 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
590 /* This takes possession of fd and closes it */
591 return find_symlinks_fd(root_dir
, name
, fd
, config_path
, config_path
, same_name_link
);
594 static int find_symlinks_in_scope(
596 const LookupPaths
*paths
,
597 const char *root_dir
,
599 UnitFileState
*state
) {
601 bool same_name_link_runtime
= false, same_name_link
= false;
605 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
609 /* First look in the persistent config path */
610 r
= find_symlinks(root_dir
, name
, paths
->persistent_config
, &same_name_link
);
614 *state
= UNIT_FILE_ENABLED
;
618 /* Then look in runtime config path */
619 r
= find_symlinks(root_dir
, name
, paths
->runtime_config
, &same_name_link_runtime
);
623 *state
= UNIT_FILE_ENABLED_RUNTIME
;
627 /* Hmm, we didn't find it, but maybe we found the same name
629 if (same_name_link
) {
630 *state
= UNIT_FILE_LINKED
;
633 if (same_name_link_runtime
) {
634 *state
= UNIT_FILE_LINKED_RUNTIME
;
641 static void install_info_free(UnitFileInstallInfo
*i
) {
648 strv_free(i
->aliases
);
649 strv_free(i
->wanted_by
);
650 strv_free(i
->required_by
);
652 free(i
->default_instance
);
653 free(i
->symlink_target
);
657 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
658 UnitFileInstallInfo
*i
;
663 while ((i
= ordered_hashmap_steal_first(m
)))
664 install_info_free(i
);
666 return ordered_hashmap_free(m
);
669 static void install_context_done(InstallContext
*c
) {
672 c
->will_process
= install_info_hashmap_free(c
->will_process
);
673 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
676 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
677 UnitFileInstallInfo
*i
;
679 i
= ordered_hashmap_get(c
->have_processed
, name
);
683 return ordered_hashmap_get(c
->will_process
, name
);
686 static int install_info_add(
690 UnitFileInstallInfo
**ret
) {
692 UnitFileInstallInfo
*i
= NULL
;
696 assert(name
|| path
);
699 name
= basename(path
);
701 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
704 i
= install_info_find(c
, name
);
711 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
715 i
= new0(UnitFileInstallInfo
, 1);
718 i
->type
= _UNIT_FILE_TYPE_INVALID
;
720 i
->name
= strdup(name
);
727 i
->path
= strdup(path
);
734 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
744 install_info_free(i
);
748 static int install_info_add_auto(
750 const char *name_or_path
,
751 UnitFileInstallInfo
**ret
) {
754 assert(name_or_path
);
756 if (path_is_absolute(name_or_path
))
757 return install_info_add(c
, NULL
, name_or_path
, ret
);
759 return install_info_add(c
, name_or_path
, NULL
, ret
);
762 static int config_parse_also(
764 const char *filename
,
767 unsigned section_line
,
774 UnitFileInstallInfo
*i
= userdata
;
775 InstallContext
*c
= data
;
783 _cleanup_free_
char *word
= NULL
;
785 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
791 r
= install_info_add(c
, word
, NULL
, NULL
);
795 r
= strv_push(&i
->also
, word
);
805 static int config_parse_default_instance(
807 const char *filename
,
810 unsigned section_line
,
817 UnitFileInstallInfo
*i
= data
;
825 r
= install_full_printf(i
, rvalue
, &printed
);
829 if (!unit_instance_is_valid(printed
)) {
834 free(i
->default_instance
);
835 i
->default_instance
= printed
;
840 static int unit_file_load(
842 UnitFileInstallInfo
*info
,
844 const char *root_dir
,
847 const ConfigTableItem items
[] = {
848 { "Install", "Alias", config_parse_strv
, 0, &info
->aliases
},
849 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
850 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
851 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
852 { "Install", "Also", config_parse_also
, 0, c
},
856 _cleanup_fclose_
FILE *f
= NULL
;
857 _cleanup_close_
int fd
= -1;
865 path
= prefix_roota(root_dir
, path
);
867 if (!(flags
& SEARCH_LOAD
)) {
868 r
= lstat(path
, &st
);
872 if (null_or_empty(&st
))
873 info
->type
= UNIT_FILE_TYPE_MASKED
;
874 else if (S_ISREG(st
.st_mode
))
875 info
->type
= UNIT_FILE_TYPE_REGULAR
;
876 else if (S_ISLNK(st
.st_mode
))
878 else if (S_ISDIR(st
.st_mode
))
886 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
889 if (fstat(fd
, &st
) < 0)
891 if (null_or_empty(&st
)) {
892 info
->type
= UNIT_FILE_TYPE_MASKED
;
895 if (S_ISDIR(st
.st_mode
))
897 if (!S_ISREG(st
.st_mode
))
900 f
= fdopen(fd
, "re");
905 r
= config_parse(NULL
, path
, f
,
907 config_item_table_lookup
, items
,
908 true, true, false, info
);
912 info
->type
= UNIT_FILE_TYPE_REGULAR
;
915 (int) strv_length(info
->aliases
) +
916 (int) strv_length(info
->wanted_by
) +
917 (int) strv_length(info
->required_by
);
920 static int unit_file_load_or_readlink(
922 UnitFileInstallInfo
*info
,
924 const char *root_dir
,
927 _cleanup_free_
char *np
= NULL
;
930 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
934 /* This is a symlink, let's read it. */
936 r
= readlink_and_make_absolute_root(root_dir
, path
, &np
);
940 if (path_equal(np
, "/dev/null"))
941 info
->type
= UNIT_FILE_TYPE_MASKED
;
948 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
950 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
953 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
955 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
958 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
960 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
965 /* Enforce that the symlink destination does not
966 * change the unit file type. */
968 a
= unit_name_to_type(info
->name
);
969 b
= unit_name_to_type(bn
);
970 if (a
< 0 || b
< 0 || a
!= b
)
973 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
974 info
->symlink_target
= np
;
981 static int unit_file_search(
983 UnitFileInstallInfo
*info
,
984 const LookupPaths
*paths
,
985 const char *root_dir
,
995 /* Was this unit already loaded? */
996 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1000 return unit_file_load_or_readlink(c
, info
, info
->path
, root_dir
, flags
);
1004 STRV_FOREACH(p
, paths
->search_path
) {
1005 _cleanup_free_
char *path
= NULL
;
1007 path
= strjoin(*p
, "/", info
->name
, NULL
);
1011 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1022 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1024 /* Unit file doesn't exist, however instance
1025 * enablement was requested. We will check if it is
1026 * possible to load template unit file. */
1028 _cleanup_free_
char *template = NULL
;
1030 r
= unit_name_template(info
->name
, &template);
1034 STRV_FOREACH(p
, paths
->search_path
) {
1035 _cleanup_free_
char *path
= NULL
;
1037 path
= strjoin(*p
, "/", template, NULL
);
1041 r
= unit_file_load_or_readlink(c
, info
, path
, root_dir
, flags
);
1056 static int install_info_follow(
1058 UnitFileInstallInfo
*i
,
1059 const char *root_dir
,
1060 SearchFlags flags
) {
1065 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1067 if (!i
->symlink_target
)
1070 /* If the basename doesn't match, the caller should add a
1071 * complete new entry for this. */
1073 if (!streq(basename(i
->symlink_target
), i
->name
))
1077 i
->path
= i
->symlink_target
;
1078 i
->symlink_target
= NULL
;
1079 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1081 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1084 static int install_info_traverse(
1085 UnitFileScope scope
,
1087 const char *root_dir
,
1088 const LookupPaths
*paths
,
1089 UnitFileInstallInfo
*start
,
1091 UnitFileInstallInfo
**ret
) {
1093 UnitFileInstallInfo
*i
;
1101 r
= unit_file_search(c
, start
, paths
, root_dir
, flags
);
1106 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1107 /* Follow the symlink */
1109 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1112 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1113 r
= path_is_config(paths
, i
->path
);
1120 r
= install_info_follow(c
, i
, root_dir
, flags
);
1122 _cleanup_free_
char *buffer
= NULL
;
1128 /* Target has a different name, create a new
1129 * install info object for that, and continue
1132 bn
= basename(i
->symlink_target
);
1134 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1135 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1137 _cleanup_free_
char *instance
= NULL
;
1139 r
= unit_name_to_instance(i
->name
, &instance
);
1143 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1150 r
= install_info_add(c
, bn
, NULL
, &i
);
1154 r
= unit_file_search(c
, i
, paths
, root_dir
, flags
);
1159 /* Try again, with the new target we found. */
1168 static int install_info_discover(
1169 UnitFileScope scope
,
1171 const char *root_dir
,
1172 const LookupPaths
*paths
,
1175 UnitFileInstallInfo
**ret
) {
1177 UnitFileInstallInfo
*i
;
1184 r
= install_info_add_auto(c
, name
, &i
);
1188 return install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, ret
);
1191 static int install_info_symlink_alias(
1192 UnitFileInstallInfo
*i
,
1193 const char *config_path
,
1195 UnitFileChange
**changes
,
1196 unsigned *n_changes
) {
1202 assert(config_path
);
1204 STRV_FOREACH(s
, i
->aliases
) {
1205 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1207 q
= install_full_printf(i
, *s
, &dst
);
1211 alias_path
= path_make_absolute(dst
, config_path
);
1215 q
= create_symlink(i
->path
, alias_path
, force
, changes
, n_changes
);
1223 static int install_info_symlink_wants(
1224 UnitFileInstallInfo
*i
,
1225 const char *config_path
,
1229 UnitFileChange
**changes
,
1230 unsigned *n_changes
) {
1232 _cleanup_free_
char *buf
= NULL
;
1238 assert(config_path
);
1240 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1242 /* Don't install any symlink if there's no default
1243 * instance configured */
1245 if (!i
->default_instance
)
1248 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1256 STRV_FOREACH(s
, list
) {
1257 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1259 q
= install_full_printf(i
, *s
, &dst
);
1263 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1268 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1272 q
= create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1280 static int install_info_symlink_link(
1281 UnitFileInstallInfo
*i
,
1282 const LookupPaths
*paths
,
1283 const char *config_path
,
1284 const char *root_dir
,
1286 UnitFileChange
**changes
,
1287 unsigned *n_changes
) {
1289 _cleanup_free_
char *path
= NULL
;
1294 assert(config_path
);
1297 r
= in_search_path(i
->path
, paths
->search_path
);
1301 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1305 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1308 static int install_info_apply(
1309 UnitFileInstallInfo
*i
,
1310 const LookupPaths
*paths
,
1311 const char *config_path
,
1312 const char *root_dir
,
1314 UnitFileChange
**changes
,
1315 unsigned *n_changes
) {
1321 assert(config_path
);
1323 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1326 r
= install_info_symlink_alias(i
, config_path
, force
, changes
, n_changes
);
1328 q
= install_info_symlink_wants(i
, config_path
, i
->wanted_by
, ".wants/", force
, changes
, n_changes
);
1332 q
= install_info_symlink_wants(i
, config_path
, i
->required_by
, ".requires/", force
, changes
, n_changes
);
1336 q
= install_info_symlink_link(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1343 static int install_context_apply(
1344 UnitFileScope scope
,
1346 const LookupPaths
*paths
,
1347 const char *config_path
,
1348 const char *root_dir
,
1351 UnitFileChange
**changes
,
1352 unsigned *n_changes
) {
1354 UnitFileInstallInfo
*i
;
1359 assert(config_path
);
1361 if (ordered_hashmap_isempty(c
->will_process
))
1364 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1369 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1372 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1376 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, flags
, NULL
);
1380 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1383 q
= install_info_apply(i
, paths
, config_path
, root_dir
, force
, changes
, n_changes
);
1395 static int install_context_mark_for_removal(
1396 UnitFileScope scope
,
1398 const LookupPaths
*paths
,
1399 Set
**remove_symlinks_to
,
1400 const char *config_path
,
1401 const char *root_dir
) {
1403 UnitFileInstallInfo
*i
;
1408 assert(config_path
);
1410 /* Marks all items for removal */
1412 if (ordered_hashmap_isempty(c
->will_process
))
1415 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1419 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1421 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1425 r
= install_info_traverse(scope
, c
, root_dir
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1429 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1432 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1441 UnitFileScope scope
,
1443 const char *root_dir
,
1446 UnitFileChange
**changes
,
1447 unsigned *n_changes
) {
1449 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1450 const char *config_path
;
1455 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1457 r
= verify_root_dir(scope
, &root_dir
);
1461 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1465 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1467 STRV_FOREACH(i
, files
) {
1468 _cleanup_free_
char *path
= NULL
;
1471 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1477 path
= path_make_absolute(*i
, config_path
);
1481 q
= create_symlink("/dev/null", path
, force
, changes
, n_changes
);
1482 if (q
< 0 && r
>= 0)
1489 int unit_file_unmask(
1490 UnitFileScope scope
,
1492 const char *root_dir
,
1494 UnitFileChange
**changes
,
1495 unsigned *n_changes
) {
1497 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1498 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1499 _cleanup_free_
char **todo
= NULL
;
1500 size_t n_todo
= 0, n_allocated
= 0;
1501 const char *config_path
;
1506 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1508 r
= verify_root_dir(scope
, &root_dir
);
1512 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1516 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1518 STRV_FOREACH(i
, files
) {
1519 _cleanup_free_
char *path
= NULL
;
1521 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1524 path
= path_make_absolute(*i
, config_path
);
1528 r
= null_or_empty_path(path
);
1536 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1539 todo
[n_todo
++] = *i
;
1545 STRV_FOREACH(i
, todo
) {
1546 _cleanup_free_
char *path
= NULL
;
1548 path
= path_make_absolute(*i
, config_path
);
1552 if (unlink(path
) < 0) {
1553 if (errno
!= -ENOENT
&& r
>= 0)
1556 q
= mark_symlink_for_removal(&remove_symlinks_to
, path
);
1560 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1564 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1572 UnitFileScope scope
,
1574 const char *root_dir
,
1577 UnitFileChange
**changes
,
1578 unsigned *n_changes
) {
1580 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1581 _cleanup_free_
char **todo
= NULL
;
1582 size_t n_todo
= 0, n_allocated
= 0;
1583 const char *config_path
;
1588 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1590 r
= verify_root_dir(scope
, &root_dir
);
1594 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1598 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1600 STRV_FOREACH(i
, files
) {
1601 _cleanup_free_
char *full
= NULL
;
1605 if (!path_is_absolute(*i
))
1609 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1612 full
= prefix_root(root_dir
, *i
);
1616 if (lstat(full
, &st
) < 0)
1618 if (S_ISLNK(st
.st_mode
))
1620 if (S_ISDIR(st
.st_mode
))
1622 if (!S_ISREG(st
.st_mode
))
1625 q
= in_search_path(*i
, paths
.search_path
);
1631 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1634 todo
[n_todo
++] = *i
;
1640 STRV_FOREACH(i
, todo
) {
1641 _cleanup_free_
char *path
= NULL
;
1643 path
= path_make_absolute(basename(*i
), config_path
);
1647 q
= create_symlink(*i
, path
, force
, changes
, n_changes
);
1648 if (q
< 0 && r
>= 0)
1655 int unit_file_add_dependency(
1656 UnitFileScope scope
,
1658 const char *root_dir
,
1663 UnitFileChange
**changes
,
1664 unsigned *n_changes
) {
1666 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1667 _cleanup_(install_context_done
) InstallContext c
= {};
1668 UnitFileInstallInfo
*i
, *target_info
;
1669 const char *config_path
;
1674 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1677 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
1680 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
1683 r
= verify_root_dir(scope
, &root_dir
);
1687 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1691 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1693 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
1696 if (target_info
->type
== UNIT_FILE_TYPE_MASKED
)
1698 if (unit_file_is_generated(&paths
, target_info
->path
))
1699 return -EADDRNOTAVAIL
;
1701 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
1703 STRV_FOREACH(f
, files
) {
1706 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1709 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1711 if (unit_file_is_generated(&paths
, i
->path
))
1712 return -EADDRNOTAVAIL
;
1714 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1716 /* We didn't actually load anything from the unit
1717 * file, but instead just add in our new symlink to
1720 if (dep
== UNIT_WANTS
)
1723 l
= &i
->required_by
;
1726 *l
= strv_new(target_info
->name
, NULL
);
1731 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
1734 int unit_file_enable(
1735 UnitFileScope scope
,
1737 const char *root_dir
,
1740 UnitFileChange
**changes
,
1741 unsigned *n_changes
) {
1743 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1744 _cleanup_(install_context_done
) InstallContext c
= {};
1745 const char *config_path
;
1746 UnitFileInstallInfo
*i
;
1751 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1753 r
= verify_root_dir(scope
, &root_dir
);
1757 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1761 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1763 STRV_FOREACH(f
, files
) {
1764 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, *f
, SEARCH_LOAD
, &i
);
1767 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1769 if (unit_file_is_generated(&paths
, i
->path
))
1770 return -EADDRNOTAVAIL
;
1772 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
1775 /* This will return the number of symlink rules that were
1776 supposed to be created, not the ones actually created. This
1777 is useful to determine whether the passed files had any
1778 installation data at all. */
1780 return install_context_apply(scope
, &c
, &paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
1783 int unit_file_disable(
1784 UnitFileScope scope
,
1786 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_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1794 const char *config_path
;
1799 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1801 r
= verify_root_dir(scope
, &root_dir
);
1805 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1809 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1811 STRV_FOREACH(i
, files
) {
1812 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1815 r
= install_info_add(&c
, *i
, NULL
, NULL
);
1820 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, root_dir
);
1824 return remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
1827 int unit_file_reenable(
1828 UnitFileScope scope
,
1830 const char *root_dir
,
1833 UnitFileChange
**changes
,
1834 unsigned *n_changes
) {
1840 /* First, we invoke the disable command with only the basename... */
1841 l
= strv_length(files
);
1842 n
= newa(char*, l
+1);
1843 for (i
= 0; i
< l
; i
++)
1844 n
[i
] = basename(files
[i
]);
1847 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
1851 /* But the enable command with the full name */
1852 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
1855 int unit_file_set_default(
1856 UnitFileScope scope
,
1857 const char *root_dir
,
1860 UnitFileChange
**changes
,
1861 unsigned *n_changes
) {
1863 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1864 _cleanup_(install_context_done
) InstallContext c
= {};
1865 UnitFileInstallInfo
*i
;
1870 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1873 if (unit_name_to_type(name
) != UNIT_TARGET
)
1875 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
1878 r
= verify_root_dir(scope
, &root_dir
);
1882 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1886 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, name
, 0, &i
);
1889 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1891 if (unit_file_is_generated(&paths
, i
->path
))
1892 return -EADDRNOTAVAIL
;
1894 path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
1896 return create_symlink(i
->path
, path
, force
, changes
, n_changes
);
1899 int unit_file_get_default(
1900 UnitFileScope scope
,
1901 const char *root_dir
,
1904 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1905 _cleanup_(install_context_done
) InstallContext c
= {};
1906 UnitFileInstallInfo
*i
;
1911 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1914 r
= verify_root_dir(scope
, &root_dir
);
1918 r
= lookup_paths_init(&paths
, scope
, root_dir
);
1922 r
= install_info_discover(scope
, &c
, root_dir
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1925 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
1928 n
= strdup(i
->name
);
1936 int unit_file_lookup_state(
1937 UnitFileScope scope
,
1938 const char *root_dir
,
1939 const LookupPaths
*paths
,
1941 UnitFileState
*ret
) {
1943 _cleanup_(install_context_done
) InstallContext c
= {};
1944 UnitFileInstallInfo
*i
;
1945 UnitFileState state
;
1951 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1954 r
= verify_root_dir(scope
, &root_dir
);
1958 r
= install_info_discover(scope
, &c
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
1962 /* Shortcut things, if the caller just wants to know if this unit exists. */
1968 case UNIT_FILE_TYPE_MASKED
:
1969 r
= path_is_runtime(paths
, i
->path
);
1973 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
1976 case UNIT_FILE_TYPE_REGULAR
:
1977 r
= unit_file_is_generated(paths
, i
->path
);
1981 state
= UNIT_FILE_GENERATED
;
1985 r
= find_symlinks_in_scope(scope
, paths
, root_dir
, i
->name
, &state
);
1989 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
1990 state
= UNIT_FILE_DISABLED
;
1991 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
1992 state
= UNIT_FILE_INDIRECT
;
1994 state
= UNIT_FILE_STATIC
;
2000 assert_not_reached("Unexpect unit file type.");
2007 int unit_file_get_state(
2008 UnitFileScope scope
,
2009 const char *root_dir
,
2011 UnitFileState
*ret
) {
2013 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2017 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2020 r
= verify_root_dir(scope
, &root_dir
);
2024 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2028 return unit_file_lookup_state(scope
, root_dir
, &paths
, name
, ret
);
2031 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2032 _cleanup_strv_free_
char **files
= NULL
;
2037 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2040 r
= verify_root_dir(scope
, &root_dir
);
2044 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2047 if (scope
== UNIT_FILE_SYSTEM
)
2048 r
= conf_files_list(&files
, ".preset", root_dir
,
2049 "/etc/systemd/system-preset",
2050 "/usr/local/lib/systemd/system-preset",
2051 "/usr/lib/systemd/system-preset",
2052 #ifdef HAVE_SPLIT_USR
2053 "/lib/systemd/system-preset",
2056 else if (scope
== UNIT_FILE_GLOBAL
)
2057 r
= conf_files_list(&files
, ".preset", root_dir
,
2058 "/etc/systemd/user-preset",
2059 "/usr/local/lib/systemd/user-preset",
2060 "/usr/lib/systemd/user-preset",
2063 return 1; /* Default is "enable" */
2068 STRV_FOREACH(p
, files
) {
2069 _cleanup_fclose_
FILE *f
;
2070 char line
[LINE_MAX
];
2072 f
= fopen(*p
, "re");
2074 if (errno
== ENOENT
)
2080 FOREACH_LINE(line
, f
, return -errno
) {
2081 const char *parameter
;
2088 if (strchr(COMMENTS
, *l
))
2091 parameter
= first_word(l
, "enable");
2093 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2094 log_debug("Preset file says enable %s.", name
);
2101 parameter
= first_word(l
, "disable");
2103 if (fnmatch(parameter
, name
, FNM_NOESCAPE
) == 0) {
2104 log_debug("Preset file says disable %s.", name
);
2111 log_debug("Couldn't parse line '%s'", l
);
2115 /* Default is "enable" */
2116 log_debug("Preset file doesn't say anything about %s, enabling.", name
);
2120 static int execute_preset(
2121 UnitFileScope scope
,
2122 InstallContext
*plus
,
2123 InstallContext
*minus
,
2124 const LookupPaths
*paths
,
2125 const char *config_path
,
2126 const char *root_dir
,
2128 UnitFilePresetMode mode
,
2130 UnitFileChange
**changes
,
2131 unsigned *n_changes
) {
2138 assert(config_path
);
2140 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2141 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2143 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, root_dir
);
2147 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, changes
, n_changes
);
2151 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2154 /* Returns number of symlinks that where supposed to be installed. */
2155 q
= install_context_apply(scope
, plus
, paths
, config_path
, root_dir
, force
, SEARCH_LOAD
, changes
, n_changes
);
2167 static int preset_prepare_one(
2168 UnitFileScope scope
,
2169 InstallContext
*plus
,
2170 InstallContext
*minus
,
2172 const char *root_dir
,
2173 UnitFilePresetMode mode
,
2176 UnitFileInstallInfo
*i
;
2179 if (install_info_find(plus
, name
) ||
2180 install_info_find(minus
, name
))
2183 r
= unit_file_query_preset(scope
, root_dir
, name
);
2188 r
= install_info_discover(scope
, plus
, root_dir
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2192 if (i
->type
== UNIT_FILE_TYPE_MASKED
)
2194 if (unit_file_is_generated(paths
, i
->path
))
2195 return -EADDRNOTAVAIL
;
2197 r
= install_info_discover(scope
, minus
, root_dir
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2202 int unit_file_preset(
2203 UnitFileScope scope
,
2205 const char *root_dir
,
2207 UnitFilePresetMode mode
,
2209 UnitFileChange
**changes
,
2210 unsigned *n_changes
) {
2212 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2213 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2214 const char *config_path
;
2219 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2220 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2222 r
= verify_root_dir(scope
, &root_dir
);
2226 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2230 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2232 STRV_FOREACH(i
, files
) {
2233 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2236 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, *i
);
2241 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, files
, mode
, force
, changes
, n_changes
);
2244 int unit_file_preset_all(
2245 UnitFileScope scope
,
2247 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 const 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(&paths
, scope
, root_dir
);
2271 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2273 STRV_FOREACH(i
, paths
.search_path
) {
2274 _cleanup_closedir_
DIR *d
= NULL
;
2275 _cleanup_free_
char *units_dir
;
2278 units_dir
= path_join(root_dir
, *i
, NULL
);
2282 d
= opendir(units_dir
);
2284 if (errno
== ENOENT
)
2290 FOREACH_DIRENT(de
, d
, return -errno
) {
2292 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2295 dirent_ensure_type(d
, de
);
2297 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2300 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, root_dir
, mode
, de
->d_name
);
2306 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, root_dir
, NULL
, mode
, force
, changes
, n_changes
);
2309 static void unit_file_list_free_one(UnitFileList
*f
) {
2317 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2320 while ((i
= hashmap_steal_first(h
)))
2321 unit_file_list_free_one(i
);
2323 return hashmap_free(h
);
2326 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2328 int unit_file_get_list(
2329 UnitFileScope scope
,
2330 const char *root_dir
,
2333 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2338 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2341 r
= verify_root_dir(scope
, &root_dir
);
2345 r
= lookup_paths_init(&paths
, scope
, root_dir
);
2349 STRV_FOREACH(i
, paths
.search_path
) {
2350 _cleanup_closedir_
DIR *d
= NULL
;
2351 _cleanup_free_
char *units_dir
;
2354 units_dir
= path_join(root_dir
, *i
, NULL
);
2358 d
= opendir(units_dir
);
2360 if (errno
== ENOENT
)
2366 FOREACH_DIRENT(de
, d
, return -errno
) {
2367 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2369 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2372 if (hashmap_get(h
, de
->d_name
))
2375 dirent_ensure_type(d
, de
);
2377 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2380 f
= new0(UnitFileList
, 1);
2384 f
->path
= path_make_absolute(de
->d_name
, units_dir
);
2388 r
= unit_file_lookup_state(scope
, root_dir
, &paths
, basename(f
->path
), &f
->state
);
2390 f
->state
= UNIT_FILE_BAD
;
2392 r
= hashmap_put(h
, basename(f
->path
), f
);
2396 f
= NULL
; /* prevent cleanup */
2403 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2404 [UNIT_FILE_ENABLED
] = "enabled",
2405 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2406 [UNIT_FILE_LINKED
] = "linked",
2407 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
2408 [UNIT_FILE_MASKED
] = "masked",
2409 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
2410 [UNIT_FILE_STATIC
] = "static",
2411 [UNIT_FILE_DISABLED
] = "disabled",
2412 [UNIT_FILE_INDIRECT
] = "indirect",
2413 [UNIT_FILE_GENERATED
] = "generated",
2414 [UNIT_FILE_BAD
] = "bad",
2417 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
2419 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
2420 [UNIT_FILE_SYMLINK
] = "symlink",
2421 [UNIT_FILE_UNLINK
] = "unlink",
2424 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
2426 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
2427 [UNIT_FILE_PRESET_FULL
] = "full",
2428 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
2429 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
2432 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);