1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2011 Lennart Poettering
18 #include "alloc-util.h"
19 #include "conf-files.h"
20 #include "conf-parser.h"
21 #include "dirent-util.h"
22 #include "extract-word.h"
27 #include "install-printf.h"
29 #include "locale-util.h"
33 #include "path-lookup.h"
34 #include "path-util.h"
38 #include "stat-util.h"
39 #include "string-table.h"
40 #include "string-util.h"
42 #include "unit-name.h"
44 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
46 typedef enum SearchFlags
{
48 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
49 SEARCH_DROPIN
= 1 << 2,
53 OrderedHashmap
*will_process
;
54 OrderedHashmap
*have_processed
;
73 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
76 return !strv_isempty(i
->aliases
) ||
77 !strv_isempty(i
->wanted_by
) ||
78 !strv_isempty(i
->required_by
);
81 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
84 return !strv_isempty(i
->also
);
87 static inline void presets_freep(Presets
*p
) {
93 for (i
= 0; i
< p
->n_rules
; i
++)
94 free(p
->rules
[i
].pattern
);
100 bool unit_type_may_alias(UnitType type
) {
110 bool unit_type_may_template(UnitType type
) {
119 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
120 [UNIT_FILE_TYPE_REGULAR
] = "regular",
121 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
122 [UNIT_FILE_TYPE_MASKED
] = "masked",
125 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
127 static int in_search_path(const LookupPaths
*p
, const char *path
) {
128 _cleanup_free_
char *parent
= NULL
;
133 parent
= dirname_malloc(path
);
137 STRV_FOREACH(i
, p
->search_path
)
138 if (path_equal(parent
, *i
))
144 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
153 e
= path_startswith(path
, p
->root_dir
);
157 /* Make sure the returned path starts with a slash */
159 if (e
== path
|| e
[-1] != '/')
168 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
169 _cleanup_free_
char *parent
= NULL
;
174 parent
= dirname_malloc(path
);
178 return path_equal_ptr(parent
, p
->generator
) ||
179 path_equal_ptr(parent
, p
->generator_early
) ||
180 path_equal_ptr(parent
, p
->generator_late
);
183 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
184 _cleanup_free_
char *parent
= NULL
;
189 parent
= dirname_malloc(path
);
193 return path_equal_ptr(parent
, p
->transient
);
196 static int path_is_control(const LookupPaths
*p
, const char *path
) {
197 _cleanup_free_
char *parent
= NULL
;
202 parent
= dirname_malloc(path
);
206 return path_equal_ptr(parent
, p
->persistent_control
) ||
207 path_equal_ptr(parent
, p
->runtime_control
);
210 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
211 _cleanup_free_
char *parent
= NULL
;
216 /* Note that we do *not* have generic checks for /etc or /run in place, since with
217 * them we couldn't discern configuration from transient or generated units */
220 parent
= dirname_malloc(path
);
227 return path_equal_ptr(path
, p
->persistent_config
) ||
228 path_equal_ptr(path
, p
->runtime_config
);
231 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
232 _cleanup_free_
char *parent
= NULL
;
238 /* Everything in /run is considered runtime. On top of that we also add
239 * explicit checks for the various runtime directories, as safety net. */
241 rpath
= skip_root(p
, path
);
242 if (rpath
&& path_startswith(rpath
, "/run"))
246 parent
= dirname_malloc(path
);
253 return path_equal_ptr(path
, p
->runtime_config
) ||
254 path_equal_ptr(path
, p
->generator
) ||
255 path_equal_ptr(path
, p
->generator_early
) ||
256 path_equal_ptr(path
, p
->generator_late
) ||
257 path_equal_ptr(path
, p
->transient
) ||
258 path_equal_ptr(path
, p
->runtime_control
);
261 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
267 rpath
= skip_root(p
, path
);
271 if (path_startswith(rpath
, "/usr"))
275 if (path_startswith(rpath
, "/lib"))
279 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
282 int unit_file_changes_add(
283 UnitFileChange
**changes
,
285 UnitFileChangeType type
,
287 const char *source
) {
289 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
293 assert(!changes
== !n_changes
);
298 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
307 if (!p
|| (source
&& !s
))
310 path_simplify(p
, false);
312 path_simplify(s
, false);
314 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
320 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
323 assert(changes
|| n_changes
== 0);
325 for (i
= 0; i
< n_changes
; i
++) {
326 free(changes
[i
].path
);
327 free(changes
[i
].source
);
333 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
337 assert(changes
|| n_changes
== 0);
338 /* If verb is not specified, errors are not allowed! */
339 assert(verb
|| r
>= 0);
341 for (i
= 0; i
< n_changes
; i
++) {
342 assert(verb
|| changes
[i
].type
>= 0);
344 switch(changes
[i
].type
) {
345 case UNIT_FILE_SYMLINK
:
347 log_info("Created symlink %s %s %s.",
349 special_glyph(ARROW
),
352 case UNIT_FILE_UNLINK
:
354 log_info("Removed %s.", changes
[i
].path
);
356 case UNIT_FILE_IS_MASKED
:
358 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
360 case UNIT_FILE_IS_DANGLING
:
362 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
366 if (changes
[i
].source
)
367 log_error_errno(changes
[i
].type
,
368 "Failed to %s unit, file %s already exists and is a symlink to %s.",
369 verb
, changes
[i
].path
, changes
[i
].source
);
371 log_error_errno(changes
[i
].type
,
372 "Failed to %s unit, file %s already exists.",
373 verb
, changes
[i
].path
);
377 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
378 verb
, changes
[i
].path
);
382 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
383 verb
, changes
[i
].path
);
387 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
388 verb
, changes
[i
].path
);
393 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
398 assert(changes
[i
].type
< 0);
399 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
400 verb
, changes
[i
].path
);
405 if (r
< 0 && !logged
)
406 log_error_errno(r
, "Failed to %s: %m.", verb
);
410 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
411 * wc should be the full path in the host file system.
413 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
414 assert(path_is_absolute(wd
));
416 /* This will give incorrect results if the paths are relative and go outside
417 * of the chroot. False negatives are possible. */
422 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
423 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
424 return path_equal_or_files_same(a
, b
, 0);
427 static int create_symlink(
428 const LookupPaths
*paths
,
429 const char *old_path
,
430 const char *new_path
,
432 UnitFileChange
**changes
,
435 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
442 rp
= skip_root(paths
, old_path
);
446 /* Actually create a symlink, and remember that we did. Is
447 * smart enough to check if there's already a valid symlink in
450 * Returns 1 if a symlink was created or already exists and points to
451 * the right place, or negative on error.
454 mkdir_parents_label(new_path
, 0755);
456 if (symlink(old_path
, new_path
) >= 0) {
457 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
461 if (errno
!= EEXIST
) {
462 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
466 r
= readlink_malloc(new_path
, &dest
);
468 /* translate EINVAL (non-symlink exists) to EEXIST */
472 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
476 dirname
= dirname_malloc(new_path
);
480 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
484 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
488 r
= symlink_atomic(old_path
, new_path
);
490 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
494 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
495 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
500 static int mark_symlink_for_removal(
501 Set
**remove_symlinks_to
,
509 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
517 path_simplify(n
, false);
519 r
= set_consume(*remove_symlinks_to
, n
);
528 static int remove_marked_symlinks_fd(
529 Set
*remove_symlinks_to
,
532 const char *config_path
,
533 const LookupPaths
*lp
,
536 UnitFileChange
**changes
,
539 _cleanup_closedir_
DIR *d
= NULL
;
543 assert(remove_symlinks_to
);
558 FOREACH_DIRENT(de
, d
, return -errno
) {
560 dirent_ensure_type(d
, de
);
562 if (de
->d_type
== DT_DIR
) {
563 _cleanup_free_
char *p
= NULL
;
566 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
576 p
= path_make_absolute(de
->d_name
, path
);
582 /* This will close nfd, regardless whether it succeeds or not */
583 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
587 } else if (de
->d_type
== DT_LNK
) {
588 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
593 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
596 p
= path_make_absolute(de
->d_name
, path
);
599 path_simplify(p
, false);
601 q
= readlink_malloc(p
, &dest
);
610 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
611 * the same name as a file that is marked. */
613 found
= set_contains(remove_symlinks_to
, dest
) ||
614 set_contains(remove_symlinks_to
, basename(dest
)) ||
615 set_contains(remove_symlinks_to
, de
->d_name
);
621 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
624 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
628 (void) rmdir_parents(p
, config_path
);
631 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
633 /* Now, remember the full path (but with the root prefix removed) of
634 * the symlink we just removed, and remove any symlinks to it, too. */
636 rp
= skip_root(lp
, p
);
637 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
640 if (q
> 0 && !dry_run
)
648 static int remove_marked_symlinks(
649 Set
*remove_symlinks_to
,
650 const char *config_path
,
651 const LookupPaths
*lp
,
653 UnitFileChange
**changes
,
656 _cleanup_close_
int fd
= -1;
663 if (set_size(remove_symlinks_to
) <= 0)
666 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
668 return errno
== ENOENT
? 0 : -errno
;
674 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
678 /* This takes possession of cfd and closes it */
679 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
687 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
690 if (streq(name
, i
->name
))
693 if (strv_contains(i
->aliases
, name
))
696 /* Look for template symlink matching DefaultInstance */
697 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
698 _cleanup_free_
char *s
= NULL
;
700 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
705 } else if (streq(name
, s
))
712 static int find_symlinks_fd(
713 const char *root_dir
,
714 UnitFileInstallInfo
*i
,
718 const char *config_path
,
719 bool *same_name_link
) {
721 _cleanup_closedir_
DIR *d
= NULL
;
729 assert(same_name_link
);
737 FOREACH_DIRENT(de
, d
, return -errno
) {
739 dirent_ensure_type(d
, de
);
741 if (de
->d_type
== DT_DIR
) {
742 _cleanup_free_
char *p
= NULL
;
745 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
755 p
= path_make_absolute(de
->d_name
, path
);
761 /* This will close nfd, regardless whether it succeeds or not */
762 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
763 p
, config_path
, same_name_link
);
769 } else if (de
->d_type
== DT_LNK
) {
770 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
771 bool found_path
, found_dest
, b
= false;
774 /* Acquire symlink name */
775 p
= path_make_absolute(de
->d_name
, path
);
779 /* Acquire symlink destination */
780 q
= readlink_malloc(p
, &dest
);
790 if (!path_is_absolute(dest
)) {
793 x
= prefix_root(root_dir
, dest
);
801 /* Check if the symlink itself matches what we
803 if (path_is_absolute(i
->name
))
804 found_path
= path_equal(p
, i
->name
);
806 found_path
= streq(de
->d_name
, i
->name
);
808 /* Check if what the symlink points to
809 * matches what we are looking for */
810 if (path_is_absolute(i
->name
))
811 found_dest
= path_equal(dest
, i
->name
);
813 found_dest
= streq(basename(dest
), i
->name
);
815 if (found_path
&& found_dest
) {
816 _cleanup_free_
char *t
= NULL
;
818 /* Filter out same name links in the main
820 t
= path_make_absolute(i
->name
, config_path
);
824 b
= path_equal(t
, p
);
828 *same_name_link
= true;
829 else if (found_path
|| found_dest
) {
833 /* Check if symlink name is in the set of names used by [Install] */
834 q
= is_symlink_with_known_name(i
, de
->d_name
);
846 static int find_symlinks(
847 const char *root_dir
,
848 UnitFileInstallInfo
*i
,
850 const char *config_path
,
851 bool *same_name_link
) {
857 assert(same_name_link
);
859 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
861 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
866 /* This takes possession of fd and closes it */
867 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
868 config_path
, config_path
, same_name_link
);
871 static int find_symlinks_in_scope(
873 const LookupPaths
*paths
,
874 UnitFileInstallInfo
*i
,
876 UnitFileState
*state
) {
878 bool same_name_link_runtime
= false, same_name_link_config
= false;
879 bool enabled_in_runtime
= false, enabled_at_all
= false;
886 STRV_FOREACH(p
, paths
->search_path
) {
887 bool same_name_link
= false;
889 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
893 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
895 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
896 /* This is the best outcome, let's return it immediately. */
897 *state
= UNIT_FILE_ENABLED
;
901 /* look for global enablement of user units */
902 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
903 *state
= UNIT_FILE_ENABLED
;
907 r
= path_is_runtime(paths
, *p
, false);
911 enabled_in_runtime
= true;
913 enabled_at_all
= true;
915 } else if (same_name_link
) {
916 if (path_equal_ptr(*p
, paths
->persistent_config
))
917 same_name_link_config
= true;
919 r
= path_is_runtime(paths
, *p
, false);
923 same_name_link_runtime
= true;
928 if (enabled_in_runtime
) {
929 *state
= UNIT_FILE_ENABLED_RUNTIME
;
933 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
934 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
935 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
936 * something, and hence are a much stronger concept. */
937 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
938 *state
= UNIT_FILE_STATIC
;
942 /* Hmm, we didn't find it, but maybe we found the same name
944 if (same_name_link_config
) {
945 *state
= UNIT_FILE_LINKED
;
948 if (same_name_link_runtime
) {
949 *state
= UNIT_FILE_LINKED_RUNTIME
;
956 static void install_info_free(UnitFileInstallInfo
*i
) {
963 strv_free(i
->aliases
);
964 strv_free(i
->wanted_by
);
965 strv_free(i
->required_by
);
967 free(i
->default_instance
);
968 free(i
->symlink_target
);
972 static void install_context_done(InstallContext
*c
) {
975 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
976 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
979 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
980 UnitFileInstallInfo
*i
;
982 i
= ordered_hashmap_get(c
->have_processed
, name
);
986 return ordered_hashmap_get(c
->will_process
, name
);
989 static int install_info_may_process(
990 UnitFileInstallInfo
*i
,
991 const LookupPaths
*paths
,
992 UnitFileChange
**changes
,
997 /* Checks whether the loaded unit file is one we should process, or is masked,
998 * transient or generated and thus not subject to enable/disable operations. */
1000 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1001 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1004 if (path_is_generator(paths
, i
->path
) ||
1005 path_is_transient(paths
, i
->path
)) {
1006 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1007 return -EADDRNOTAVAIL
;
1014 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1015 * hashmap, or retrieves the existing one if already present.
1017 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1019 static int install_info_add(
1024 UnitFileInstallInfo
**ret
) {
1026 UnitFileInstallInfo
*i
= NULL
;
1030 assert(name
|| path
);
1033 name
= basename(path
);
1035 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1038 i
= install_info_find(c
, name
);
1040 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1047 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1051 i
= new0(UnitFileInstallInfo
, 1);
1054 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1055 i
->auxiliary
= auxiliary
;
1057 i
->name
= strdup(name
);
1064 i
->path
= strdup(path
);
1071 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1081 install_info_free(i
);
1085 static int config_parse_alias(
1087 const char *filename
,
1089 const char *section
,
1090 unsigned section_line
,
1104 type
= unit_name_to_type(unit
);
1105 if (!unit_type_may_alias(type
))
1106 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1107 "Alias= is not allowed for %s units, ignoring.",
1108 unit_type_to_string(type
));
1110 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1111 lvalue
, ltype
, rvalue
, data
, userdata
);
1114 static int config_parse_also(
1116 const char *filename
,
1118 const char *section
,
1119 unsigned section_line
,
1126 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1127 InstallContext
*c
= data
;
1136 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1138 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1144 r
= install_full_printf(info
, word
, &printed
);
1148 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1151 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1155 r
= strv_push(&info
->also
, printed
);
1165 static int config_parse_default_instance(
1167 const char *filename
,
1169 const char *section
,
1170 unsigned section_line
,
1177 UnitFileInstallInfo
*i
= data
;
1178 _cleanup_free_
char *printed
= NULL
;
1186 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1187 /* When enabling an instance, we might be using a template unit file,
1188 * but we should ignore DefaultInstance silently. */
1190 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1191 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1192 "DefaultInstance= only makes sense for template units, ignoring.");
1194 r
= install_full_printf(i
, rvalue
, &printed
);
1198 if (!unit_instance_is_valid(printed
))
1201 return free_and_replace(i
->default_instance
, printed
);
1204 static int unit_file_load(
1206 UnitFileInstallInfo
*info
,
1208 const char *root_dir
,
1209 SearchFlags flags
) {
1211 const ConfigTableItem items
[] = {
1212 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1213 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1214 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1215 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1216 { "Install", "Also", config_parse_also
, 0, c
},
1221 _cleanup_fclose_
FILE *f
= NULL
;
1222 _cleanup_close_
int fd
= -1;
1229 if (!(flags
& SEARCH_DROPIN
)) {
1230 /* Loading or checking for the main unit file… */
1232 type
= unit_name_to_type(info
->name
);
1235 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1236 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1240 if (!(flags
& SEARCH_LOAD
)) {
1241 r
= lstat(path
, &st
);
1245 if (null_or_empty(&st
))
1246 info
->type
= UNIT_FILE_TYPE_MASKED
;
1247 else if (S_ISREG(st
.st_mode
))
1248 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1249 else if (S_ISLNK(st
.st_mode
))
1251 else if (S_ISDIR(st
.st_mode
))
1259 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1263 /* 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. */
1265 if (!(flags
& SEARCH_LOAD
))
1268 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1273 if (fstat(fd
, &st
) < 0)
1276 if (null_or_empty(&st
)) {
1277 if ((flags
& SEARCH_DROPIN
) == 0)
1278 info
->type
= UNIT_FILE_TYPE_MASKED
;
1283 r
= stat_verify_regular(&st
);
1287 f
= fdopen(fd
, "re");
1292 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1295 r
= config_parse(info
->name
, path
, f
,
1297 config_item_table_lookup
, items
,
1298 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1300 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1302 if ((flags
& SEARCH_DROPIN
) == 0)
1303 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1306 (int) strv_length(info
->aliases
) +
1307 (int) strv_length(info
->wanted_by
) +
1308 (int) strv_length(info
->required_by
);
1311 static int unit_file_load_or_readlink(
1313 UnitFileInstallInfo
*info
,
1315 const char *root_dir
,
1316 SearchFlags flags
) {
1318 _cleanup_free_
char *target
= NULL
;
1321 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1322 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1325 /* This is a symlink, let's read it. */
1327 r
= readlink_malloc(path
, &target
);
1331 if (path_equal(target
, "/dev/null"))
1332 info
->type
= UNIT_FILE_TYPE_MASKED
;
1337 bn
= basename(target
);
1339 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1341 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1344 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1346 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1349 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1351 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1356 /* Enforce that the symlink destination does not
1357 * change the unit file type. */
1359 a
= unit_name_to_type(info
->name
);
1360 b
= unit_name_to_type(bn
);
1361 if (a
< 0 || b
< 0 || a
!= b
)
1364 if (path_is_absolute(target
))
1365 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1366 info
->symlink_target
= prefix_root(root_dir
, target
);
1368 /* This is a relative path, take it relative to the dir the symlink is located in. */
1369 info
->symlink_target
= file_in_same_dir(path
, target
);
1370 if (!info
->symlink_target
)
1373 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1379 static int unit_file_search(
1381 UnitFileInstallInfo
*info
,
1382 const LookupPaths
*paths
,
1383 SearchFlags flags
) {
1385 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1386 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1387 _cleanup_free_
char *template = NULL
;
1388 bool found_unit
= false;
1395 /* Was this unit already loaded? */
1396 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1400 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1404 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1405 r
= unit_name_template(info
->name
, &template);
1410 STRV_FOREACH(p
, paths
->search_path
) {
1411 _cleanup_free_
char *path
= NULL
;
1413 path
= strjoin(*p
, "/", info
->name
);
1417 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1419 info
->path
= TAKE_PTR(path
);
1423 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1427 if (!found_unit
&& template) {
1429 /* Unit file doesn't exist, however instance
1430 * enablement was requested. We will check if it is
1431 * possible to load template unit file. */
1433 STRV_FOREACH(p
, paths
->search_path
) {
1434 _cleanup_free_
char *path
= NULL
;
1436 path
= strjoin(*p
, "/", template);
1440 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1442 info
->path
= TAKE_PTR(path
);
1446 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1452 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1456 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1459 /* Search for drop-in directories */
1461 dropin_dir_name
= strjoina(info
->name
, ".d");
1462 STRV_FOREACH(p
, paths
->search_path
) {
1465 path
= path_join(NULL
, *p
, dropin_dir_name
);
1469 r
= strv_consume(&dirs
, path
);
1475 dropin_template_dir_name
= strjoina(template, ".d");
1476 STRV_FOREACH(p
, paths
->search_path
) {
1479 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1483 r
= strv_consume(&dirs
, path
);
1489 /* Load drop-in conf files */
1491 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1493 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1495 STRV_FOREACH(p
, files
) {
1496 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1498 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1504 static int install_info_follow(
1506 UnitFileInstallInfo
*i
,
1507 const char *root_dir
,
1509 bool ignore_different_name
) {
1514 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1516 if (!i
->symlink_target
)
1519 /* If the basename doesn't match, the caller should add a
1520 * complete new entry for this. */
1522 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1525 free_and_replace(i
->path
, i
->symlink_target
);
1526 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1528 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1532 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1533 * target, maybe more than once. Propagate the instance name if present.
1535 static int install_info_traverse(
1536 UnitFileScope scope
,
1538 const LookupPaths
*paths
,
1539 UnitFileInstallInfo
*start
,
1541 UnitFileInstallInfo
**ret
) {
1543 UnitFileInstallInfo
*i
;
1551 r
= unit_file_search(c
, start
, paths
, flags
);
1556 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1557 /* Follow the symlink */
1559 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1562 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1563 r
= path_is_config(paths
, i
->path
, true);
1570 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1572 _cleanup_free_
char *buffer
= NULL
;
1575 /* Target has a different name, create a new
1576 * install info object for that, and continue
1579 bn
= basename(i
->symlink_target
);
1581 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1582 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1584 _cleanup_free_
char *instance
= NULL
;
1586 r
= unit_name_to_instance(i
->name
, &instance
);
1590 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1594 if (streq(buffer
, i
->name
)) {
1596 /* We filled in the instance, and the target stayed the same? If so, then let's
1597 * honour the link as it is. */
1599 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1609 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1613 /* Try again, with the new target we found. */
1614 r
= unit_file_search(c
, i
, paths
, flags
);
1616 /* Translate error code to highlight this specific case */
1631 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1632 * or the name (otherwise). root_dir is prepended to the path.
1634 static int install_info_add_auto(
1636 const LookupPaths
*paths
,
1637 const char *name_or_path
,
1638 UnitFileInstallInfo
**ret
) {
1641 assert(name_or_path
);
1643 if (path_is_absolute(name_or_path
)) {
1646 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1648 return install_info_add(c
, NULL
, pp
, false, ret
);
1650 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1653 static int install_info_discover(
1654 UnitFileScope scope
,
1656 const LookupPaths
*paths
,
1659 UnitFileInstallInfo
**ret
,
1660 UnitFileChange
**changes
,
1661 size_t *n_changes
) {
1663 UnitFileInstallInfo
*i
;
1670 r
= install_info_add_auto(c
, paths
, name
, &i
);
1672 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1675 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1679 static int install_info_symlink_alias(
1680 UnitFileInstallInfo
*i
,
1681 const LookupPaths
*paths
,
1682 const char *config_path
,
1684 UnitFileChange
**changes
,
1685 size_t *n_changes
) {
1692 assert(config_path
);
1694 STRV_FOREACH(s
, i
->aliases
) {
1695 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1697 q
= install_full_printf(i
, *s
, &dst
);
1701 alias_path
= path_make_absolute(dst
, config_path
);
1705 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1713 static int install_info_symlink_wants(
1714 UnitFileInstallInfo
*i
,
1715 const LookupPaths
*paths
,
1716 const char *config_path
,
1719 UnitFileChange
**changes
,
1720 size_t *n_changes
) {
1722 _cleanup_free_
char *buf
= NULL
;
1729 assert(config_path
);
1731 if (strv_isempty(list
))
1734 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1735 UnitFileInstallInfo instance
= {
1736 .type
= _UNIT_FILE_TYPE_INVALID
,
1738 _cleanup_free_
char *path
= NULL
;
1740 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1744 instance
.name
= buf
;
1745 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1749 path
= TAKE_PTR(instance
.path
);
1751 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1752 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1760 STRV_FOREACH(s
, list
) {
1761 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1763 q
= install_full_printf(i
, *s
, &dst
);
1767 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1772 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1776 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1784 static int install_info_symlink_link(
1785 UnitFileInstallInfo
*i
,
1786 const LookupPaths
*paths
,
1787 const char *config_path
,
1789 UnitFileChange
**changes
,
1790 size_t *n_changes
) {
1792 _cleanup_free_
char *path
= NULL
;
1797 assert(config_path
);
1800 r
= in_search_path(paths
, i
->path
);
1806 path
= strjoin(config_path
, "/", i
->name
);
1810 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1813 static int install_info_apply(
1814 UnitFileInstallInfo
*i
,
1815 const LookupPaths
*paths
,
1816 const char *config_path
,
1818 UnitFileChange
**changes
,
1819 size_t *n_changes
) {
1825 assert(config_path
);
1827 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1830 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1832 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1836 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1840 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1841 /* Do not count links to the unit file towards the "carries_install_info" count */
1842 if (r
== 0 && q
< 0)
1848 static int install_context_apply(
1849 UnitFileScope scope
,
1851 const LookupPaths
*paths
,
1852 const char *config_path
,
1855 UnitFileChange
**changes
,
1856 size_t *n_changes
) {
1858 UnitFileInstallInfo
*i
;
1863 assert(config_path
);
1865 if (ordered_hashmap_isempty(c
->will_process
))
1868 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1873 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1876 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1880 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1882 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1886 /* We can attempt to process a masked unit when a different unit
1887 * that we were processing specifies it in Also=. */
1888 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1889 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1891 /* Assume that something *could* have been enabled here,
1892 * avoid "empty [Install] section" warning. */
1897 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1900 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1912 static int install_context_mark_for_removal(
1913 UnitFileScope scope
,
1915 const LookupPaths
*paths
,
1916 Set
**remove_symlinks_to
,
1917 UnitFileChange
**changes
,
1918 size_t *n_changes
) {
1920 UnitFileInstallInfo
*i
;
1926 /* Marks all items for removal */
1928 if (ordered_hashmap_isempty(c
->will_process
))
1931 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1935 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1937 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1941 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1942 if (r
== -ENOLINK
) {
1943 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1944 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1945 } else if (r
== -ENOENT
) {
1947 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1948 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1950 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1951 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1955 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1956 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1957 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1958 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1959 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1961 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1962 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1966 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1975 UnitFileScope scope
,
1976 UnitFileFlags flags
,
1977 const char *root_dir
,
1979 UnitFileChange
**changes
,
1980 size_t *n_changes
) {
1982 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
1983 const char *config_path
;
1988 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1990 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1994 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
1998 STRV_FOREACH(i
, files
) {
1999 _cleanup_free_
char *path
= NULL
;
2002 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2008 path
= path_make_absolute(*i
, config_path
);
2012 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2013 if (q
< 0 && r
>= 0)
2020 int unit_file_unmask(
2021 UnitFileScope scope
,
2022 UnitFileFlags flags
,
2023 const char *root_dir
,
2025 UnitFileChange
**changes
,
2026 size_t *n_changes
) {
2028 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2029 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2030 _cleanup_strv_free_
char **todo
= NULL
;
2031 size_t n_todo
= 0, n_allocated
= 0;
2032 const char *config_path
;
2034 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2038 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2040 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2044 STRV_FOREACH(i
, files
) {
2045 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2048 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2049 _cleanup_free_
char *path
= NULL
;
2051 path
= path_make_absolute(*i
, config_path
);
2055 r
= null_or_empty_path(path
);
2063 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2066 todo
[n_todo
] = strdup(*i
);
2077 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2078 STRV_FOREACH(i
, todo
) {
2079 _cleanup_free_
char *path
= NULL
;
2082 path
= path_make_absolute(*i
, config_path
);
2086 if (!dry_run
&& unlink(path
) < 0) {
2087 if (errno
!= ENOENT
) {
2090 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2096 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2098 rp
= skip_root(&paths
, path
);
2099 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2104 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2113 UnitFileScope scope
,
2114 UnitFileFlags flags
,
2115 const char *root_dir
,
2117 UnitFileChange
**changes
,
2118 size_t *n_changes
) {
2120 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2121 _cleanup_strv_free_
char **todo
= NULL
;
2122 size_t n_todo
= 0, n_allocated
= 0;
2123 const char *config_path
;
2128 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2130 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2134 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2138 STRV_FOREACH(i
, files
) {
2139 _cleanup_free_
char *full
= NULL
;
2143 if (!path_is_absolute(*i
))
2147 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2150 full
= prefix_root(paths
.root_dir
, *i
);
2154 if (lstat(full
, &st
) < 0)
2156 r
= stat_verify_regular(&st
);
2160 q
= in_search_path(&paths
, *i
);
2166 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2169 todo
[n_todo
] = strdup(*i
);
2179 STRV_FOREACH(i
, todo
) {
2180 _cleanup_free_
char *new_path
= NULL
;
2182 new_path
= path_make_absolute(basename(*i
), config_path
);
2186 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2187 if (q
< 0 && r
>= 0)
2194 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2200 /* Checks whether the path is one where the drop-in directories shall be removed. */
2202 r
= path_is_config(paths
, path
, true);
2206 r
= path_is_control(paths
, path
);
2210 return path_is_transient(paths
, path
);
2213 int unit_file_revert(
2214 UnitFileScope scope
,
2215 const char *root_dir
,
2217 UnitFileChange
**changes
,
2218 size_t *n_changes
) {
2220 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2221 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2222 _cleanup_strv_free_
char **todo
= NULL
;
2223 size_t n_todo
= 0, n_allocated
= 0;
2227 /* Puts a unit file back into vendor state. This means:
2229 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2230 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2232 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2233 * "config", but not in "transient" or "control" or even "generated").
2235 * We remove all that in both the runtime and the persistent directories, if that applies.
2238 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2242 STRV_FOREACH(i
, files
) {
2243 bool has_vendor
= false;
2246 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2249 STRV_FOREACH(p
, paths
.search_path
) {
2250 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2253 path
= path_make_absolute(*i
, *p
);
2257 r
= lstat(path
, &st
);
2259 if (errno
!= ENOENT
)
2261 } else if (S_ISREG(st
.st_mode
)) {
2262 /* Check if there's a vendor version */
2263 r
= path_is_vendor(&paths
, path
);
2270 dropin
= strappend(path
, ".d");
2274 r
= lstat(dropin
, &st
);
2276 if (errno
!= ENOENT
)
2278 } else if (S_ISDIR(st
.st_mode
)) {
2279 /* Remove the drop-ins */
2280 r
= path_shall_revert(&paths
, dropin
);
2284 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2287 todo
[n_todo
++] = TAKE_PTR(dropin
);
2295 /* OK, there's a vendor version, hence drop all configuration versions */
2296 STRV_FOREACH(p
, paths
.search_path
) {
2297 _cleanup_free_
char *path
= NULL
;
2300 path
= path_make_absolute(*i
, *p
);
2304 r
= lstat(path
, &st
);
2306 if (errno
!= ENOENT
)
2308 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2309 r
= path_is_config(&paths
, path
, true);
2313 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2316 todo
[n_todo
++] = TAKE_PTR(path
);
2325 STRV_FOREACH(i
, todo
) {
2326 _cleanup_strv_free_
char **fs
= NULL
;
2330 (void) get_files_in_directory(*i
, &fs
);
2332 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2333 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2338 STRV_FOREACH(j
, fs
) {
2339 _cleanup_free_
char *t
= NULL
;
2341 t
= strjoin(*i
, "/", *j
);
2345 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2348 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2350 rp
= skip_root(&paths
, *i
);
2351 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2356 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2360 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2367 int unit_file_add_dependency(
2368 UnitFileScope scope
,
2369 UnitFileFlags flags
,
2370 const char *root_dir
,
2374 UnitFileChange
**changes
,
2375 size_t *n_changes
) {
2377 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2378 _cleanup_(install_context_done
) InstallContext c
= {};
2379 UnitFileInstallInfo
*i
, *target_info
;
2380 const char *config_path
;
2385 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2388 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2391 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2394 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2398 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2402 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2403 &target_info
, changes
, n_changes
);
2406 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2410 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2412 STRV_FOREACH(f
, files
) {
2415 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2416 &i
, changes
, n_changes
);
2419 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2423 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2425 /* We didn't actually load anything from the unit
2426 * file, but instead just add in our new symlink to
2429 if (dep
== UNIT_WANTS
)
2432 l
= &i
->required_by
;
2435 *l
= strv_new(target_info
->name
, NULL
);
2440 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2443 int unit_file_enable(
2444 UnitFileScope scope
,
2445 UnitFileFlags flags
,
2446 const char *root_dir
,
2448 UnitFileChange
**changes
,
2449 size_t *n_changes
) {
2451 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2452 _cleanup_(install_context_done
) InstallContext c
= {};
2453 const char *config_path
;
2454 UnitFileInstallInfo
*i
;
2459 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2461 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2465 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2469 STRV_FOREACH(f
, files
) {
2470 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2471 &i
, changes
, n_changes
);
2474 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2478 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2481 /* This will return the number of symlink rules that were
2482 supposed to be created, not the ones actually created. This
2483 is useful to determine whether the passed files had any
2484 installation data at all. */
2486 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2489 int unit_file_disable(
2490 UnitFileScope scope
,
2491 UnitFileFlags flags
,
2492 const char *root_dir
,
2494 UnitFileChange
**changes
,
2495 size_t *n_changes
) {
2497 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2498 _cleanup_(install_context_done
) InstallContext c
= {};
2499 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2500 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2501 const char *config_path
;
2506 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2508 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2512 STRV_FOREACH(i
, files
) {
2513 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2516 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2521 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2525 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2526 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2534 int unit_file_reenable(
2535 UnitFileScope scope
,
2536 UnitFileFlags flags
,
2537 const char *root_dir
,
2539 UnitFileChange
**changes
,
2540 size_t *n_changes
) {
2546 /* First, we invoke the disable command with only the basename... */
2547 l
= strv_length(files
);
2548 n
= newa(char*, l
+1);
2549 for (i
= 0; i
< l
; i
++)
2550 n
[i
] = basename(files
[i
]);
2553 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2557 /* But the enable command with the full name */
2558 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2561 int unit_file_set_default(
2562 UnitFileScope scope
,
2563 UnitFileFlags flags
,
2564 const char *root_dir
,
2566 UnitFileChange
**changes
,
2567 size_t *n_changes
) {
2569 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2570 _cleanup_(install_context_done
) InstallContext c
= {};
2571 UnitFileInstallInfo
*i
;
2572 const char *new_path
;
2576 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2579 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2581 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2584 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2588 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2591 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2595 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2596 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2599 int unit_file_get_default(
2600 UnitFileScope scope
,
2601 const char *root_dir
,
2604 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2605 _cleanup_(install_context_done
) InstallContext c
= {};
2606 UnitFileInstallInfo
*i
;
2611 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2614 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2618 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2622 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2626 n
= strdup(i
->name
);
2634 int unit_file_lookup_state(
2635 UnitFileScope scope
,
2636 const LookupPaths
*paths
,
2638 UnitFileState
*ret
) {
2640 _cleanup_(install_context_done
) InstallContext c
= {};
2641 UnitFileInstallInfo
*i
;
2642 UnitFileState state
;
2648 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2651 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2656 /* Shortcut things, if the caller just wants to know if this unit exists. */
2662 case UNIT_FILE_TYPE_MASKED
:
2663 r
= path_is_runtime(paths
, i
->path
, true);
2667 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2670 case UNIT_FILE_TYPE_REGULAR
:
2671 r
= path_is_generator(paths
, i
->path
);
2675 state
= UNIT_FILE_GENERATED
;
2679 r
= path_is_transient(paths
, i
->path
);
2683 state
= UNIT_FILE_TRANSIENT
;
2687 /* Check if any of the Alias= symlinks have been created.
2688 * We ignore other aliases, and only check those that would
2689 * be created by systemctl enable for this unit. */
2690 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2696 /* Check if the file is known under other names. If it is,
2697 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2698 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2702 state
= UNIT_FILE_INDIRECT
;
2704 if (unit_file_install_info_has_rules(i
))
2705 state
= UNIT_FILE_DISABLED
;
2706 else if (unit_file_install_info_has_also(i
))
2707 state
= UNIT_FILE_INDIRECT
;
2709 state
= UNIT_FILE_STATIC
;
2715 assert_not_reached("Unexpect unit file type.");
2722 int unit_file_get_state(
2723 UnitFileScope scope
,
2724 const char *root_dir
,
2726 UnitFileState
*ret
) {
2728 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2732 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2735 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2739 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2742 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2743 _cleanup_(install_context_done
) InstallContext c
= {};
2749 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2752 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2761 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2762 _cleanup_(presets_freep
) Presets ps
= {};
2763 size_t n_allocated
= 0;
2764 _cleanup_strv_free_
char **files
= NULL
;
2769 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2773 case UNIT_FILE_SYSTEM
:
2774 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2775 "/etc/systemd/system-preset",
2776 "/run/systemd/system-preset",
2777 "/usr/local/lib/systemd/system-preset",
2778 "/usr/lib/systemd/system-preset",
2780 "/lib/systemd/system-preset",
2785 case UNIT_FILE_GLOBAL
:
2786 case UNIT_FILE_USER
:
2787 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2788 "/etc/systemd/user-preset",
2789 "/run/systemd/user-preset",
2790 "/usr/local/lib/systemd/user-preset",
2791 "/usr/lib/systemd/user-preset",
2796 assert_not_reached("Invalid unit file scope");
2802 STRV_FOREACH(p
, files
) {
2803 _cleanup_fclose_
FILE *f
;
2804 char line
[LINE_MAX
];
2807 f
= fopen(*p
, "re");
2809 if (errno
== ENOENT
)
2815 FOREACH_LINE(line
, f
, return -errno
) {
2816 PresetRule rule
= {};
2817 const char *parameter
;
2825 if (strchr(COMMENTS
, *l
))
2828 parameter
= first_word(l
, "enable");
2832 pattern
= strdup(parameter
);
2836 rule
= (PresetRule
) {
2838 .action
= PRESET_ENABLE
,
2842 parameter
= first_word(l
, "disable");
2846 pattern
= strdup(parameter
);
2850 rule
= (PresetRule
) {
2852 .action
= PRESET_DISABLE
,
2857 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2860 ps
.rules
[ps
.n_rules
++] = rule
;
2864 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2874 static int query_presets(const char *name
, const Presets presets
) {
2875 PresetAction action
= PRESET_UNKNOWN
;
2878 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2881 for (i
= 0; i
< presets
.n_rules
; i
++)
2882 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2883 action
= presets
.rules
[i
].action
;
2888 case PRESET_UNKNOWN
:
2889 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2892 log_debug("Preset files say enable %s.", name
);
2894 case PRESET_DISABLE
:
2895 log_debug("Preset files say disable %s.", name
);
2898 assert_not_reached("invalid preset action");
2902 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2903 _cleanup_(presets_freep
) Presets presets
= {};
2906 r
= read_presets(scope
, root_dir
, &presets
);
2910 return query_presets(name
, presets
);
2913 static int execute_preset(
2914 UnitFileScope scope
,
2915 UnitFileFlags flags
,
2916 InstallContext
*plus
,
2917 InstallContext
*minus
,
2918 const LookupPaths
*paths
,
2920 UnitFilePresetMode mode
,
2921 UnitFileChange
**changes
,
2922 size_t *n_changes
) {
2924 const char *config_path
;
2925 bool force
= !!(flags
& UNIT_FILE_FORCE
);
2926 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
2933 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2934 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2936 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
2940 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
2941 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2947 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2948 /* Returns number of symlinks that where supposed to be installed. */
2949 q
= install_context_apply(scope
, plus
, paths
,
2950 runtime
? paths
->runtime_config
: paths
->persistent_config
,
2951 force
, SEARCH_LOAD
, changes
, n_changes
);
2959 static int preset_prepare_one(
2960 UnitFileScope scope
,
2961 InstallContext
*plus
,
2962 InstallContext
*minus
,
2966 UnitFileChange
**changes
,
2967 size_t *n_changes
) {
2969 _cleanup_(install_context_done
) InstallContext tmp
= {};
2970 UnitFileInstallInfo
*i
;
2973 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2976 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2977 &i
, changes
, n_changes
);
2980 if (!streq(name
, i
->name
)) {
2981 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
2985 r
= query_presets(name
, presets
);
2990 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2991 &i
, changes
, n_changes
);
2995 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
2999 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3000 &i
, changes
, n_changes
);
3005 int unit_file_preset(
3006 UnitFileScope scope
,
3007 UnitFileFlags flags
,
3008 const char *root_dir
,
3010 UnitFilePresetMode mode
,
3011 UnitFileChange
**changes
,
3012 size_t *n_changes
) {
3014 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3015 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3016 _cleanup_(presets_freep
) Presets presets
= {};
3021 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3022 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3024 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3028 r
= read_presets(scope
, root_dir
, &presets
);
3032 STRV_FOREACH(i
, files
) {
3033 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3038 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3041 int unit_file_preset_all(
3042 UnitFileScope scope
,
3043 UnitFileFlags flags
,
3044 const char *root_dir
,
3045 UnitFilePresetMode mode
,
3046 UnitFileChange
**changes
,
3047 size_t *n_changes
) {
3049 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3050 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3051 _cleanup_(presets_freep
) Presets presets
= {};
3056 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3057 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3059 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3063 r
= read_presets(scope
, root_dir
, &presets
);
3067 STRV_FOREACH(i
, paths
.search_path
) {
3068 _cleanup_closedir_
DIR *d
= NULL
;
3073 if (errno
== ENOENT
)
3079 FOREACH_DIRENT(de
, d
, return -errno
) {
3080 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3083 dirent_ensure_type(d
, de
);
3085 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3088 /* we don't pass changes[] in, because we want to handle errors on our own */
3089 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3091 r
= unit_file_changes_add(changes
, n_changes
,
3092 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3093 else if (r
== -ENOLINK
)
3094 r
= unit_file_changes_add(changes
, n_changes
,
3095 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3096 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3103 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3106 static void unit_file_list_free_one(UnitFileList
*f
) {
3114 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3115 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3118 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3120 int unit_file_get_list(
3121 UnitFileScope scope
,
3122 const char *root_dir
,
3127 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3132 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3135 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3139 STRV_FOREACH(i
, paths
.search_path
) {
3140 _cleanup_closedir_
DIR *d
= NULL
;
3145 if (errno
== ENOENT
)
3147 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3148 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3155 FOREACH_DIRENT(de
, d
, return -errno
) {
3156 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3158 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3161 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3164 if (hashmap_get(h
, de
->d_name
))
3167 dirent_ensure_type(d
, de
);
3169 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3172 f
= new0(UnitFileList
, 1);
3176 f
->path
= path_make_absolute(de
->d_name
, *i
);
3180 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3182 f
->state
= UNIT_FILE_BAD
;
3184 if (!strv_isempty(states
) &&
3185 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3188 r
= hashmap_put(h
, basename(f
->path
), f
);
3192 f
= NULL
; /* prevent cleanup */
3199 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3200 [UNIT_FILE_ENABLED
] = "enabled",
3201 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3202 [UNIT_FILE_LINKED
] = "linked",
3203 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3204 [UNIT_FILE_MASKED
] = "masked",
3205 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3206 [UNIT_FILE_STATIC
] = "static",
3207 [UNIT_FILE_DISABLED
] = "disabled",
3208 [UNIT_FILE_INDIRECT
] = "indirect",
3209 [UNIT_FILE_GENERATED
] = "generated",
3210 [UNIT_FILE_TRANSIENT
] = "transient",
3211 [UNIT_FILE_BAD
] = "bad",
3214 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3216 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3217 [UNIT_FILE_SYMLINK
] = "symlink",
3218 [UNIT_FILE_UNLINK
] = "unlink",
3219 [UNIT_FILE_IS_MASKED
] = "masked",
3220 [UNIT_FILE_IS_DANGLING
] = "dangling",
3223 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3225 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3226 [UNIT_FILE_PRESET_FULL
] = "full",
3227 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3228 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3231 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);