1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
20 #include "alloc-util.h"
21 #include "conf-files.h"
22 #include "conf-parser.h"
23 #include "dirent-util.h"
24 #include "extract-word.h"
29 #include "install-printf.h"
31 #include "locale-util.h"
35 #include "path-lookup.h"
36 #include "path-util.h"
40 #include "stat-util.h"
41 #include "string-table.h"
42 #include "string-util.h"
44 #include "unit-name.h"
46 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
48 typedef enum SearchFlags
{
49 SEARCH_LOAD
= 1U << 0,
50 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1U << 1,
51 SEARCH_DROPIN
= 1U << 2,
55 OrderedHashmap
*will_process
;
56 OrderedHashmap
*have_processed
;
75 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
78 return !strv_isempty(i
->aliases
) ||
79 !strv_isempty(i
->wanted_by
) ||
80 !strv_isempty(i
->required_by
);
83 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
86 return !strv_isempty(i
->also
);
89 static inline void presets_freep(Presets
*p
) {
95 for (i
= 0; i
< p
->n_rules
; i
++)
96 free(p
->rules
[i
].pattern
);
102 static int unit_file_lookup_state(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
, UnitFileState
*ret
);
104 bool unit_type_may_alias(UnitType type
) {
114 bool unit_type_may_template(UnitType type
) {
123 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
124 [UNIT_FILE_TYPE_REGULAR
] = "regular",
125 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
126 [UNIT_FILE_TYPE_MASKED
] = "masked",
129 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
131 static int in_search_path(const LookupPaths
*p
, const char *path
) {
132 _cleanup_free_
char *parent
= NULL
;
137 parent
= dirname_malloc(path
);
141 STRV_FOREACH(i
, p
->search_path
)
142 if (path_equal(parent
, *i
))
148 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
157 e
= path_startswith(path
, p
->root_dir
);
161 /* Make sure the returned path starts with a slash */
163 if (e
== path
|| e
[-1] != '/')
172 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
173 _cleanup_free_
char *parent
= NULL
;
178 parent
= dirname_malloc(path
);
182 return path_equal_ptr(parent
, p
->generator
) ||
183 path_equal_ptr(parent
, p
->generator_early
) ||
184 path_equal_ptr(parent
, p
->generator_late
);
187 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
188 _cleanup_free_
char *parent
= NULL
;
193 parent
= dirname_malloc(path
);
197 return path_equal_ptr(parent
, p
->transient
);
200 static int path_is_control(const LookupPaths
*p
, const char *path
) {
201 _cleanup_free_
char *parent
= NULL
;
206 parent
= dirname_malloc(path
);
210 return path_equal_ptr(parent
, p
->persistent_control
) ||
211 path_equal_ptr(parent
, p
->runtime_control
);
214 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
215 _cleanup_free_
char *parent
= NULL
;
220 /* Note that we do *not* have generic checks for /etc or /run in place, since with
221 * them we couldn't discern configuration from transient or generated units */
224 parent
= dirname_malloc(path
);
231 return path_equal_ptr(path
, p
->persistent_config
) ||
232 path_equal_ptr(path
, p
->runtime_config
);
235 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
236 _cleanup_free_
char *parent
= NULL
;
242 /* Everything in /run is considered runtime. On top of that we also add
243 * explicit checks for the various runtime directories, as safety net. */
245 rpath
= skip_root(p
, path
);
246 if (rpath
&& path_startswith(rpath
, "/run"))
250 parent
= dirname_malloc(path
);
257 return path_equal_ptr(path
, p
->runtime_config
) ||
258 path_equal_ptr(path
, p
->generator
) ||
259 path_equal_ptr(path
, p
->generator_early
) ||
260 path_equal_ptr(path
, p
->generator_late
) ||
261 path_equal_ptr(path
, p
->transient
) ||
262 path_equal_ptr(path
, p
->runtime_control
);
265 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
271 rpath
= skip_root(p
, path
);
275 if (path_startswith(rpath
, "/usr"))
279 if (path_startswith(rpath
, "/lib"))
283 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
286 int unit_file_changes_add(
287 UnitFileChange
**changes
,
289 UnitFileChangeType type
,
291 const char *source
) {
293 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
297 assert(!changes
== !n_changes
);
302 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
311 if (!p
|| (source
&& !s
))
314 path_kill_slashes(p
);
316 path_kill_slashes(s
);
318 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
324 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
327 assert(changes
|| n_changes
== 0);
329 for (i
= 0; i
< n_changes
; i
++) {
330 free(changes
[i
].path
);
331 free(changes
[i
].source
);
337 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, unsigned n_changes
, bool quiet
) {
341 assert(changes
|| n_changes
== 0);
342 /* If verb is not specified, errors are not allowed! */
343 assert(verb
|| r
>= 0);
345 for (i
= 0; i
< n_changes
; i
++) {
346 assert(verb
|| changes
[i
].type
>= 0);
348 switch(changes
[i
].type
) {
349 case UNIT_FILE_SYMLINK
:
351 log_info("Created symlink %s %s %s.",
353 special_glyph(ARROW
),
356 case UNIT_FILE_UNLINK
:
358 log_info("Removed %s.", changes
[i
].path
);
360 case UNIT_FILE_IS_MASKED
:
362 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
364 case UNIT_FILE_IS_DANGLING
:
366 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
370 if (changes
[i
].source
)
371 log_error_errno(changes
[i
].type
,
372 "Failed to %s unit, file %s already exists and is a symlink to %s.",
373 verb
, changes
[i
].path
, changes
[i
].source
);
375 log_error_errno(changes
[i
].type
,
376 "Failed to %s unit, file %s already exists.",
377 verb
, changes
[i
].path
);
381 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
382 verb
, changes
[i
].path
);
386 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
387 verb
, changes
[i
].path
);
391 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
392 verb
, changes
[i
].path
);
397 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
402 assert(changes
[i
].type
< 0);
403 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
404 verb
, changes
[i
].path
);
409 if (r
< 0 && !logged
)
410 log_error_errno(r
, "Failed to %s: %m.", verb
);
414 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
415 * wc should be the full path in the host file system.
417 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
418 assert(path_is_absolute(wd
));
420 /* This will give incorrect results if the paths are relative and go outside
421 * of the chroot. False negatives are possible. */
426 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
427 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
428 return path_equal_or_files_same(a
, b
, 0);
431 static int create_symlink(
432 const LookupPaths
*paths
,
433 const char *old_path
,
434 const char *new_path
,
436 UnitFileChange
**changes
,
437 unsigned *n_changes
) {
439 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
446 rp
= skip_root(paths
, old_path
);
450 /* Actually create a symlink, and remember that we did. Is
451 * smart enough to check if there's already a valid symlink in
454 * Returns 1 if a symlink was created or already exists and points to
455 * the right place, or negative on error.
458 mkdir_parents_label(new_path
, 0755);
460 if (symlink(old_path
, new_path
) >= 0) {
461 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
465 if (errno
!= EEXIST
) {
466 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
470 r
= readlink_malloc(new_path
, &dest
);
472 /* translate EINVAL (non-symlink exists) to EEXIST */
476 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
480 dirname
= dirname_malloc(new_path
);
484 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
488 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
492 r
= symlink_atomic(old_path
, new_path
);
494 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
498 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
499 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
504 static int mark_symlink_for_removal(
505 Set
**remove_symlinks_to
,
513 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
521 path_kill_slashes(n
);
523 r
= set_consume(*remove_symlinks_to
, n
);
532 static int remove_marked_symlinks_fd(
533 Set
*remove_symlinks_to
,
536 const char *config_path
,
537 const LookupPaths
*lp
,
540 UnitFileChange
**changes
,
541 unsigned *n_changes
) {
543 _cleanup_closedir_
DIR *d
= NULL
;
547 assert(remove_symlinks_to
);
562 FOREACH_DIRENT(de
, d
, return -errno
) {
564 dirent_ensure_type(d
, de
);
566 if (de
->d_type
== DT_DIR
) {
567 _cleanup_free_
char *p
= NULL
;
570 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
580 p
= path_make_absolute(de
->d_name
, path
);
586 /* This will close nfd, regardless whether it succeeds or not */
587 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
591 } else if (de
->d_type
== DT_LNK
) {
592 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
597 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
600 p
= path_make_absolute(de
->d_name
, path
);
603 path_kill_slashes(p
);
605 q
= readlink_malloc(p
, &dest
);
614 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
615 * the same name as a file that is marked. */
617 found
= set_contains(remove_symlinks_to
, dest
) ||
618 set_contains(remove_symlinks_to
, basename(dest
)) ||
619 set_contains(remove_symlinks_to
, de
->d_name
);
625 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
628 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
632 (void) rmdir_parents(p
, config_path
);
635 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
637 /* Now, remember the full path (but with the root prefix removed) of
638 * the symlink we just removed, and remove any symlinks to it, too. */
640 rp
= skip_root(lp
, p
);
641 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
644 if (q
> 0 && !dry_run
)
652 static int remove_marked_symlinks(
653 Set
*remove_symlinks_to
,
654 const char *config_path
,
655 const LookupPaths
*lp
,
657 UnitFileChange
**changes
,
658 unsigned *n_changes
) {
660 _cleanup_close_
int fd
= -1;
667 if (set_size(remove_symlinks_to
) <= 0)
670 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
672 return errno
== ENOENT
? 0 : -errno
;
678 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
682 /* This takes possession of cfd and closes it */
683 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
691 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
694 if (streq(name
, i
->name
))
697 if (strv_contains(i
->aliases
, name
))
700 /* Look for template symlink matching DefaultInstance */
701 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
702 _cleanup_free_
char *s
= NULL
;
704 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
709 } else if (streq(name
, s
))
716 static int find_symlinks_fd(
717 const char *root_dir
,
718 UnitFileInstallInfo
*i
,
722 const char *config_path
,
723 bool *same_name_link
) {
725 _cleanup_closedir_
DIR *d
= NULL
;
733 assert(same_name_link
);
741 FOREACH_DIRENT(de
, d
, return -errno
) {
743 dirent_ensure_type(d
, de
);
745 if (de
->d_type
== DT_DIR
) {
746 _cleanup_free_
char *p
= NULL
;
749 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
759 p
= path_make_absolute(de
->d_name
, path
);
765 /* This will close nfd, regardless whether it succeeds or not */
766 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
767 p
, config_path
, same_name_link
);
773 } else if (de
->d_type
== DT_LNK
) {
774 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
775 bool found_path
, found_dest
, b
= false;
778 /* Acquire symlink name */
779 p
= path_make_absolute(de
->d_name
, path
);
783 /* Acquire symlink destination */
784 q
= readlink_malloc(p
, &dest
);
794 if (!path_is_absolute(dest
)) {
797 x
= prefix_root(root_dir
, dest
);
805 /* Check if the symlink itself matches what we
807 if (path_is_absolute(i
->name
))
808 found_path
= path_equal(p
, i
->name
);
810 found_path
= streq(de
->d_name
, i
->name
);
812 /* Check if what the symlink points to
813 * matches what we are looking for */
814 if (path_is_absolute(i
->name
))
815 found_dest
= path_equal(dest
, i
->name
);
817 found_dest
= streq(basename(dest
), i
->name
);
819 if (found_path
&& found_dest
) {
820 _cleanup_free_
char *t
= NULL
;
822 /* Filter out same name links in the main
824 t
= path_make_absolute(i
->name
, config_path
);
828 b
= path_equal(t
, p
);
832 *same_name_link
= true;
833 else if (found_path
|| found_dest
) {
837 /* Check if symlink name is in the set of names used by [Install] */
838 q
= is_symlink_with_known_name(i
, de
->d_name
);
850 static int find_symlinks(
851 const char *root_dir
,
852 UnitFileInstallInfo
*i
,
854 const char *config_path
,
855 bool *same_name_link
) {
861 assert(same_name_link
);
863 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
865 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
870 /* This takes possession of fd and closes it */
871 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
872 config_path
, config_path
, same_name_link
);
875 static int find_symlinks_in_scope(
877 const LookupPaths
*paths
,
878 UnitFileInstallInfo
*i
,
880 UnitFileState
*state
) {
882 bool same_name_link_runtime
= false, same_name_link_config
= false;
883 bool enabled_in_runtime
= false, enabled_at_all
= false;
890 STRV_FOREACH(p
, paths
->search_path
) {
891 bool same_name_link
= false;
893 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
897 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
899 r
= path_is_config(paths
, *p
, false);
903 /* This is the best outcome, let's return it immediately. */
904 *state
= UNIT_FILE_ENABLED
;
908 /* look for globally enablement of user units */
909 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
910 *state
= UNIT_FILE_ENABLED
;
914 r
= path_is_runtime(paths
, *p
, false);
918 enabled_in_runtime
= true;
920 enabled_at_all
= true;
922 } else if (same_name_link
) {
924 r
= path_is_config(paths
, *p
, false);
928 same_name_link_config
= true;
930 r
= path_is_runtime(paths
, *p
, false);
934 same_name_link_runtime
= true;
939 if (enabled_in_runtime
) {
940 *state
= UNIT_FILE_ENABLED_RUNTIME
;
944 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
945 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
946 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
947 * something, and hence are a much stronger concept. */
948 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
949 *state
= UNIT_FILE_STATIC
;
953 /* Hmm, we didn't find it, but maybe we found the same name
955 if (same_name_link_config
) {
956 *state
= UNIT_FILE_LINKED
;
959 if (same_name_link_runtime
) {
960 *state
= UNIT_FILE_LINKED_RUNTIME
;
967 static void install_info_free(UnitFileInstallInfo
*i
) {
974 strv_free(i
->aliases
);
975 strv_free(i
->wanted_by
);
976 strv_free(i
->required_by
);
978 free(i
->default_instance
);
979 free(i
->symlink_target
);
983 static void install_context_done(InstallContext
*c
) {
986 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
987 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
990 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
991 UnitFileInstallInfo
*i
;
993 i
= ordered_hashmap_get(c
->have_processed
, name
);
997 return ordered_hashmap_get(c
->will_process
, name
);
1000 static int install_info_may_process(
1001 UnitFileInstallInfo
*i
,
1002 const LookupPaths
*paths
,
1003 UnitFileChange
**changes
,
1004 unsigned *n_changes
) {
1008 /* Checks whether the loaded unit file is one we should process, or is masked,
1009 * transient or generated and thus not subject to enable/disable operations. */
1011 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1012 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1015 if (path_is_generator(paths
, i
->path
) ||
1016 path_is_transient(paths
, i
->path
)) {
1017 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1018 return -EADDRNOTAVAIL
;
1025 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1026 * hashmap, or retrieves the existing one if already present.
1028 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1030 static int install_info_add(
1035 UnitFileInstallInfo
**ret
) {
1037 UnitFileInstallInfo
*i
= NULL
;
1041 assert(name
|| path
);
1044 name
= basename(path
);
1046 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1049 i
= install_info_find(c
, name
);
1051 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1058 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1062 i
= new0(UnitFileInstallInfo
, 1);
1065 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1066 i
->auxiliary
= auxiliary
;
1068 i
->name
= strdup(name
);
1075 i
->path
= strdup(path
);
1082 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1092 install_info_free(i
);
1096 static int config_parse_alias(
1098 const char *filename
,
1100 const char *section
,
1101 unsigned section_line
,
1115 type
= unit_name_to_type(unit
);
1116 if (!unit_type_may_alias(type
))
1117 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1118 "Alias= is not allowed for %s units, ignoring.",
1119 unit_type_to_string(type
));
1121 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1122 lvalue
, ltype
, rvalue
, data
, userdata
);
1125 static int config_parse_also(
1127 const char *filename
,
1129 const char *section
,
1130 unsigned section_line
,
1137 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1138 InstallContext
*c
= data
;
1147 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1149 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1155 r
= install_full_printf(info
, word
, &printed
);
1159 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1162 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1166 r
= strv_push(&info
->also
, printed
);
1176 static int config_parse_default_instance(
1178 const char *filename
,
1180 const char *section
,
1181 unsigned section_line
,
1188 UnitFileInstallInfo
*i
= data
;
1189 _cleanup_free_
char *printed
= NULL
;
1197 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1198 /* When enabling an instance, we might be using a template unit file,
1199 * but we should ignore DefaultInstance silently. */
1201 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1202 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1203 "DefaultInstance= only makes sense for template units, ignoring.");
1205 r
= install_full_printf(i
, rvalue
, &printed
);
1209 if (!unit_instance_is_valid(printed
))
1212 return free_and_replace(i
->default_instance
, printed
);
1215 static int unit_file_load(
1217 UnitFileInstallInfo
*info
,
1219 const char *root_dir
,
1220 SearchFlags flags
) {
1222 const ConfigTableItem items
[] = {
1223 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1224 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1225 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1226 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1227 { "Install", "Also", config_parse_also
, 0, c
},
1232 _cleanup_fclose_
FILE *f
= NULL
;
1233 _cleanup_close_
int fd
= -1;
1240 if (!(flags
& SEARCH_DROPIN
)) {
1241 /* Loading or checking for the main unit file… */
1243 type
= unit_name_to_type(info
->name
);
1246 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1247 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1251 if (!(flags
& SEARCH_LOAD
)) {
1252 r
= lstat(path
, &st
);
1256 if (null_or_empty(&st
))
1257 info
->type
= UNIT_FILE_TYPE_MASKED
;
1258 else if (S_ISREG(st
.st_mode
))
1259 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1260 else if (S_ISLNK(st
.st_mode
))
1262 else if (S_ISDIR(st
.st_mode
))
1270 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1274 /* Operating on a drop-in file. If we aren't supposed to load the unit file drop-ins don't matter, let's hence shortcut this. */
1276 if (!(flags
& SEARCH_LOAD
))
1279 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1284 if (fstat(fd
, &st
) < 0)
1287 if (null_or_empty(&st
)) {
1288 if ((flags
& SEARCH_DROPIN
) == 0)
1289 info
->type
= UNIT_FILE_TYPE_MASKED
;
1294 r
= stat_verify_regular(&st
);
1298 f
= fdopen(fd
, "re");
1303 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1306 r
= config_parse(info
->name
, path
, f
,
1308 config_item_table_lookup
, items
,
1309 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1311 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1313 if ((flags
& SEARCH_DROPIN
) == 0)
1314 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1317 (int) strv_length(info
->aliases
) +
1318 (int) strv_length(info
->wanted_by
) +
1319 (int) strv_length(info
->required_by
);
1322 static int unit_file_load_or_readlink(
1324 UnitFileInstallInfo
*info
,
1326 const char *root_dir
,
1327 SearchFlags flags
) {
1329 _cleanup_free_
char *target
= NULL
;
1332 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1333 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1336 /* This is a symlink, let's read it. */
1338 r
= readlink_malloc(path
, &target
);
1342 if (path_equal(target
, "/dev/null"))
1343 info
->type
= UNIT_FILE_TYPE_MASKED
;
1348 bn
= basename(target
);
1350 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1352 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1355 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1357 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1360 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1362 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1367 /* Enforce that the symlink destination does not
1368 * change the unit file type. */
1370 a
= unit_name_to_type(info
->name
);
1371 b
= unit_name_to_type(bn
);
1372 if (a
< 0 || b
< 0 || a
!= b
)
1375 if (path_is_absolute(target
))
1376 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1377 info
->symlink_target
= prefix_root(root_dir
, target
);
1379 /* This is a relative path, take it relative to the dir the symlink is located in. */
1380 info
->symlink_target
= file_in_same_dir(path
, target
);
1381 if (!info
->symlink_target
)
1384 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1390 static int unit_file_search(
1392 UnitFileInstallInfo
*info
,
1393 const LookupPaths
*paths
,
1394 SearchFlags flags
) {
1396 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1397 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1398 _cleanup_free_
char *template = NULL
;
1399 bool found_unit
= false;
1406 /* Was this unit already loaded? */
1407 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1411 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1415 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1416 r
= unit_name_template(info
->name
, &template);
1421 STRV_FOREACH(p
, paths
->search_path
) {
1422 _cleanup_free_
char *path
= NULL
;
1424 path
= strjoin(*p
, "/", info
->name
);
1428 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1430 info
->path
= TAKE_PTR(path
);
1434 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1438 if (!found_unit
&& template) {
1440 /* Unit file doesn't exist, however instance
1441 * enablement was requested. We will check if it is
1442 * possible to load template unit file. */
1444 STRV_FOREACH(p
, paths
->search_path
) {
1445 _cleanup_free_
char *path
= NULL
;
1447 path
= strjoin(*p
, "/", template);
1451 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1453 info
->path
= TAKE_PTR(path
);
1457 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1463 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1467 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1470 /* Search for drop-in directories */
1472 dropin_dir_name
= strjoina(info
->name
, ".d");
1473 STRV_FOREACH(p
, paths
->search_path
) {
1476 path
= path_join(NULL
, *p
, dropin_dir_name
);
1480 r
= strv_consume(&dirs
, path
);
1486 dropin_template_dir_name
= strjoina(template, ".d");
1487 STRV_FOREACH(p
, paths
->search_path
) {
1490 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1494 r
= strv_consume(&dirs
, path
);
1500 /* Load drop-in conf files */
1502 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1504 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1506 STRV_FOREACH(p
, files
) {
1507 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1509 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1515 static int install_info_follow(
1517 UnitFileInstallInfo
*i
,
1518 const char *root_dir
,
1520 bool ignore_different_name
) {
1525 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1527 if (!i
->symlink_target
)
1530 /* If the basename doesn't match, the caller should add a
1531 * complete new entry for this. */
1533 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1536 free_and_replace(i
->path
, i
->symlink_target
);
1537 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1539 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1543 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1544 * target, maybe more than once. Propagate the instance name if present.
1546 static int install_info_traverse(
1547 UnitFileScope scope
,
1549 const LookupPaths
*paths
,
1550 UnitFileInstallInfo
*start
,
1552 UnitFileInstallInfo
**ret
) {
1554 UnitFileInstallInfo
*i
;
1562 r
= unit_file_search(c
, start
, paths
, flags
);
1567 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1568 /* Follow the symlink */
1570 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1573 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1574 r
= path_is_config(paths
, i
->path
, true);
1581 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1583 _cleanup_free_
char *buffer
= NULL
;
1586 /* Target has a different name, create a new
1587 * install info object for that, and continue
1590 bn
= basename(i
->symlink_target
);
1592 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1593 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1595 _cleanup_free_
char *instance
= NULL
;
1597 r
= unit_name_to_instance(i
->name
, &instance
);
1601 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1605 if (streq(buffer
, i
->name
)) {
1607 /* We filled in the instance, and the target stayed the same? If so, then let's
1608 * honour the link as it is. */
1610 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1620 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1624 /* Try again, with the new target we found. */
1625 r
= unit_file_search(c
, i
, paths
, flags
);
1627 /* Translate error code to highlight this specific case */
1642 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1643 * or the name (otherwise). root_dir is prepended to the path.
1645 static int install_info_add_auto(
1647 const LookupPaths
*paths
,
1648 const char *name_or_path
,
1649 UnitFileInstallInfo
**ret
) {
1652 assert(name_or_path
);
1654 if (path_is_absolute(name_or_path
)) {
1657 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1659 return install_info_add(c
, NULL
, pp
, false, ret
);
1661 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1664 static int install_info_discover(
1665 UnitFileScope scope
,
1667 const LookupPaths
*paths
,
1670 UnitFileInstallInfo
**ret
,
1671 UnitFileChange
**changes
,
1672 unsigned *n_changes
) {
1674 UnitFileInstallInfo
*i
;
1681 r
= install_info_add_auto(c
, paths
, name
, &i
);
1683 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1686 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1690 static int install_info_symlink_alias(
1691 UnitFileInstallInfo
*i
,
1692 const LookupPaths
*paths
,
1693 const char *config_path
,
1695 UnitFileChange
**changes
,
1696 unsigned *n_changes
) {
1703 assert(config_path
);
1705 STRV_FOREACH(s
, i
->aliases
) {
1706 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1708 q
= install_full_printf(i
, *s
, &dst
);
1712 alias_path
= path_make_absolute(dst
, config_path
);
1716 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1724 static int install_info_symlink_wants(
1725 UnitFileInstallInfo
*i
,
1726 const LookupPaths
*paths
,
1727 const char *config_path
,
1730 UnitFileChange
**changes
,
1731 unsigned *n_changes
) {
1733 _cleanup_free_
char *buf
= NULL
;
1740 assert(config_path
);
1742 if (strv_isempty(list
))
1745 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1746 UnitFileInstallInfo instance
= {
1747 .type
= _UNIT_FILE_TYPE_INVALID
,
1749 _cleanup_free_
char *path
= NULL
;
1751 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1755 instance
.name
= buf
;
1756 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1760 path
= TAKE_PTR(instance
.path
);
1762 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1763 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1771 STRV_FOREACH(s
, list
) {
1772 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1774 q
= install_full_printf(i
, *s
, &dst
);
1778 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1783 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1787 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1795 static int install_info_symlink_link(
1796 UnitFileInstallInfo
*i
,
1797 const LookupPaths
*paths
,
1798 const char *config_path
,
1800 UnitFileChange
**changes
,
1801 unsigned *n_changes
) {
1803 _cleanup_free_
char *path
= NULL
;
1808 assert(config_path
);
1811 r
= in_search_path(paths
, i
->path
);
1817 path
= strjoin(config_path
, "/", i
->name
);
1821 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1824 static int install_info_apply(
1825 UnitFileInstallInfo
*i
,
1826 const LookupPaths
*paths
,
1827 const char *config_path
,
1829 UnitFileChange
**changes
,
1830 unsigned *n_changes
) {
1836 assert(config_path
);
1838 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1841 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1843 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1847 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1851 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1852 /* Do not count links to the unit file towards the "carries_install_info" count */
1853 if (r
== 0 && q
< 0)
1859 static int install_context_apply(
1860 UnitFileScope scope
,
1862 const LookupPaths
*paths
,
1863 const char *config_path
,
1866 UnitFileChange
**changes
,
1867 unsigned *n_changes
) {
1869 UnitFileInstallInfo
*i
;
1874 assert(config_path
);
1876 if (ordered_hashmap_isempty(c
->will_process
))
1879 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1884 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1887 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1891 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1893 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1897 /* We can attempt to process a masked unit when a different unit
1898 * that we were processing specifies it in Also=. */
1899 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1900 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1902 /* Assume that something *could* have been enabled here,
1903 * avoid "empty [Install] section" warning. */
1908 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1911 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1923 static int install_context_mark_for_removal(
1924 UnitFileScope scope
,
1926 const LookupPaths
*paths
,
1927 Set
**remove_symlinks_to
,
1928 const char *config_path
,
1929 UnitFileChange
**changes
,
1930 unsigned *n_changes
) {
1932 UnitFileInstallInfo
*i
;
1937 assert(config_path
);
1939 /* Marks all items for removal */
1941 if (ordered_hashmap_isempty(c
->will_process
))
1944 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1948 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1950 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1954 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1955 if (r
== -ENOLINK
) {
1956 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1957 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1958 } else if (r
== -ENOENT
) {
1960 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1961 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1963 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1964 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1968 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1969 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1970 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1971 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1972 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1974 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1975 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1979 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1988 UnitFileScope scope
,
1989 UnitFileFlags flags
,
1990 const char *root_dir
,
1992 UnitFileChange
**changes
,
1993 unsigned *n_changes
) {
1995 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
1996 const char *config_path
;
2001 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2003 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2007 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2011 STRV_FOREACH(i
, files
) {
2012 _cleanup_free_
char *path
= NULL
;
2015 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2021 path
= path_make_absolute(*i
, config_path
);
2025 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2026 if (q
< 0 && r
>= 0)
2033 int unit_file_unmask(
2034 UnitFileScope scope
,
2035 UnitFileFlags flags
,
2036 const char *root_dir
,
2038 UnitFileChange
**changes
,
2039 unsigned *n_changes
) {
2041 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2042 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2043 _cleanup_strv_free_
char **todo
= NULL
;
2044 size_t n_todo
= 0, n_allocated
= 0;
2045 const char *config_path
;
2051 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2053 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2057 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2061 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2063 STRV_FOREACH(i
, files
) {
2064 _cleanup_free_
char *path
= NULL
;
2066 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2069 path
= path_make_absolute(*i
, config_path
);
2073 r
= null_or_empty_path(path
);
2081 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2084 todo
[n_todo
] = strdup(*i
);
2094 STRV_FOREACH(i
, todo
) {
2095 _cleanup_free_
char *path
= NULL
;
2098 path
= path_make_absolute(*i
, config_path
);
2102 if (!dry_run
&& unlink(path
) < 0) {
2103 if (errno
!= ENOENT
) {
2106 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2112 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2114 rp
= skip_root(&paths
, path
);
2115 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2120 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2128 UnitFileScope scope
,
2129 UnitFileFlags flags
,
2130 const char *root_dir
,
2132 UnitFileChange
**changes
,
2133 unsigned *n_changes
) {
2135 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2136 _cleanup_strv_free_
char **todo
= NULL
;
2137 size_t n_todo
= 0, n_allocated
= 0;
2138 const char *config_path
;
2143 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2145 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2149 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2153 STRV_FOREACH(i
, files
) {
2154 _cleanup_free_
char *full
= NULL
;
2158 if (!path_is_absolute(*i
))
2162 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2165 full
= prefix_root(paths
.root_dir
, *i
);
2169 if (lstat(full
, &st
) < 0)
2171 r
= stat_verify_regular(&st
);
2175 q
= in_search_path(&paths
, *i
);
2181 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2184 todo
[n_todo
] = strdup(*i
);
2194 STRV_FOREACH(i
, todo
) {
2195 _cleanup_free_
char *new_path
= NULL
;
2197 new_path
= path_make_absolute(basename(*i
), config_path
);
2201 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2202 if (q
< 0 && r
>= 0)
2209 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2215 /* Checks whether the path is one where the drop-in directories shall be removed. */
2217 r
= path_is_config(paths
, path
, true);
2221 r
= path_is_control(paths
, path
);
2225 return path_is_transient(paths
, path
);
2228 int unit_file_revert(
2229 UnitFileScope scope
,
2230 const char *root_dir
,
2232 UnitFileChange
**changes
,
2233 unsigned *n_changes
) {
2235 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2236 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2237 _cleanup_strv_free_
char **todo
= NULL
;
2238 size_t n_todo
= 0, n_allocated
= 0;
2242 /* Puts a unit file back into vendor state. This means:
2244 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2245 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2247 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2248 * "config", but not in "transient" or "control" or even "generated").
2250 * We remove all that in both the runtime and the persistent directories, if that applies.
2253 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2257 STRV_FOREACH(i
, files
) {
2258 bool has_vendor
= false;
2261 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2264 STRV_FOREACH(p
, paths
.search_path
) {
2265 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2268 path
= path_make_absolute(*i
, *p
);
2272 r
= lstat(path
, &st
);
2274 if (errno
!= ENOENT
)
2276 } else if (S_ISREG(st
.st_mode
)) {
2277 /* Check if there's a vendor version */
2278 r
= path_is_vendor(&paths
, path
);
2285 dropin
= strappend(path
, ".d");
2289 r
= lstat(dropin
, &st
);
2291 if (errno
!= ENOENT
)
2293 } else if (S_ISDIR(st
.st_mode
)) {
2294 /* Remove the drop-ins */
2295 r
= path_shall_revert(&paths
, dropin
);
2299 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2302 todo
[n_todo
++] = TAKE_PTR(dropin
);
2310 /* OK, there's a vendor version, hence drop all configuration versions */
2311 STRV_FOREACH(p
, paths
.search_path
) {
2312 _cleanup_free_
char *path
= NULL
;
2315 path
= path_make_absolute(*i
, *p
);
2319 r
= lstat(path
, &st
);
2321 if (errno
!= ENOENT
)
2323 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2324 r
= path_is_config(&paths
, path
, true);
2328 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2331 todo
[n_todo
++] = TAKE_PTR(path
);
2340 STRV_FOREACH(i
, todo
) {
2341 _cleanup_strv_free_
char **fs
= NULL
;
2345 (void) get_files_in_directory(*i
, &fs
);
2347 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2348 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2353 STRV_FOREACH(j
, fs
) {
2354 _cleanup_free_
char *t
= NULL
;
2356 t
= strjoin(*i
, "/", *j
);
2360 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2363 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2365 rp
= skip_root(&paths
, *i
);
2366 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2371 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2375 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2382 int unit_file_add_dependency(
2383 UnitFileScope scope
,
2384 UnitFileFlags flags
,
2385 const char *root_dir
,
2389 UnitFileChange
**changes
,
2390 unsigned *n_changes
) {
2392 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2393 _cleanup_(install_context_done
) InstallContext c
= {};
2394 UnitFileInstallInfo
*i
, *target_info
;
2395 const char *config_path
;
2400 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2403 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2406 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2409 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2413 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2417 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2418 &target_info
, changes
, n_changes
);
2421 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2425 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2427 STRV_FOREACH(f
, files
) {
2430 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2431 &i
, changes
, n_changes
);
2434 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2438 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2440 /* We didn't actually load anything from the unit
2441 * file, but instead just add in our new symlink to
2444 if (dep
== UNIT_WANTS
)
2447 l
= &i
->required_by
;
2450 *l
= strv_new(target_info
->name
, NULL
);
2455 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2458 int unit_file_enable(
2459 UnitFileScope scope
,
2460 UnitFileFlags flags
,
2461 const char *root_dir
,
2463 UnitFileChange
**changes
,
2464 unsigned *n_changes
) {
2466 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2467 _cleanup_(install_context_done
) InstallContext c
= {};
2468 const char *config_path
;
2469 UnitFileInstallInfo
*i
;
2474 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2476 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2480 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2484 STRV_FOREACH(f
, files
) {
2485 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2486 &i
, changes
, n_changes
);
2489 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2493 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2496 /* This will return the number of symlink rules that were
2497 supposed to be created, not the ones actually created. This
2498 is useful to determine whether the passed files had any
2499 installation data at all. */
2501 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2504 int unit_file_disable(
2505 UnitFileScope scope
,
2506 UnitFileFlags flags
,
2507 const char *root_dir
,
2509 UnitFileChange
**changes
,
2510 unsigned *n_changes
) {
2512 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2513 _cleanup_(install_context_done
) InstallContext c
= {};
2514 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2515 const char *config_path
;
2520 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2522 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2526 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2530 STRV_FOREACH(i
, files
) {
2531 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2534 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2539 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2543 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2546 int unit_file_reenable(
2547 UnitFileScope scope
,
2548 UnitFileFlags flags
,
2549 const char *root_dir
,
2551 UnitFileChange
**changes
,
2552 unsigned *n_changes
) {
2558 /* First, we invoke the disable command with only the basename... */
2559 l
= strv_length(files
);
2560 n
= newa(char*, l
+1);
2561 for (i
= 0; i
< l
; i
++)
2562 n
[i
] = basename(files
[i
]);
2565 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2569 /* But the enable command with the full name */
2570 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2573 int unit_file_set_default(
2574 UnitFileScope scope
,
2575 UnitFileFlags flags
,
2576 const char *root_dir
,
2578 UnitFileChange
**changes
,
2579 unsigned *n_changes
) {
2581 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2582 _cleanup_(install_context_done
) InstallContext c
= {};
2583 UnitFileInstallInfo
*i
;
2584 const char *new_path
;
2588 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2591 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2593 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2596 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2600 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2603 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2607 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2608 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2611 int unit_file_get_default(
2612 UnitFileScope scope
,
2613 const char *root_dir
,
2616 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2617 _cleanup_(install_context_done
) InstallContext c
= {};
2618 UnitFileInstallInfo
*i
;
2623 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2626 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2630 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2634 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2638 n
= strdup(i
->name
);
2646 static int unit_file_lookup_state(
2647 UnitFileScope scope
,
2648 const LookupPaths
*paths
,
2650 UnitFileState
*ret
) {
2652 _cleanup_(install_context_done
) InstallContext c
= {};
2653 UnitFileInstallInfo
*i
;
2654 UnitFileState state
;
2660 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2663 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2668 /* Shortcut things, if the caller just wants to know if this unit exists. */
2674 case UNIT_FILE_TYPE_MASKED
:
2675 r
= path_is_runtime(paths
, i
->path
, true);
2679 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2682 case UNIT_FILE_TYPE_REGULAR
:
2683 r
= path_is_generator(paths
, i
->path
);
2687 state
= UNIT_FILE_GENERATED
;
2691 r
= path_is_transient(paths
, i
->path
);
2695 state
= UNIT_FILE_TRANSIENT
;
2699 /* Check if any of the Alias= symlinks have been created.
2700 * We ignore other aliases, and only check those that would
2701 * be created by systemctl enable for this unit. */
2702 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2708 /* Check if the file is known under other names. If it is,
2709 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2710 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2714 state
= UNIT_FILE_INDIRECT
;
2716 if (unit_file_install_info_has_rules(i
))
2717 state
= UNIT_FILE_DISABLED
;
2718 else if (unit_file_install_info_has_also(i
))
2719 state
= UNIT_FILE_INDIRECT
;
2721 state
= UNIT_FILE_STATIC
;
2727 assert_not_reached("Unexpect unit file type.");
2734 int unit_file_get_state(
2735 UnitFileScope scope
,
2736 const char *root_dir
,
2738 UnitFileState
*ret
) {
2740 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2744 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2747 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2751 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2754 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2755 _cleanup_(install_context_done
) InstallContext c
= {};
2761 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2764 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2773 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2774 _cleanup_(presets_freep
) Presets ps
= {};
2775 size_t n_allocated
= 0;
2776 _cleanup_strv_free_
char **files
= NULL
;
2781 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2784 if (scope
== UNIT_FILE_SYSTEM
)
2785 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2786 "/etc/systemd/system-preset",
2787 "/run/systemd/system-preset",
2788 "/usr/local/lib/systemd/system-preset",
2789 "/usr/lib/systemd/system-preset",
2791 "/lib/systemd/system-preset",
2794 else if (scope
== UNIT_FILE_GLOBAL
)
2795 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2796 "/etc/systemd/user-preset",
2797 "/run/systemd/user-preset",
2798 "/usr/local/lib/systemd/user-preset",
2799 "/usr/lib/systemd/user-preset",
2802 *presets
= (Presets
){};
2810 STRV_FOREACH(p
, files
) {
2811 _cleanup_fclose_
FILE *f
;
2812 char line
[LINE_MAX
];
2815 f
= fopen(*p
, "re");
2817 if (errno
== ENOENT
)
2823 FOREACH_LINE(line
, f
, return -errno
) {
2824 PresetRule rule
= {};
2825 const char *parameter
;
2833 if (strchr(COMMENTS
, *l
))
2836 parameter
= first_word(l
, "enable");
2840 pattern
= strdup(parameter
);
2844 rule
= (PresetRule
) {
2846 .action
= PRESET_ENABLE
,
2850 parameter
= first_word(l
, "disable");
2854 pattern
= strdup(parameter
);
2858 rule
= (PresetRule
) {
2860 .action
= PRESET_DISABLE
,
2865 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2868 ps
.rules
[ps
.n_rules
++] = rule
;
2872 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2882 static int query_presets(const char *name
, const Presets presets
) {
2883 PresetAction action
= PRESET_UNKNOWN
;
2886 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2889 for (i
= 0; i
< presets
.n_rules
; i
++)
2890 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2891 action
= presets
.rules
[i
].action
;
2896 case PRESET_UNKNOWN
:
2897 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2900 log_debug("Preset files say enable %s.", name
);
2902 case PRESET_DISABLE
:
2903 log_debug("Preset files say disable %s.", name
);
2906 assert_not_reached("invalid preset action");
2910 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2911 _cleanup_(presets_freep
) Presets presets
= {};
2914 r
= read_presets(scope
, root_dir
, &presets
);
2918 return query_presets(name
, presets
);
2921 static int execute_preset(
2922 UnitFileScope scope
,
2923 InstallContext
*plus
,
2924 InstallContext
*minus
,
2925 const LookupPaths
*paths
,
2926 const char *config_path
,
2928 UnitFilePresetMode mode
,
2930 UnitFileChange
**changes
,
2931 unsigned *n_changes
) {
2938 assert(config_path
);
2940 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2941 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2943 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2947 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2951 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2954 /* Returns number of symlinks that where supposed to be installed. */
2955 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2967 static int preset_prepare_one(
2968 UnitFileScope scope
,
2969 InstallContext
*plus
,
2970 InstallContext
*minus
,
2974 UnitFileChange
**changes
,
2975 unsigned *n_changes
) {
2977 _cleanup_(install_context_done
) InstallContext tmp
= {};
2978 UnitFileInstallInfo
*i
;
2981 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2984 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2985 &i
, changes
, n_changes
);
2988 if (!streq(name
, i
->name
)) {
2989 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
2993 r
= query_presets(name
, presets
);
2998 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2999 &i
, changes
, n_changes
);
3003 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
3007 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3008 &i
, changes
, n_changes
);
3013 int unit_file_preset(
3014 UnitFileScope scope
,
3015 UnitFileFlags flags
,
3016 const char *root_dir
,
3018 UnitFilePresetMode mode
,
3019 UnitFileChange
**changes
,
3020 unsigned *n_changes
) {
3022 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3023 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3024 _cleanup_(presets_freep
) Presets presets
= {};
3025 const char *config_path
;
3030 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3031 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3033 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3037 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3041 r
= read_presets(scope
, root_dir
, &presets
);
3045 STRV_FOREACH(i
, files
) {
3046 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3051 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3054 int unit_file_preset_all(
3055 UnitFileScope scope
,
3056 UnitFileFlags flags
,
3057 const char *root_dir
,
3058 UnitFilePresetMode mode
,
3059 UnitFileChange
**changes
,
3060 unsigned *n_changes
) {
3062 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3063 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3064 _cleanup_(presets_freep
) Presets presets
= {};
3065 const char *config_path
= NULL
;
3070 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3071 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3073 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3077 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3081 r
= read_presets(scope
, root_dir
, &presets
);
3085 STRV_FOREACH(i
, paths
.search_path
) {
3086 _cleanup_closedir_
DIR *d
= NULL
;
3091 if (errno
== ENOENT
)
3097 FOREACH_DIRENT(de
, d
, return -errno
) {
3099 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3102 dirent_ensure_type(d
, de
);
3104 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3107 /* we don't pass changes[] in, because we want to handle errors on our own */
3108 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3110 r
= unit_file_changes_add(changes
, n_changes
,
3111 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3112 else if (r
== -ENOLINK
)
3113 r
= unit_file_changes_add(changes
, n_changes
,
3114 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3115 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3122 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3125 static void unit_file_list_free_one(UnitFileList
*f
) {
3133 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3134 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3137 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3139 int unit_file_get_list(
3140 UnitFileScope scope
,
3141 const char *root_dir
,
3146 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3151 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3154 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3158 STRV_FOREACH(i
, paths
.search_path
) {
3159 _cleanup_closedir_
DIR *d
= NULL
;
3164 if (errno
== ENOENT
)
3166 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3167 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3174 FOREACH_DIRENT(de
, d
, return -errno
) {
3175 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3177 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3180 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3183 if (hashmap_get(h
, de
->d_name
))
3186 dirent_ensure_type(d
, de
);
3188 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3191 f
= new0(UnitFileList
, 1);
3195 f
->path
= path_make_absolute(de
->d_name
, *i
);
3199 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3201 f
->state
= UNIT_FILE_BAD
;
3203 if (!strv_isempty(states
) &&
3204 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3207 r
= hashmap_put(h
, basename(f
->path
), f
);
3211 f
= NULL
; /* prevent cleanup */
3218 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3219 [UNIT_FILE_ENABLED
] = "enabled",
3220 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3221 [UNIT_FILE_LINKED
] = "linked",
3222 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3223 [UNIT_FILE_MASKED
] = "masked",
3224 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3225 [UNIT_FILE_STATIC
] = "static",
3226 [UNIT_FILE_DISABLED
] = "disabled",
3227 [UNIT_FILE_INDIRECT
] = "indirect",
3228 [UNIT_FILE_GENERATED
] = "generated",
3229 [UNIT_FILE_TRANSIENT
] = "transient",
3230 [UNIT_FILE_BAD
] = "bad",
3233 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3235 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3236 [UNIT_FILE_SYMLINK
] = "symlink",
3237 [UNIT_FILE_UNLINK
] = "unlink",
3238 [UNIT_FILE_IS_MASKED
] = "masked",
3239 [UNIT_FILE_IS_DANGLING
] = "dangling",
3242 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3244 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3245 [UNIT_FILE_PRESET_FULL
] = "full",
3246 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3247 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3250 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);