1 /* SPDX-License-Identifier: LGPL-2.1+ */
12 #include "alloc-util.h"
13 #include "conf-files.h"
14 #include "conf-parser.h"
16 #include "dirent-util.h"
17 #include "extract-word.h"
22 #include "install-printf.h"
24 #include "locale-util.h"
28 #include "path-lookup.h"
29 #include "path-util.h"
33 #include "stat-util.h"
34 #include "string-table.h"
35 #include "string-util.h"
37 #include "unit-file.h"
39 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
41 typedef enum SearchFlags
{
43 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
44 SEARCH_DROPIN
= 1 << 2,
48 OrderedHashmap
*will_process
;
49 OrderedHashmap
*have_processed
;
69 static bool unit_file_install_info_has_rules(const UnitFileInstallInfo
*i
) {
72 return !strv_isempty(i
->aliases
) ||
73 !strv_isempty(i
->wanted_by
) ||
74 !strv_isempty(i
->required_by
);
77 static bool unit_file_install_info_has_also(const UnitFileInstallInfo
*i
) {
80 return !strv_isempty(i
->also
);
83 static void presets_freep(Presets
*p
) {
89 for (i
= 0; i
< p
->n_rules
; i
++) {
90 free(p
->rules
[i
].pattern
);
91 strv_free(p
->rules
[i
].instances
);
98 static const char *const unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
99 [UNIT_FILE_TYPE_REGULAR
] = "regular",
100 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
101 [UNIT_FILE_TYPE_MASKED
] = "masked",
104 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
106 static int in_search_path(const LookupPaths
*p
, const char *path
) {
107 _cleanup_free_
char *parent
= NULL
;
112 parent
= dirname_malloc(path
);
116 STRV_FOREACH(i
, p
->search_path
)
117 if (path_equal(parent
, *i
))
123 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
132 e
= path_startswith(path
, p
->root_dir
);
136 /* Make sure the returned path starts with a slash */
138 if (e
== path
|| e
[-1] != '/')
147 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
148 _cleanup_free_
char *parent
= NULL
;
153 parent
= dirname_malloc(path
);
157 return path_equal_ptr(parent
, p
->generator
) ||
158 path_equal_ptr(parent
, p
->generator_early
) ||
159 path_equal_ptr(parent
, p
->generator_late
);
162 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
163 _cleanup_free_
char *parent
= NULL
;
168 parent
= dirname_malloc(path
);
172 return path_equal_ptr(parent
, p
->transient
);
175 static int path_is_control(const LookupPaths
*p
, const char *path
) {
176 _cleanup_free_
char *parent
= NULL
;
181 parent
= dirname_malloc(path
);
185 return path_equal_ptr(parent
, p
->persistent_control
) ||
186 path_equal_ptr(parent
, p
->runtime_control
);
189 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
190 _cleanup_free_
char *parent
= NULL
;
195 /* Note that we do *not* have generic checks for /etc or /run in place, since with
196 * them we couldn't discern configuration from transient or generated units */
199 parent
= dirname_malloc(path
);
206 return path_equal_ptr(path
, p
->persistent_config
) ||
207 path_equal_ptr(path
, p
->runtime_config
);
210 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
211 _cleanup_free_
char *parent
= NULL
;
217 /* Everything in /run is considered runtime. On top of that we also add
218 * explicit checks for the various runtime directories, as safety net. */
220 rpath
= skip_root(p
, path
);
221 if (rpath
&& path_startswith(rpath
, "/run"))
225 parent
= dirname_malloc(path
);
232 return path_equal_ptr(path
, p
->runtime_config
) ||
233 path_equal_ptr(path
, p
->generator
) ||
234 path_equal_ptr(path
, p
->generator_early
) ||
235 path_equal_ptr(path
, p
->generator_late
) ||
236 path_equal_ptr(path
, p
->transient
) ||
237 path_equal_ptr(path
, p
->runtime_control
);
240 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
246 rpath
= skip_root(p
, path
);
250 if (path_startswith(rpath
, "/usr"))
254 if (path_startswith(rpath
, "/lib"))
258 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
261 int unit_file_changes_add(
262 UnitFileChange
**changes
,
264 UnitFileChangeType type
,
266 const char *source
) {
268 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
272 assert(!changes
== !n_changes
);
277 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
286 if (!p
|| (source
&& !s
))
289 path_simplify(p
, false);
291 path_simplify(s
, false);
293 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
299 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
302 assert(changes
|| n_changes
== 0);
304 for (i
= 0; i
< n_changes
; i
++) {
305 free(changes
[i
].path
);
306 free(changes
[i
].source
);
312 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
316 assert(changes
|| n_changes
== 0);
317 /* If verb is not specified, errors are not allowed! */
318 assert(verb
|| r
>= 0);
320 for (i
= 0; i
< n_changes
; i
++) {
321 assert(verb
|| changes
[i
].type
>= 0);
323 switch(changes
[i
].type
) {
324 case UNIT_FILE_SYMLINK
:
326 log_info("Created symlink %s %s %s.",
328 special_glyph(SPECIAL_GLYPH_ARROW
),
331 case UNIT_FILE_UNLINK
:
333 log_info("Removed %s.", changes
[i
].path
);
335 case UNIT_FILE_IS_MASKED
:
337 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
339 case UNIT_FILE_IS_DANGLING
:
341 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
345 if (changes
[i
].source
)
346 log_error_errno(changes
[i
].type
,
347 "Failed to %s unit, file %s already exists and is a symlink to %s.",
348 verb
, changes
[i
].path
, changes
[i
].source
);
350 log_error_errno(changes
[i
].type
,
351 "Failed to %s unit, file %s already exists.",
352 verb
, changes
[i
].path
);
356 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
357 verb
, changes
[i
].path
);
361 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
362 verb
, changes
[i
].path
);
366 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
367 verb
, changes
[i
].path
);
372 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
377 assert(changes
[i
].type
< 0);
378 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
379 verb
, changes
[i
].path
);
384 if (r
< 0 && !logged
)
385 log_error_errno(r
, "Failed to %s: %m.", verb
);
389 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
390 * wc should be the full path in the host file system.
392 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
393 assert(path_is_absolute(wd
));
395 /* This will give incorrect results if the paths are relative and go outside
396 * of the chroot. False negatives are possible. */
401 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
402 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
403 return path_equal_or_files_same(a
, b
, 0);
406 static int create_symlink(
407 const LookupPaths
*paths
,
408 const char *old_path
,
409 const char *new_path
,
411 UnitFileChange
**changes
,
414 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
421 rp
= skip_root(paths
, old_path
);
425 /* Actually create a symlink, and remember that we did. Is
426 * smart enough to check if there's already a valid symlink in
429 * Returns 1 if a symlink was created or already exists and points to
430 * the right place, or negative on error.
433 mkdir_parents_label(new_path
, 0755);
435 if (symlink(old_path
, new_path
) >= 0) {
436 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
440 if (errno
!= EEXIST
) {
441 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
445 r
= readlink_malloc(new_path
, &dest
);
447 /* translate EINVAL (non-symlink exists) to EEXIST */
451 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
455 dirname
= dirname_malloc(new_path
);
459 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
)) {
460 log_debug("Symlink %s → %s already exists", new_path
, dest
);
465 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
469 r
= symlink_atomic(old_path
, new_path
);
471 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
475 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
476 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
481 static int mark_symlink_for_removal(
482 Set
**remove_symlinks_to
,
490 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
498 path_simplify(n
, false);
500 r
= set_consume(*remove_symlinks_to
, n
);
509 static int remove_marked_symlinks_fd(
510 Set
*remove_symlinks_to
,
513 const char *config_path
,
514 const LookupPaths
*lp
,
517 UnitFileChange
**changes
,
520 _cleanup_closedir_
DIR *d
= NULL
;
524 assert(remove_symlinks_to
);
539 FOREACH_DIRENT(de
, d
, return -errno
) {
541 dirent_ensure_type(d
, de
);
543 if (de
->d_type
== DT_DIR
) {
544 _cleanup_free_
char *p
= NULL
;
547 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
557 p
= path_make_absolute(de
->d_name
, path
);
563 /* This will close nfd, regardless whether it succeeds or not */
564 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
568 } else if (de
->d_type
== DT_LNK
) {
569 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
574 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
577 p
= path_make_absolute(de
->d_name
, path
);
580 path_simplify(p
, false);
582 q
= readlink_malloc(p
, &dest
);
591 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
592 * the same name as a file that is marked. */
594 found
= set_contains(remove_symlinks_to
, dest
) ||
595 set_contains(remove_symlinks_to
, basename(dest
)) ||
596 set_contains(remove_symlinks_to
, de
->d_name
);
602 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
605 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
609 (void) rmdir_parents(p
, config_path
);
612 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
614 /* Now, remember the full path (but with the root prefix removed) of
615 * the symlink we just removed, and remove any symlinks to it, too. */
617 rp
= skip_root(lp
, p
);
618 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
621 if (q
> 0 && !dry_run
)
629 static int remove_marked_symlinks(
630 Set
*remove_symlinks_to
,
631 const char *config_path
,
632 const LookupPaths
*lp
,
634 UnitFileChange
**changes
,
637 _cleanup_close_
int fd
= -1;
644 if (set_size(remove_symlinks_to
) <= 0)
647 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
649 return errno
== ENOENT
? 0 : -errno
;
655 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
659 /* This takes possession of cfd and closes it */
660 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
668 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
671 if (streq(name
, i
->name
))
674 if (strv_contains(i
->aliases
, name
))
677 /* Look for template symlink matching DefaultInstance */
678 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
679 _cleanup_free_
char *s
= NULL
;
681 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
686 } else if (streq(name
, s
))
693 static int find_symlinks_fd(
694 const char *root_dir
,
695 const UnitFileInstallInfo
*i
,
697 bool ignore_same_name
,
700 const char *config_path
,
701 bool *same_name_link
) {
703 _cleanup_closedir_
DIR *d
= NULL
;
711 assert(same_name_link
);
719 FOREACH_DIRENT(de
, d
, return -errno
) {
721 dirent_ensure_type(d
, de
);
723 if (de
->d_type
== DT_DIR
) {
724 _cleanup_free_
char *p
= NULL
;
727 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
737 p
= path_make_absolute(de
->d_name
, path
);
743 /* This will close nfd, regardless whether it succeeds or not */
744 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, ignore_same_name
, nfd
,
745 p
, config_path
, same_name_link
);
751 } else if (de
->d_type
== DT_LNK
) {
752 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
753 bool found_path
= false, found_dest
, b
= false;
756 /* Acquire symlink name */
757 p
= path_make_absolute(de
->d_name
, path
);
761 /* Acquire symlink destination */
762 q
= readlink_malloc(p
, &dest
);
772 if (!path_is_absolute(dest
)) {
775 x
= path_join(root_dir
, dest
);
779 free_and_replace(dest
, x
);
782 assert(unit_name_is_valid(i
->name
, UNIT_NAME_ANY
));
783 if (!ignore_same_name
)
784 /* Check if the symlink itself matches what we are looking for.
786 * If ignore_same_name is specified, we are in one of the directories which
787 * have lower priority than the unit file, and even if a file or symlink with
788 * this name was found, we should ignore it. */
789 found_path
= streq(de
->d_name
, i
->name
);
791 /* Check if what the symlink points to matches what we are looking for */
792 found_dest
= streq(basename(dest
), i
->name
);
794 if (found_path
&& found_dest
) {
795 _cleanup_free_
char *t
= NULL
;
797 /* Filter out same name links in the main
799 t
= path_make_absolute(i
->name
, config_path
);
803 b
= path_equal(t
, p
);
807 *same_name_link
= true;
808 else if (found_path
|| found_dest
) {
812 /* Check if symlink name is in the set of names used by [Install] */
813 q
= is_symlink_with_known_name(i
, de
->d_name
);
825 static int find_symlinks(
826 const char *root_dir
,
827 const UnitFileInstallInfo
*i
,
829 bool ignore_same_name
,
830 const char *config_path
,
831 bool *same_name_link
) {
837 assert(same_name_link
);
839 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
841 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
846 /* This takes possession of fd and closes it */
847 return find_symlinks_fd(root_dir
, i
, match_name
, ignore_same_name
, fd
,
848 config_path
, config_path
, same_name_link
);
851 static int find_symlinks_in_scope(
853 const LookupPaths
*paths
,
854 const UnitFileInstallInfo
*i
,
856 UnitFileState
*state
) {
858 bool same_name_link_runtime
= false, same_name_link_config
= false;
859 bool enabled_in_runtime
= false, enabled_at_all
= false;
860 bool ignore_same_name
= false;
867 /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name"
868 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
869 * effectively masked, so we should ignore them. */
871 STRV_FOREACH(p
, paths
->search_path
) {
872 bool same_name_link
= false;
874 r
= find_symlinks(paths
->root_dir
, i
, match_name
, ignore_same_name
, *p
, &same_name_link
);
878 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
880 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
881 /* This is the best outcome, let's return it immediately. */
882 *state
= UNIT_FILE_ENABLED
;
886 /* look for global enablement of user units */
887 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
888 *state
= UNIT_FILE_ENABLED
;
892 r
= path_is_runtime(paths
, *p
, false);
896 enabled_in_runtime
= true;
898 enabled_at_all
= true;
900 } else if (same_name_link
) {
901 if (path_equal_ptr(*p
, paths
->persistent_config
))
902 same_name_link_config
= true;
904 r
= path_is_runtime(paths
, *p
, false);
908 same_name_link_runtime
= true;
912 /* Check if next iteration will be "below" the unit file (either a regular file
913 * or a symlink), and hence should be ignored */
914 if (!ignore_same_name
&& path_startswith(i
->path
, *p
))
915 ignore_same_name
= true;
918 if (enabled_in_runtime
) {
919 *state
= UNIT_FILE_ENABLED_RUNTIME
;
923 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
924 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
925 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
926 * something, and hence are a much stronger concept. */
927 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
928 *state
= UNIT_FILE_STATIC
;
932 /* Hmm, we didn't find it, but maybe we found the same name
934 if (same_name_link_config
) {
935 *state
= UNIT_FILE_LINKED
;
938 if (same_name_link_runtime
) {
939 *state
= UNIT_FILE_LINKED_RUNTIME
;
946 static void install_info_free(UnitFileInstallInfo
*i
) {
953 strv_free(i
->aliases
);
954 strv_free(i
->wanted_by
);
955 strv_free(i
->required_by
);
957 free(i
->default_instance
);
958 free(i
->symlink_target
);
962 static void install_context_done(InstallContext
*c
) {
965 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
966 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
969 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
970 UnitFileInstallInfo
*i
;
972 i
= ordered_hashmap_get(c
->have_processed
, name
);
976 return ordered_hashmap_get(c
->will_process
, name
);
979 static int install_info_may_process(
980 const UnitFileInstallInfo
*i
,
981 const LookupPaths
*paths
,
982 UnitFileChange
**changes
,
987 /* Checks whether the loaded unit file is one we should process, or is masked,
988 * transient or generated and thus not subject to enable/disable operations. */
990 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
991 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
994 if (path_is_generator(paths
, i
->path
) ||
995 path_is_transient(paths
, i
->path
)) {
996 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
997 return -EADDRNOTAVAIL
;
1004 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1005 * hashmap, or retrieves the existing one if already present.
1007 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1009 static int install_info_add(
1014 UnitFileInstallInfo
**ret
) {
1016 UnitFileInstallInfo
*i
= NULL
;
1020 assert(name
|| path
);
1023 name
= basename(path
);
1025 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1028 i
= install_info_find(c
, name
);
1030 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1037 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1041 i
= new(UnitFileInstallInfo
, 1);
1045 *i
= (UnitFileInstallInfo
) {
1046 .type
= _UNIT_FILE_TYPE_INVALID
,
1047 .auxiliary
= auxiliary
,
1050 i
->name
= strdup(name
);
1057 i
->path
= strdup(path
);
1064 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1074 install_info_free(i
);
1078 static int config_parse_alias(
1080 const char *filename
,
1082 const char *section
,
1083 unsigned section_line
,
1097 type
= unit_name_to_type(unit
);
1098 if (!unit_type_may_alias(type
))
1099 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1100 "Alias= is not allowed for %s units, ignoring.",
1101 unit_type_to_string(type
));
1103 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1104 lvalue
, ltype
, rvalue
, data
, userdata
);
1107 static int config_parse_also(
1109 const char *filename
,
1111 const char *section
,
1112 unsigned section_line
,
1119 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1120 InstallContext
*c
= data
;
1129 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1131 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1137 r
= install_full_printf(info
, word
, &printed
);
1141 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1144 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1148 r
= strv_push(&info
->also
, printed
);
1158 static int config_parse_default_instance(
1160 const char *filename
,
1162 const char *section
,
1163 unsigned section_line
,
1170 UnitFileInstallInfo
*i
= data
;
1171 _cleanup_free_
char *printed
= NULL
;
1179 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1180 /* When enabling an instance, we might be using a template unit file,
1181 * but we should ignore DefaultInstance silently. */
1183 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1184 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1185 "DefaultInstance= only makes sense for template units, ignoring.");
1187 r
= install_full_printf(i
, rvalue
, &printed
);
1191 if (!unit_instance_is_valid(printed
))
1194 return free_and_replace(i
->default_instance
, printed
);
1197 static int unit_file_load(
1199 UnitFileInstallInfo
*info
,
1201 const char *root_dir
,
1202 SearchFlags flags
) {
1204 const ConfigTableItem items
[] = {
1205 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1206 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1207 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1208 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1209 { "Install", "Also", config_parse_also
, 0, c
},
1214 _cleanup_fclose_
FILE *f
= NULL
;
1215 _cleanup_close_
int fd
= -1;
1222 if (!(flags
& SEARCH_DROPIN
)) {
1223 /* Loading or checking for the main unit file… */
1225 type
= unit_name_to_type(info
->name
);
1228 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1229 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1230 "Unit type %s cannot be templated.", unit_type_to_string(type
));
1232 if (!(flags
& SEARCH_LOAD
)) {
1233 r
= lstat(path
, &st
);
1237 if (null_or_empty(&st
))
1238 info
->type
= UNIT_FILE_TYPE_MASKED
;
1239 else if (S_ISREG(st
.st_mode
))
1240 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1241 else if (S_ISLNK(st
.st_mode
))
1243 else if (S_ISDIR(st
.st_mode
))
1251 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1255 /* 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. */
1257 if (!(flags
& SEARCH_LOAD
))
1260 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1265 if (fstat(fd
, &st
) < 0)
1268 if (null_or_empty(&st
)) {
1269 if ((flags
& SEARCH_DROPIN
) == 0)
1270 info
->type
= UNIT_FILE_TYPE_MASKED
;
1275 r
= stat_verify_regular(&st
);
1279 f
= fdopen(fd
, "r");
1284 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1287 r
= config_parse(info
->name
, path
, f
,
1289 config_item_table_lookup
, items
,
1290 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1292 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1294 if ((flags
& SEARCH_DROPIN
) == 0)
1295 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1298 (int) strv_length(info
->aliases
) +
1299 (int) strv_length(info
->wanted_by
) +
1300 (int) strv_length(info
->required_by
);
1303 static int unit_file_load_or_readlink(
1305 UnitFileInstallInfo
*info
,
1307 const char *root_dir
,
1308 SearchFlags flags
) {
1310 _cleanup_free_
char *target
= NULL
;
1313 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1314 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1317 /* This is a symlink, let's read it. */
1319 r
= readlink_malloc(path
, &target
);
1323 if (path_equal(target
, "/dev/null"))
1324 info
->type
= UNIT_FILE_TYPE_MASKED
;
1329 bn
= basename(target
);
1331 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1333 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1336 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1338 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1341 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1343 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1348 /* Enforce that the symlink destination does not
1349 * change the unit file type. */
1351 a
= unit_name_to_type(info
->name
);
1352 b
= unit_name_to_type(bn
);
1353 if (a
< 0 || b
< 0 || a
!= b
)
1356 if (path_is_absolute(target
))
1357 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1358 info
->symlink_target
= path_join(root_dir
, target
);
1360 /* This is a relative path, take it relative to the dir the symlink is located in. */
1361 info
->symlink_target
= file_in_same_dir(path
, target
);
1362 if (!info
->symlink_target
)
1365 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1371 static int unit_file_search(
1373 UnitFileInstallInfo
*info
,
1374 const LookupPaths
*paths
,
1375 SearchFlags flags
) {
1377 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1378 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1379 _cleanup_free_
char *template = NULL
;
1380 bool found_unit
= false;
1387 /* Was this unit already loaded? */
1388 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1392 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1396 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1397 r
= unit_name_template(info
->name
, &template);
1402 STRV_FOREACH(p
, paths
->search_path
) {
1403 _cleanup_free_
char *path
= NULL
;
1405 path
= path_join(*p
, info
->name
);
1409 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1411 info
->path
= TAKE_PTR(path
);
1415 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1419 if (!found_unit
&& template) {
1421 /* Unit file doesn't exist, however instance
1422 * enablement was requested. We will check if it is
1423 * possible to load template unit file. */
1425 STRV_FOREACH(p
, paths
->search_path
) {
1426 _cleanup_free_
char *path
= NULL
;
1428 path
= path_join(*p
, template);
1432 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1434 info
->path
= TAKE_PTR(path
);
1438 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1444 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1445 "Cannot find unit %s%s%s.",
1446 info
->name
, template ? " or " : "", strempty(template));
1448 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1451 /* Search for drop-in directories */
1453 dropin_dir_name
= strjoina(info
->name
, ".d");
1454 STRV_FOREACH(p
, paths
->search_path
) {
1457 path
= path_join(*p
, dropin_dir_name
);
1461 r
= strv_consume(&dirs
, path
);
1467 dropin_template_dir_name
= strjoina(template, ".d");
1468 STRV_FOREACH(p
, paths
->search_path
) {
1471 path
= path_join(*p
, dropin_template_dir_name
);
1475 r
= strv_consume(&dirs
, path
);
1481 /* Load drop-in conf files */
1483 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1485 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1487 STRV_FOREACH(p
, files
) {
1488 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1490 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1496 static int install_info_follow(
1498 UnitFileInstallInfo
*i
,
1499 const char *root_dir
,
1501 bool ignore_different_name
) {
1506 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1508 if (!i
->symlink_target
)
1511 /* If the basename doesn't match, the caller should add a
1512 * complete new entry for this. */
1514 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1517 free_and_replace(i
->path
, i
->symlink_target
);
1518 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1520 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1524 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1525 * target, maybe more than once. Propagate the instance name if present.
1527 static int install_info_traverse(
1528 UnitFileScope scope
,
1530 const LookupPaths
*paths
,
1531 UnitFileInstallInfo
*start
,
1533 UnitFileInstallInfo
**ret
) {
1535 UnitFileInstallInfo
*i
;
1543 r
= unit_file_search(c
, start
, paths
, flags
);
1548 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1549 /* Follow the symlink */
1551 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1554 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1555 r
= path_is_config(paths
, i
->path
, true);
1562 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1564 _cleanup_free_
char *buffer
= NULL
;
1567 /* Target has a different name, create a new
1568 * install info object for that, and continue
1571 bn
= basename(i
->symlink_target
);
1573 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1574 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1576 _cleanup_free_
char *instance
= NULL
;
1578 r
= unit_name_to_instance(i
->name
, &instance
);
1582 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1586 if (streq(buffer
, i
->name
)) {
1588 /* We filled in the instance, and the target stayed the same? If so, then let's
1589 * honour the link as it is. */
1591 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1601 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1605 /* Try again, with the new target we found. */
1606 r
= unit_file_search(c
, i
, paths
, flags
);
1608 /* Translate error code to highlight this specific case */
1623 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1624 * or the name (otherwise). root_dir is prepended to the path.
1626 static int install_info_add_auto(
1628 const LookupPaths
*paths
,
1629 const char *name_or_path
,
1630 UnitFileInstallInfo
**ret
) {
1633 assert(name_or_path
);
1635 if (path_is_absolute(name_or_path
)) {
1638 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1640 return install_info_add(c
, NULL
, pp
, false, ret
);
1642 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1645 static int install_info_discover(
1646 UnitFileScope scope
,
1648 const LookupPaths
*paths
,
1651 UnitFileInstallInfo
**ret
,
1652 UnitFileChange
**changes
,
1653 size_t *n_changes
) {
1655 UnitFileInstallInfo
*i
;
1662 r
= install_info_add_auto(c
, paths
, name
, &i
);
1664 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1667 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1671 static int install_info_discover_and_check(
1672 UnitFileScope scope
,
1674 const LookupPaths
*paths
,
1677 UnitFileInstallInfo
**ret
,
1678 UnitFileChange
**changes
,
1679 size_t *n_changes
) {
1683 r
= install_info_discover(scope
, c
, paths
, name
, flags
, ret
, changes
, n_changes
);
1687 return install_info_may_process(ret
? *ret
: NULL
, paths
, changes
, n_changes
);
1690 static int install_info_symlink_alias(
1691 UnitFileInstallInfo
*i
,
1692 const LookupPaths
*paths
,
1693 const char *config_path
,
1695 UnitFileChange
**changes
,
1696 size_t *n_changes
) {
1703 assert(config_path
);
1705 STRV_FOREACH(s
, i
->aliases
) {
1706 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1708 q
= install_full_printf(i
, *s
, &dst
);
1712 alias_path
= path_make_absolute(dst
, config_path
);
1716 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1724 static int install_info_symlink_wants(
1725 UnitFileInstallInfo
*i
,
1726 const LookupPaths
*paths
,
1727 const char *config_path
,
1730 UnitFileChange
**changes
,
1731 size_t *n_changes
) {
1733 _cleanup_free_
char *buf
= NULL
;
1740 assert(config_path
);
1742 if (strv_isempty(list
))
1745 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1746 UnitFileInstallInfo instance
= {
1747 .type
= _UNIT_FILE_TYPE_INVALID
,
1749 _cleanup_free_
char *path
= NULL
;
1751 /* If this is a template, and we have no instance, don't do anything */
1752 if (!i
->default_instance
)
1755 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1759 instance
.name
= buf
;
1760 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1764 path
= TAKE_PTR(instance
.path
);
1766 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1767 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1775 STRV_FOREACH(s
, list
) {
1776 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1778 q
= install_full_printf(i
, *s
, &dst
);
1782 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1787 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1791 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1799 static int install_info_symlink_link(
1800 UnitFileInstallInfo
*i
,
1801 const LookupPaths
*paths
,
1802 const char *config_path
,
1804 UnitFileChange
**changes
,
1805 size_t *n_changes
) {
1807 _cleanup_free_
char *path
= NULL
;
1812 assert(config_path
);
1815 r
= in_search_path(paths
, i
->path
);
1821 path
= path_join(config_path
, i
->name
);
1825 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1828 static int install_info_apply(
1829 UnitFileInstallInfo
*i
,
1830 const LookupPaths
*paths
,
1831 const char *config_path
,
1833 UnitFileChange
**changes
,
1834 size_t *n_changes
) {
1840 assert(config_path
);
1842 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1845 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1847 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1851 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1855 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1856 /* Do not count links to the unit file towards the "carries_install_info" count */
1857 if (r
== 0 && q
< 0)
1863 static int install_context_apply(
1864 UnitFileScope scope
,
1866 const LookupPaths
*paths
,
1867 const char *config_path
,
1870 UnitFileChange
**changes
,
1871 size_t *n_changes
) {
1873 UnitFileInstallInfo
*i
;
1878 assert(config_path
);
1880 if (ordered_hashmap_isempty(c
->will_process
))
1883 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1888 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1891 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1895 q
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1897 unit_file_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
1901 /* We can attempt to process a masked unit when a different unit
1902 * that we were processing specifies it in Also=. */
1903 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1904 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1906 /* Assume that something *could* have been enabled here,
1907 * avoid "empty [Install] section" warning. */
1912 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1915 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1927 static int install_context_mark_for_removal(
1928 UnitFileScope scope
,
1930 const LookupPaths
*paths
,
1931 Set
**remove_symlinks_to
,
1932 const char *config_path
,
1933 UnitFileChange
**changes
,
1934 size_t *n_changes
) {
1936 UnitFileInstallInfo
*i
;
1941 assert(config_path
);
1943 /* Marks all items for removal */
1945 if (ordered_hashmap_isempty(c
->will_process
))
1948 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1952 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1954 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1958 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1959 if (r
== -ENOLINK
) {
1960 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1961 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1962 } else if (r
== -ENOENT
) {
1964 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1965 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1967 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1968 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1972 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1973 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1974 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1975 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1976 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1978 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1979 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1983 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1992 UnitFileScope scope
,
1993 UnitFileFlags flags
,
1994 const char *root_dir
,
1996 UnitFileChange
**changes
,
1997 size_t *n_changes
) {
1999 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2000 const char *config_path
;
2005 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2007 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2011 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2015 STRV_FOREACH(i
, files
) {
2016 _cleanup_free_
char *path
= NULL
;
2019 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2025 path
= path_make_absolute(*i
, config_path
);
2029 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2030 if (q
< 0 && r
>= 0)
2037 int unit_file_unmask(
2038 UnitFileScope scope
,
2039 UnitFileFlags flags
,
2040 const char *root_dir
,
2042 UnitFileChange
**changes
,
2043 size_t *n_changes
) {
2045 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2046 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2047 _cleanup_strv_free_
char **todo
= NULL
;
2048 size_t n_todo
= 0, n_allocated
= 0;
2049 const char *config_path
;
2055 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2057 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2061 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2065 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2067 STRV_FOREACH(i
, files
) {
2068 _cleanup_free_
char *path
= NULL
;
2070 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2073 path
= path_make_absolute(*i
, config_path
);
2077 r
= null_or_empty_path(path
);
2085 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2088 todo
[n_todo
] = strdup(*i
);
2098 STRV_FOREACH(i
, todo
) {
2099 _cleanup_free_
char *path
= NULL
;
2102 path
= path_make_absolute(*i
, config_path
);
2106 if (!dry_run
&& unlink(path
) < 0) {
2107 if (errno
!= ENOENT
) {
2110 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2116 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2118 rp
= skip_root(&paths
, path
);
2119 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2124 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2132 UnitFileScope scope
,
2133 UnitFileFlags flags
,
2134 const char *root_dir
,
2136 UnitFileChange
**changes
,
2137 size_t *n_changes
) {
2139 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2140 _cleanup_strv_free_
char **todo
= NULL
;
2141 size_t n_todo
= 0, n_allocated
= 0;
2142 const char *config_path
;
2147 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2149 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2153 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2157 STRV_FOREACH(i
, files
) {
2158 _cleanup_free_
char *full
= NULL
;
2162 if (!path_is_absolute(*i
))
2166 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2169 full
= path_join(paths
.root_dir
, *i
);
2173 if (lstat(full
, &st
) < 0)
2175 r
= stat_verify_regular(&st
);
2179 q
= in_search_path(&paths
, *i
);
2185 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2188 todo
[n_todo
] = strdup(*i
);
2198 STRV_FOREACH(i
, todo
) {
2199 _cleanup_free_
char *new_path
= NULL
;
2201 new_path
= path_make_absolute(basename(*i
), config_path
);
2205 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2206 if (q
< 0 && r
>= 0)
2213 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2219 /* Checks whether the path is one where the drop-in directories shall be removed. */
2221 r
= path_is_config(paths
, path
, true);
2225 r
= path_is_control(paths
, path
);
2229 return path_is_transient(paths
, path
);
2232 int unit_file_revert(
2233 UnitFileScope scope
,
2234 const char *root_dir
,
2236 UnitFileChange
**changes
,
2237 size_t *n_changes
) {
2239 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2240 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2241 _cleanup_strv_free_
char **todo
= NULL
;
2242 size_t n_todo
= 0, n_allocated
= 0;
2246 /* Puts a unit file back into vendor state. This means:
2248 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2249 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2251 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2252 * "config", but not in "transient" or "control" or even "generated").
2254 * We remove all that in both the runtime and the persistent directories, if that applies.
2257 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2261 STRV_FOREACH(i
, files
) {
2262 bool has_vendor
= false;
2265 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2268 STRV_FOREACH(p
, paths
.search_path
) {
2269 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2272 path
= path_make_absolute(*i
, *p
);
2276 r
= lstat(path
, &st
);
2278 if (errno
!= ENOENT
)
2280 } else if (S_ISREG(st
.st_mode
)) {
2281 /* Check if there's a vendor version */
2282 r
= path_is_vendor(&paths
, path
);
2289 dropin
= strjoin(path
, ".d");
2293 r
= lstat(dropin
, &st
);
2295 if (errno
!= ENOENT
)
2297 } else if (S_ISDIR(st
.st_mode
)) {
2298 /* Remove the drop-ins */
2299 r
= path_shall_revert(&paths
, dropin
);
2303 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2306 todo
[n_todo
++] = TAKE_PTR(dropin
);
2314 /* OK, there's a vendor version, hence drop all configuration versions */
2315 STRV_FOREACH(p
, paths
.search_path
) {
2316 _cleanup_free_
char *path
= NULL
;
2319 path
= path_make_absolute(*i
, *p
);
2323 r
= lstat(path
, &st
);
2325 if (errno
!= ENOENT
)
2327 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2328 r
= path_is_config(&paths
, path
, true);
2332 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2335 todo
[n_todo
++] = TAKE_PTR(path
);
2344 STRV_FOREACH(i
, todo
) {
2345 _cleanup_strv_free_
char **fs
= NULL
;
2349 (void) get_files_in_directory(*i
, &fs
);
2351 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2352 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2357 STRV_FOREACH(j
, fs
) {
2358 _cleanup_free_
char *t
= NULL
;
2360 t
= path_join(*i
, *j
);
2364 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2367 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2369 rp
= skip_root(&paths
, *i
);
2370 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2375 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2379 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2386 int unit_file_add_dependency(
2387 UnitFileScope scope
,
2388 UnitFileFlags flags
,
2389 const char *root_dir
,
2393 UnitFileChange
**changes
,
2394 size_t *n_changes
) {
2396 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2397 _cleanup_(install_context_done
) InstallContext c
= {};
2398 UnitFileInstallInfo
*i
, *target_info
;
2399 const char *config_path
;
2404 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2407 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2410 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2413 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2417 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2421 r
= install_info_discover_and_check(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2422 &target_info
, changes
, n_changes
);
2426 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2428 STRV_FOREACH(f
, files
) {
2431 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2432 &i
, 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
);
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_and_check(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2484 &i
, changes
, n_changes
);
2488 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2491 /* This will return the number of symlink rules that were
2492 supposed to be created, not the ones actually created. This
2493 is useful to determine whether the passed files had any
2494 installation data at all. */
2496 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2499 int unit_file_disable(
2500 UnitFileScope scope
,
2501 UnitFileFlags flags
,
2502 const char *root_dir
,
2504 UnitFileChange
**changes
,
2505 size_t *n_changes
) {
2507 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2508 _cleanup_(install_context_done
) InstallContext c
= {};
2509 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2510 const char *config_path
;
2515 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2517 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2521 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2525 STRV_FOREACH(i
, files
) {
2526 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2529 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2534 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2538 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2541 int unit_file_reenable(
2542 UnitFileScope scope
,
2543 UnitFileFlags flags
,
2544 const char *root_dir
,
2546 UnitFileChange
**changes
,
2547 size_t *n_changes
) {
2553 /* First, we invoke the disable command with only the basename... */
2554 l
= strv_length(files
);
2555 n
= newa(char*, l
+1);
2556 for (i
= 0; i
< l
; i
++)
2557 n
[i
] = basename(files
[i
]);
2560 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2564 /* But the enable command with the full name */
2565 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2568 int unit_file_set_default(
2569 UnitFileScope scope
,
2570 UnitFileFlags flags
,
2571 const char *root_dir
,
2573 UnitFileChange
**changes
,
2574 size_t *n_changes
) {
2576 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2577 _cleanup_(install_context_done
) InstallContext c
= {};
2578 UnitFileInstallInfo
*i
;
2579 const char *new_path
;
2583 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2586 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2588 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2591 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2595 r
= install_info_discover_and_check(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2599 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2600 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2603 int unit_file_get_default(
2604 UnitFileScope scope
,
2605 const char *root_dir
,
2608 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2609 _cleanup_(install_context_done
) InstallContext c
= {};
2610 UnitFileInstallInfo
*i
;
2615 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2618 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2622 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2626 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2630 n
= strdup(i
->name
);
2638 int unit_file_lookup_state(
2639 UnitFileScope scope
,
2640 const LookupPaths
*paths
,
2642 UnitFileState
*ret
) {
2644 _cleanup_(install_context_done
) InstallContext c
= {};
2645 UnitFileInstallInfo
*i
;
2646 UnitFileState state
;
2652 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2655 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2658 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2660 assert(IN_SET(i
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2661 log_debug("Found unit %s at %s (%s)", name
, strna(i
->path
),
2662 i
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2664 /* Shortcut things, if the caller just wants to know if this unit exists. */
2670 case UNIT_FILE_TYPE_MASKED
:
2671 r
= path_is_runtime(paths
, i
->path
, true);
2675 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2678 case UNIT_FILE_TYPE_REGULAR
:
2679 r
= path_is_generator(paths
, i
->path
);
2683 state
= UNIT_FILE_GENERATED
;
2687 r
= path_is_transient(paths
, i
->path
);
2691 state
= UNIT_FILE_TRANSIENT
;
2695 /* Check if any of the Alias= symlinks have been created.
2696 * We ignore other aliases, and only check those that would
2697 * be created by systemctl enable for this unit. */
2698 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2704 /* Check if the file is known under other names. If it is,
2705 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2706 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2710 state
= UNIT_FILE_INDIRECT
;
2712 if (unit_file_install_info_has_rules(i
))
2713 state
= UNIT_FILE_DISABLED
;
2714 else if (unit_file_install_info_has_also(i
))
2715 state
= UNIT_FILE_INDIRECT
;
2717 state
= UNIT_FILE_STATIC
;
2723 assert_not_reached("Unexpected unit file type.");
2730 int unit_file_get_state(
2731 UnitFileScope scope
,
2732 const char *root_dir
,
2734 UnitFileState
*ret
) {
2736 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2740 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2743 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2747 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2750 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2751 _cleanup_(install_context_done
) InstallContext c
= {};
2757 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2760 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2769 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2770 _cleanup_strv_free_
char **instances
= NULL
;
2771 _cleanup_free_
char *unit_name
= NULL
;
2775 assert(out_instances
);
2776 assert(out_unit_name
);
2778 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
2782 /* We handle the instances logic when unit name is extracted */
2784 /* We only create instances when a rule of templated unit
2785 * is seen. A rule like enable foo@.service a b c will
2786 * result in an array of (a, b, c) as instance names */
2787 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2790 instances
= strv_split(pattern
, WHITESPACE
);
2794 *out_instances
= TAKE_PTR(instances
);
2797 *out_unit_name
= TAKE_PTR(unit_name
);
2802 static int presets_find_config(UnitFileScope scope
, const char *root_dir
, char ***files
) {
2803 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
2804 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
2805 const char* const* dirs
;
2808 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2810 if (scope
== UNIT_FILE_SYSTEM
)
2812 else if (IN_SET(scope
, UNIT_FILE_GLOBAL
, UNIT_FILE_USER
))
2815 assert_not_reached("Invalid unit file scope");
2817 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
2820 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2821 _cleanup_(presets_freep
) Presets ps
= {};
2822 size_t n_allocated
= 0;
2823 _cleanup_strv_free_
char **files
= NULL
;
2828 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2831 r
= presets_find_config(scope
, root_dir
, &files
);
2835 STRV_FOREACH(p
, files
) {
2836 _cleanup_fclose_
FILE *f
;
2839 f
= fopen(*p
, "re");
2841 if (errno
== ENOENT
)
2848 _cleanup_free_
char *line
= NULL
;
2849 PresetRule rule
= {};
2850 const char *parameter
;
2853 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2864 if (strchr(COMMENTS
, *l
))
2867 parameter
= first_word(l
, "enable");
2870 char **instances
= NULL
;
2872 /* Unit_name will remain the same as parameter when no instances are specified */
2873 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2875 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2879 rule
= (PresetRule
) {
2880 .pattern
= unit_name
,
2881 .action
= PRESET_ENABLE
,
2882 .instances
= instances
,
2886 parameter
= first_word(l
, "disable");
2890 pattern
= strdup(parameter
);
2894 rule
= (PresetRule
) {
2896 .action
= PRESET_DISABLE
,
2901 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2904 ps
.rules
[ps
.n_rules
++] = rule
;
2908 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2918 static int pattern_match_multiple_instances(
2919 const PresetRule rule
,
2920 const char *unit_name
,
2923 _cleanup_free_
char *templated_name
= NULL
;
2926 /* If no ret is needed or the rule itself does not have instances
2927 * initialized, we return not matching */
2928 if (!ret
|| !rule
.instances
)
2931 r
= unit_name_template(unit_name
, &templated_name
);
2934 if (!streq(rule
.pattern
, templated_name
))
2937 /* Compose a list of specified instances when unit name is a template */
2938 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
2939 _cleanup_free_
char *prefix
= NULL
;
2940 _cleanup_strv_free_
char **out_strv
= NULL
;
2943 r
= unit_name_to_prefix(unit_name
, &prefix
);
2947 STRV_FOREACH(iter
, rule
.instances
) {
2948 _cleanup_free_
char *name
= NULL
;
2949 r
= unit_name_build(prefix
, *iter
, ".service", &name
);
2952 r
= strv_extend(&out_strv
, name
);
2957 *ret
= TAKE_PTR(out_strv
);
2960 /* We now know the input unit name is an instance name */
2961 _cleanup_free_
char *instance_name
= NULL
;
2963 r
= unit_name_to_instance(unit_name
, &instance_name
);
2967 if (strv_find(rule
.instances
, instance_name
))
2973 static int query_presets(const char *name
, const Presets presets
, char ***instance_name_list
) {
2974 PresetAction action
= PRESET_UNKNOWN
;
2977 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2980 for (i
= 0; i
< presets
.n_rules
; i
++)
2981 if (pattern_match_multiple_instances(presets
.rules
[i
], name
, instance_name_list
) > 0 ||
2982 fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2983 action
= presets
.rules
[i
].action
;
2988 case PRESET_UNKNOWN
:
2989 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2992 if (instance_name_list
&& *instance_name_list
)
2993 STRV_FOREACH(s
, *instance_name_list
)
2994 log_debug("Preset files say enable %s.", *s
);
2996 log_debug("Preset files say enable %s.", name
);
2998 case PRESET_DISABLE
:
2999 log_debug("Preset files say disable %s.", name
);
3002 assert_not_reached("invalid preset action");
3006 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
3007 _cleanup_(presets_freep
) Presets presets
= {};
3010 r
= read_presets(scope
, root_dir
, &presets
);
3014 return query_presets(name
, presets
, NULL
);
3017 static int execute_preset(
3018 UnitFileScope scope
,
3019 InstallContext
*plus
,
3020 InstallContext
*minus
,
3021 const LookupPaths
*paths
,
3022 const char *config_path
,
3024 UnitFilePresetMode mode
,
3026 UnitFileChange
**changes
,
3027 size_t *n_changes
) {
3034 assert(config_path
);
3036 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3037 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3039 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3043 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
3047 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3050 /* Returns number of symlinks that where supposed to be installed. */
3051 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
3063 static int preset_prepare_one(
3064 UnitFileScope scope
,
3065 InstallContext
*plus
,
3066 InstallContext
*minus
,
3070 UnitFileChange
**changes
,
3071 size_t *n_changes
) {
3073 _cleanup_(install_context_done
) InstallContext tmp
= {};
3074 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3075 UnitFileInstallInfo
*i
;
3078 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3081 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3082 &i
, changes
, n_changes
);
3085 if (!streq(name
, i
->name
)) {
3086 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3090 r
= query_presets(name
, presets
, &instance_name_list
);
3095 if (instance_name_list
) {
3097 STRV_FOREACH(s
, instance_name_list
) {
3098 r
= install_info_discover_and_check(scope
, plus
, paths
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3099 &i
, changes
, n_changes
);
3104 r
= install_info_discover_and_check(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3105 &i
, changes
, n_changes
);
3111 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3112 &i
, changes
, n_changes
);
3117 int unit_file_preset(
3118 UnitFileScope scope
,
3119 UnitFileFlags flags
,
3120 const char *root_dir
,
3122 UnitFilePresetMode mode
,
3123 UnitFileChange
**changes
,
3124 size_t *n_changes
) {
3126 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3127 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3128 _cleanup_(presets_freep
) Presets presets
= {};
3129 const char *config_path
;
3134 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3135 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3137 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3141 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3145 r
= read_presets(scope
, root_dir
, &presets
);
3149 STRV_FOREACH(i
, files
) {
3150 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3155 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3158 int unit_file_preset_all(
3159 UnitFileScope scope
,
3160 UnitFileFlags flags
,
3161 const char *root_dir
,
3162 UnitFilePresetMode mode
,
3163 UnitFileChange
**changes
,
3164 size_t *n_changes
) {
3166 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3167 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3168 _cleanup_(presets_freep
) Presets presets
= {};
3169 const char *config_path
= NULL
;
3174 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3175 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3177 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3181 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3185 r
= read_presets(scope
, root_dir
, &presets
);
3189 STRV_FOREACH(i
, paths
.search_path
) {
3190 _cleanup_closedir_
DIR *d
= NULL
;
3195 if (errno
== ENOENT
)
3201 FOREACH_DIRENT(de
, d
, return -errno
) {
3203 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3206 dirent_ensure_type(d
, de
);
3208 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3211 /* we don't pass changes[] in, because we want to handle errors on our own */
3212 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3214 r
= unit_file_changes_add(changes
, n_changes
,
3215 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3216 else if (r
== -ENOLINK
)
3217 r
= unit_file_changes_add(changes
, n_changes
,
3218 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3219 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3226 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3229 static void unit_file_list_free_one(UnitFileList
*f
) {
3237 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3238 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3241 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3243 int unit_file_get_list(
3244 UnitFileScope scope
,
3245 const char *root_dir
,
3250 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3255 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3258 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3262 STRV_FOREACH(i
, paths
.search_path
) {
3263 _cleanup_closedir_
DIR *d
= NULL
;
3268 if (errno
== ENOENT
)
3270 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3271 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3278 FOREACH_DIRENT(de
, d
, return -errno
) {
3279 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3281 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3284 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3287 if (hashmap_get(h
, de
->d_name
))
3290 dirent_ensure_type(d
, de
);
3292 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3295 f
= new0(UnitFileList
, 1);
3299 f
->path
= path_make_absolute(de
->d_name
, *i
);
3303 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3305 f
->state
= UNIT_FILE_BAD
;
3307 if (!strv_isempty(states
) &&
3308 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3311 r
= hashmap_put(h
, basename(f
->path
), f
);
3315 f
= NULL
; /* prevent cleanup */
3322 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3323 [UNIT_FILE_ENABLED
] = "enabled",
3324 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3325 [UNIT_FILE_LINKED
] = "linked",
3326 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3327 [UNIT_FILE_MASKED
] = "masked",
3328 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3329 [UNIT_FILE_STATIC
] = "static",
3330 [UNIT_FILE_DISABLED
] = "disabled",
3331 [UNIT_FILE_INDIRECT
] = "indirect",
3332 [UNIT_FILE_GENERATED
] = "generated",
3333 [UNIT_FILE_TRANSIENT
] = "transient",
3334 [UNIT_FILE_BAD
] = "bad",
3337 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3339 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3340 [UNIT_FILE_SYMLINK
] = "symlink",
3341 [UNIT_FILE_UNLINK
] = "unlink",
3342 [UNIT_FILE_IS_MASKED
] = "masked",
3343 [UNIT_FILE_IS_DANGLING
] = "dangling",
3346 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3348 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3349 [UNIT_FILE_PRESET_FULL
] = "full",
3350 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3351 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3354 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);