1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include "alloc-util.h"
16 #include "conf-files.h"
17 #include "conf-parser.h"
18 #include "dirent-util.h"
19 #include "extract-word.h"
24 #include "install-printf.h"
26 #include "locale-util.h"
30 #include "path-lookup.h"
31 #include "path-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
39 #include "unit-name.h"
41 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
43 typedef enum SearchFlags
{
45 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
46 SEARCH_DROPIN
= 1 << 2,
50 OrderedHashmap
*will_process
;
51 OrderedHashmap
*have_processed
;
70 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
73 return !strv_isempty(i
->aliases
) ||
74 !strv_isempty(i
->wanted_by
) ||
75 !strv_isempty(i
->required_by
);
78 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
81 return !strv_isempty(i
->also
);
84 static inline void presets_freep(Presets
*p
) {
90 for (i
= 0; i
< p
->n_rules
; i
++)
91 free(p
->rules
[i
].pattern
);
97 bool unit_type_may_alias(UnitType type
) {
107 bool unit_type_may_template(UnitType type
) {
116 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
117 [UNIT_FILE_TYPE_REGULAR
] = "regular",
118 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
119 [UNIT_FILE_TYPE_MASKED
] = "masked",
122 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
124 static int in_search_path(const LookupPaths
*p
, const char *path
) {
125 _cleanup_free_
char *parent
= NULL
;
130 parent
= dirname_malloc(path
);
134 STRV_FOREACH(i
, p
->search_path
)
135 if (path_equal(parent
, *i
))
141 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
150 e
= path_startswith(path
, p
->root_dir
);
154 /* Make sure the returned path starts with a slash */
156 if (e
== path
|| e
[-1] != '/')
165 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
166 _cleanup_free_
char *parent
= NULL
;
171 parent
= dirname_malloc(path
);
175 return path_equal_ptr(parent
, p
->generator
) ||
176 path_equal_ptr(parent
, p
->generator_early
) ||
177 path_equal_ptr(parent
, p
->generator_late
);
180 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
181 _cleanup_free_
char *parent
= NULL
;
186 parent
= dirname_malloc(path
);
190 return path_equal_ptr(parent
, p
->transient
);
193 static int path_is_control(const LookupPaths
*p
, const char *path
) {
194 _cleanup_free_
char *parent
= NULL
;
199 parent
= dirname_malloc(path
);
203 return path_equal_ptr(parent
, p
->persistent_control
) ||
204 path_equal_ptr(parent
, p
->runtime_control
);
207 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
208 _cleanup_free_
char *parent
= NULL
;
213 /* Note that we do *not* have generic checks for /etc or /run in place, since with
214 * them we couldn't discern configuration from transient or generated units */
217 parent
= dirname_malloc(path
);
224 return path_equal_ptr(path
, p
->persistent_config
) ||
225 path_equal_ptr(path
, p
->runtime_config
);
228 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
229 _cleanup_free_
char *parent
= NULL
;
235 /* Everything in /run is considered runtime. On top of that we also add
236 * explicit checks for the various runtime directories, as safety net. */
238 rpath
= skip_root(p
, path
);
239 if (rpath
&& path_startswith(rpath
, "/run"))
243 parent
= dirname_malloc(path
);
250 return path_equal_ptr(path
, p
->runtime_config
) ||
251 path_equal_ptr(path
, p
->generator
) ||
252 path_equal_ptr(path
, p
->generator_early
) ||
253 path_equal_ptr(path
, p
->generator_late
) ||
254 path_equal_ptr(path
, p
->transient
) ||
255 path_equal_ptr(path
, p
->runtime_control
);
258 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
264 rpath
= skip_root(p
, path
);
268 if (path_startswith(rpath
, "/usr"))
272 if (path_startswith(rpath
, "/lib"))
276 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
279 int unit_file_changes_add(
280 UnitFileChange
**changes
,
282 UnitFileChangeType type
,
284 const char *source
) {
286 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
290 assert(!changes
== !n_changes
);
295 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
304 if (!p
|| (source
&& !s
))
307 path_simplify(p
, false);
309 path_simplify(s
, false);
311 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
317 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
320 assert(changes
|| n_changes
== 0);
322 for (i
= 0; i
< n_changes
; i
++) {
323 free(changes
[i
].path
);
324 free(changes
[i
].source
);
330 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
334 assert(changes
|| n_changes
== 0);
335 /* If verb is not specified, errors are not allowed! */
336 assert(verb
|| r
>= 0);
338 for (i
= 0; i
< n_changes
; i
++) {
339 assert(verb
|| changes
[i
].type
>= 0);
341 switch(changes
[i
].type
) {
342 case UNIT_FILE_SYMLINK
:
344 log_info("Created symlink %s %s %s.",
346 special_glyph(ARROW
),
349 case UNIT_FILE_UNLINK
:
351 log_info("Removed %s.", changes
[i
].path
);
353 case UNIT_FILE_IS_MASKED
:
355 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
357 case UNIT_FILE_IS_DANGLING
:
359 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
363 if (changes
[i
].source
)
364 log_error_errno(changes
[i
].type
,
365 "Failed to %s unit, file %s already exists and is a symlink to %s.",
366 verb
, changes
[i
].path
, changes
[i
].source
);
368 log_error_errno(changes
[i
].type
,
369 "Failed to %s unit, file %s already exists.",
370 verb
, changes
[i
].path
);
374 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
375 verb
, changes
[i
].path
);
379 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
380 verb
, changes
[i
].path
);
384 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
385 verb
, changes
[i
].path
);
390 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
395 assert(changes
[i
].type
< 0);
396 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
397 verb
, changes
[i
].path
);
402 if (r
< 0 && !logged
)
403 log_error_errno(r
, "Failed to %s: %m.", verb
);
407 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
408 * wc should be the full path in the host file system.
410 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
411 assert(path_is_absolute(wd
));
413 /* This will give incorrect results if the paths are relative and go outside
414 * of the chroot. False negatives are possible. */
419 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
420 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
421 return path_equal_or_files_same(a
, b
, 0);
424 static int create_symlink(
425 const LookupPaths
*paths
,
426 const char *old_path
,
427 const char *new_path
,
429 UnitFileChange
**changes
,
432 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
439 rp
= skip_root(paths
, old_path
);
443 /* Actually create a symlink, and remember that we did. Is
444 * smart enough to check if there's already a valid symlink in
447 * Returns 1 if a symlink was created or already exists and points to
448 * the right place, or negative on error.
451 mkdir_parents_label(new_path
, 0755);
453 if (symlink(old_path
, new_path
) >= 0) {
454 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
458 if (errno
!= EEXIST
) {
459 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
463 r
= readlink_malloc(new_path
, &dest
);
465 /* translate EINVAL (non-symlink exists) to EEXIST */
469 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
473 dirname
= dirname_malloc(new_path
);
477 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
481 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
485 r
= symlink_atomic(old_path
, new_path
);
487 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
491 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
492 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
497 static int mark_symlink_for_removal(
498 Set
**remove_symlinks_to
,
506 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
514 path_simplify(n
, false);
516 r
= set_consume(*remove_symlinks_to
, n
);
525 static int remove_marked_symlinks_fd(
526 Set
*remove_symlinks_to
,
529 const char *config_path
,
530 const LookupPaths
*lp
,
533 UnitFileChange
**changes
,
536 _cleanup_closedir_
DIR *d
= NULL
;
540 assert(remove_symlinks_to
);
555 FOREACH_DIRENT(de
, d
, return -errno
) {
557 dirent_ensure_type(d
, de
);
559 if (de
->d_type
== DT_DIR
) {
560 _cleanup_free_
char *p
= NULL
;
563 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
573 p
= path_make_absolute(de
->d_name
, path
);
579 /* This will close nfd, regardless whether it succeeds or not */
580 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
584 } else if (de
->d_type
== DT_LNK
) {
585 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
590 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
593 p
= path_make_absolute(de
->d_name
, path
);
596 path_simplify(p
, false);
598 q
= readlink_malloc(p
, &dest
);
607 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
608 * the same name as a file that is marked. */
610 found
= set_contains(remove_symlinks_to
, dest
) ||
611 set_contains(remove_symlinks_to
, basename(dest
)) ||
612 set_contains(remove_symlinks_to
, de
->d_name
);
618 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
621 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
625 (void) rmdir_parents(p
, config_path
);
628 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
630 /* Now, remember the full path (but with the root prefix removed) of
631 * the symlink we just removed, and remove any symlinks to it, too. */
633 rp
= skip_root(lp
, p
);
634 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
637 if (q
> 0 && !dry_run
)
645 static int remove_marked_symlinks(
646 Set
*remove_symlinks_to
,
647 const char *config_path
,
648 const LookupPaths
*lp
,
650 UnitFileChange
**changes
,
653 _cleanup_close_
int fd
= -1;
660 if (set_size(remove_symlinks_to
) <= 0)
663 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
665 return errno
== ENOENT
? 0 : -errno
;
671 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
675 /* This takes possession of cfd and closes it */
676 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
684 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
687 if (streq(name
, i
->name
))
690 if (strv_contains(i
->aliases
, name
))
693 /* Look for template symlink matching DefaultInstance */
694 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
695 _cleanup_free_
char *s
= NULL
;
697 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
702 } else if (streq(name
, s
))
709 static int find_symlinks_fd(
710 const char *root_dir
,
711 UnitFileInstallInfo
*i
,
715 const char *config_path
,
716 bool *same_name_link
) {
718 _cleanup_closedir_
DIR *d
= NULL
;
726 assert(same_name_link
);
734 FOREACH_DIRENT(de
, d
, return -errno
) {
736 dirent_ensure_type(d
, de
);
738 if (de
->d_type
== DT_DIR
) {
739 _cleanup_free_
char *p
= NULL
;
742 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
752 p
= path_make_absolute(de
->d_name
, path
);
758 /* This will close nfd, regardless whether it succeeds or not */
759 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
760 p
, config_path
, same_name_link
);
766 } else if (de
->d_type
== DT_LNK
) {
767 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
768 bool found_path
, found_dest
, b
= false;
771 /* Acquire symlink name */
772 p
= path_make_absolute(de
->d_name
, path
);
776 /* Acquire symlink destination */
777 q
= readlink_malloc(p
, &dest
);
787 if (!path_is_absolute(dest
)) {
790 x
= prefix_root(root_dir
, dest
);
798 /* Check if the symlink itself matches what we
800 if (path_is_absolute(i
->name
))
801 found_path
= path_equal(p
, i
->name
);
803 found_path
= streq(de
->d_name
, i
->name
);
805 /* Check if what the symlink points to
806 * matches what we are looking for */
807 if (path_is_absolute(i
->name
))
808 found_dest
= path_equal(dest
, i
->name
);
810 found_dest
= streq(basename(dest
), i
->name
);
812 if (found_path
&& found_dest
) {
813 _cleanup_free_
char *t
= NULL
;
815 /* Filter out same name links in the main
817 t
= path_make_absolute(i
->name
, config_path
);
821 b
= path_equal(t
, p
);
825 *same_name_link
= true;
826 else if (found_path
|| found_dest
) {
830 /* Check if symlink name is in the set of names used by [Install] */
831 q
= is_symlink_with_known_name(i
, de
->d_name
);
843 static int find_symlinks(
844 const char *root_dir
,
845 UnitFileInstallInfo
*i
,
847 const char *config_path
,
848 bool *same_name_link
) {
854 assert(same_name_link
);
856 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
858 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
863 /* This takes possession of fd and closes it */
864 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
865 config_path
, config_path
, same_name_link
);
868 static int find_symlinks_in_scope(
870 const LookupPaths
*paths
,
871 UnitFileInstallInfo
*i
,
873 UnitFileState
*state
) {
875 bool same_name_link_runtime
= false, same_name_link_config
= false;
876 bool enabled_in_runtime
= false, enabled_at_all
= false;
883 STRV_FOREACH(p
, paths
->search_path
) {
884 bool same_name_link
= false;
886 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
890 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
892 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
893 /* This is the best outcome, let's return it immediately. */
894 *state
= UNIT_FILE_ENABLED
;
898 /* look for global enablement of user units */
899 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
900 *state
= UNIT_FILE_ENABLED
;
904 r
= path_is_runtime(paths
, *p
, false);
908 enabled_in_runtime
= true;
910 enabled_at_all
= true;
912 } else if (same_name_link
) {
913 if (path_equal_ptr(*p
, paths
->persistent_config
))
914 same_name_link_config
= true;
916 r
= path_is_runtime(paths
, *p
, false);
920 same_name_link_runtime
= true;
925 if (enabled_in_runtime
) {
926 *state
= UNIT_FILE_ENABLED_RUNTIME
;
930 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
931 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
932 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
933 * something, and hence are a much stronger concept. */
934 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
935 *state
= UNIT_FILE_STATIC
;
939 /* Hmm, we didn't find it, but maybe we found the same name
941 if (same_name_link_config
) {
942 *state
= UNIT_FILE_LINKED
;
945 if (same_name_link_runtime
) {
946 *state
= UNIT_FILE_LINKED_RUNTIME
;
953 static void install_info_free(UnitFileInstallInfo
*i
) {
960 strv_free(i
->aliases
);
961 strv_free(i
->wanted_by
);
962 strv_free(i
->required_by
);
964 free(i
->default_instance
);
965 free(i
->symlink_target
);
969 static void install_context_done(InstallContext
*c
) {
972 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
973 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
976 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
977 UnitFileInstallInfo
*i
;
979 i
= ordered_hashmap_get(c
->have_processed
, name
);
983 return ordered_hashmap_get(c
->will_process
, name
);
986 static int install_info_may_process(
987 UnitFileInstallInfo
*i
,
988 const LookupPaths
*paths
,
989 UnitFileChange
**changes
,
994 /* Checks whether the loaded unit file is one we should process, or is masked,
995 * transient or generated and thus not subject to enable/disable operations. */
997 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
998 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1001 if (path_is_generator(paths
, i
->path
) ||
1002 path_is_transient(paths
, i
->path
)) {
1003 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1004 return -EADDRNOTAVAIL
;
1011 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1012 * hashmap, or retrieves the existing one if already present.
1014 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1016 static int install_info_add(
1021 UnitFileInstallInfo
**ret
) {
1023 UnitFileInstallInfo
*i
= NULL
;
1027 assert(name
|| path
);
1030 name
= basename(path
);
1032 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1035 i
= install_info_find(c
, name
);
1037 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1044 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1048 i
= new0(UnitFileInstallInfo
, 1);
1051 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1052 i
->auxiliary
= auxiliary
;
1054 i
->name
= strdup(name
);
1061 i
->path
= strdup(path
);
1068 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1078 install_info_free(i
);
1082 static int config_parse_alias(
1084 const char *filename
,
1086 const char *section
,
1087 unsigned section_line
,
1101 type
= unit_name_to_type(unit
);
1102 if (!unit_type_may_alias(type
))
1103 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1104 "Alias= is not allowed for %s units, ignoring.",
1105 unit_type_to_string(type
));
1107 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1108 lvalue
, ltype
, rvalue
, data
, userdata
);
1111 static int config_parse_also(
1113 const char *filename
,
1115 const char *section
,
1116 unsigned section_line
,
1123 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1124 InstallContext
*c
= data
;
1133 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1135 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1141 r
= install_full_printf(info
, word
, &printed
);
1145 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1148 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1152 r
= strv_push(&info
->also
, printed
);
1162 static int config_parse_default_instance(
1164 const char *filename
,
1166 const char *section
,
1167 unsigned section_line
,
1174 UnitFileInstallInfo
*i
= data
;
1175 _cleanup_free_
char *printed
= NULL
;
1183 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1184 /* When enabling an instance, we might be using a template unit file,
1185 * but we should ignore DefaultInstance silently. */
1187 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1188 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1189 "DefaultInstance= only makes sense for template units, ignoring.");
1191 r
= install_full_printf(i
, rvalue
, &printed
);
1195 if (!unit_instance_is_valid(printed
))
1198 return free_and_replace(i
->default_instance
, printed
);
1201 static int unit_file_load(
1203 UnitFileInstallInfo
*info
,
1205 const char *root_dir
,
1206 SearchFlags flags
) {
1208 const ConfigTableItem items
[] = {
1209 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1210 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1211 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1212 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1213 { "Install", "Also", config_parse_also
, 0, c
},
1218 _cleanup_fclose_
FILE *f
= NULL
;
1219 _cleanup_close_
int fd
= -1;
1226 if (!(flags
& SEARCH_DROPIN
)) {
1227 /* Loading or checking for the main unit file… */
1229 type
= unit_name_to_type(info
->name
);
1232 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1233 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1237 if (!(flags
& SEARCH_LOAD
)) {
1238 r
= lstat(path
, &st
);
1242 if (null_or_empty(&st
))
1243 info
->type
= UNIT_FILE_TYPE_MASKED
;
1244 else if (S_ISREG(st
.st_mode
))
1245 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1246 else if (S_ISLNK(st
.st_mode
))
1248 else if (S_ISDIR(st
.st_mode
))
1256 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1260 /* 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. */
1262 if (!(flags
& SEARCH_LOAD
))
1265 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1270 if (fstat(fd
, &st
) < 0)
1273 if (null_or_empty(&st
)) {
1274 if ((flags
& SEARCH_DROPIN
) == 0)
1275 info
->type
= UNIT_FILE_TYPE_MASKED
;
1280 r
= stat_verify_regular(&st
);
1284 f
= fdopen(fd
, "re");
1289 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1292 r
= config_parse(info
->name
, path
, f
,
1294 config_item_table_lookup
, items
,
1295 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1297 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1299 if ((flags
& SEARCH_DROPIN
) == 0)
1300 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1303 (int) strv_length(info
->aliases
) +
1304 (int) strv_length(info
->wanted_by
) +
1305 (int) strv_length(info
->required_by
);
1308 static int unit_file_load_or_readlink(
1310 UnitFileInstallInfo
*info
,
1312 const char *root_dir
,
1313 SearchFlags flags
) {
1315 _cleanup_free_
char *target
= NULL
;
1318 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1319 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1322 /* This is a symlink, let's read it. */
1324 r
= readlink_malloc(path
, &target
);
1328 if (path_equal(target
, "/dev/null"))
1329 info
->type
= UNIT_FILE_TYPE_MASKED
;
1334 bn
= basename(target
);
1336 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1338 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1341 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1343 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1346 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1348 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1353 /* Enforce that the symlink destination does not
1354 * change the unit file type. */
1356 a
= unit_name_to_type(info
->name
);
1357 b
= unit_name_to_type(bn
);
1358 if (a
< 0 || b
< 0 || a
!= b
)
1361 if (path_is_absolute(target
))
1362 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1363 info
->symlink_target
= prefix_root(root_dir
, target
);
1365 /* This is a relative path, take it relative to the dir the symlink is located in. */
1366 info
->symlink_target
= file_in_same_dir(path
, target
);
1367 if (!info
->symlink_target
)
1370 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1376 static int unit_file_search(
1378 UnitFileInstallInfo
*info
,
1379 const LookupPaths
*paths
,
1380 SearchFlags flags
) {
1382 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1383 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1384 _cleanup_free_
char *template = NULL
;
1385 bool found_unit
= false;
1392 /* Was this unit already loaded? */
1393 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1397 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1401 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1402 r
= unit_name_template(info
->name
, &template);
1407 STRV_FOREACH(p
, paths
->search_path
) {
1408 _cleanup_free_
char *path
= NULL
;
1410 path
= strjoin(*p
, "/", info
->name
);
1414 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1416 info
->path
= TAKE_PTR(path
);
1420 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1424 if (!found_unit
&& template) {
1426 /* Unit file doesn't exist, however instance
1427 * enablement was requested. We will check if it is
1428 * possible to load template unit file. */
1430 STRV_FOREACH(p
, paths
->search_path
) {
1431 _cleanup_free_
char *path
= NULL
;
1433 path
= strjoin(*p
, "/", template);
1437 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1439 info
->path
= TAKE_PTR(path
);
1443 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1449 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1453 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1456 /* Search for drop-in directories */
1458 dropin_dir_name
= strjoina(info
->name
, ".d");
1459 STRV_FOREACH(p
, paths
->search_path
) {
1462 path
= path_join(NULL
, *p
, dropin_dir_name
);
1466 r
= strv_consume(&dirs
, path
);
1472 dropin_template_dir_name
= strjoina(template, ".d");
1473 STRV_FOREACH(p
, paths
->search_path
) {
1476 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1480 r
= strv_consume(&dirs
, path
);
1486 /* Load drop-in conf files */
1488 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1490 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1492 STRV_FOREACH(p
, files
) {
1493 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1495 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1501 static int install_info_follow(
1503 UnitFileInstallInfo
*i
,
1504 const char *root_dir
,
1506 bool ignore_different_name
) {
1511 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1513 if (!i
->symlink_target
)
1516 /* If the basename doesn't match, the caller should add a
1517 * complete new entry for this. */
1519 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1522 free_and_replace(i
->path
, i
->symlink_target
);
1523 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1525 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1529 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1530 * target, maybe more than once. Propagate the instance name if present.
1532 static int install_info_traverse(
1533 UnitFileScope scope
,
1535 const LookupPaths
*paths
,
1536 UnitFileInstallInfo
*start
,
1538 UnitFileInstallInfo
**ret
) {
1540 UnitFileInstallInfo
*i
;
1548 r
= unit_file_search(c
, start
, paths
, flags
);
1553 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1554 /* Follow the symlink */
1556 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1559 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1560 r
= path_is_config(paths
, i
->path
, true);
1567 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1569 _cleanup_free_
char *buffer
= NULL
;
1572 /* Target has a different name, create a new
1573 * install info object for that, and continue
1576 bn
= basename(i
->symlink_target
);
1578 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1579 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1581 _cleanup_free_
char *instance
= NULL
;
1583 r
= unit_name_to_instance(i
->name
, &instance
);
1587 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1591 if (streq(buffer
, i
->name
)) {
1593 /* We filled in the instance, and the target stayed the same? If so, then let's
1594 * honour the link as it is. */
1596 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1606 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1610 /* Try again, with the new target we found. */
1611 r
= unit_file_search(c
, i
, paths
, flags
);
1613 /* Translate error code to highlight this specific case */
1628 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1629 * or the name (otherwise). root_dir is prepended to the path.
1631 static int install_info_add_auto(
1633 const LookupPaths
*paths
,
1634 const char *name_or_path
,
1635 UnitFileInstallInfo
**ret
) {
1638 assert(name_or_path
);
1640 if (path_is_absolute(name_or_path
)) {
1643 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1645 return install_info_add(c
, NULL
, pp
, false, ret
);
1647 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1650 static int install_info_discover(
1651 UnitFileScope scope
,
1653 const LookupPaths
*paths
,
1656 UnitFileInstallInfo
**ret
,
1657 UnitFileChange
**changes
,
1658 size_t *n_changes
) {
1660 UnitFileInstallInfo
*i
;
1667 r
= install_info_add_auto(c
, paths
, name
, &i
);
1669 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1672 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1676 static int install_info_symlink_alias(
1677 UnitFileInstallInfo
*i
,
1678 const LookupPaths
*paths
,
1679 const char *config_path
,
1681 UnitFileChange
**changes
,
1682 size_t *n_changes
) {
1689 assert(config_path
);
1691 STRV_FOREACH(s
, i
->aliases
) {
1692 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1694 q
= install_full_printf(i
, *s
, &dst
);
1698 alias_path
= path_make_absolute(dst
, config_path
);
1702 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1710 static int install_info_symlink_wants(
1711 UnitFileInstallInfo
*i
,
1712 const LookupPaths
*paths
,
1713 const char *config_path
,
1716 UnitFileChange
**changes
,
1717 size_t *n_changes
) {
1719 _cleanup_free_
char *buf
= NULL
;
1726 assert(config_path
);
1728 if (strv_isempty(list
))
1731 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1732 UnitFileInstallInfo instance
= {
1733 .type
= _UNIT_FILE_TYPE_INVALID
,
1735 _cleanup_free_
char *path
= NULL
;
1737 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1741 instance
.name
= buf
;
1742 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1746 path
= TAKE_PTR(instance
.path
);
1748 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1749 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1757 STRV_FOREACH(s
, list
) {
1758 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1760 q
= install_full_printf(i
, *s
, &dst
);
1764 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1769 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1773 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1781 static int install_info_symlink_link(
1782 UnitFileInstallInfo
*i
,
1783 const LookupPaths
*paths
,
1784 const char *config_path
,
1786 UnitFileChange
**changes
,
1787 size_t *n_changes
) {
1789 _cleanup_free_
char *path
= NULL
;
1794 assert(config_path
);
1797 r
= in_search_path(paths
, i
->path
);
1803 path
= strjoin(config_path
, "/", i
->name
);
1807 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1810 static int install_info_apply(
1811 UnitFileInstallInfo
*i
,
1812 const LookupPaths
*paths
,
1813 const char *config_path
,
1815 UnitFileChange
**changes
,
1816 size_t *n_changes
) {
1822 assert(config_path
);
1824 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1827 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1829 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1833 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1837 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1838 /* Do not count links to the unit file towards the "carries_install_info" count */
1839 if (r
== 0 && q
< 0)
1845 static int install_context_apply(
1846 UnitFileScope scope
,
1848 const LookupPaths
*paths
,
1849 const char *config_path
,
1852 UnitFileChange
**changes
,
1853 size_t *n_changes
) {
1855 UnitFileInstallInfo
*i
;
1860 assert(config_path
);
1862 if (ordered_hashmap_isempty(c
->will_process
))
1865 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1870 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1873 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1877 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1879 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1883 /* We can attempt to process a masked unit when a different unit
1884 * that we were processing specifies it in Also=. */
1885 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1886 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1888 /* Assume that something *could* have been enabled here,
1889 * avoid "empty [Install] section" warning. */
1894 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1897 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1909 static int install_context_mark_for_removal(
1910 UnitFileScope scope
,
1912 const LookupPaths
*paths
,
1913 Set
**remove_symlinks_to
,
1914 UnitFileChange
**changes
,
1915 size_t *n_changes
) {
1917 UnitFileInstallInfo
*i
;
1923 /* Marks all items for removal */
1925 if (ordered_hashmap_isempty(c
->will_process
))
1928 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1932 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1934 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1938 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1939 if (r
== -ENOLINK
) {
1940 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1941 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1942 } else if (r
== -ENOENT
) {
1944 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1945 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1947 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1948 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1952 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1953 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1954 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1955 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1956 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1958 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1959 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1963 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1972 UnitFileScope scope
,
1973 UnitFileFlags flags
,
1974 const char *root_dir
,
1976 UnitFileChange
**changes
,
1977 size_t *n_changes
) {
1979 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
1980 const char *config_path
;
1985 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1987 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1991 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
1995 STRV_FOREACH(i
, files
) {
1996 _cleanup_free_
char *path
= NULL
;
1999 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2005 path
= path_make_absolute(*i
, config_path
);
2009 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2010 if (q
< 0 && r
>= 0)
2017 int unit_file_unmask(
2018 UnitFileScope scope
,
2019 UnitFileFlags flags
,
2020 const char *root_dir
,
2022 UnitFileChange
**changes
,
2023 size_t *n_changes
) {
2025 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2026 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2027 _cleanup_strv_free_
char **todo
= NULL
;
2028 size_t n_todo
= 0, n_allocated
= 0;
2029 const char *config_path
;
2031 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2035 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2037 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2041 STRV_FOREACH(i
, files
) {
2042 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2045 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2046 _cleanup_free_
char *path
= NULL
;
2048 path
= path_make_absolute(*i
, config_path
);
2052 r
= null_or_empty_path(path
);
2060 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2063 todo
[n_todo
] = strdup(*i
);
2074 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2075 STRV_FOREACH(i
, todo
) {
2076 _cleanup_free_
char *path
= NULL
;
2079 path
= path_make_absolute(*i
, config_path
);
2083 if (!dry_run
&& unlink(path
) < 0) {
2084 if (errno
!= ENOENT
) {
2087 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2093 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2095 rp
= skip_root(&paths
, path
);
2096 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2101 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2110 UnitFileScope scope
,
2111 UnitFileFlags flags
,
2112 const char *root_dir
,
2114 UnitFileChange
**changes
,
2115 size_t *n_changes
) {
2117 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2118 _cleanup_strv_free_
char **todo
= NULL
;
2119 size_t n_todo
= 0, n_allocated
= 0;
2120 const char *config_path
;
2125 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2127 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2131 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2135 STRV_FOREACH(i
, files
) {
2136 _cleanup_free_
char *full
= NULL
;
2140 if (!path_is_absolute(*i
))
2144 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2147 full
= prefix_root(paths
.root_dir
, *i
);
2151 if (lstat(full
, &st
) < 0)
2153 r
= stat_verify_regular(&st
);
2157 q
= in_search_path(&paths
, *i
);
2163 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2166 todo
[n_todo
] = strdup(*i
);
2176 STRV_FOREACH(i
, todo
) {
2177 _cleanup_free_
char *new_path
= NULL
;
2179 new_path
= path_make_absolute(basename(*i
), config_path
);
2183 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2184 if (q
< 0 && r
>= 0)
2191 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2197 /* Checks whether the path is one where the drop-in directories shall be removed. */
2199 r
= path_is_config(paths
, path
, true);
2203 r
= path_is_control(paths
, path
);
2207 return path_is_transient(paths
, path
);
2210 int unit_file_revert(
2211 UnitFileScope scope
,
2212 const char *root_dir
,
2214 UnitFileChange
**changes
,
2215 size_t *n_changes
) {
2217 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2218 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2219 _cleanup_strv_free_
char **todo
= NULL
;
2220 size_t n_todo
= 0, n_allocated
= 0;
2224 /* Puts a unit file back into vendor state. This means:
2226 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2227 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2229 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2230 * "config", but not in "transient" or "control" or even "generated").
2232 * We remove all that in both the runtime and the persistent directories, if that applies.
2235 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2239 STRV_FOREACH(i
, files
) {
2240 bool has_vendor
= false;
2243 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2246 STRV_FOREACH(p
, paths
.search_path
) {
2247 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2250 path
= path_make_absolute(*i
, *p
);
2254 r
= lstat(path
, &st
);
2256 if (errno
!= ENOENT
)
2258 } else if (S_ISREG(st
.st_mode
)) {
2259 /* Check if there's a vendor version */
2260 r
= path_is_vendor(&paths
, path
);
2267 dropin
= strappend(path
, ".d");
2271 r
= lstat(dropin
, &st
);
2273 if (errno
!= ENOENT
)
2275 } else if (S_ISDIR(st
.st_mode
)) {
2276 /* Remove the drop-ins */
2277 r
= path_shall_revert(&paths
, dropin
);
2281 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2284 todo
[n_todo
++] = TAKE_PTR(dropin
);
2292 /* OK, there's a vendor version, hence drop all configuration versions */
2293 STRV_FOREACH(p
, paths
.search_path
) {
2294 _cleanup_free_
char *path
= NULL
;
2297 path
= path_make_absolute(*i
, *p
);
2301 r
= lstat(path
, &st
);
2303 if (errno
!= ENOENT
)
2305 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2306 r
= path_is_config(&paths
, path
, true);
2310 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2313 todo
[n_todo
++] = TAKE_PTR(path
);
2322 STRV_FOREACH(i
, todo
) {
2323 _cleanup_strv_free_
char **fs
= NULL
;
2327 (void) get_files_in_directory(*i
, &fs
);
2329 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2330 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2335 STRV_FOREACH(j
, fs
) {
2336 _cleanup_free_
char *t
= NULL
;
2338 t
= strjoin(*i
, "/", *j
);
2342 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2345 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2347 rp
= skip_root(&paths
, *i
);
2348 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2353 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2357 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2364 int unit_file_add_dependency(
2365 UnitFileScope scope
,
2366 UnitFileFlags flags
,
2367 const char *root_dir
,
2371 UnitFileChange
**changes
,
2372 size_t *n_changes
) {
2374 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2375 _cleanup_(install_context_done
) InstallContext c
= {};
2376 UnitFileInstallInfo
*i
, *target_info
;
2377 const char *config_path
;
2382 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2385 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2388 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2391 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2395 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2399 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2400 &target_info
, changes
, n_changes
);
2403 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2407 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2409 STRV_FOREACH(f
, files
) {
2412 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2413 &i
, changes
, n_changes
);
2416 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2420 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2422 /* We didn't actually load anything from the unit
2423 * file, but instead just add in our new symlink to
2426 if (dep
== UNIT_WANTS
)
2429 l
= &i
->required_by
;
2432 *l
= strv_new(target_info
->name
, NULL
);
2437 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2440 int unit_file_enable(
2441 UnitFileScope scope
,
2442 UnitFileFlags flags
,
2443 const char *root_dir
,
2445 UnitFileChange
**changes
,
2446 size_t *n_changes
) {
2448 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2449 _cleanup_(install_context_done
) InstallContext c
= {};
2450 const char *config_path
;
2451 UnitFileInstallInfo
*i
;
2456 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2458 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2462 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2466 STRV_FOREACH(f
, files
) {
2467 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2468 &i
, changes
, n_changes
);
2471 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2475 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2478 /* This will return the number of symlink rules that were
2479 supposed to be created, not the ones actually created. This
2480 is useful to determine whether the passed files had any
2481 installation data at all. */
2483 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2486 int unit_file_disable(
2487 UnitFileScope scope
,
2488 UnitFileFlags flags
,
2489 const char *root_dir
,
2491 UnitFileChange
**changes
,
2492 size_t *n_changes
) {
2494 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2495 _cleanup_(install_context_done
) InstallContext c
= {};
2496 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2497 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2498 const char *config_path
;
2503 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2505 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2509 STRV_FOREACH(i
, files
) {
2510 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2513 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2518 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2522 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2523 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2531 int unit_file_reenable(
2532 UnitFileScope scope
,
2533 UnitFileFlags flags
,
2534 const char *root_dir
,
2536 UnitFileChange
**changes
,
2537 size_t *n_changes
) {
2543 /* First, we invoke the disable command with only the basename... */
2544 l
= strv_length(files
);
2545 n
= newa(char*, l
+1);
2546 for (i
= 0; i
< l
; i
++)
2547 n
[i
] = basename(files
[i
]);
2550 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2554 /* But the enable command with the full name */
2555 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2558 int unit_file_set_default(
2559 UnitFileScope scope
,
2560 UnitFileFlags flags
,
2561 const char *root_dir
,
2563 UnitFileChange
**changes
,
2564 size_t *n_changes
) {
2566 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2567 _cleanup_(install_context_done
) InstallContext c
= {};
2568 UnitFileInstallInfo
*i
;
2569 const char *new_path
;
2573 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2576 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2578 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2581 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2585 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2588 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2592 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2593 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2596 int unit_file_get_default(
2597 UnitFileScope scope
,
2598 const char *root_dir
,
2601 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2602 _cleanup_(install_context_done
) InstallContext c
= {};
2603 UnitFileInstallInfo
*i
;
2608 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2611 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2615 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2619 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2623 n
= strdup(i
->name
);
2631 int unit_file_lookup_state(
2632 UnitFileScope scope
,
2633 const LookupPaths
*paths
,
2635 UnitFileState
*ret
) {
2637 _cleanup_(install_context_done
) InstallContext c
= {};
2638 UnitFileInstallInfo
*i
;
2639 UnitFileState state
;
2645 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2648 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2653 /* Shortcut things, if the caller just wants to know if this unit exists. */
2659 case UNIT_FILE_TYPE_MASKED
:
2660 r
= path_is_runtime(paths
, i
->path
, true);
2664 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2667 case UNIT_FILE_TYPE_REGULAR
:
2668 r
= path_is_generator(paths
, i
->path
);
2672 state
= UNIT_FILE_GENERATED
;
2676 r
= path_is_transient(paths
, i
->path
);
2680 state
= UNIT_FILE_TRANSIENT
;
2684 /* Check if any of the Alias= symlinks have been created.
2685 * We ignore other aliases, and only check those that would
2686 * be created by systemctl enable for this unit. */
2687 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2693 /* Check if the file is known under other names. If it is,
2694 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2695 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2699 state
= UNIT_FILE_INDIRECT
;
2701 if (unit_file_install_info_has_rules(i
))
2702 state
= UNIT_FILE_DISABLED
;
2703 else if (unit_file_install_info_has_also(i
))
2704 state
= UNIT_FILE_INDIRECT
;
2706 state
= UNIT_FILE_STATIC
;
2712 assert_not_reached("Unexpect unit file type.");
2719 int unit_file_get_state(
2720 UnitFileScope scope
,
2721 const char *root_dir
,
2723 UnitFileState
*ret
) {
2725 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2729 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2732 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2736 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2739 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2740 _cleanup_(install_context_done
) InstallContext c
= {};
2746 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2749 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2758 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2759 _cleanup_(presets_freep
) Presets ps
= {};
2760 size_t n_allocated
= 0;
2761 _cleanup_strv_free_
char **files
= NULL
;
2766 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2770 case UNIT_FILE_SYSTEM
:
2771 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2772 "/etc/systemd/system-preset",
2773 "/run/systemd/system-preset",
2774 "/usr/local/lib/systemd/system-preset",
2775 "/usr/lib/systemd/system-preset",
2777 "/lib/systemd/system-preset",
2782 case UNIT_FILE_GLOBAL
:
2783 case UNIT_FILE_USER
:
2784 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2785 "/etc/systemd/user-preset",
2786 "/run/systemd/user-preset",
2787 "/usr/local/lib/systemd/user-preset",
2788 "/usr/lib/systemd/user-preset",
2793 assert_not_reached("Invalid unit file scope");
2799 STRV_FOREACH(p
, files
) {
2800 _cleanup_fclose_
FILE *f
;
2801 char line
[LINE_MAX
];
2804 f
= fopen(*p
, "re");
2806 if (errno
== ENOENT
)
2812 FOREACH_LINE(line
, f
, return -errno
) {
2813 PresetRule rule
= {};
2814 const char *parameter
;
2822 if (strchr(COMMENTS
, *l
))
2825 parameter
= first_word(l
, "enable");
2829 pattern
= strdup(parameter
);
2833 rule
= (PresetRule
) {
2835 .action
= PRESET_ENABLE
,
2839 parameter
= first_word(l
, "disable");
2843 pattern
= strdup(parameter
);
2847 rule
= (PresetRule
) {
2849 .action
= PRESET_DISABLE
,
2854 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2857 ps
.rules
[ps
.n_rules
++] = rule
;
2861 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2871 static int query_presets(const char *name
, const Presets presets
) {
2872 PresetAction action
= PRESET_UNKNOWN
;
2875 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2878 for (i
= 0; i
< presets
.n_rules
; i
++)
2879 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2880 action
= presets
.rules
[i
].action
;
2885 case PRESET_UNKNOWN
:
2886 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2889 log_debug("Preset files say enable %s.", name
);
2891 case PRESET_DISABLE
:
2892 log_debug("Preset files say disable %s.", name
);
2895 assert_not_reached("invalid preset action");
2899 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2900 _cleanup_(presets_freep
) Presets presets
= {};
2903 r
= read_presets(scope
, root_dir
, &presets
);
2907 return query_presets(name
, presets
);
2910 static int execute_preset(
2911 UnitFileScope scope
,
2912 UnitFileFlags flags
,
2913 InstallContext
*plus
,
2914 InstallContext
*minus
,
2915 const LookupPaths
*paths
,
2917 UnitFilePresetMode mode
,
2918 UnitFileChange
**changes
,
2919 size_t *n_changes
) {
2921 const char *config_path
;
2922 bool force
= !!(flags
& UNIT_FILE_FORCE
);
2923 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
2930 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2931 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2933 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
2937 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
2938 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2944 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2945 /* Returns number of symlinks that where supposed to be installed. */
2946 q
= install_context_apply(scope
, plus
, paths
,
2947 runtime
? paths
->runtime_config
: paths
->persistent_config
,
2948 force
, SEARCH_LOAD
, changes
, n_changes
);
2956 static int preset_prepare_one(
2957 UnitFileScope scope
,
2958 InstallContext
*plus
,
2959 InstallContext
*minus
,
2963 UnitFileChange
**changes
,
2964 size_t *n_changes
) {
2966 _cleanup_(install_context_done
) InstallContext tmp
= {};
2967 UnitFileInstallInfo
*i
;
2970 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2973 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2974 &i
, changes
, n_changes
);
2977 if (!streq(name
, i
->name
)) {
2978 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
2982 r
= query_presets(name
, presets
);
2987 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2988 &i
, changes
, n_changes
);
2992 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
2996 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2997 &i
, changes
, n_changes
);
3002 int unit_file_preset(
3003 UnitFileScope scope
,
3004 UnitFileFlags flags
,
3005 const char *root_dir
,
3007 UnitFilePresetMode mode
,
3008 UnitFileChange
**changes
,
3009 size_t *n_changes
) {
3011 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3012 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3013 _cleanup_(presets_freep
) Presets presets
= {};
3018 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3019 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3021 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3025 r
= read_presets(scope
, root_dir
, &presets
);
3029 STRV_FOREACH(i
, files
) {
3030 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3035 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3038 int unit_file_preset_all(
3039 UnitFileScope scope
,
3040 UnitFileFlags flags
,
3041 const char *root_dir
,
3042 UnitFilePresetMode mode
,
3043 UnitFileChange
**changes
,
3044 size_t *n_changes
) {
3046 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3047 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3048 _cleanup_(presets_freep
) Presets presets
= {};
3053 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3054 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3056 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3060 r
= read_presets(scope
, root_dir
, &presets
);
3064 STRV_FOREACH(i
, paths
.search_path
) {
3065 _cleanup_closedir_
DIR *d
= NULL
;
3070 if (errno
== ENOENT
)
3076 FOREACH_DIRENT(de
, d
, return -errno
) {
3077 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3080 dirent_ensure_type(d
, de
);
3082 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3085 /* we don't pass changes[] in, because we want to handle errors on our own */
3086 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3088 r
= unit_file_changes_add(changes
, n_changes
,
3089 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3090 else if (r
== -ENOLINK
)
3091 r
= unit_file_changes_add(changes
, n_changes
,
3092 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3093 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3100 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3103 static void unit_file_list_free_one(UnitFileList
*f
) {
3111 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3112 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3115 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3117 int unit_file_get_list(
3118 UnitFileScope scope
,
3119 const char *root_dir
,
3124 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3129 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3132 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3136 STRV_FOREACH(i
, paths
.search_path
) {
3137 _cleanup_closedir_
DIR *d
= NULL
;
3142 if (errno
== ENOENT
)
3144 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3145 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3152 FOREACH_DIRENT(de
, d
, return -errno
) {
3153 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3155 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3158 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3161 if (hashmap_get(h
, de
->d_name
))
3164 dirent_ensure_type(d
, de
);
3166 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3169 f
= new0(UnitFileList
, 1);
3173 f
->path
= path_make_absolute(de
->d_name
, *i
);
3177 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3179 f
->state
= UNIT_FILE_BAD
;
3181 if (!strv_isempty(states
) &&
3182 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3185 r
= hashmap_put(h
, basename(f
->path
), f
);
3189 f
= NULL
; /* prevent cleanup */
3196 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3197 [UNIT_FILE_ENABLED
] = "enabled",
3198 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3199 [UNIT_FILE_LINKED
] = "linked",
3200 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3201 [UNIT_FILE_MASKED
] = "masked",
3202 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3203 [UNIT_FILE_STATIC
] = "static",
3204 [UNIT_FILE_DISABLED
] = "disabled",
3205 [UNIT_FILE_INDIRECT
] = "indirect",
3206 [UNIT_FILE_GENERATED
] = "generated",
3207 [UNIT_FILE_TRANSIENT
] = "transient",
3208 [UNIT_FILE_BAD
] = "bad",
3211 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3213 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3214 [UNIT_FILE_SYMLINK
] = "symlink",
3215 [UNIT_FILE_UNLINK
] = "unlink",
3216 [UNIT_FILE_IS_MASKED
] = "masked",
3217 [UNIT_FILE_IS_DANGLING
] = "dangling",
3220 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3222 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3223 [UNIT_FILE_PRESET_FULL
] = "full",
3224 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3225 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3228 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);