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 bool unit_type_may_alias(UnitType type
) {
112 bool unit_type_may_template(UnitType type
) {
121 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
122 [UNIT_FILE_TYPE_REGULAR
] = "regular",
123 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
124 [UNIT_FILE_TYPE_MASKED
] = "masked",
127 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
129 static int in_search_path(const LookupPaths
*p
, const char *path
) {
130 _cleanup_free_
char *parent
= NULL
;
135 parent
= dirname_malloc(path
);
139 STRV_FOREACH(i
, p
->search_path
)
140 if (path_equal(parent
, *i
))
146 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
155 e
= path_startswith(path
, p
->root_dir
);
159 /* Make sure the returned path starts with a slash */
161 if (e
== path
|| e
[-1] != '/')
170 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
171 _cleanup_free_
char *parent
= NULL
;
176 parent
= dirname_malloc(path
);
180 return path_equal_ptr(parent
, p
->generator
) ||
181 path_equal_ptr(parent
, p
->generator_early
) ||
182 path_equal_ptr(parent
, p
->generator_late
);
185 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
186 _cleanup_free_
char *parent
= NULL
;
191 parent
= dirname_malloc(path
);
195 return path_equal_ptr(parent
, p
->transient
);
198 static int path_is_control(const LookupPaths
*p
, const char *path
) {
199 _cleanup_free_
char *parent
= NULL
;
204 parent
= dirname_malloc(path
);
208 return path_equal_ptr(parent
, p
->persistent_control
) ||
209 path_equal_ptr(parent
, p
->runtime_control
);
212 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
213 _cleanup_free_
char *parent
= NULL
;
218 /* Note that we do *not* have generic checks for /etc or /run in place, since with
219 * them we couldn't discern configuration from transient or generated units */
222 parent
= dirname_malloc(path
);
229 return path_equal_ptr(path
, p
->persistent_config
) ||
230 path_equal_ptr(path
, p
->runtime_config
);
233 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
234 _cleanup_free_
char *parent
= NULL
;
240 /* Everything in /run is considered runtime. On top of that we also add
241 * explicit checks for the various runtime directories, as safety net. */
243 rpath
= skip_root(p
, path
);
244 if (rpath
&& path_startswith(rpath
, "/run"))
248 parent
= dirname_malloc(path
);
255 return path_equal_ptr(path
, p
->runtime_config
) ||
256 path_equal_ptr(path
, p
->generator
) ||
257 path_equal_ptr(path
, p
->generator_early
) ||
258 path_equal_ptr(path
, p
->generator_late
) ||
259 path_equal_ptr(path
, p
->transient
) ||
260 path_equal_ptr(path
, p
->runtime_control
);
263 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
269 rpath
= skip_root(p
, path
);
273 if (path_startswith(rpath
, "/usr"))
277 if (path_startswith(rpath
, "/lib"))
281 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
284 int unit_file_changes_add(
285 UnitFileChange
**changes
,
287 UnitFileChangeType type
,
289 const char *source
) {
291 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
295 assert(!changes
== !n_changes
);
300 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
309 if (!p
|| (source
&& !s
))
312 path_simplify(p
, false);
314 path_simplify(s
, false);
316 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
322 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
325 assert(changes
|| n_changes
== 0);
327 for (i
= 0; i
< n_changes
; i
++) {
328 free(changes
[i
].path
);
329 free(changes
[i
].source
);
335 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
339 assert(changes
|| n_changes
== 0);
340 /* If verb is not specified, errors are not allowed! */
341 assert(verb
|| r
>= 0);
343 for (i
= 0; i
< n_changes
; i
++) {
344 assert(verb
|| changes
[i
].type
>= 0);
346 switch(changes
[i
].type
) {
347 case UNIT_FILE_SYMLINK
:
349 log_info("Created symlink %s %s %s.",
351 special_glyph(ARROW
),
354 case UNIT_FILE_UNLINK
:
356 log_info("Removed %s.", changes
[i
].path
);
358 case UNIT_FILE_IS_MASKED
:
360 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
362 case UNIT_FILE_IS_DANGLING
:
364 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
368 if (changes
[i
].source
)
369 log_error_errno(changes
[i
].type
,
370 "Failed to %s unit, file %s already exists and is a symlink to %s.",
371 verb
, changes
[i
].path
, changes
[i
].source
);
373 log_error_errno(changes
[i
].type
,
374 "Failed to %s unit, file %s already exists.",
375 verb
, changes
[i
].path
);
379 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
380 verb
, changes
[i
].path
);
384 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
385 verb
, changes
[i
].path
);
389 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
390 verb
, changes
[i
].path
);
395 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
400 assert(changes
[i
].type
< 0);
401 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
402 verb
, changes
[i
].path
);
407 if (r
< 0 && !logged
)
408 log_error_errno(r
, "Failed to %s: %m.", verb
);
412 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
413 * wc should be the full path in the host file system.
415 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
416 assert(path_is_absolute(wd
));
418 /* This will give incorrect results if the paths are relative and go outside
419 * of the chroot. False negatives are possible. */
424 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
425 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
426 return path_equal_or_files_same(a
, b
, 0);
429 static int create_symlink(
430 const LookupPaths
*paths
,
431 const char *old_path
,
432 const char *new_path
,
434 UnitFileChange
**changes
,
437 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
444 rp
= skip_root(paths
, old_path
);
448 /* Actually create a symlink, and remember that we did. Is
449 * smart enough to check if there's already a valid symlink in
452 * Returns 1 if a symlink was created or already exists and points to
453 * the right place, or negative on error.
456 mkdir_parents_label(new_path
, 0755);
458 if (symlink(old_path
, new_path
) >= 0) {
459 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
463 if (errno
!= EEXIST
) {
464 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
468 r
= readlink_malloc(new_path
, &dest
);
470 /* translate EINVAL (non-symlink exists) to EEXIST */
474 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
478 dirname
= dirname_malloc(new_path
);
482 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
486 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
490 r
= symlink_atomic(old_path
, new_path
);
492 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
496 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
497 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
502 static int mark_symlink_for_removal(
503 Set
**remove_symlinks_to
,
511 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
519 path_simplify(n
, false);
521 r
= set_consume(*remove_symlinks_to
, n
);
530 static int remove_marked_symlinks_fd(
531 Set
*remove_symlinks_to
,
534 const char *config_path
,
535 const LookupPaths
*lp
,
538 UnitFileChange
**changes
,
541 _cleanup_closedir_
DIR *d
= NULL
;
545 assert(remove_symlinks_to
);
560 FOREACH_DIRENT(de
, d
, return -errno
) {
562 dirent_ensure_type(d
, de
);
564 if (de
->d_type
== DT_DIR
) {
565 _cleanup_free_
char *p
= NULL
;
568 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
578 p
= path_make_absolute(de
->d_name
, path
);
584 /* This will close nfd, regardless whether it succeeds or not */
585 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
589 } else if (de
->d_type
== DT_LNK
) {
590 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
595 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
598 p
= path_make_absolute(de
->d_name
, path
);
601 path_simplify(p
, false);
603 q
= readlink_malloc(p
, &dest
);
612 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
613 * the same name as a file that is marked. */
615 found
= set_contains(remove_symlinks_to
, dest
) ||
616 set_contains(remove_symlinks_to
, basename(dest
)) ||
617 set_contains(remove_symlinks_to
, de
->d_name
);
623 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
626 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
630 (void) rmdir_parents(p
, config_path
);
633 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
635 /* Now, remember the full path (but with the root prefix removed) of
636 * the symlink we just removed, and remove any symlinks to it, too. */
638 rp
= skip_root(lp
, p
);
639 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
642 if (q
> 0 && !dry_run
)
650 static int remove_marked_symlinks(
651 Set
*remove_symlinks_to
,
652 const char *config_path
,
653 const LookupPaths
*lp
,
655 UnitFileChange
**changes
,
658 _cleanup_close_
int fd
= -1;
665 if (set_size(remove_symlinks_to
) <= 0)
668 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
670 return errno
== ENOENT
? 0 : -errno
;
676 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
680 /* This takes possession of cfd and closes it */
681 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
689 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
692 if (streq(name
, i
->name
))
695 if (strv_contains(i
->aliases
, name
))
698 /* Look for template symlink matching DefaultInstance */
699 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
700 _cleanup_free_
char *s
= NULL
;
702 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
707 } else if (streq(name
, s
))
714 static int find_symlinks_fd(
715 const char *root_dir
,
716 UnitFileInstallInfo
*i
,
720 const char *config_path
,
721 bool *same_name_link
) {
723 _cleanup_closedir_
DIR *d
= NULL
;
731 assert(same_name_link
);
739 FOREACH_DIRENT(de
, d
, return -errno
) {
741 dirent_ensure_type(d
, de
);
743 if (de
->d_type
== DT_DIR
) {
744 _cleanup_free_
char *p
= NULL
;
747 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
757 p
= path_make_absolute(de
->d_name
, path
);
763 /* This will close nfd, regardless whether it succeeds or not */
764 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
765 p
, config_path
, same_name_link
);
771 } else if (de
->d_type
== DT_LNK
) {
772 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
773 bool found_path
, found_dest
, b
= false;
776 /* Acquire symlink name */
777 p
= path_make_absolute(de
->d_name
, path
);
781 /* Acquire symlink destination */
782 q
= readlink_malloc(p
, &dest
);
792 if (!path_is_absolute(dest
)) {
795 x
= prefix_root(root_dir
, dest
);
803 /* Check if the symlink itself matches what we
805 if (path_is_absolute(i
->name
))
806 found_path
= path_equal(p
, i
->name
);
808 found_path
= streq(de
->d_name
, i
->name
);
810 /* Check if what the symlink points to
811 * matches what we are looking for */
812 if (path_is_absolute(i
->name
))
813 found_dest
= path_equal(dest
, i
->name
);
815 found_dest
= streq(basename(dest
), i
->name
);
817 if (found_path
&& found_dest
) {
818 _cleanup_free_
char *t
= NULL
;
820 /* Filter out same name links in the main
822 t
= path_make_absolute(i
->name
, config_path
);
826 b
= path_equal(t
, p
);
830 *same_name_link
= true;
831 else if (found_path
|| found_dest
) {
835 /* Check if symlink name is in the set of names used by [Install] */
836 q
= is_symlink_with_known_name(i
, de
->d_name
);
848 static int find_symlinks(
849 const char *root_dir
,
850 UnitFileInstallInfo
*i
,
852 const char *config_path
,
853 bool *same_name_link
) {
859 assert(same_name_link
);
861 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
863 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
868 /* This takes possession of fd and closes it */
869 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
870 config_path
, config_path
, same_name_link
);
873 static int find_symlinks_in_scope(
875 const LookupPaths
*paths
,
876 UnitFileInstallInfo
*i
,
878 UnitFileState
*state
) {
880 bool same_name_link_runtime
= false, same_name_link_config
= false;
881 bool enabled_in_runtime
= false, enabled_at_all
= false;
888 STRV_FOREACH(p
, paths
->search_path
) {
889 bool same_name_link
= false;
891 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
895 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
897 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
898 /* This is the best outcome, let's return it immediately. */
899 *state
= UNIT_FILE_ENABLED
;
903 /* look for global enablement of user units */
904 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
905 *state
= UNIT_FILE_ENABLED
;
909 r
= path_is_runtime(paths
, *p
, false);
913 enabled_in_runtime
= true;
915 enabled_at_all
= true;
917 } else if (same_name_link
) {
918 if (path_equal_ptr(*p
, paths
->persistent_config
))
919 same_name_link_config
= true;
921 r
= path_is_runtime(paths
, *p
, false);
925 same_name_link_runtime
= true;
930 if (enabled_in_runtime
) {
931 *state
= UNIT_FILE_ENABLED_RUNTIME
;
935 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
936 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
937 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
938 * something, and hence are a much stronger concept. */
939 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
940 *state
= UNIT_FILE_STATIC
;
944 /* Hmm, we didn't find it, but maybe we found the same name
946 if (same_name_link_config
) {
947 *state
= UNIT_FILE_LINKED
;
950 if (same_name_link_runtime
) {
951 *state
= UNIT_FILE_LINKED_RUNTIME
;
958 static void install_info_free(UnitFileInstallInfo
*i
) {
965 strv_free(i
->aliases
);
966 strv_free(i
->wanted_by
);
967 strv_free(i
->required_by
);
969 free(i
->default_instance
);
970 free(i
->symlink_target
);
974 static void install_context_done(InstallContext
*c
) {
977 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
978 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
981 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
982 UnitFileInstallInfo
*i
;
984 i
= ordered_hashmap_get(c
->have_processed
, name
);
988 return ordered_hashmap_get(c
->will_process
, name
);
991 static int install_info_may_process(
992 UnitFileInstallInfo
*i
,
993 const LookupPaths
*paths
,
994 UnitFileChange
**changes
,
999 /* Checks whether the loaded unit file is one we should process, or is masked,
1000 * transient or generated and thus not subject to enable/disable operations. */
1002 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1003 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1006 if (path_is_generator(paths
, i
->path
) ||
1007 path_is_transient(paths
, i
->path
)) {
1008 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1009 return -EADDRNOTAVAIL
;
1016 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1017 * hashmap, or retrieves the existing one if already present.
1019 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1021 static int install_info_add(
1026 UnitFileInstallInfo
**ret
) {
1028 UnitFileInstallInfo
*i
= NULL
;
1032 assert(name
|| path
);
1035 name
= basename(path
);
1037 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1040 i
= install_info_find(c
, name
);
1042 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1049 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1053 i
= new0(UnitFileInstallInfo
, 1);
1056 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1057 i
->auxiliary
= auxiliary
;
1059 i
->name
= strdup(name
);
1066 i
->path
= strdup(path
);
1073 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1083 install_info_free(i
);
1087 static int config_parse_alias(
1089 const char *filename
,
1091 const char *section
,
1092 unsigned section_line
,
1106 type
= unit_name_to_type(unit
);
1107 if (!unit_type_may_alias(type
))
1108 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1109 "Alias= is not allowed for %s units, ignoring.",
1110 unit_type_to_string(type
));
1112 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1113 lvalue
, ltype
, rvalue
, data
, userdata
);
1116 static int config_parse_also(
1118 const char *filename
,
1120 const char *section
,
1121 unsigned section_line
,
1128 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1129 InstallContext
*c
= data
;
1138 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1140 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1146 r
= install_full_printf(info
, word
, &printed
);
1150 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1153 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1157 r
= strv_push(&info
->also
, printed
);
1167 static int config_parse_default_instance(
1169 const char *filename
,
1171 const char *section
,
1172 unsigned section_line
,
1179 UnitFileInstallInfo
*i
= data
;
1180 _cleanup_free_
char *printed
= NULL
;
1188 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1189 /* When enabling an instance, we might be using a template unit file,
1190 * but we should ignore DefaultInstance silently. */
1192 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1193 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1194 "DefaultInstance= only makes sense for template units, ignoring.");
1196 r
= install_full_printf(i
, rvalue
, &printed
);
1200 if (!unit_instance_is_valid(printed
))
1203 return free_and_replace(i
->default_instance
, printed
);
1206 static int unit_file_load(
1208 UnitFileInstallInfo
*info
,
1210 const char *root_dir
,
1211 SearchFlags flags
) {
1213 const ConfigTableItem items
[] = {
1214 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1215 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1216 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1217 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1218 { "Install", "Also", config_parse_also
, 0, c
},
1223 _cleanup_fclose_
FILE *f
= NULL
;
1224 _cleanup_close_
int fd
= -1;
1231 if (!(flags
& SEARCH_DROPIN
)) {
1232 /* Loading or checking for the main unit file… */
1234 type
= unit_name_to_type(info
->name
);
1237 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1238 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1242 if (!(flags
& SEARCH_LOAD
)) {
1243 r
= lstat(path
, &st
);
1247 if (null_or_empty(&st
))
1248 info
->type
= UNIT_FILE_TYPE_MASKED
;
1249 else if (S_ISREG(st
.st_mode
))
1250 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1251 else if (S_ISLNK(st
.st_mode
))
1253 else if (S_ISDIR(st
.st_mode
))
1261 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1265 /* 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. */
1267 if (!(flags
& SEARCH_LOAD
))
1270 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1275 if (fstat(fd
, &st
) < 0)
1278 if (null_or_empty(&st
)) {
1279 if ((flags
& SEARCH_DROPIN
) == 0)
1280 info
->type
= UNIT_FILE_TYPE_MASKED
;
1285 r
= stat_verify_regular(&st
);
1289 f
= fdopen(fd
, "re");
1294 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1297 r
= config_parse(info
->name
, path
, f
,
1299 config_item_table_lookup
, items
,
1300 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1302 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1304 if ((flags
& SEARCH_DROPIN
) == 0)
1305 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1308 (int) strv_length(info
->aliases
) +
1309 (int) strv_length(info
->wanted_by
) +
1310 (int) strv_length(info
->required_by
);
1313 static int unit_file_load_or_readlink(
1315 UnitFileInstallInfo
*info
,
1317 const char *root_dir
,
1318 SearchFlags flags
) {
1320 _cleanup_free_
char *target
= NULL
;
1323 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1324 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1327 /* This is a symlink, let's read it. */
1329 r
= readlink_malloc(path
, &target
);
1333 if (path_equal(target
, "/dev/null"))
1334 info
->type
= UNIT_FILE_TYPE_MASKED
;
1339 bn
= basename(target
);
1341 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1343 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1346 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1348 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1351 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1353 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1358 /* Enforce that the symlink destination does not
1359 * change the unit file type. */
1361 a
= unit_name_to_type(info
->name
);
1362 b
= unit_name_to_type(bn
);
1363 if (a
< 0 || b
< 0 || a
!= b
)
1366 if (path_is_absolute(target
))
1367 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1368 info
->symlink_target
= prefix_root(root_dir
, target
);
1370 /* This is a relative path, take it relative to the dir the symlink is located in. */
1371 info
->symlink_target
= file_in_same_dir(path
, target
);
1372 if (!info
->symlink_target
)
1375 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1381 static int unit_file_search(
1383 UnitFileInstallInfo
*info
,
1384 const LookupPaths
*paths
,
1385 SearchFlags flags
) {
1387 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1388 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1389 _cleanup_free_
char *template = NULL
;
1390 bool found_unit
= false;
1397 /* Was this unit already loaded? */
1398 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1402 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1406 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1407 r
= unit_name_template(info
->name
, &template);
1412 STRV_FOREACH(p
, paths
->search_path
) {
1413 _cleanup_free_
char *path
= NULL
;
1415 path
= strjoin(*p
, "/", info
->name
);
1419 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1421 info
->path
= TAKE_PTR(path
);
1425 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1429 if (!found_unit
&& template) {
1431 /* Unit file doesn't exist, however instance
1432 * enablement was requested. We will check if it is
1433 * possible to load template unit file. */
1435 STRV_FOREACH(p
, paths
->search_path
) {
1436 _cleanup_free_
char *path
= NULL
;
1438 path
= strjoin(*p
, "/", template);
1442 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1444 info
->path
= TAKE_PTR(path
);
1448 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1454 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1458 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1461 /* Search for drop-in directories */
1463 dropin_dir_name
= strjoina(info
->name
, ".d");
1464 STRV_FOREACH(p
, paths
->search_path
) {
1467 path
= path_join(NULL
, *p
, dropin_dir_name
);
1471 r
= strv_consume(&dirs
, path
);
1477 dropin_template_dir_name
= strjoina(template, ".d");
1478 STRV_FOREACH(p
, paths
->search_path
) {
1481 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1485 r
= strv_consume(&dirs
, path
);
1491 /* Load drop-in conf files */
1493 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1495 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1497 STRV_FOREACH(p
, files
) {
1498 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1500 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1506 static int install_info_follow(
1508 UnitFileInstallInfo
*i
,
1509 const char *root_dir
,
1511 bool ignore_different_name
) {
1516 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1518 if (!i
->symlink_target
)
1521 /* If the basename doesn't match, the caller should add a
1522 * complete new entry for this. */
1524 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1527 free_and_replace(i
->path
, i
->symlink_target
);
1528 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1530 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1534 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1535 * target, maybe more than once. Propagate the instance name if present.
1537 static int install_info_traverse(
1538 UnitFileScope scope
,
1540 const LookupPaths
*paths
,
1541 UnitFileInstallInfo
*start
,
1543 UnitFileInstallInfo
**ret
) {
1545 UnitFileInstallInfo
*i
;
1553 r
= unit_file_search(c
, start
, paths
, flags
);
1558 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1559 /* Follow the symlink */
1561 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1564 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1565 r
= path_is_config(paths
, i
->path
, true);
1572 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1574 _cleanup_free_
char *buffer
= NULL
;
1577 /* Target has a different name, create a new
1578 * install info object for that, and continue
1581 bn
= basename(i
->symlink_target
);
1583 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1584 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1586 _cleanup_free_
char *instance
= NULL
;
1588 r
= unit_name_to_instance(i
->name
, &instance
);
1592 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1596 if (streq(buffer
, i
->name
)) {
1598 /* We filled in the instance, and the target stayed the same? If so, then let's
1599 * honour the link as it is. */
1601 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1611 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1615 /* Try again, with the new target we found. */
1616 r
= unit_file_search(c
, i
, paths
, flags
);
1618 /* Translate error code to highlight this specific case */
1633 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1634 * or the name (otherwise). root_dir is prepended to the path.
1636 static int install_info_add_auto(
1638 const LookupPaths
*paths
,
1639 const char *name_or_path
,
1640 UnitFileInstallInfo
**ret
) {
1643 assert(name_or_path
);
1645 if (path_is_absolute(name_or_path
)) {
1648 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1650 return install_info_add(c
, NULL
, pp
, false, ret
);
1652 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1655 static int install_info_discover(
1656 UnitFileScope scope
,
1658 const LookupPaths
*paths
,
1661 UnitFileInstallInfo
**ret
,
1662 UnitFileChange
**changes
,
1663 size_t *n_changes
) {
1665 UnitFileInstallInfo
*i
;
1672 r
= install_info_add_auto(c
, paths
, name
, &i
);
1674 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1677 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1681 static int install_info_symlink_alias(
1682 UnitFileInstallInfo
*i
,
1683 const LookupPaths
*paths
,
1684 const char *config_path
,
1686 UnitFileChange
**changes
,
1687 size_t *n_changes
) {
1694 assert(config_path
);
1696 STRV_FOREACH(s
, i
->aliases
) {
1697 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1699 q
= install_full_printf(i
, *s
, &dst
);
1703 alias_path
= path_make_absolute(dst
, config_path
);
1707 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1715 static int install_info_symlink_wants(
1716 UnitFileInstallInfo
*i
,
1717 const LookupPaths
*paths
,
1718 const char *config_path
,
1721 UnitFileChange
**changes
,
1722 size_t *n_changes
) {
1724 _cleanup_free_
char *buf
= NULL
;
1731 assert(config_path
);
1733 if (strv_isempty(list
))
1736 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1737 UnitFileInstallInfo instance
= {
1738 .type
= _UNIT_FILE_TYPE_INVALID
,
1740 _cleanup_free_
char *path
= NULL
;
1742 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1746 instance
.name
= buf
;
1747 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1751 path
= TAKE_PTR(instance
.path
);
1753 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1754 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1762 STRV_FOREACH(s
, list
) {
1763 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1765 q
= install_full_printf(i
, *s
, &dst
);
1769 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1774 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1778 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1786 static int install_info_symlink_link(
1787 UnitFileInstallInfo
*i
,
1788 const LookupPaths
*paths
,
1789 const char *config_path
,
1791 UnitFileChange
**changes
,
1792 size_t *n_changes
) {
1794 _cleanup_free_
char *path
= NULL
;
1799 assert(config_path
);
1802 r
= in_search_path(paths
, i
->path
);
1808 path
= strjoin(config_path
, "/", i
->name
);
1812 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1815 static int install_info_apply(
1816 UnitFileInstallInfo
*i
,
1817 const LookupPaths
*paths
,
1818 const char *config_path
,
1820 UnitFileChange
**changes
,
1821 size_t *n_changes
) {
1827 assert(config_path
);
1829 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1832 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1834 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1838 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1842 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1843 /* Do not count links to the unit file towards the "carries_install_info" count */
1844 if (r
== 0 && q
< 0)
1850 static int install_context_apply(
1851 UnitFileScope scope
,
1853 const LookupPaths
*paths
,
1854 const char *config_path
,
1857 UnitFileChange
**changes
,
1858 size_t *n_changes
) {
1860 UnitFileInstallInfo
*i
;
1865 assert(config_path
);
1867 if (ordered_hashmap_isempty(c
->will_process
))
1870 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1875 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1878 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1882 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1884 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1888 /* We can attempt to process a masked unit when a different unit
1889 * that we were processing specifies it in Also=. */
1890 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1891 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1893 /* Assume that something *could* have been enabled here,
1894 * avoid "empty [Install] section" warning. */
1899 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1902 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1914 static int install_context_mark_for_removal(
1915 UnitFileScope scope
,
1917 const LookupPaths
*paths
,
1918 Set
**remove_symlinks_to
,
1919 UnitFileChange
**changes
,
1920 size_t *n_changes
) {
1922 UnitFileInstallInfo
*i
;
1928 /* Marks all items for removal */
1930 if (ordered_hashmap_isempty(c
->will_process
))
1933 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1937 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1939 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1943 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1944 if (r
== -ENOLINK
) {
1945 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1946 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1947 } else if (r
== -ENOENT
) {
1949 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1950 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1952 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1953 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1957 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1958 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1959 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1960 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1961 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1963 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1964 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1968 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1977 UnitFileScope scope
,
1978 UnitFileFlags flags
,
1979 const char *root_dir
,
1981 UnitFileChange
**changes
,
1982 size_t *n_changes
) {
1984 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
1985 const char *config_path
;
1990 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1992 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1996 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2000 STRV_FOREACH(i
, files
) {
2001 _cleanup_free_
char *path
= NULL
;
2004 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2010 path
= path_make_absolute(*i
, config_path
);
2014 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2015 if (q
< 0 && r
>= 0)
2022 int unit_file_unmask(
2023 UnitFileScope scope
,
2024 UnitFileFlags flags
,
2025 const char *root_dir
,
2027 UnitFileChange
**changes
,
2028 size_t *n_changes
) {
2030 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2031 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2032 _cleanup_strv_free_
char **todo
= NULL
;
2033 size_t n_todo
= 0, n_allocated
= 0;
2034 const char *config_path
;
2036 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2040 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2042 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2046 STRV_FOREACH(i
, files
) {
2047 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2050 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2051 _cleanup_free_
char *path
= NULL
;
2053 path
= path_make_absolute(*i
, config_path
);
2057 r
= null_or_empty_path(path
);
2065 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2068 todo
[n_todo
] = strdup(*i
);
2079 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2080 STRV_FOREACH(i
, todo
) {
2081 _cleanup_free_
char *path
= NULL
;
2084 path
= path_make_absolute(*i
, config_path
);
2088 if (!dry_run
&& unlink(path
) < 0) {
2089 if (errno
!= ENOENT
) {
2092 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2098 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2100 rp
= skip_root(&paths
, path
);
2101 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2106 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2115 UnitFileScope scope
,
2116 UnitFileFlags flags
,
2117 const char *root_dir
,
2119 UnitFileChange
**changes
,
2120 size_t *n_changes
) {
2122 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2123 _cleanup_strv_free_
char **todo
= NULL
;
2124 size_t n_todo
= 0, n_allocated
= 0;
2125 const char *config_path
;
2130 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2132 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2136 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2140 STRV_FOREACH(i
, files
) {
2141 _cleanup_free_
char *full
= NULL
;
2145 if (!path_is_absolute(*i
))
2149 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2152 full
= prefix_root(paths
.root_dir
, *i
);
2156 if (lstat(full
, &st
) < 0)
2158 r
= stat_verify_regular(&st
);
2162 q
= in_search_path(&paths
, *i
);
2168 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2171 todo
[n_todo
] = strdup(*i
);
2181 STRV_FOREACH(i
, todo
) {
2182 _cleanup_free_
char *new_path
= NULL
;
2184 new_path
= path_make_absolute(basename(*i
), config_path
);
2188 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2189 if (q
< 0 && r
>= 0)
2196 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2202 /* Checks whether the path is one where the drop-in directories shall be removed. */
2204 r
= path_is_config(paths
, path
, true);
2208 r
= path_is_control(paths
, path
);
2212 return path_is_transient(paths
, path
);
2215 int unit_file_revert(
2216 UnitFileScope scope
,
2217 const char *root_dir
,
2219 UnitFileChange
**changes
,
2220 size_t *n_changes
) {
2222 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2223 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2224 _cleanup_strv_free_
char **todo
= NULL
;
2225 size_t n_todo
= 0, n_allocated
= 0;
2229 /* Puts a unit file back into vendor state. This means:
2231 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2232 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2234 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2235 * "config", but not in "transient" or "control" or even "generated").
2237 * We remove all that in both the runtime and the persistent directories, if that applies.
2240 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2244 STRV_FOREACH(i
, files
) {
2245 bool has_vendor
= false;
2248 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2251 STRV_FOREACH(p
, paths
.search_path
) {
2252 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2255 path
= path_make_absolute(*i
, *p
);
2259 r
= lstat(path
, &st
);
2261 if (errno
!= ENOENT
)
2263 } else if (S_ISREG(st
.st_mode
)) {
2264 /* Check if there's a vendor version */
2265 r
= path_is_vendor(&paths
, path
);
2272 dropin
= strappend(path
, ".d");
2276 r
= lstat(dropin
, &st
);
2278 if (errno
!= ENOENT
)
2280 } else if (S_ISDIR(st
.st_mode
)) {
2281 /* Remove the drop-ins */
2282 r
= path_shall_revert(&paths
, dropin
);
2286 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2289 todo
[n_todo
++] = TAKE_PTR(dropin
);
2297 /* OK, there's a vendor version, hence drop all configuration versions */
2298 STRV_FOREACH(p
, paths
.search_path
) {
2299 _cleanup_free_
char *path
= NULL
;
2302 path
= path_make_absolute(*i
, *p
);
2306 r
= lstat(path
, &st
);
2308 if (errno
!= ENOENT
)
2310 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2311 r
= path_is_config(&paths
, path
, true);
2315 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2318 todo
[n_todo
++] = TAKE_PTR(path
);
2327 STRV_FOREACH(i
, todo
) {
2328 _cleanup_strv_free_
char **fs
= NULL
;
2332 (void) get_files_in_directory(*i
, &fs
);
2334 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2335 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2340 STRV_FOREACH(j
, fs
) {
2341 _cleanup_free_
char *t
= NULL
;
2343 t
= strjoin(*i
, "/", *j
);
2347 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2350 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2352 rp
= skip_root(&paths
, *i
);
2353 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2358 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2362 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2369 int unit_file_add_dependency(
2370 UnitFileScope scope
,
2371 UnitFileFlags flags
,
2372 const char *root_dir
,
2376 UnitFileChange
**changes
,
2377 size_t *n_changes
) {
2379 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2380 _cleanup_(install_context_done
) InstallContext c
= {};
2381 UnitFileInstallInfo
*i
, *target_info
;
2382 const char *config_path
;
2387 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2390 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2393 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2396 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2400 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2404 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2405 &target_info
, changes
, n_changes
);
2408 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2412 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2414 STRV_FOREACH(f
, files
) {
2417 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2418 &i
, changes
, n_changes
);
2421 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2425 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2427 /* We didn't actually load anything from the unit
2428 * file, but instead just add in our new symlink to
2431 if (dep
== UNIT_WANTS
)
2434 l
= &i
->required_by
;
2437 *l
= strv_new(target_info
->name
, NULL
);
2442 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2445 int unit_file_enable(
2446 UnitFileScope scope
,
2447 UnitFileFlags flags
,
2448 const char *root_dir
,
2450 UnitFileChange
**changes
,
2451 size_t *n_changes
) {
2453 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2454 _cleanup_(install_context_done
) InstallContext c
= {};
2455 const char *config_path
;
2456 UnitFileInstallInfo
*i
;
2461 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2463 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2467 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2471 STRV_FOREACH(f
, files
) {
2472 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2473 &i
, changes
, n_changes
);
2476 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2480 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2483 /* This will return the number of symlink rules that were
2484 supposed to be created, not the ones actually created. This
2485 is useful to determine whether the passed files had any
2486 installation data at all. */
2488 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2491 int unit_file_disable(
2492 UnitFileScope scope
,
2493 UnitFileFlags flags
,
2494 const char *root_dir
,
2496 UnitFileChange
**changes
,
2497 size_t *n_changes
) {
2499 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2500 _cleanup_(install_context_done
) InstallContext c
= {};
2501 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2502 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2503 const char *config_path
;
2508 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2510 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2514 STRV_FOREACH(i
, files
) {
2515 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2518 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2523 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2527 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2528 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2536 int unit_file_reenable(
2537 UnitFileScope scope
,
2538 UnitFileFlags flags
,
2539 const char *root_dir
,
2541 UnitFileChange
**changes
,
2542 size_t *n_changes
) {
2548 /* First, we invoke the disable command with only the basename... */
2549 l
= strv_length(files
);
2550 n
= newa(char*, l
+1);
2551 for (i
= 0; i
< l
; i
++)
2552 n
[i
] = basename(files
[i
]);
2555 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2559 /* But the enable command with the full name */
2560 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2563 int unit_file_set_default(
2564 UnitFileScope scope
,
2565 UnitFileFlags flags
,
2566 const char *root_dir
,
2568 UnitFileChange
**changes
,
2569 size_t *n_changes
) {
2571 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2572 _cleanup_(install_context_done
) InstallContext c
= {};
2573 UnitFileInstallInfo
*i
;
2574 const char *new_path
;
2578 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2581 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2583 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2586 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2590 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2593 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2597 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2598 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2601 int unit_file_get_default(
2602 UnitFileScope scope
,
2603 const char *root_dir
,
2606 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2607 _cleanup_(install_context_done
) InstallContext c
= {};
2608 UnitFileInstallInfo
*i
;
2613 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2616 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2620 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2624 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2628 n
= strdup(i
->name
);
2636 int unit_file_lookup_state(
2637 UnitFileScope scope
,
2638 const LookupPaths
*paths
,
2640 UnitFileState
*ret
) {
2642 _cleanup_(install_context_done
) InstallContext c
= {};
2643 UnitFileInstallInfo
*i
;
2644 UnitFileState state
;
2650 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2653 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2658 /* Shortcut things, if the caller just wants to know if this unit exists. */
2664 case UNIT_FILE_TYPE_MASKED
:
2665 r
= path_is_runtime(paths
, i
->path
, true);
2669 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2672 case UNIT_FILE_TYPE_REGULAR
:
2673 r
= path_is_generator(paths
, i
->path
);
2677 state
= UNIT_FILE_GENERATED
;
2681 r
= path_is_transient(paths
, i
->path
);
2685 state
= UNIT_FILE_TRANSIENT
;
2689 /* Check if any of the Alias= symlinks have been created.
2690 * We ignore other aliases, and only check those that would
2691 * be created by systemctl enable for this unit. */
2692 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2698 /* Check if the file is known under other names. If it is,
2699 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2700 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2704 state
= UNIT_FILE_INDIRECT
;
2706 if (unit_file_install_info_has_rules(i
))
2707 state
= UNIT_FILE_DISABLED
;
2708 else if (unit_file_install_info_has_also(i
))
2709 state
= UNIT_FILE_INDIRECT
;
2711 state
= UNIT_FILE_STATIC
;
2717 assert_not_reached("Unexpect unit file type.");
2724 int unit_file_get_state(
2725 UnitFileScope scope
,
2726 const char *root_dir
,
2728 UnitFileState
*ret
) {
2730 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2734 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2737 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2741 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2744 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2745 _cleanup_(install_context_done
) InstallContext c
= {};
2751 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2754 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2763 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2764 _cleanup_(presets_freep
) Presets ps
= {};
2765 size_t n_allocated
= 0;
2766 _cleanup_strv_free_
char **files
= NULL
;
2771 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2775 case UNIT_FILE_SYSTEM
:
2776 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2777 "/etc/systemd/system-preset",
2778 "/run/systemd/system-preset",
2779 "/usr/local/lib/systemd/system-preset",
2780 "/usr/lib/systemd/system-preset",
2782 "/lib/systemd/system-preset",
2787 case UNIT_FILE_GLOBAL
:
2788 case UNIT_FILE_USER
:
2789 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2790 "/etc/systemd/user-preset",
2791 "/run/systemd/user-preset",
2792 "/usr/local/lib/systemd/user-preset",
2793 "/usr/lib/systemd/user-preset",
2798 assert_not_reached("Invalid unit file scope");
2804 STRV_FOREACH(p
, files
) {
2805 _cleanup_fclose_
FILE *f
;
2806 char line
[LINE_MAX
];
2809 f
= fopen(*p
, "re");
2811 if (errno
== ENOENT
)
2817 FOREACH_LINE(line
, f
, return -errno
) {
2818 PresetRule rule
= {};
2819 const char *parameter
;
2827 if (strchr(COMMENTS
, *l
))
2830 parameter
= first_word(l
, "enable");
2834 pattern
= strdup(parameter
);
2838 rule
= (PresetRule
) {
2840 .action
= PRESET_ENABLE
,
2844 parameter
= first_word(l
, "disable");
2848 pattern
= strdup(parameter
);
2852 rule
= (PresetRule
) {
2854 .action
= PRESET_DISABLE
,
2859 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2862 ps
.rules
[ps
.n_rules
++] = rule
;
2866 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2876 static int query_presets(const char *name
, const Presets presets
) {
2877 PresetAction action
= PRESET_UNKNOWN
;
2880 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2883 for (i
= 0; i
< presets
.n_rules
; i
++)
2884 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2885 action
= presets
.rules
[i
].action
;
2890 case PRESET_UNKNOWN
:
2891 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2894 log_debug("Preset files say enable %s.", name
);
2896 case PRESET_DISABLE
:
2897 log_debug("Preset files say disable %s.", name
);
2900 assert_not_reached("invalid preset action");
2904 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2905 _cleanup_(presets_freep
) Presets presets
= {};
2908 r
= read_presets(scope
, root_dir
, &presets
);
2912 return query_presets(name
, presets
);
2915 static int execute_preset(
2916 UnitFileScope scope
,
2917 UnitFileFlags flags
,
2918 InstallContext
*plus
,
2919 InstallContext
*minus
,
2920 const LookupPaths
*paths
,
2922 UnitFilePresetMode mode
,
2923 UnitFileChange
**changes
,
2924 size_t *n_changes
) {
2926 const char *config_path
;
2927 bool force
= !!(flags
& UNIT_FILE_FORCE
);
2928 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
2935 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2936 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2938 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
2942 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
2943 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2949 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2950 /* Returns number of symlinks that where supposed to be installed. */
2951 q
= install_context_apply(scope
, plus
, paths
,
2952 runtime
? paths
->runtime_config
: paths
->persistent_config
,
2953 force
, SEARCH_LOAD
, changes
, n_changes
);
2961 static int preset_prepare_one(
2962 UnitFileScope scope
,
2963 InstallContext
*plus
,
2964 InstallContext
*minus
,
2968 UnitFileChange
**changes
,
2969 size_t *n_changes
) {
2971 _cleanup_(install_context_done
) InstallContext tmp
= {};
2972 UnitFileInstallInfo
*i
;
2975 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2978 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2979 &i
, changes
, n_changes
);
2982 if (!streq(name
, i
->name
)) {
2983 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
2987 r
= query_presets(name
, presets
);
2992 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2993 &i
, changes
, n_changes
);
2997 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
3001 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3002 &i
, changes
, n_changes
);
3007 int unit_file_preset(
3008 UnitFileScope scope
,
3009 UnitFileFlags flags
,
3010 const char *root_dir
,
3012 UnitFilePresetMode mode
,
3013 UnitFileChange
**changes
,
3014 size_t *n_changes
) {
3016 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3017 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3018 _cleanup_(presets_freep
) Presets presets
= {};
3023 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3024 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3026 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3030 r
= read_presets(scope
, root_dir
, &presets
);
3034 STRV_FOREACH(i
, files
) {
3035 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3040 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3043 int unit_file_preset_all(
3044 UnitFileScope scope
,
3045 UnitFileFlags flags
,
3046 const char *root_dir
,
3047 UnitFilePresetMode mode
,
3048 UnitFileChange
**changes
,
3049 size_t *n_changes
) {
3051 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3052 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3053 _cleanup_(presets_freep
) Presets presets
= {};
3058 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3059 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3061 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3065 r
= read_presets(scope
, root_dir
, &presets
);
3069 STRV_FOREACH(i
, paths
.search_path
) {
3070 _cleanup_closedir_
DIR *d
= NULL
;
3075 if (errno
== ENOENT
)
3081 FOREACH_DIRENT(de
, d
, return -errno
) {
3082 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3085 dirent_ensure_type(d
, de
);
3087 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3090 /* we don't pass changes[] in, because we want to handle errors on our own */
3091 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3093 r
= unit_file_changes_add(changes
, n_changes
,
3094 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3095 else if (r
== -ENOLINK
)
3096 r
= unit_file_changes_add(changes
, n_changes
,
3097 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3098 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3105 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3108 static void unit_file_list_free_one(UnitFileList
*f
) {
3116 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3117 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3120 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3122 int unit_file_get_list(
3123 UnitFileScope scope
,
3124 const char *root_dir
,
3129 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3134 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3137 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3141 STRV_FOREACH(i
, paths
.search_path
) {
3142 _cleanup_closedir_
DIR *d
= NULL
;
3147 if (errno
== ENOENT
)
3149 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3150 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3157 FOREACH_DIRENT(de
, d
, return -errno
) {
3158 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3160 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3163 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3166 if (hashmap_get(h
, de
->d_name
))
3169 dirent_ensure_type(d
, de
);
3171 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3174 f
= new0(UnitFileList
, 1);
3178 f
->path
= path_make_absolute(de
->d_name
, *i
);
3182 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3184 f
->state
= UNIT_FILE_BAD
;
3186 if (!strv_isempty(states
) &&
3187 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3190 r
= hashmap_put(h
, basename(f
->path
), f
);
3194 f
= NULL
; /* prevent cleanup */
3201 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3202 [UNIT_FILE_ENABLED
] = "enabled",
3203 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3204 [UNIT_FILE_LINKED
] = "linked",
3205 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3206 [UNIT_FILE_MASKED
] = "masked",
3207 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3208 [UNIT_FILE_STATIC
] = "static",
3209 [UNIT_FILE_DISABLED
] = "disabled",
3210 [UNIT_FILE_INDIRECT
] = "indirect",
3211 [UNIT_FILE_GENERATED
] = "generated",
3212 [UNIT_FILE_TRANSIENT
] = "transient",
3213 [UNIT_FILE_BAD
] = "bad",
3216 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3218 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3219 [UNIT_FILE_SYMLINK
] = "symlink",
3220 [UNIT_FILE_UNLINK
] = "unlink",
3221 [UNIT_FILE_IS_MASKED
] = "masked",
3222 [UNIT_FILE_IS_DANGLING
] = "dangling",
3225 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3227 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3228 [UNIT_FILE_PRESET_FULL
] = "full",
3229 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3230 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3233 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);