1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
20 #include "alloc-util.h"
21 #include "conf-files.h"
22 #include "conf-parser.h"
23 #include "dirent-util.h"
24 #include "extract-word.h"
29 #include "install-printf.h"
31 #include "locale-util.h"
35 #include "path-lookup.h"
36 #include "path-util.h"
40 #include "stat-util.h"
41 #include "string-table.h"
42 #include "string-util.h"
44 #include "unit-name.h"
46 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
48 typedef enum SearchFlags
{
49 SEARCH_LOAD
= 1U << 0,
50 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1U << 1,
51 SEARCH_DROPIN
= 1U << 2,
55 OrderedHashmap
*will_process
;
56 OrderedHashmap
*have_processed
;
75 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
78 return !strv_isempty(i
->aliases
) ||
79 !strv_isempty(i
->wanted_by
) ||
80 !strv_isempty(i
->required_by
);
83 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
86 return !strv_isempty(i
->also
);
89 static inline void presets_freep(Presets
*p
) {
95 for (i
= 0; i
< p
->n_rules
; i
++)
96 free(p
->rules
[i
].pattern
);
102 bool unit_type_may_alias(UnitType type
) {
112 bool unit_type_may_template(UnitType type
) {
121 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
122 [UNIT_FILE_TYPE_REGULAR
] = "regular",
123 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
124 [UNIT_FILE_TYPE_MASKED
] = "masked",
127 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
129 static int in_search_path(const LookupPaths
*p
, const char *path
) {
130 _cleanup_free_
char *parent
= NULL
;
135 parent
= dirname_malloc(path
);
139 STRV_FOREACH(i
, p
->search_path
)
140 if (path_equal(parent
, *i
))
146 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
155 e
= path_startswith(path
, p
->root_dir
);
159 /* Make sure the returned path starts with a slash */
161 if (e
== path
|| e
[-1] != '/')
170 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
171 _cleanup_free_
char *parent
= NULL
;
176 parent
= dirname_malloc(path
);
180 return path_equal_ptr(parent
, p
->generator
) ||
181 path_equal_ptr(parent
, p
->generator_early
) ||
182 path_equal_ptr(parent
, p
->generator_late
);
185 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
186 _cleanup_free_
char *parent
= NULL
;
191 parent
= dirname_malloc(path
);
195 return path_equal_ptr(parent
, p
->transient
);
198 static int path_is_control(const LookupPaths
*p
, const char *path
) {
199 _cleanup_free_
char *parent
= NULL
;
204 parent
= dirname_malloc(path
);
208 return path_equal_ptr(parent
, p
->persistent_control
) ||
209 path_equal_ptr(parent
, p
->runtime_control
);
212 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
213 _cleanup_free_
char *parent
= NULL
;
218 /* Note that we do *not* have generic checks for /etc or /run in place, since with
219 * them we couldn't discern configuration from transient or generated units */
222 parent
= dirname_malloc(path
);
229 return path_equal_ptr(path
, p
->persistent_config
) ||
230 path_equal_ptr(path
, p
->runtime_config
);
233 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
234 _cleanup_free_
char *parent
= NULL
;
240 /* Everything in /run is considered runtime. On top of that we also add
241 * explicit checks for the various runtime directories, as safety net. */
243 rpath
= skip_root(p
, path
);
244 if (rpath
&& path_startswith(rpath
, "/run"))
248 parent
= dirname_malloc(path
);
255 return path_equal_ptr(path
, p
->runtime_config
) ||
256 path_equal_ptr(path
, p
->generator
) ||
257 path_equal_ptr(path
, p
->generator_early
) ||
258 path_equal_ptr(path
, p
->generator_late
) ||
259 path_equal_ptr(path
, p
->transient
) ||
260 path_equal_ptr(path
, p
->runtime_control
);
263 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
269 rpath
= skip_root(p
, path
);
273 if (path_startswith(rpath
, "/usr"))
277 if (path_startswith(rpath
, "/lib"))
281 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
284 int unit_file_changes_add(
285 UnitFileChange
**changes
,
287 UnitFileChangeType type
,
289 const char *source
) {
291 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
295 assert(!changes
== !n_changes
);
300 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
309 if (!p
|| (source
&& !s
))
312 path_simplify(p
, false);
314 path_simplify(s
, false);
316 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
322 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
325 assert(changes
|| n_changes
== 0);
327 for (i
= 0; i
< n_changes
; i
++) {
328 free(changes
[i
].path
);
329 free(changes
[i
].source
);
335 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
339 assert(changes
|| n_changes
== 0);
340 /* If verb is not specified, errors are not allowed! */
341 assert(verb
|| r
>= 0);
343 for (i
= 0; i
< n_changes
; i
++) {
344 assert(verb
|| changes
[i
].type
>= 0);
346 switch(changes
[i
].type
) {
347 case UNIT_FILE_SYMLINK
:
349 log_info("Created symlink %s %s %s.",
351 special_glyph(ARROW
),
354 case UNIT_FILE_UNLINK
:
356 log_info("Removed %s.", changes
[i
].path
);
358 case UNIT_FILE_IS_MASKED
:
360 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
362 case UNIT_FILE_IS_DANGLING
:
364 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
368 if (changes
[i
].source
)
369 log_error_errno(changes
[i
].type
,
370 "Failed to %s unit, file %s already exists and is a symlink to %s.",
371 verb
, changes
[i
].path
, changes
[i
].source
);
373 log_error_errno(changes
[i
].type
,
374 "Failed to %s unit, file %s already exists.",
375 verb
, changes
[i
].path
);
379 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
380 verb
, changes
[i
].path
);
384 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
385 verb
, changes
[i
].path
);
389 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
390 verb
, changes
[i
].path
);
395 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
400 assert(changes
[i
].type
< 0);
401 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
402 verb
, changes
[i
].path
);
407 if (r
< 0 && !logged
)
408 log_error_errno(r
, "Failed to %s: %m.", verb
);
412 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
413 * wc should be the full path in the host file system.
415 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
416 assert(path_is_absolute(wd
));
418 /* This will give incorrect results if the paths are relative and go outside
419 * of the chroot. False negatives are possible. */
424 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
425 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
426 return path_equal_or_files_same(a
, b
, 0);
429 static int create_symlink(
430 const LookupPaths
*paths
,
431 const char *old_path
,
432 const char *new_path
,
434 UnitFileChange
**changes
,
437 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
444 rp
= skip_root(paths
, old_path
);
448 /* Actually create a symlink, and remember that we did. Is
449 * smart enough to check if there's already a valid symlink in
452 * Returns 1 if a symlink was created or already exists and points to
453 * the right place, or negative on error.
456 mkdir_parents_label(new_path
, 0755);
458 if (symlink(old_path
, new_path
) >= 0) {
459 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
463 if (errno
!= EEXIST
) {
464 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
468 r
= readlink_malloc(new_path
, &dest
);
470 /* translate EINVAL (non-symlink exists) to EEXIST */
474 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
478 dirname
= dirname_malloc(new_path
);
482 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
486 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
490 r
= symlink_atomic(old_path
, new_path
);
492 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
496 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
497 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
502 static int mark_symlink_for_removal(
503 Set
**remove_symlinks_to
,
511 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
519 path_simplify(n
, false);
521 r
= set_consume(*remove_symlinks_to
, n
);
530 static int remove_marked_symlinks_fd(
531 Set
*remove_symlinks_to
,
534 const char *config_path
,
535 const LookupPaths
*lp
,
538 UnitFileChange
**changes
,
541 _cleanup_closedir_
DIR *d
= NULL
;
545 assert(remove_symlinks_to
);
560 FOREACH_DIRENT(de
, d
, return -errno
) {
562 dirent_ensure_type(d
, de
);
564 if (de
->d_type
== DT_DIR
) {
565 _cleanup_free_
char *p
= NULL
;
568 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
578 p
= path_make_absolute(de
->d_name
, path
);
584 /* This will close nfd, regardless whether it succeeds or not */
585 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
589 } else if (de
->d_type
== DT_LNK
) {
590 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
595 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
598 p
= path_make_absolute(de
->d_name
, path
);
601 path_simplify(p
, false);
603 q
= readlink_malloc(p
, &dest
);
612 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
613 * the same name as a file that is marked. */
615 found
= set_contains(remove_symlinks_to
, dest
) ||
616 set_contains(remove_symlinks_to
, basename(dest
)) ||
617 set_contains(remove_symlinks_to
, de
->d_name
);
623 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
626 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
630 (void) rmdir_parents(p
, config_path
);
633 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
635 /* Now, remember the full path (but with the root prefix removed) of
636 * the symlink we just removed, and remove any symlinks to it, too. */
638 rp
= skip_root(lp
, p
);
639 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
642 if (q
> 0 && !dry_run
)
650 static int remove_marked_symlinks(
651 Set
*remove_symlinks_to
,
652 const char *config_path
,
653 const LookupPaths
*lp
,
655 UnitFileChange
**changes
,
658 _cleanup_close_
int fd
= -1;
665 if (set_size(remove_symlinks_to
) <= 0)
668 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
670 return errno
== ENOENT
? 0 : -errno
;
676 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
680 /* This takes possession of cfd and closes it */
681 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
689 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
692 if (streq(name
, i
->name
))
695 if (strv_contains(i
->aliases
, name
))
698 /* Look for template symlink matching DefaultInstance */
699 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
700 _cleanup_free_
char *s
= NULL
;
702 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
707 } else if (streq(name
, s
))
714 static int find_symlinks_fd(
715 const char *root_dir
,
716 UnitFileInstallInfo
*i
,
720 const char *config_path
,
721 bool *same_name_link
) {
723 _cleanup_closedir_
DIR *d
= NULL
;
731 assert(same_name_link
);
739 FOREACH_DIRENT(de
, d
, return -errno
) {
741 dirent_ensure_type(d
, de
);
743 if (de
->d_type
== DT_DIR
) {
744 _cleanup_free_
char *p
= NULL
;
747 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
757 p
= path_make_absolute(de
->d_name
, path
);
763 /* This will close nfd, regardless whether it succeeds or not */
764 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
765 p
, config_path
, same_name_link
);
771 } else if (de
->d_type
== DT_LNK
) {
772 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
773 bool found_path
, found_dest
, b
= false;
776 /* Acquire symlink name */
777 p
= path_make_absolute(de
->d_name
, path
);
781 /* Acquire symlink destination */
782 q
= readlink_malloc(p
, &dest
);
792 if (!path_is_absolute(dest
)) {
795 x
= prefix_root(root_dir
, dest
);
803 /* Check if the symlink itself matches what we
805 if (path_is_absolute(i
->name
))
806 found_path
= path_equal(p
, i
->name
);
808 found_path
= streq(de
->d_name
, i
->name
);
810 /* Check if what the symlink points to
811 * matches what we are looking for */
812 if (path_is_absolute(i
->name
))
813 found_dest
= path_equal(dest
, i
->name
);
815 found_dest
= streq(basename(dest
), i
->name
);
817 if (found_path
&& found_dest
) {
818 _cleanup_free_
char *t
= NULL
;
820 /* Filter out same name links in the main
822 t
= path_make_absolute(i
->name
, config_path
);
826 b
= path_equal(t
, p
);
830 *same_name_link
= true;
831 else if (found_path
|| found_dest
) {
835 /* Check if symlink name is in the set of names used by [Install] */
836 q
= is_symlink_with_known_name(i
, de
->d_name
);
848 static int find_symlinks(
849 const char *root_dir
,
850 UnitFileInstallInfo
*i
,
852 const char *config_path
,
853 bool *same_name_link
) {
859 assert(same_name_link
);
861 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
863 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
868 /* This takes possession of fd and closes it */
869 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
870 config_path
, config_path
, same_name_link
);
873 static int find_symlinks_in_scope(
875 const LookupPaths
*paths
,
876 UnitFileInstallInfo
*i
,
878 UnitFileState
*state
) {
880 bool same_name_link_runtime
= false, same_name_link_config
= false;
881 bool enabled_in_runtime
= false, enabled_at_all
= false;
888 STRV_FOREACH(p
, paths
->search_path
) {
889 bool same_name_link
= false;
891 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
895 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
897 r
= path_is_config(paths
, *p
, false);
901 /* This is the best outcome, let's return it immediately. */
902 *state
= UNIT_FILE_ENABLED
;
906 /* look for globally enablement of user units */
907 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
908 *state
= UNIT_FILE_ENABLED
;
912 r
= path_is_runtime(paths
, *p
, false);
916 enabled_in_runtime
= true;
918 enabled_at_all
= true;
920 } else if (same_name_link
) {
922 r
= path_is_config(paths
, *p
, false);
926 same_name_link_config
= true;
928 r
= path_is_runtime(paths
, *p
, false);
932 same_name_link_runtime
= true;
937 if (enabled_in_runtime
) {
938 *state
= UNIT_FILE_ENABLED_RUNTIME
;
942 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
943 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
944 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
945 * something, and hence are a much stronger concept. */
946 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
947 *state
= UNIT_FILE_STATIC
;
951 /* Hmm, we didn't find it, but maybe we found the same name
953 if (same_name_link_config
) {
954 *state
= UNIT_FILE_LINKED
;
957 if (same_name_link_runtime
) {
958 *state
= UNIT_FILE_LINKED_RUNTIME
;
965 static void install_info_free(UnitFileInstallInfo
*i
) {
972 strv_free(i
->aliases
);
973 strv_free(i
->wanted_by
);
974 strv_free(i
->required_by
);
976 free(i
->default_instance
);
977 free(i
->symlink_target
);
981 static void install_context_done(InstallContext
*c
) {
984 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
985 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
988 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
989 UnitFileInstallInfo
*i
;
991 i
= ordered_hashmap_get(c
->have_processed
, name
);
995 return ordered_hashmap_get(c
->will_process
, name
);
998 static int install_info_may_process(
999 UnitFileInstallInfo
*i
,
1000 const LookupPaths
*paths
,
1001 UnitFileChange
**changes
,
1002 size_t *n_changes
) {
1006 /* Checks whether the loaded unit file is one we should process, or is masked,
1007 * transient or generated and thus not subject to enable/disable operations. */
1009 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1010 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1013 if (path_is_generator(paths
, i
->path
) ||
1014 path_is_transient(paths
, i
->path
)) {
1015 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1016 return -EADDRNOTAVAIL
;
1023 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1024 * hashmap, or retrieves the existing one if already present.
1026 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1028 static int install_info_add(
1033 UnitFileInstallInfo
**ret
) {
1035 UnitFileInstallInfo
*i
= NULL
;
1039 assert(name
|| path
);
1042 name
= basename(path
);
1044 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1047 i
= install_info_find(c
, name
);
1049 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1056 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1060 i
= new0(UnitFileInstallInfo
, 1);
1063 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1064 i
->auxiliary
= auxiliary
;
1066 i
->name
= strdup(name
);
1073 i
->path
= strdup(path
);
1080 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1090 install_info_free(i
);
1094 static int config_parse_alias(
1096 const char *filename
,
1098 const char *section
,
1099 unsigned section_line
,
1113 type
= unit_name_to_type(unit
);
1114 if (!unit_type_may_alias(type
))
1115 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1116 "Alias= is not allowed for %s units, ignoring.",
1117 unit_type_to_string(type
));
1119 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1120 lvalue
, ltype
, rvalue
, data
, userdata
);
1123 static int config_parse_also(
1125 const char *filename
,
1127 const char *section
,
1128 unsigned section_line
,
1135 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1136 InstallContext
*c
= data
;
1145 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1147 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1153 r
= install_full_printf(info
, word
, &printed
);
1157 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1160 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1164 r
= strv_push(&info
->also
, printed
);
1174 static int config_parse_default_instance(
1176 const char *filename
,
1178 const char *section
,
1179 unsigned section_line
,
1186 UnitFileInstallInfo
*i
= data
;
1187 _cleanup_free_
char *printed
= NULL
;
1195 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1196 /* When enabling an instance, we might be using a template unit file,
1197 * but we should ignore DefaultInstance silently. */
1199 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1200 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1201 "DefaultInstance= only makes sense for template units, ignoring.");
1203 r
= install_full_printf(i
, rvalue
, &printed
);
1207 if (!unit_instance_is_valid(printed
))
1210 return free_and_replace(i
->default_instance
, printed
);
1213 static int unit_file_load(
1215 UnitFileInstallInfo
*info
,
1217 const char *root_dir
,
1218 SearchFlags flags
) {
1220 const ConfigTableItem items
[] = {
1221 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1222 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1223 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1224 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1225 { "Install", "Also", config_parse_also
, 0, c
},
1230 _cleanup_fclose_
FILE *f
= NULL
;
1231 _cleanup_close_
int fd
= -1;
1238 if (!(flags
& SEARCH_DROPIN
)) {
1239 /* Loading or checking for the main unit file… */
1241 type
= unit_name_to_type(info
->name
);
1244 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1245 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1249 if (!(flags
& SEARCH_LOAD
)) {
1250 r
= lstat(path
, &st
);
1254 if (null_or_empty(&st
))
1255 info
->type
= UNIT_FILE_TYPE_MASKED
;
1256 else if (S_ISREG(st
.st_mode
))
1257 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1258 else if (S_ISLNK(st
.st_mode
))
1260 else if (S_ISDIR(st
.st_mode
))
1268 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1272 /* 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. */
1274 if (!(flags
& SEARCH_LOAD
))
1277 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1282 if (fstat(fd
, &st
) < 0)
1285 if (null_or_empty(&st
)) {
1286 if ((flags
& SEARCH_DROPIN
) == 0)
1287 info
->type
= UNIT_FILE_TYPE_MASKED
;
1292 r
= stat_verify_regular(&st
);
1296 f
= fdopen(fd
, "re");
1301 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1304 r
= config_parse(info
->name
, path
, f
,
1306 config_item_table_lookup
, items
,
1307 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1309 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1311 if ((flags
& SEARCH_DROPIN
) == 0)
1312 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1315 (int) strv_length(info
->aliases
) +
1316 (int) strv_length(info
->wanted_by
) +
1317 (int) strv_length(info
->required_by
);
1320 static int unit_file_load_or_readlink(
1322 UnitFileInstallInfo
*info
,
1324 const char *root_dir
,
1325 SearchFlags flags
) {
1327 _cleanup_free_
char *target
= NULL
;
1330 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1331 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1334 /* This is a symlink, let's read it. */
1336 r
= readlink_malloc(path
, &target
);
1340 if (path_equal(target
, "/dev/null"))
1341 info
->type
= UNIT_FILE_TYPE_MASKED
;
1346 bn
= basename(target
);
1348 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1350 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1353 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1355 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1358 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1360 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1365 /* Enforce that the symlink destination does not
1366 * change the unit file type. */
1368 a
= unit_name_to_type(info
->name
);
1369 b
= unit_name_to_type(bn
);
1370 if (a
< 0 || b
< 0 || a
!= b
)
1373 if (path_is_absolute(target
))
1374 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1375 info
->symlink_target
= prefix_root(root_dir
, target
);
1377 /* This is a relative path, take it relative to the dir the symlink is located in. */
1378 info
->symlink_target
= file_in_same_dir(path
, target
);
1379 if (!info
->symlink_target
)
1382 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1388 static int unit_file_search(
1390 UnitFileInstallInfo
*info
,
1391 const LookupPaths
*paths
,
1392 SearchFlags flags
) {
1394 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1395 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1396 _cleanup_free_
char *template = NULL
;
1397 bool found_unit
= false;
1404 /* Was this unit already loaded? */
1405 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1409 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1413 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1414 r
= unit_name_template(info
->name
, &template);
1419 STRV_FOREACH(p
, paths
->search_path
) {
1420 _cleanup_free_
char *path
= NULL
;
1422 path
= strjoin(*p
, "/", info
->name
);
1426 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1428 info
->path
= TAKE_PTR(path
);
1432 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1436 if (!found_unit
&& template) {
1438 /* Unit file doesn't exist, however instance
1439 * enablement was requested. We will check if it is
1440 * possible to load template unit file. */
1442 STRV_FOREACH(p
, paths
->search_path
) {
1443 _cleanup_free_
char *path
= NULL
;
1445 path
= strjoin(*p
, "/", template);
1449 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1451 info
->path
= TAKE_PTR(path
);
1455 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1461 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1465 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1468 /* Search for drop-in directories */
1470 dropin_dir_name
= strjoina(info
->name
, ".d");
1471 STRV_FOREACH(p
, paths
->search_path
) {
1474 path
= path_join(NULL
, *p
, dropin_dir_name
);
1478 r
= strv_consume(&dirs
, path
);
1484 dropin_template_dir_name
= strjoina(template, ".d");
1485 STRV_FOREACH(p
, paths
->search_path
) {
1488 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1492 r
= strv_consume(&dirs
, path
);
1498 /* Load drop-in conf files */
1500 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1502 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1504 STRV_FOREACH(p
, files
) {
1505 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1507 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1513 static int install_info_follow(
1515 UnitFileInstallInfo
*i
,
1516 const char *root_dir
,
1518 bool ignore_different_name
) {
1523 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1525 if (!i
->symlink_target
)
1528 /* If the basename doesn't match, the caller should add a
1529 * complete new entry for this. */
1531 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1534 free_and_replace(i
->path
, i
->symlink_target
);
1535 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1537 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1541 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1542 * target, maybe more than once. Propagate the instance name if present.
1544 static int install_info_traverse(
1545 UnitFileScope scope
,
1547 const LookupPaths
*paths
,
1548 UnitFileInstallInfo
*start
,
1550 UnitFileInstallInfo
**ret
) {
1552 UnitFileInstallInfo
*i
;
1560 r
= unit_file_search(c
, start
, paths
, flags
);
1565 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1566 /* Follow the symlink */
1568 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1571 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1572 r
= path_is_config(paths
, i
->path
, true);
1579 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1581 _cleanup_free_
char *buffer
= NULL
;
1584 /* Target has a different name, create a new
1585 * install info object for that, and continue
1588 bn
= basename(i
->symlink_target
);
1590 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1591 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1593 _cleanup_free_
char *instance
= NULL
;
1595 r
= unit_name_to_instance(i
->name
, &instance
);
1599 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1603 if (streq(buffer
, i
->name
)) {
1605 /* We filled in the instance, and the target stayed the same? If so, then let's
1606 * honour the link as it is. */
1608 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1618 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1622 /* Try again, with the new target we found. */
1623 r
= unit_file_search(c
, i
, paths
, flags
);
1625 /* Translate error code to highlight this specific case */
1640 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1641 * or the name (otherwise). root_dir is prepended to the path.
1643 static int install_info_add_auto(
1645 const LookupPaths
*paths
,
1646 const char *name_or_path
,
1647 UnitFileInstallInfo
**ret
) {
1650 assert(name_or_path
);
1652 if (path_is_absolute(name_or_path
)) {
1655 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1657 return install_info_add(c
, NULL
, pp
, false, ret
);
1659 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1662 static int install_info_discover(
1663 UnitFileScope scope
,
1665 const LookupPaths
*paths
,
1668 UnitFileInstallInfo
**ret
,
1669 UnitFileChange
**changes
,
1670 size_t *n_changes
) {
1672 UnitFileInstallInfo
*i
;
1679 r
= install_info_add_auto(c
, paths
, name
, &i
);
1681 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1684 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1688 static int install_info_symlink_alias(
1689 UnitFileInstallInfo
*i
,
1690 const LookupPaths
*paths
,
1691 const char *config_path
,
1693 UnitFileChange
**changes
,
1694 size_t *n_changes
) {
1701 assert(config_path
);
1703 STRV_FOREACH(s
, i
->aliases
) {
1704 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1706 q
= install_full_printf(i
, *s
, &dst
);
1710 alias_path
= path_make_absolute(dst
, config_path
);
1714 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1722 static int install_info_symlink_wants(
1723 UnitFileInstallInfo
*i
,
1724 const LookupPaths
*paths
,
1725 const char *config_path
,
1728 UnitFileChange
**changes
,
1729 size_t *n_changes
) {
1731 _cleanup_free_
char *buf
= NULL
;
1738 assert(config_path
);
1740 if (strv_isempty(list
))
1743 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1744 UnitFileInstallInfo instance
= {
1745 .type
= _UNIT_FILE_TYPE_INVALID
,
1747 _cleanup_free_
char *path
= NULL
;
1749 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1753 instance
.name
= buf
;
1754 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1758 path
= TAKE_PTR(instance
.path
);
1760 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1761 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1769 STRV_FOREACH(s
, list
) {
1770 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1772 q
= install_full_printf(i
, *s
, &dst
);
1776 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1781 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1785 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1793 static int install_info_symlink_link(
1794 UnitFileInstallInfo
*i
,
1795 const LookupPaths
*paths
,
1796 const char *config_path
,
1798 UnitFileChange
**changes
,
1799 size_t *n_changes
) {
1801 _cleanup_free_
char *path
= NULL
;
1806 assert(config_path
);
1809 r
= in_search_path(paths
, i
->path
);
1815 path
= strjoin(config_path
, "/", i
->name
);
1819 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1822 static int install_info_apply(
1823 UnitFileInstallInfo
*i
,
1824 const LookupPaths
*paths
,
1825 const char *config_path
,
1827 UnitFileChange
**changes
,
1828 size_t *n_changes
) {
1834 assert(config_path
);
1836 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1839 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1841 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1845 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1849 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1850 /* Do not count links to the unit file towards the "carries_install_info" count */
1851 if (r
== 0 && q
< 0)
1857 static int install_context_apply(
1858 UnitFileScope scope
,
1860 const LookupPaths
*paths
,
1861 const char *config_path
,
1864 UnitFileChange
**changes
,
1865 size_t *n_changes
) {
1867 UnitFileInstallInfo
*i
;
1872 assert(config_path
);
1874 if (ordered_hashmap_isempty(c
->will_process
))
1877 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1882 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1885 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1889 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1891 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1895 /* We can attempt to process a masked unit when a different unit
1896 * that we were processing specifies it in Also=. */
1897 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1898 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1900 /* Assume that something *could* have been enabled here,
1901 * avoid "empty [Install] section" warning. */
1906 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1909 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1921 static int install_context_mark_for_removal(
1922 UnitFileScope scope
,
1924 const LookupPaths
*paths
,
1925 Set
**remove_symlinks_to
,
1926 const char *config_path
,
1927 UnitFileChange
**changes
,
1928 size_t *n_changes
) {
1930 UnitFileInstallInfo
*i
;
1935 assert(config_path
);
1937 /* Marks all items for removal */
1939 if (ordered_hashmap_isempty(c
->will_process
))
1942 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1946 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1948 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1952 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1953 if (r
== -ENOLINK
) {
1954 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1955 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1956 } else if (r
== -ENOENT
) {
1958 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1959 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1961 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1962 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1966 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1967 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1968 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1969 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1970 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1972 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1973 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1977 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1986 UnitFileScope scope
,
1987 UnitFileFlags flags
,
1988 const char *root_dir
,
1990 UnitFileChange
**changes
,
1991 size_t *n_changes
) {
1993 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
1994 const char *config_path
;
1999 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2001 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2005 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2009 STRV_FOREACH(i
, files
) {
2010 _cleanup_free_
char *path
= NULL
;
2013 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2019 path
= path_make_absolute(*i
, config_path
);
2023 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2024 if (q
< 0 && r
>= 0)
2031 int unit_file_unmask(
2032 UnitFileScope scope
,
2033 UnitFileFlags flags
,
2034 const char *root_dir
,
2036 UnitFileChange
**changes
,
2037 size_t *n_changes
) {
2039 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2040 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2041 _cleanup_strv_free_
char **todo
= NULL
;
2042 size_t n_todo
= 0, n_allocated
= 0;
2043 const char *config_path
;
2049 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2051 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2055 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2059 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2061 STRV_FOREACH(i
, files
) {
2062 _cleanup_free_
char *path
= NULL
;
2064 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2067 path
= path_make_absolute(*i
, config_path
);
2071 r
= null_or_empty_path(path
);
2079 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2082 todo
[n_todo
] = strdup(*i
);
2092 STRV_FOREACH(i
, todo
) {
2093 _cleanup_free_
char *path
= NULL
;
2096 path
= path_make_absolute(*i
, config_path
);
2100 if (!dry_run
&& unlink(path
) < 0) {
2101 if (errno
!= ENOENT
) {
2104 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2110 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2112 rp
= skip_root(&paths
, path
);
2113 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2118 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2126 UnitFileScope scope
,
2127 UnitFileFlags flags
,
2128 const char *root_dir
,
2130 UnitFileChange
**changes
,
2131 size_t *n_changes
) {
2133 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2134 _cleanup_strv_free_
char **todo
= NULL
;
2135 size_t n_todo
= 0, n_allocated
= 0;
2136 const char *config_path
;
2141 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2143 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2147 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2151 STRV_FOREACH(i
, files
) {
2152 _cleanup_free_
char *full
= NULL
;
2156 if (!path_is_absolute(*i
))
2160 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2163 full
= prefix_root(paths
.root_dir
, *i
);
2167 if (lstat(full
, &st
) < 0)
2169 r
= stat_verify_regular(&st
);
2173 q
= in_search_path(&paths
, *i
);
2179 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2182 todo
[n_todo
] = strdup(*i
);
2192 STRV_FOREACH(i
, todo
) {
2193 _cleanup_free_
char *new_path
= NULL
;
2195 new_path
= path_make_absolute(basename(*i
), config_path
);
2199 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2200 if (q
< 0 && r
>= 0)
2207 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2213 /* Checks whether the path is one where the drop-in directories shall be removed. */
2215 r
= path_is_config(paths
, path
, true);
2219 r
= path_is_control(paths
, path
);
2223 return path_is_transient(paths
, path
);
2226 int unit_file_revert(
2227 UnitFileScope scope
,
2228 const char *root_dir
,
2230 UnitFileChange
**changes
,
2231 size_t *n_changes
) {
2233 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2234 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2235 _cleanup_strv_free_
char **todo
= NULL
;
2236 size_t n_todo
= 0, n_allocated
= 0;
2240 /* Puts a unit file back into vendor state. This means:
2242 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2243 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2245 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2246 * "config", but not in "transient" or "control" or even "generated").
2248 * We remove all that in both the runtime and the persistent directories, if that applies.
2251 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2255 STRV_FOREACH(i
, files
) {
2256 bool has_vendor
= false;
2259 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2262 STRV_FOREACH(p
, paths
.search_path
) {
2263 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2266 path
= path_make_absolute(*i
, *p
);
2270 r
= lstat(path
, &st
);
2272 if (errno
!= ENOENT
)
2274 } else if (S_ISREG(st
.st_mode
)) {
2275 /* Check if there's a vendor version */
2276 r
= path_is_vendor(&paths
, path
);
2283 dropin
= strappend(path
, ".d");
2287 r
= lstat(dropin
, &st
);
2289 if (errno
!= ENOENT
)
2291 } else if (S_ISDIR(st
.st_mode
)) {
2292 /* Remove the drop-ins */
2293 r
= path_shall_revert(&paths
, dropin
);
2297 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2300 todo
[n_todo
++] = TAKE_PTR(dropin
);
2308 /* OK, there's a vendor version, hence drop all configuration versions */
2309 STRV_FOREACH(p
, paths
.search_path
) {
2310 _cleanup_free_
char *path
= NULL
;
2313 path
= path_make_absolute(*i
, *p
);
2317 r
= lstat(path
, &st
);
2319 if (errno
!= ENOENT
)
2321 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2322 r
= path_is_config(&paths
, path
, true);
2326 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2329 todo
[n_todo
++] = TAKE_PTR(path
);
2338 STRV_FOREACH(i
, todo
) {
2339 _cleanup_strv_free_
char **fs
= NULL
;
2343 (void) get_files_in_directory(*i
, &fs
);
2345 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2346 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2351 STRV_FOREACH(j
, fs
) {
2352 _cleanup_free_
char *t
= NULL
;
2354 t
= strjoin(*i
, "/", *j
);
2358 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2361 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2363 rp
= skip_root(&paths
, *i
);
2364 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2369 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2373 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2380 int unit_file_add_dependency(
2381 UnitFileScope scope
,
2382 UnitFileFlags flags
,
2383 const char *root_dir
,
2387 UnitFileChange
**changes
,
2388 size_t *n_changes
) {
2390 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2391 _cleanup_(install_context_done
) InstallContext c
= {};
2392 UnitFileInstallInfo
*i
, *target_info
;
2393 const char *config_path
;
2398 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2401 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2404 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2407 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2411 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2415 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2416 &target_info
, changes
, n_changes
);
2419 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2423 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2425 STRV_FOREACH(f
, files
) {
2428 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2429 &i
, changes
, n_changes
);
2432 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2436 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2438 /* We didn't actually load anything from the unit
2439 * file, but instead just add in our new symlink to
2442 if (dep
== UNIT_WANTS
)
2445 l
= &i
->required_by
;
2448 *l
= strv_new(target_info
->name
, NULL
);
2453 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2456 int unit_file_enable(
2457 UnitFileScope scope
,
2458 UnitFileFlags flags
,
2459 const char *root_dir
,
2461 UnitFileChange
**changes
,
2462 size_t *n_changes
) {
2464 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2465 _cleanup_(install_context_done
) InstallContext c
= {};
2466 const char *config_path
;
2467 UnitFileInstallInfo
*i
;
2472 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2474 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2478 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2482 STRV_FOREACH(f
, files
) {
2483 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2484 &i
, changes
, n_changes
);
2487 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2491 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2494 /* This will return the number of symlink rules that were
2495 supposed to be created, not the ones actually created. This
2496 is useful to determine whether the passed files had any
2497 installation data at all. */
2499 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2502 int unit_file_disable(
2503 UnitFileScope scope
,
2504 UnitFileFlags flags
,
2505 const char *root_dir
,
2507 UnitFileChange
**changes
,
2508 size_t *n_changes
) {
2510 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2511 _cleanup_(install_context_done
) InstallContext c
= {};
2512 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2513 const char *config_path
;
2518 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2520 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2524 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2528 STRV_FOREACH(i
, files
) {
2529 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2532 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2537 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2541 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2544 int unit_file_reenable(
2545 UnitFileScope scope
,
2546 UnitFileFlags flags
,
2547 const char *root_dir
,
2549 UnitFileChange
**changes
,
2550 size_t *n_changes
) {
2556 /* First, we invoke the disable command with only the basename... */
2557 l
= strv_length(files
);
2558 n
= newa(char*, l
+1);
2559 for (i
= 0; i
< l
; i
++)
2560 n
[i
] = basename(files
[i
]);
2563 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2567 /* But the enable command with the full name */
2568 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2571 int unit_file_set_default(
2572 UnitFileScope scope
,
2573 UnitFileFlags flags
,
2574 const char *root_dir
,
2576 UnitFileChange
**changes
,
2577 size_t *n_changes
) {
2579 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2580 _cleanup_(install_context_done
) InstallContext c
= {};
2581 UnitFileInstallInfo
*i
;
2582 const char *new_path
;
2586 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2589 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2591 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2594 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2598 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2601 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2605 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2606 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2609 int unit_file_get_default(
2610 UnitFileScope scope
,
2611 const char *root_dir
,
2614 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2615 _cleanup_(install_context_done
) InstallContext c
= {};
2616 UnitFileInstallInfo
*i
;
2621 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2624 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2628 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2632 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2636 n
= strdup(i
->name
);
2644 int unit_file_lookup_state(
2645 UnitFileScope scope
,
2646 const LookupPaths
*paths
,
2648 UnitFileState
*ret
) {
2650 _cleanup_(install_context_done
) InstallContext c
= {};
2651 UnitFileInstallInfo
*i
;
2652 UnitFileState state
;
2658 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2661 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2666 /* Shortcut things, if the caller just wants to know if this unit exists. */
2672 case UNIT_FILE_TYPE_MASKED
:
2673 r
= path_is_runtime(paths
, i
->path
, true);
2677 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2680 case UNIT_FILE_TYPE_REGULAR
:
2681 r
= path_is_generator(paths
, i
->path
);
2685 state
= UNIT_FILE_GENERATED
;
2689 r
= path_is_transient(paths
, i
->path
);
2693 state
= UNIT_FILE_TRANSIENT
;
2697 /* Check if any of the Alias= symlinks have been created.
2698 * We ignore other aliases, and only check those that would
2699 * be created by systemctl enable for this unit. */
2700 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2706 /* Check if the file is known under other names. If it is,
2707 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2708 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2712 state
= UNIT_FILE_INDIRECT
;
2714 if (unit_file_install_info_has_rules(i
))
2715 state
= UNIT_FILE_DISABLED
;
2716 else if (unit_file_install_info_has_also(i
))
2717 state
= UNIT_FILE_INDIRECT
;
2719 state
= UNIT_FILE_STATIC
;
2725 assert_not_reached("Unexpect unit file type.");
2732 int unit_file_get_state(
2733 UnitFileScope scope
,
2734 const char *root_dir
,
2736 UnitFileState
*ret
) {
2738 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2742 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2745 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2749 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2752 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2753 _cleanup_(install_context_done
) InstallContext c
= {};
2759 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2762 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2771 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2772 _cleanup_(presets_freep
) Presets ps
= {};
2773 size_t n_allocated
= 0;
2774 _cleanup_strv_free_
char **files
= NULL
;
2779 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2783 case UNIT_FILE_SYSTEM
:
2784 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2785 "/etc/systemd/system-preset",
2786 "/run/systemd/system-preset",
2787 "/usr/local/lib/systemd/system-preset",
2788 "/usr/lib/systemd/system-preset",
2790 "/lib/systemd/system-preset",
2795 case UNIT_FILE_GLOBAL
:
2796 case UNIT_FILE_USER
:
2797 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2798 "/etc/systemd/user-preset",
2799 "/run/systemd/user-preset",
2800 "/usr/local/lib/systemd/user-preset",
2801 "/usr/lib/systemd/user-preset",
2806 assert_not_reached("Invalid unit file scope");
2812 STRV_FOREACH(p
, files
) {
2813 _cleanup_fclose_
FILE *f
;
2814 char line
[LINE_MAX
];
2817 f
= fopen(*p
, "re");
2819 if (errno
== ENOENT
)
2825 FOREACH_LINE(line
, f
, return -errno
) {
2826 PresetRule rule
= {};
2827 const char *parameter
;
2835 if (strchr(COMMENTS
, *l
))
2838 parameter
= first_word(l
, "enable");
2842 pattern
= strdup(parameter
);
2846 rule
= (PresetRule
) {
2848 .action
= PRESET_ENABLE
,
2852 parameter
= first_word(l
, "disable");
2856 pattern
= strdup(parameter
);
2860 rule
= (PresetRule
) {
2862 .action
= PRESET_DISABLE
,
2867 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2870 ps
.rules
[ps
.n_rules
++] = rule
;
2874 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2884 static int query_presets(const char *name
, const Presets presets
) {
2885 PresetAction action
= PRESET_UNKNOWN
;
2888 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2891 for (i
= 0; i
< presets
.n_rules
; i
++)
2892 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2893 action
= presets
.rules
[i
].action
;
2898 case PRESET_UNKNOWN
:
2899 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2902 log_debug("Preset files say enable %s.", name
);
2904 case PRESET_DISABLE
:
2905 log_debug("Preset files say disable %s.", name
);
2908 assert_not_reached("invalid preset action");
2912 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2913 _cleanup_(presets_freep
) Presets presets
= {};
2916 r
= read_presets(scope
, root_dir
, &presets
);
2920 return query_presets(name
, presets
);
2923 static int execute_preset(
2924 UnitFileScope scope
,
2925 InstallContext
*plus
,
2926 InstallContext
*minus
,
2927 const LookupPaths
*paths
,
2928 const char *config_path
,
2930 UnitFilePresetMode mode
,
2932 UnitFileChange
**changes
,
2933 size_t *n_changes
) {
2940 assert(config_path
);
2942 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2943 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2945 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2949 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2953 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2956 /* Returns number of symlinks that where supposed to be installed. */
2957 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2969 static int preset_prepare_one(
2970 UnitFileScope scope
,
2971 InstallContext
*plus
,
2972 InstallContext
*minus
,
2976 UnitFileChange
**changes
,
2977 size_t *n_changes
) {
2979 _cleanup_(install_context_done
) InstallContext tmp
= {};
2980 UnitFileInstallInfo
*i
;
2983 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2986 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2987 &i
, changes
, n_changes
);
2990 if (!streq(name
, i
->name
)) {
2991 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
2995 r
= query_presets(name
, presets
);
3000 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3001 &i
, changes
, n_changes
);
3005 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
3009 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3010 &i
, changes
, n_changes
);
3015 int unit_file_preset(
3016 UnitFileScope scope
,
3017 UnitFileFlags flags
,
3018 const char *root_dir
,
3020 UnitFilePresetMode mode
,
3021 UnitFileChange
**changes
,
3022 size_t *n_changes
) {
3024 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3025 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3026 _cleanup_(presets_freep
) Presets presets
= {};
3027 const char *config_path
;
3032 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3033 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3035 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3039 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3043 r
= read_presets(scope
, root_dir
, &presets
);
3047 STRV_FOREACH(i
, files
) {
3048 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3053 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3056 int unit_file_preset_all(
3057 UnitFileScope scope
,
3058 UnitFileFlags flags
,
3059 const char *root_dir
,
3060 UnitFilePresetMode mode
,
3061 UnitFileChange
**changes
,
3062 size_t *n_changes
) {
3064 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3065 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3066 _cleanup_(presets_freep
) Presets presets
= {};
3067 const char *config_path
= NULL
;
3072 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3073 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3075 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3079 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3083 r
= read_presets(scope
, root_dir
, &presets
);
3087 STRV_FOREACH(i
, paths
.search_path
) {
3088 _cleanup_closedir_
DIR *d
= NULL
;
3093 if (errno
== ENOENT
)
3099 FOREACH_DIRENT(de
, d
, return -errno
) {
3101 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3104 dirent_ensure_type(d
, de
);
3106 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3109 /* we don't pass changes[] in, because we want to handle errors on our own */
3110 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3112 r
= unit_file_changes_add(changes
, n_changes
,
3113 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3114 else if (r
== -ENOLINK
)
3115 r
= unit_file_changes_add(changes
, n_changes
,
3116 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3117 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3124 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3127 static void unit_file_list_free_one(UnitFileList
*f
) {
3135 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3136 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3139 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3141 int unit_file_get_list(
3142 UnitFileScope scope
,
3143 const char *root_dir
,
3148 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3153 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3156 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3160 STRV_FOREACH(i
, paths
.search_path
) {
3161 _cleanup_closedir_
DIR *d
= NULL
;
3166 if (errno
== ENOENT
)
3168 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3169 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3176 FOREACH_DIRENT(de
, d
, return -errno
) {
3177 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3179 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3182 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3185 if (hashmap_get(h
, de
->d_name
))
3188 dirent_ensure_type(d
, de
);
3190 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3193 f
= new0(UnitFileList
, 1);
3197 f
->path
= path_make_absolute(de
->d_name
, *i
);
3201 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3203 f
->state
= UNIT_FILE_BAD
;
3205 if (!strv_isempty(states
) &&
3206 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3209 r
= hashmap_put(h
, basename(f
->path
), f
);
3213 f
= NULL
; /* prevent cleanup */
3220 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3221 [UNIT_FILE_ENABLED
] = "enabled",
3222 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3223 [UNIT_FILE_LINKED
] = "linked",
3224 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3225 [UNIT_FILE_MASKED
] = "masked",
3226 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3227 [UNIT_FILE_STATIC
] = "static",
3228 [UNIT_FILE_DISABLED
] = "disabled",
3229 [UNIT_FILE_INDIRECT
] = "indirect",
3230 [UNIT_FILE_GENERATED
] = "generated",
3231 [UNIT_FILE_TRANSIENT
] = "transient",
3232 [UNIT_FILE_BAD
] = "bad",
3235 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3237 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3238 [UNIT_FILE_SYMLINK
] = "symlink",
3239 [UNIT_FILE_UNLINK
] = "unlink",
3240 [UNIT_FILE_IS_MASKED
] = "masked",
3241 [UNIT_FILE_IS_DANGLING
] = "dangling",
3244 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3246 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3247 [UNIT_FILE_PRESET_FULL
] = "full",
3248 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3249 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3252 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);