1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
12 #include "alloc-util.h"
13 #include "chase-symlinks.h"
14 #include "conf-files.h"
15 #include "conf-parser.h"
17 #include "dirent-util.h"
18 #include "errno-list.h"
19 #include "extract-word.h"
24 #include "install-printf.h"
26 #include "locale-util.h"
29 #include "mkdir-label.h"
30 #include "path-lookup.h"
31 #include "path-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
39 #include "unit-file.h"
41 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
43 typedef enum SearchFlags
{
45 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
46 SEARCH_DROPIN
= 1 << 2,
51 OrderedHashmap
*will_process
;
52 OrderedHashmap
*have_processed
;
61 struct UnitFilePresetRule
{
67 static bool unit_file_install_info_has_rules(const UnitFileInstallInfo
*i
) {
70 return !strv_isempty(i
->aliases
) ||
71 !strv_isempty(i
->wanted_by
) ||
72 !strv_isempty(i
->required_by
);
75 static bool unit_file_install_info_has_also(const UnitFileInstallInfo
*i
) {
78 return !strv_isempty(i
->also
);
81 void unit_file_presets_freep(UnitFilePresets
*p
) {
85 for (size_t i
= 0; i
< p
->n_rules
; i
++) {
86 free(p
->rules
[i
].pattern
);
87 strv_free(p
->rules
[i
].instances
);
94 static const char *const unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
95 [UNIT_FILE_TYPE_REGULAR
] = "regular",
96 [UNIT_FILE_TYPE_LINKED
] = "linked",
97 [UNIT_FILE_TYPE_ALIAS
] = "alias",
98 [UNIT_FILE_TYPE_MASKED
] = "masked",
101 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
103 static int in_search_path(const LookupPaths
*lp
, const char *path
) {
104 _cleanup_free_
char *parent
= NULL
;
108 parent
= dirname_malloc(path
);
112 return path_strv_contains(lp
->search_path
, parent
);
115 static const char* skip_root(const char *root_dir
, const char *path
) {
121 const char *e
= path_startswith(path
, root_dir
);
125 /* Make sure the returned path starts with a slash */
127 if (e
== path
|| e
[-1] != '/')
136 static int path_is_generator(const LookupPaths
*lp
, const char *path
) {
137 _cleanup_free_
char *parent
= NULL
;
142 parent
= dirname_malloc(path
);
146 return path_equal_ptr(parent
, lp
->generator
) ||
147 path_equal_ptr(parent
, lp
->generator_early
) ||
148 path_equal_ptr(parent
, lp
->generator_late
);
151 static int path_is_transient(const LookupPaths
*lp
, const char *path
) {
152 _cleanup_free_
char *parent
= NULL
;
157 parent
= dirname_malloc(path
);
161 return path_equal_ptr(parent
, lp
->transient
);
164 static int path_is_control(const LookupPaths
*lp
, const char *path
) {
165 _cleanup_free_
char *parent
= NULL
;
170 parent
= dirname_malloc(path
);
174 return path_equal_ptr(parent
, lp
->persistent_control
) ||
175 path_equal_ptr(parent
, lp
->runtime_control
);
178 static int path_is_config(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
179 _cleanup_free_
char *parent
= NULL
;
184 /* Note that we do *not* have generic checks for /etc or /run in place, since with
185 * them we couldn't discern configuration from transient or generated units */
188 parent
= dirname_malloc(path
);
195 return path_equal_ptr(path
, lp
->persistent_config
) ||
196 path_equal_ptr(path
, lp
->runtime_config
);
199 static int path_is_runtime(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
200 _cleanup_free_
char *parent
= NULL
;
206 /* Everything in /run is considered runtime. On top of that we also add
207 * explicit checks for the various runtime directories, as safety net. */
209 rpath
= skip_root(lp
->root_dir
, path
);
210 if (rpath
&& path_startswith(rpath
, "/run"))
214 parent
= dirname_malloc(path
);
221 return path_equal_ptr(path
, lp
->runtime_config
) ||
222 path_equal_ptr(path
, lp
->generator
) ||
223 path_equal_ptr(path
, lp
->generator_early
) ||
224 path_equal_ptr(path
, lp
->generator_late
) ||
225 path_equal_ptr(path
, lp
->transient
) ||
226 path_equal_ptr(path
, lp
->runtime_control
);
229 static int path_is_vendor_or_generator(const LookupPaths
*lp
, const char *path
) {
235 rpath
= skip_root(lp
->root_dir
, path
);
239 if (path_startswith(rpath
, "/usr"))
243 if (path_startswith(rpath
, "/lib"))
247 if (path_is_generator(lp
, rpath
))
250 return path_equal(rpath
, SYSTEM_DATA_UNIT_DIR
);
253 static const char* config_path_from_flags(const LookupPaths
*lp
, UnitFileFlags flags
) {
256 if (FLAGS_SET(flags
, UNIT_FILE_PORTABLE
))
257 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_attached
: lp
->persistent_attached
;
259 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_config
: lp
->persistent_config
;
262 int unit_file_changes_add(
263 UnitFileChange
**changes
,
265 int type_or_errno
, /* UNIT_FILE_SYMLINK, _UNLINK, _IS_MASKED, _IS_DANGLING if positive or errno if negative */
267 const char *source
) {
269 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
272 assert(!changes
== !n_changes
);
274 if (type_or_errno
>= 0)
275 assert(type_or_errno
< _UNIT_FILE_CHANGE_TYPE_MAX
);
277 assert(type_or_errno
>= -ERRNO_MAX
);
282 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
303 c
[(*n_changes
)++] = (UnitFileChange
) {
304 .type_or_errno
= type_or_errno
,
306 .source
= TAKE_PTR(s
),
312 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
313 assert(changes
|| n_changes
== 0);
315 for (size_t i
= 0; i
< n_changes
; i
++) {
316 free(changes
[i
].path
);
317 free(changes
[i
].source
);
323 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
326 assert(changes
|| n_changes
== 0);
327 /* If verb is not specified, errors are not allowed! */
328 assert(verb
|| r
>= 0);
330 for (size_t i
= 0; i
< n_changes
; i
++) {
331 assert(verb
|| changes
[i
].type_or_errno
>= 0);
333 switch (changes
[i
].type_or_errno
) {
334 case UNIT_FILE_SYMLINK
:
336 log_info("Created symlink %s %s %s.",
338 special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
),
341 case UNIT_FILE_UNLINK
:
343 log_info("Removed \"%s\".", changes
[i
].path
);
345 case UNIT_FILE_IS_MASKED
:
347 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
349 case UNIT_FILE_IS_DANGLING
:
351 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
354 case UNIT_FILE_DESTINATION_NOT_PRESENT
:
356 log_warning("Unit %s is added as a dependency to a non-existent unit %s.",
357 changes
[i
].source
, changes
[i
].path
);
359 case UNIT_FILE_AUXILIARY_FAILED
:
361 log_warning("Failed to enable auxiliary unit %s, ignoring.", changes
[i
].source
);
364 if (changes
[i
].source
)
365 err
= log_error_errno(changes
[i
].type_or_errno
,
366 "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".",
367 verb
, changes
[i
].path
, changes
[i
].source
);
369 err
= log_error_errno(changes
[i
].type_or_errno
,
370 "Failed to %s unit, file \"%s\" already exists.",
371 verb
, changes
[i
].path
);
374 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is masked.",
375 verb
, changes
[i
].path
);
378 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is transient or generated.",
379 verb
, changes
[i
].path
);
382 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid specifier in \"%s\".",
383 verb
, changes
[i
].path
);
386 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s %s, destination unit %s is a non-template unit.",
387 verb
, changes
[i
].source
, changes
[i
].path
);
390 err
= log_error_errno(changes
[i
].type_or_errno
,
391 "Failed to %s unit, \"%s\" is not a valid unit name.",
392 verb
, changes
[i
].path
);
395 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, refusing to operate on linked unit file %s.",
396 verb
, changes
[i
].path
);
399 if (changes
[i
].source
)
400 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot alias %s as %s.",
401 verb
, changes
[i
].source
, changes
[i
].path
);
403 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid unit reference \"%s\".",
404 verb
, changes
[i
].path
);
407 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s does not exist.",
408 verb
, changes
[i
].path
);
411 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot resolve specifiers in \"%s\".",
412 verb
, changes
[i
].path
);
415 assert(changes
[i
].type_or_errno
< 0);
416 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, file \"%s\": %m",
417 verb
, changes
[i
].path
);
421 if (r
< 0 && err
>= 0)
422 log_error_errno(r
, "Failed to %s: %m.", verb
);
426 * Checks if two symlink targets (starting from src) are equivalent as far as the unit enablement logic is
427 * concerned. If the target is in the unit search path, then anything with the same name is equivalent.
428 * If outside the unit search path, paths must be identical.
430 static int chroot_unit_symlinks_equivalent(
431 const LookupPaths
*lp
,
433 const char *target_a
,
434 const char *target_b
) {
441 /* This will give incorrect results if the paths are relative and go outside
442 * of the chroot. False negatives are possible. */
444 const char *root
= lp
->root_dir
?: "/";
445 _cleanup_free_
char *dirname
= NULL
;
448 if (!path_is_absolute(target_a
) || !path_is_absolute(target_b
)) {
449 r
= path_extract_directory(src
, &dirname
);
454 _cleanup_free_
char *a
= path_join(path_is_absolute(target_a
) ? root
: dirname
, target_a
);
455 _cleanup_free_
char *b
= path_join(path_is_absolute(target_b
) ? root
: dirname
, target_b
);
459 r
= path_equal_or_files_same(a
, b
, 0);
463 _cleanup_free_
char *a_name
= NULL
, *b_name
= NULL
;
464 r
= path_extract_filename(a
, &a_name
);
467 r
= path_extract_filename(b
, &b_name
);
471 return streq(a_name
, b_name
) &&
472 path_startswith_strv(a
, lp
->search_path
) &&
473 path_startswith_strv(b
, lp
->search_path
);
476 static int create_symlink(
477 const LookupPaths
*lp
,
478 const char *old_path
,
479 const char *new_path
,
481 UnitFileChange
**changes
,
484 _cleanup_free_
char *dest
= NULL
;
491 rp
= skip_root(lp
->root_dir
, old_path
);
495 /* Actually create a symlink, and remember that we did. This function is
496 * smart enough to check if there's already a valid symlink in place.
498 * Returns 1 if a symlink was created or already exists and points to the
499 * right place, or negative on error.
502 (void) mkdir_parents_label(new_path
, 0755);
504 if (symlink(old_path
, new_path
) >= 0) {
505 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
509 if (errno
!= EEXIST
) {
510 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
514 r
= readlink_malloc(new_path
, &dest
);
516 /* translate EINVAL (non-symlink exists) to EEXIST */
520 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
524 if (chroot_unit_symlinks_equivalent(lp
, new_path
, dest
, old_path
)) {
525 log_debug("Symlink %s %s %s already exists",
526 new_path
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
), dest
);
531 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
535 r
= symlink_atomic(old_path
, new_path
);
537 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
541 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
542 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
547 static int mark_symlink_for_removal(
548 Set
**remove_symlinks_to
,
556 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
566 r
= set_consume(*remove_symlinks_to
, n
);
575 static int remove_marked_symlinks_fd(
576 Set
*remove_symlinks_to
,
579 const char *config_path
,
580 const LookupPaths
*lp
,
583 UnitFileChange
**changes
,
586 _cleanup_closedir_
DIR *d
= NULL
;
589 assert(remove_symlinks_to
);
604 FOREACH_DIRENT(de
, d
, return -errno
)
606 if (de
->d_type
== DT_DIR
) {
607 _cleanup_free_
char *p
= NULL
;
610 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
620 p
= path_make_absolute(de
->d_name
, path
);
626 /* This will close nfd, regardless whether it succeeds or not */
627 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
631 } else if (de
->d_type
== DT_LNK
) {
632 _cleanup_free_
char *p
= NULL
;
636 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
639 p
= path_make_absolute(de
->d_name
, path
);
644 /* We remove all links pointing to a file or path that is marked, as well as all
645 * files sharing the same name as a file that is marked, and files sharing the same
646 * name after the instance has been removed. Do path chasing only if we don't already
647 * know that we want to remove the symlink. */
648 found
= set_contains(remove_symlinks_to
, de
->d_name
);
651 _cleanup_free_
char *template = NULL
;
653 q
= unit_name_template(de
->d_name
, &template);
654 if (q
< 0 && q
!= -EINVAL
)
657 found
= set_contains(remove_symlinks_to
, template);
661 _cleanup_free_
char *dest
= NULL
;
663 q
= chase_symlinks(p
, lp
->root_dir
, CHASE_NONEXISTENT
, &dest
, NULL
);
667 log_debug_errno(q
, "Failed to resolve symlink \"%s\": %m", p
);
668 unit_file_changes_add(changes
, n_changes
, q
, p
, NULL
);
675 found
= set_contains(remove_symlinks_to
, dest
) ||
676 set_contains(remove_symlinks_to
, basename(dest
));
685 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
688 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
692 (void) rmdir_parents(p
, config_path
);
695 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
697 /* Now, remember the full path (but with the root prefix removed) of
698 * the symlink we just removed, and remove any symlinks to it, too. */
700 const char *rp
= skip_root(lp
->root_dir
, p
);
701 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
704 if (q
> 0 && !dry_run
)
711 static int remove_marked_symlinks(
712 Set
*remove_symlinks_to
,
713 const char *config_path
,
714 const LookupPaths
*lp
,
716 UnitFileChange
**changes
,
719 _cleanup_close_
int fd
= -1;
726 if (set_size(remove_symlinks_to
) <= 0)
729 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
731 return errno
== ENOENT
? 0 : -errno
;
737 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
741 /* This takes possession of cfd and closes it */
742 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
750 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
753 if (streq(name
, i
->name
))
756 if (strv_contains(i
->aliases
, name
))
759 /* Look for template symlink matching DefaultInstance */
760 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
761 _cleanup_free_
char *s
= NULL
;
763 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
768 } else if (streq(name
, s
))
775 static int find_symlinks_in_directory(
777 const char *dir_path
,
778 const char *root_dir
,
779 const UnitFileInstallInfo
*info
,
780 bool ignore_destination
,
782 bool ignore_same_name
,
783 const char *config_path
,
784 bool *same_name_link
) {
788 FOREACH_DIRENT(de
, dir
, return -errno
) {
789 bool found_path
= false, found_dest
= false, b
= false;
792 if (de
->d_type
!= DT_LNK
)
795 if (!ignore_destination
) {
796 _cleanup_free_
char *dest
= NULL
;
798 /* Acquire symlink destination */
799 q
= readlinkat_malloc(dirfd(dir
), de
->d_name
, &dest
);
809 if (!path_is_absolute(dest
)) {
812 x
= path_join(dir_path
, dest
);
816 free_and_replace(dest
, x
);
819 /* Check if what the symlink points to matches what we are looking for */
820 found_dest
= streq(basename(dest
), info
->name
);
823 assert(unit_name_is_valid(info
->name
, UNIT_NAME_ANY
));
825 /* Check if the symlink itself matches what we are looking for.
827 * If ignore_destination is specified, we only look at the source name.
829 * If ignore_same_name is specified, we are in one of the directories which
830 * have lower priority than the unit file, and even if a file or symlink with
831 * this name was found, we should ignore it. */
833 if (ignore_destination
|| !ignore_same_name
)
834 found_path
= streq(de
->d_name
, info
->name
);
836 if (!found_path
&& ignore_destination
) {
837 _cleanup_free_
char *template = NULL
;
839 q
= unit_name_template(de
->d_name
, &template);
840 if (q
< 0 && q
!= -EINVAL
)
843 found_dest
= streq(template, info
->name
);
846 if (found_path
&& found_dest
) {
847 _cleanup_free_
char *p
= NULL
, *t
= NULL
;
849 /* Filter out same name links in the main config path */
850 p
= path_make_absolute(de
->d_name
, dir_path
);
851 t
= path_make_absolute(info
->name
, config_path
);
856 b
= path_equal(p
, t
);
860 *same_name_link
= true;
861 else if (found_path
|| found_dest
) {
865 /* Check if symlink name is in the set of names used by [Install] */
866 q
= is_symlink_with_known_name(info
, de
->d_name
);
877 static int find_symlinks(
878 const char *root_dir
,
879 const UnitFileInstallInfo
*i
,
881 bool ignore_same_name
,
882 const char *config_path
,
883 bool *same_name_link
) {
885 _cleanup_closedir_
DIR *config_dir
= NULL
;
890 assert(same_name_link
);
892 config_dir
= opendir(config_path
);
894 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
899 FOREACH_DIRENT(de
, config_dir
, return -errno
) {
901 _cleanup_free_
const char *path
= NULL
;
902 _cleanup_closedir_
DIR *d
= NULL
;
904 if (de
->d_type
!= DT_DIR
)
907 suffix
= strrchr(de
->d_name
, '.');
908 if (!STRPTR_IN_SET(suffix
, ".wants", ".requires"))
911 path
= path_join(config_path
, de
->d_name
);
917 log_error_errno(errno
, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path
);
921 r
= find_symlinks_in_directory(d
, path
, root_dir
, i
,
922 /* ignore_destination= */ true,
923 /* match_name= */ match_name
,
924 /* ignore_same_name= */ ignore_same_name
,
930 log_debug_errno(r
, "Failed to look up symlinks in \"%s\": %m", path
);
933 /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
934 rewinddir(config_dir
);
935 return find_symlinks_in_directory(config_dir
, config_path
, root_dir
, i
,
936 /* ignore_destination= */ false,
937 /* match_name= */ match_name
,
938 /* ignore_same_name= */ ignore_same_name
,
943 static int find_symlinks_in_scope(
945 const LookupPaths
*lp
,
946 const UnitFileInstallInfo
*info
,
948 UnitFileState
*state
) {
950 bool same_name_link_runtime
= false, same_name_link_config
= false;
951 bool enabled_in_runtime
= false, enabled_at_all
= false;
952 bool ignore_same_name
= false;
958 /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name"
959 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
960 * effectively masked, so we should ignore them. */
962 STRV_FOREACH(p
, lp
->search_path
) {
963 bool same_name_link
= false;
965 r
= find_symlinks(lp
->root_dir
, info
, match_name
, ignore_same_name
, *p
, &same_name_link
);
969 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
971 if (path_equal_ptr(*p
, lp
->persistent_config
)) {
972 /* This is the best outcome, let's return it immediately. */
973 *state
= UNIT_FILE_ENABLED
;
977 /* look for global enablement of user units */
978 if (scope
== LOOKUP_SCOPE_USER
&& path_is_user_config_dir(*p
)) {
979 *state
= UNIT_FILE_ENABLED
;
983 r
= path_is_runtime(lp
, *p
, false);
987 enabled_in_runtime
= true;
989 enabled_at_all
= true;
991 } else if (same_name_link
) {
992 if (path_equal_ptr(*p
, lp
->persistent_config
))
993 same_name_link_config
= true;
995 r
= path_is_runtime(lp
, *p
, false);
999 same_name_link_runtime
= true;
1003 /* Check if next iteration will be "below" the unit file (either a regular file
1004 * or a symlink), and hence should be ignored */
1005 if (!ignore_same_name
&& path_startswith(info
->path
, *p
))
1006 ignore_same_name
= true;
1009 if (enabled_in_runtime
) {
1010 *state
= UNIT_FILE_ENABLED_RUNTIME
;
1014 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
1015 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
1016 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
1017 * something, and hence are a much stronger concept. */
1018 if (enabled_at_all
&& unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1019 *state
= UNIT_FILE_STATIC
;
1023 /* Hmm, we didn't find it, but maybe we found the same name
1025 if (same_name_link_config
) {
1026 *state
= UNIT_FILE_LINKED
;
1029 if (same_name_link_runtime
) {
1030 *state
= UNIT_FILE_LINKED_RUNTIME
;
1037 static void install_info_free(UnitFileInstallInfo
*i
) {
1044 strv_free(i
->aliases
);
1045 strv_free(i
->wanted_by
);
1046 strv_free(i
->required_by
);
1048 free(i
->default_instance
);
1049 free(i
->symlink_target
);
1053 static void install_context_done(InstallContext
*ctx
) {
1056 ctx
->will_process
= ordered_hashmap_free_with_destructor(ctx
->will_process
, install_info_free
);
1057 ctx
->have_processed
= ordered_hashmap_free_with_destructor(ctx
->have_processed
, install_info_free
);
1060 static UnitFileInstallInfo
*install_info_find(InstallContext
*ctx
, const char *name
) {
1061 UnitFileInstallInfo
*i
;
1063 i
= ordered_hashmap_get(ctx
->have_processed
, name
);
1067 return ordered_hashmap_get(ctx
->will_process
, name
);
1070 static int install_info_may_process(
1071 const UnitFileInstallInfo
*i
,
1072 const LookupPaths
*lp
,
1073 UnitFileChange
**changes
,
1074 size_t *n_changes
) {
1078 /* Checks whether the loaded unit file is one we should process, or is masked,
1079 * transient or generated and thus not subject to enable/disable operations. */
1081 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1082 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1085 if (path_is_generator(lp
, i
->path
) ||
1086 path_is_transient(lp
, i
->path
)) {
1087 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1088 return -EADDRNOTAVAIL
;
1095 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1096 * hashmap, or retrieves the existing one if already present.
1098 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1100 static int install_info_add(
1101 InstallContext
*ctx
,
1106 UnitFileInstallInfo
**ret
) {
1108 UnitFileInstallInfo
*i
= NULL
;
1114 /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
1115 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
1116 * but this cannot be possible in any code path (See #6119). */
1118 name
= basename(path
);
1121 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1124 i
= install_info_find(ctx
, name
);
1126 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1133 i
= new(UnitFileInstallInfo
, 1);
1137 *i
= (UnitFileInstallInfo
) {
1138 .type
= _UNIT_FILE_TYPE_INVALID
,
1139 .auxiliary
= auxiliary
,
1142 i
->name
= strdup(name
);
1149 i
->root
= strdup(root
);
1157 i
->path
= strdup(path
);
1164 r
= ordered_hashmap_ensure_put(&ctx
->will_process
, &string_hash_ops
, i
->name
, i
);
1174 install_info_free(i
);
1178 static int config_parse_alias(
1180 const char *filename
,
1182 const char *section
,
1183 unsigned section_line
,
1197 type
= unit_name_to_type(unit
);
1198 if (!unit_type_may_alias(type
))
1199 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1200 "Alias= is not allowed for %s units, ignoring.",
1201 unit_type_to_string(type
));
1203 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1204 lvalue
, ltype
, rvalue
, data
, userdata
);
1207 static int config_parse_also(
1209 const char *filename
,
1211 const char *section
,
1212 unsigned section_line
,
1219 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1220 InstallContext
*ctx
= ASSERT_PTR(data
);
1229 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1231 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1237 r
= install_name_printf(ctx
->scope
, info
, word
, &printed
);
1239 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1240 "Failed to resolve unit name in Also=\"%s\": %m", word
);
1242 r
= install_info_add(ctx
, printed
, NULL
, info
->root
, /* auxiliary= */ true, NULL
);
1246 r
= strv_push(&info
->also
, printed
);
1256 static int config_parse_default_instance(
1258 const char *filename
,
1260 const char *section
,
1261 unsigned section_line
,
1268 InstallContext
*ctx
= ASSERT_PTR(data
);
1269 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1270 _cleanup_free_
char *printed
= NULL
;
1278 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1279 /* When enabling an instance, we might be using a template unit file,
1280 * but we should ignore DefaultInstance silently. */
1282 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1283 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1284 "DefaultInstance= only makes sense for template units, ignoring.");
1286 r
= install_name_printf(ctx
->scope
, info
, rvalue
, &printed
);
1288 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1289 "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue
);
1291 if (isempty(printed
))
1292 printed
= mfree(printed
);
1294 if (printed
&& !unit_instance_is_valid(printed
))
1295 return log_syntax(unit
, LOG_WARNING
, filename
, line
, SYNTHETIC_ERRNO(EINVAL
),
1296 "Invalid DefaultInstance= value \"%s\".", printed
);
1298 return free_and_replace(info
->default_instance
, printed
);
1301 static int unit_file_load(
1302 InstallContext
*ctx
,
1303 UnitFileInstallInfo
*info
,
1305 const char *root_dir
,
1306 SearchFlags flags
) {
1308 const ConfigTableItem items
[] = {
1309 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1310 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1311 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1312 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1313 { "Install", "Also", config_parse_also
, 0, ctx
},
1318 _cleanup_fclose_
FILE *f
= NULL
;
1319 _cleanup_close_
int fd
= -1;
1326 if (!(flags
& SEARCH_DROPIN
)) {
1327 /* Loading or checking for the main unit file… */
1329 type
= unit_name_to_type(info
->name
);
1332 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1333 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1334 "%s: unit type %s cannot be templated, ignoring.", path
, unit_type_to_string(type
));
1336 if (!(flags
& SEARCH_LOAD
)) {
1337 if (lstat(path
, &st
) < 0)
1340 if (null_or_empty(&st
))
1341 info
->type
= UNIT_FILE_TYPE_MASKED
;
1342 else if (S_ISREG(st
.st_mode
))
1343 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1344 else if (S_ISLNK(st
.st_mode
))
1346 else if (S_ISDIR(st
.st_mode
))
1354 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1358 /* 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. */
1360 if (!(flags
& SEARCH_LOAD
))
1363 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1368 if (fstat(fd
, &st
) < 0)
1371 if (null_or_empty(&st
)) {
1372 if ((flags
& SEARCH_DROPIN
) == 0)
1373 info
->type
= UNIT_FILE_TYPE_MASKED
;
1378 r
= stat_verify_regular(&st
);
1382 f
= take_fdopen(&fd
, "r");
1386 /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1389 r
= config_parse(info
->name
, path
, f
,
1403 config_item_table_lookup
, items
,
1407 return log_debug_errno(r
, "Failed to parse \"%s\": %m", info
->name
);
1409 if ((flags
& SEARCH_DROPIN
) == 0)
1410 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1413 (int) strv_length(info
->aliases
) +
1414 (int) strv_length(info
->wanted_by
) +
1415 (int) strv_length(info
->required_by
);
1418 static int unit_file_load_or_readlink(
1419 InstallContext
*ctx
,
1420 UnitFileInstallInfo
*info
,
1422 const LookupPaths
*lp
,
1423 SearchFlags flags
) {
1426 r
= unit_file_load(ctx
, info
, path
, lp
->root_dir
, flags
);
1427 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1430 /* This is a symlink, let's read and verify it. */
1431 r
= unit_file_resolve_symlink(lp
->root_dir
, lp
->search_path
,
1432 NULL
, AT_FDCWD
, path
,
1433 true, &info
->symlink_target
);
1436 bool outside_search_path
= r
> 0;
1438 r
= null_or_empty_path_with_root(info
->symlink_target
, lp
->root_dir
);
1439 if (r
< 0 && r
!= -ENOENT
)
1440 return log_debug_errno(r
, "Failed to stat %s: %m", info
->symlink_target
);
1442 info
->type
= UNIT_FILE_TYPE_MASKED
;
1443 else if (outside_search_path
)
1444 info
->type
= UNIT_FILE_TYPE_LINKED
;
1446 info
->type
= UNIT_FILE_TYPE_ALIAS
;
1451 static int unit_file_search(
1452 InstallContext
*ctx
,
1453 UnitFileInstallInfo
*info
,
1454 const LookupPaths
*lp
,
1455 SearchFlags flags
) {
1457 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1458 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1459 _cleanup_free_
char *template = NULL
;
1460 bool found_unit
= false;
1466 /* Was this unit already loaded? */
1467 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1471 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1475 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1476 r
= unit_name_template(info
->name
, &template);
1481 STRV_FOREACH(p
, lp
->search_path
) {
1482 _cleanup_free_
char *path
= NULL
;
1484 path
= path_join(*p
, info
->name
);
1488 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1490 info
->path
= TAKE_PTR(path
);
1494 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1498 if (!found_unit
&& template) {
1500 /* Unit file doesn't exist, however instance
1501 * enablement was requested. We will check if it is
1502 * possible to load template unit file. */
1504 STRV_FOREACH(p
, lp
->search_path
) {
1505 _cleanup_free_
char *path
= NULL
;
1507 path
= path_join(*p
, template);
1511 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1513 info
->path
= TAKE_PTR(path
);
1517 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1523 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1524 "Cannot find unit %s%s%s.",
1525 info
->name
, template ? " or " : "", strempty(template));
1527 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1530 /* Search for drop-in directories */
1532 dropin_dir_name
= strjoina(info
->name
, ".d");
1533 STRV_FOREACH(p
, lp
->search_path
) {
1536 path
= path_join(*p
, dropin_dir_name
);
1540 r
= strv_consume(&dirs
, path
);
1546 dropin_template_dir_name
= strjoina(template, ".d");
1547 STRV_FOREACH(p
, lp
->search_path
) {
1550 path
= path_join(*p
, dropin_template_dir_name
);
1554 r
= strv_consume(&dirs
, path
);
1560 /* Load drop-in conf files */
1562 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1564 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1566 STRV_FOREACH(p
, files
) {
1567 r
= unit_file_load_or_readlink(ctx
, info
, *p
, lp
, flags
| SEARCH_DROPIN
);
1569 return log_debug_errno(r
, "Failed to load conf file \"%s\": %m", *p
);
1575 static int install_info_follow(
1576 InstallContext
*ctx
,
1577 UnitFileInstallInfo
*info
,
1578 const LookupPaths
*lp
,
1580 bool ignore_different_name
) {
1585 if (!IN_SET(info
->type
, UNIT_FILE_TYPE_ALIAS
, UNIT_FILE_TYPE_LINKED
))
1587 if (!info
->symlink_target
)
1590 /* If the basename doesn't match, the caller should add a complete new entry for this. */
1592 if (!ignore_different_name
&& !streq(basename(info
->symlink_target
), info
->name
))
1595 free_and_replace(info
->path
, info
->symlink_target
);
1596 info
->type
= _UNIT_FILE_TYPE_INVALID
;
1598 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1602 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1603 * target, maybe more than once. Propagate the instance name if present.
1605 static int install_info_traverse(
1606 InstallContext
*ctx
,
1607 const LookupPaths
*lp
,
1608 UnitFileInstallInfo
*start
,
1610 UnitFileInstallInfo
**ret
) {
1612 UnitFileInstallInfo
*i
;
1620 r
= unit_file_search(ctx
, start
, lp
, flags
);
1625 while (IN_SET(i
->type
, UNIT_FILE_TYPE_ALIAS
, UNIT_FILE_TYPE_LINKED
)) {
1626 /* Follow the symlink */
1628 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1631 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1632 r
= path_is_config(lp
, i
->path
, true);
1639 r
= install_info_follow(ctx
, i
, lp
, flags
,
1640 /* If linked, don't look at the target name */
1641 /* ignore_different_name= */ i
->type
== UNIT_FILE_TYPE_LINKED
);
1643 _cleanup_free_
char *buffer
= NULL
;
1646 /* Target is an alias, create a new install info object and continue with that. */
1648 bn
= basename(i
->symlink_target
);
1650 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1651 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1653 _cleanup_free_
char *instance
= NULL
;
1655 r
= unit_name_to_instance(i
->name
, &instance
);
1659 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1663 if (streq(buffer
, i
->name
)) {
1665 /* We filled in the instance, and the target stayed the same? If so,
1666 * then let's honour the link as it is. */
1668 r
= install_info_follow(ctx
, i
, lp
, flags
, true);
1678 r
= install_info_add(ctx
, bn
, NULL
, lp
->root_dir
, /* auxiliary= */ false, &i
);
1682 /* Try again, with the new target we found. */
1683 r
= unit_file_search(ctx
, i
, lp
, flags
);
1685 /* Translate error code to highlight this specific case */
1700 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1701 * or the name (otherwise). root_dir is prepended to the path.
1703 static int install_info_add_auto(
1704 InstallContext
*ctx
,
1705 const LookupPaths
*lp
,
1706 const char *name_or_path
,
1707 UnitFileInstallInfo
**ret
) {
1710 assert(name_or_path
);
1712 if (path_is_absolute(name_or_path
)) {
1715 pp
= prefix_roota(lp
->root_dir
, name_or_path
);
1717 return install_info_add(ctx
, NULL
, pp
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1719 return install_info_add(ctx
, name_or_path
, NULL
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1722 static int install_info_discover(
1723 InstallContext
*ctx
,
1724 const LookupPaths
*lp
,
1727 UnitFileInstallInfo
**ret
,
1728 UnitFileChange
**changes
,
1729 size_t *n_changes
) {
1731 UnitFileInstallInfo
*info
;
1738 r
= install_info_add_auto(ctx
, lp
, name
, &info
);
1740 r
= install_info_traverse(ctx
, lp
, info
, flags
, ret
);
1743 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1747 static int install_info_discover_and_check(
1748 InstallContext
*ctx
,
1749 const LookupPaths
*lp
,
1752 UnitFileInstallInfo
**ret
,
1753 UnitFileChange
**changes
,
1754 size_t *n_changes
) {
1758 r
= install_info_discover(ctx
, lp
, name
, flags
, ret
, changes
, n_changes
);
1762 return install_info_may_process(ret
? *ret
: NULL
, lp
, changes
, n_changes
);
1765 int unit_file_verify_alias(
1766 const UnitFileInstallInfo
*info
,
1769 UnitFileChange
**changes
,
1770 size_t *n_changes
) {
1772 _cleanup_free_
char *dst_updated
= NULL
;
1775 /* Verify that dst is a valid either a valid alias or a valid .wants/.requires symlink for the target
1776 * unit *i. Return negative on error or if not compatible, zero on success.
1778 * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
1779 * inserted into dst. It is not normally set, even on success, so that the caller can easily
1780 * distinguish the case where instance propagation occurred.
1783 * -EXDEV when the alias doesn't match the unit,
1784 * -EUCLEAN when the name is invalid,
1785 * -ELOOP when the alias it to the unit itself.
1788 const char *path_alias
= strrchr(dst
, '/');
1790 /* This branch covers legacy Alias= function of creating .wants and .requires symlinks. */
1791 _cleanup_free_
char *dir
= NULL
;
1794 path_alias
++; /* skip over slash */
1796 dir
= dirname_malloc(dst
);
1800 p
= endswith(dir
, ".wants");
1802 p
= endswith(dir
, ".requires");
1804 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1805 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
), "Invalid path \"%s\" in alias.", dir
);
1808 *p
= '\0'; /* dir should now be a unit name */
1810 UnitNameFlags type
= unit_name_classify(dir
);
1812 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1813 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1814 "Invalid unit name component \"%s\" in alias.", dir
);
1817 const bool instance_propagation
= type
== UNIT_NAME_TEMPLATE
;
1819 /* That's the name we want to use for verification. */
1820 r
= unit_symlink_name_compatible(path_alias
, info
->name
, instance_propagation
);
1822 return log_error_errno(r
, "Failed to verify alias validity: %m");
1824 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, info
->name
);
1825 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1826 "Invalid unit \"%s\" symlink \"%s\".",
1831 /* If the symlink target has an instance set and the symlink source doesn't, we "propagate
1832 * the instance", i.e. instantiate the symlink source with the target instance. */
1833 if (unit_name_is_valid(dst
, UNIT_NAME_TEMPLATE
)) {
1834 _cleanup_free_
char *inst
= NULL
;
1836 UnitNameFlags type
= unit_name_to_instance(info
->name
, &inst
);
1838 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, info
->name
, NULL
);
1839 return log_debug_errno(type
, "Failed to extract instance name from \"%s\": %m", info
->name
);
1842 if (type
== UNIT_NAME_INSTANCE
) {
1843 r
= unit_name_replace_instance(dst
, inst
, &dst_updated
);
1845 return log_error_errno(r
, "Failed to build unit name from %s+%s: %m",
1850 r
= unit_validate_alias_symlink_or_warn(LOG_DEBUG
, dst_updated
?: dst
, info
->name
);
1851 if (r
== -ELOOP
) /* -ELOOP means self-alias, which we (quietly) ignore */
1854 unit_file_changes_add(changes
, n_changes
,
1855 r
== -EINVAL
? -EXDEV
: r
,
1862 *ret_dst
= TAKE_PTR(dst_updated
);
1866 static int install_info_symlink_alias(
1868 UnitFileInstallInfo
*info
,
1869 const LookupPaths
*lp
,
1870 const char *config_path
,
1872 UnitFileChange
**changes
,
1873 size_t *n_changes
) {
1879 assert(config_path
);
1881 STRV_FOREACH(s
, info
->aliases
) {
1882 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
, *dst_updated
= NULL
;
1884 q
= install_name_printf(scope
, info
, *s
, &dst
);
1886 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1891 q
= unit_file_verify_alias(info
, dst
, &dst_updated
, changes
, n_changes
);
1899 alias_path
= path_make_absolute(dst_updated
?: dst
, config_path
);
1903 q
= create_symlink(lp
, info
->path
, alias_path
, force
, changes
, n_changes
);
1910 static int install_info_symlink_wants(
1912 UnitFileFlags file_flags
,
1913 UnitFileInstallInfo
*info
,
1914 const LookupPaths
*lp
,
1915 const char *config_path
,
1918 UnitFileChange
**changes
,
1919 size_t *n_changes
) {
1921 _cleanup_free_
char *buf
= NULL
;
1922 UnitNameFlags valid_dst_type
= UNIT_NAME_ANY
;
1928 assert(config_path
);
1930 if (strv_isempty(list
))
1933 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
| UNIT_NAME_INSTANCE
))
1934 /* Not a template unit. Use the name directly. */
1937 else if (info
->default_instance
) {
1938 UnitFileInstallInfo instance
= {
1939 .type
= _UNIT_FILE_TYPE_INVALID
,
1941 _cleanup_free_
char *path
= NULL
;
1943 /* If this is a template, and we have a default instance, use it. */
1945 r
= unit_name_replace_instance(info
->name
, info
->default_instance
, &buf
);
1949 instance
.name
= buf
;
1950 r
= unit_file_search(NULL
, &instance
, lp
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1954 path
= TAKE_PTR(instance
.path
);
1956 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1957 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1964 /* We have a template, but no instance yet. When used with an instantiated unit, we will get
1965 * the instance from that unit. Cannot be used with non-instance units. */
1967 valid_dst_type
= UNIT_NAME_INSTANCE
| UNIT_NAME_TEMPLATE
;
1971 STRV_FOREACH(s
, list
) {
1972 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1974 q
= install_name_printf(scope
, info
, *s
, &dst
);
1976 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1980 if (!unit_name_is_valid(dst
, valid_dst_type
)) {
1981 /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the
1982 * template status doesn't match. If we are doing presets don't bother reporting the
1983 * error. This also covers cases like 'systemctl preset serial-getty@.service', which
1984 * has no DefaultInstance, so there is nothing we can do. At the same time,
1985 * 'systemctl enable serial-getty@.service' should fail, the user should specify an
1986 * instance like in 'systemctl enable serial-getty@ttyS0.service'.
1988 if (file_flags
& UNIT_FILE_IGNORE_AUXILIARY_FAILURE
)
1991 if (unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1992 unit_file_changes_add(changes
, n_changes
, -EIDRM
, dst
, n
);
1995 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, dst
, NULL
);
2002 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
2006 q
= create_symlink(lp
, info
->path
, path
, true, changes
, n_changes
);
2010 if (unit_file_exists(scope
, lp
, dst
) == 0)
2011 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_DESTINATION_NOT_PRESENT
, dst
, info
->path
);
2017 static int install_info_symlink_link(
2018 UnitFileInstallInfo
*info
,
2019 const LookupPaths
*lp
,
2020 const char *config_path
,
2022 UnitFileChange
**changes
,
2023 size_t *n_changes
) {
2025 _cleanup_free_
char *path
= NULL
;
2030 assert(config_path
);
2033 r
= in_search_path(lp
, info
->path
);
2039 path
= path_join(config_path
, info
->name
);
2043 return create_symlink(lp
, info
->path
, path
, force
, changes
, n_changes
);
2046 static int install_info_apply(
2048 UnitFileFlags file_flags
,
2049 UnitFileInstallInfo
*info
,
2050 const LookupPaths
*lp
,
2051 const char *config_path
,
2052 UnitFileChange
**changes
,
2053 size_t *n_changes
) {
2059 assert(config_path
);
2061 if (info
->type
!= UNIT_FILE_TYPE_REGULAR
)
2064 bool force
= file_flags
& UNIT_FILE_FORCE
;
2066 r
= install_info_symlink_link(info
, lp
, config_path
, force
, changes
, n_changes
);
2067 /* Do not count links to the unit file towards the "carries_install_info" count */
2069 /* If linking of the file failed, do not try to create other symlinks,
2070 * because they might would pointing to a non-existent or wrong unit. */
2073 r
= install_info_symlink_alias(scope
, info
, lp
, config_path
, force
, changes
, n_changes
);
2075 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->wanted_by
, ".wants/", changes
, n_changes
);
2079 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->required_by
, ".requires/", changes
, n_changes
);
2086 static int install_context_apply(
2087 InstallContext
*ctx
,
2088 const LookupPaths
*lp
,
2089 UnitFileFlags file_flags
,
2090 const char *config_path
,
2092 UnitFileChange
**changes
,
2093 size_t *n_changes
) {
2095 UnitFileInstallInfo
*i
;
2100 assert(config_path
);
2102 if (ordered_hashmap_isempty(ctx
->will_process
))
2105 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2110 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2113 q
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2117 q
= install_info_traverse(ctx
, lp
, i
, flags
, NULL
);
2120 q
= unit_file_changes_add(changes
, n_changes
, UNIT_FILE_AUXILIARY_FAILED
, NULL
, i
->name
);
2126 unit_file_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
2130 /* We can attempt to process a masked unit when a different unit
2131 * that we were processing specifies it in Also=. */
2132 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2133 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
2135 /* Assume that something *could* have been enabled here,
2136 * avoid "empty [Install] section" warning. */
2141 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
2144 q
= install_info_apply(ctx
->scope
, file_flags
, i
, lp
, config_path
, changes
, n_changes
);
2156 static int install_context_mark_for_removal(
2157 InstallContext
*ctx
,
2158 const LookupPaths
*lp
,
2159 Set
**remove_symlinks_to
,
2160 const char *config_path
,
2161 UnitFileChange
**changes
,
2162 size_t *n_changes
) {
2164 UnitFileInstallInfo
*i
;
2169 assert(config_path
);
2171 /* Marks all items for removal */
2173 if (ordered_hashmap_isempty(ctx
->will_process
))
2176 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2180 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2182 r
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2186 r
= install_info_traverse(ctx
, lp
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2187 if (r
== -ENOLINK
) {
2188 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
2189 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
2190 } else if (r
== -ENOENT
) {
2192 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
2193 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
2195 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
2196 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2200 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
2201 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2202 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2203 log_debug("Unit file %s is masked, ignoring.", i
->name
);
2204 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
2206 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
2207 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
2211 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2221 UnitFileFlags flags
,
2222 const char *root_dir
,
2224 UnitFileChange
**changes
,
2225 size_t *n_changes
) {
2227 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2228 const char *config_path
;
2232 assert(scope
< _LOOKUP_SCOPE_MAX
);
2234 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2238 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2242 STRV_FOREACH(i
, files
) {
2243 _cleanup_free_
char *path
= NULL
;
2246 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2252 path
= path_make_absolute(*i
, config_path
);
2256 q
= create_symlink(&lp
, "/dev/null", path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2257 if (q
< 0 && r
>= 0)
2264 int unit_file_unmask(
2266 UnitFileFlags flags
,
2267 const char *root_dir
,
2269 UnitFileChange
**changes
,
2270 size_t *n_changes
) {
2272 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2273 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2274 _cleanup_strv_free_
char **todo
= NULL
;
2275 const char *config_path
;
2280 assert(scope
< _LOOKUP_SCOPE_MAX
);
2282 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2286 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2290 bool dry_run
= flags
& UNIT_FILE_DRY_RUN
;
2292 STRV_FOREACH(i
, files
) {
2293 _cleanup_free_
char *path
= NULL
;
2295 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2298 path
= path_make_absolute(*i
, config_path
);
2302 r
= null_or_empty_path(path
);
2310 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2313 todo
[n_todo
] = strdup(*i
);
2323 STRV_FOREACH(i
, todo
) {
2324 _cleanup_free_
char *path
= NULL
;
2327 path
= path_make_absolute(*i
, config_path
);
2331 if (!dry_run
&& unlink(path
) < 0) {
2332 if (errno
!= ENOENT
) {
2335 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2341 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2343 rp
= skip_root(lp
.root_dir
, path
);
2344 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2349 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, dry_run
, changes
, n_changes
);
2358 UnitFileFlags flags
,
2359 const char *root_dir
,
2361 UnitFileChange
**changes
,
2362 size_t *n_changes
) {
2364 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2365 _cleanup_strv_free_
char **todo
= NULL
;
2366 const char *config_path
;
2371 assert(scope
< _LOOKUP_SCOPE_MAX
);
2373 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2377 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2381 STRV_FOREACH(i
, files
) {
2382 _cleanup_free_
char *full
= NULL
;
2386 if (!path_is_absolute(*i
))
2390 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2393 full
= path_join(lp
.root_dir
, *i
);
2397 if (lstat(full
, &st
) < 0)
2399 r
= stat_verify_regular(&st
);
2403 q
= in_search_path(&lp
, *i
);
2409 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2412 todo
[n_todo
] = strdup(*i
);
2422 STRV_FOREACH(i
, todo
) {
2423 _cleanup_free_
char *new_path
= NULL
;
2425 new_path
= path_make_absolute(basename(*i
), config_path
);
2429 q
= create_symlink(&lp
, *i
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2430 if (q
< 0 && r
>= 0)
2437 static int path_shall_revert(const LookupPaths
*lp
, const char *path
) {
2443 /* Checks whether the path is one where the drop-in directories shall be removed. */
2445 r
= path_is_config(lp
, path
, true);
2449 r
= path_is_control(lp
, path
);
2453 return path_is_transient(lp
, path
);
2456 int unit_file_revert(
2458 const char *root_dir
,
2460 UnitFileChange
**changes
,
2461 size_t *n_changes
) {
2463 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2464 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2465 _cleanup_strv_free_
char **todo
= NULL
;
2469 /* Puts a unit file back into vendor state. This means:
2471 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2472 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2474 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2475 * "config", but not in "transient" or "control" or even "generated").
2477 * We remove all that in both the runtime and the persistent directories, if that applies.
2480 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2484 STRV_FOREACH(i
, files
) {
2485 bool has_vendor
= false;
2487 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2490 STRV_FOREACH(p
, lp
.search_path
) {
2491 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2494 path
= path_make_absolute(*i
, *p
);
2498 r
= lstat(path
, &st
);
2500 if (errno
!= ENOENT
)
2502 } else if (S_ISREG(st
.st_mode
)) {
2503 /* Check if there's a vendor version */
2504 r
= path_is_vendor_or_generator(&lp
, path
);
2511 dropin
= strjoin(path
, ".d");
2515 r
= lstat(dropin
, &st
);
2517 if (errno
!= ENOENT
)
2519 } else if (S_ISDIR(st
.st_mode
)) {
2520 /* Remove the drop-ins */
2521 r
= path_shall_revert(&lp
, dropin
);
2525 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2528 todo
[n_todo
++] = TAKE_PTR(dropin
);
2536 /* OK, there's a vendor version, hence drop all configuration versions */
2537 STRV_FOREACH(p
, lp
.search_path
) {
2538 _cleanup_free_
char *path
= NULL
;
2541 path
= path_make_absolute(*i
, *p
);
2545 r
= lstat(path
, &st
);
2547 if (errno
!= ENOENT
)
2549 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2550 r
= path_is_config(&lp
, path
, true);
2554 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2557 todo
[n_todo
++] = TAKE_PTR(path
);
2566 STRV_FOREACH(i
, todo
) {
2567 _cleanup_strv_free_
char **fs
= NULL
;
2570 (void) get_files_in_directory(*i
, &fs
);
2572 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2573 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2578 STRV_FOREACH(j
, fs
) {
2579 _cleanup_free_
char *t
= NULL
;
2581 t
= path_join(*i
, *j
);
2585 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2588 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2590 rp
= skip_root(lp
.root_dir
, *i
);
2591 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2596 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.runtime_config
, &lp
, false, changes
, n_changes
);
2600 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.persistent_config
, &lp
, false, changes
, n_changes
);
2607 int unit_file_add_dependency(
2609 UnitFileFlags file_flags
,
2610 const char *root_dir
,
2614 UnitFileChange
**changes
,
2615 size_t *n_changes
) {
2617 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2618 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2619 UnitFileInstallInfo
*info
, *target_info
;
2620 const char *config_path
;
2624 assert(scope
< _LOOKUP_SCOPE_MAX
);
2627 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2630 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2633 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2637 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2641 r
= install_info_discover_and_check(&ctx
, &lp
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2642 &target_info
, changes
, n_changes
);
2646 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2648 STRV_FOREACH(f
, files
) {
2651 r
= install_info_discover_and_check(&ctx
, &lp
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2652 &info
, changes
, n_changes
);
2656 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2658 /* We didn't actually load anything from the unit
2659 * file, but instead just add in our new symlink to
2662 if (dep
== UNIT_WANTS
)
2663 l
= &info
->wanted_by
;
2665 l
= &info
->required_by
;
2668 *l
= strv_new(target_info
->name
);
2673 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2674 SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2677 static int do_unit_file_enable(
2678 const LookupPaths
*lp
,
2680 UnitFileFlags flags
,
2681 const char *config_path
,
2683 UnitFileChange
**changes
,
2684 size_t *n_changes
) {
2686 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2687 UnitFileInstallInfo
*info
;
2690 STRV_FOREACH(f
, files
) {
2691 r
= install_info_discover_and_check(&ctx
, lp
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2692 &info
, changes
, n_changes
);
2696 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2699 /* This will return the number of symlink rules that were
2700 supposed to be created, not the ones actually created. This
2701 is useful to determine whether the passed files had any
2702 installation data at all. */
2704 return install_context_apply(&ctx
, lp
, flags
, config_path
,
2705 SEARCH_LOAD
, changes
, n_changes
);
2708 int unit_file_enable(
2710 UnitFileFlags flags
,
2711 const char *root_dir
,
2713 UnitFileChange
**changes
,
2714 size_t *n_changes
) {
2716 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2720 assert(scope
< _LOOKUP_SCOPE_MAX
);
2722 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2726 const char *config_path
= config_path_from_flags(&lp
, flags
);
2730 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2733 static int do_unit_file_disable(
2734 const LookupPaths
*lp
,
2736 UnitFileFlags flags
,
2737 const char *config_path
,
2739 UnitFileChange
**changes
,
2740 size_t *n_changes
) {
2742 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2743 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2746 STRV_FOREACH(i
, files
) {
2747 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2750 r
= install_info_add(&ctx
, *i
, NULL
, lp
->root_dir
, /* auxiliary= */ false, NULL
);
2755 r
= install_context_mark_for_removal(&ctx
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2759 return remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, flags
& UNIT_FILE_DRY_RUN
, changes
, n_changes
);
2763 int unit_file_disable(
2765 UnitFileFlags flags
,
2766 const char *root_dir
,
2768 UnitFileChange
**changes
,
2769 size_t *n_changes
) {
2771 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2775 assert(scope
< _LOOKUP_SCOPE_MAX
);
2777 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2781 const char *config_path
= config_path_from_flags(&lp
, flags
);
2785 return do_unit_file_disable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2788 static int normalize_linked_files(
2790 const LookupPaths
*lp
,
2791 char **names_or_paths
,
2793 char ***ret_files
) {
2795 /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/,
2796 * but operates on real unit names. For each argument we we look up the actual path
2797 * where the unit is found. This way linked units can be re-enabled successfully. */
2799 _cleanup_strv_free_
char **files
= NULL
, **names
= NULL
;
2802 STRV_FOREACH(a
, names_or_paths
) {
2803 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2804 UnitFileInstallInfo
*i
= NULL
;
2805 _cleanup_free_
char *n
= NULL
;
2807 r
= path_extract_filename(*a
, &n
);
2810 if (r
== O_DIRECTORY
)
2811 return log_debug_errno(SYNTHETIC_ERRNO(EISDIR
),
2812 "Unexpected path to a directory \"%s\", refusing.", *a
);
2815 r
= install_info_discover(&ctx
, lp
, n
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
, NULL
, NULL
);
2817 log_debug_errno(r
, "Failed to discover unit \"%s\", operating on name: %m", n
);
2820 r
= strv_consume(&names
, TAKE_PTR(n
));
2824 const char *p
= NULL
;
2825 if (i
&& i
->path
&& i
->root
)
2826 /* Use startswith here, because we know that paths are normalized, and
2827 * path_startswith() would give us a relative path, but we need an absolute path
2828 * relative to i->root.
2830 * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service
2831 * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute"
2832 * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/.
2834 p
= startswith(i
->path
, i
->root
);
2836 r
= strv_extend(&files
, p
?: *a
);
2841 *ret_names
= TAKE_PTR(names
);
2842 *ret_files
= TAKE_PTR(files
);
2846 int unit_file_reenable(
2848 UnitFileFlags flags
,
2849 const char *root_dir
,
2850 char **names_or_paths
,
2851 UnitFileChange
**changes
,
2852 size_t *n_changes
) {
2854 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2855 _cleanup_strv_free_
char **names
= NULL
, **files
= NULL
;
2859 assert(scope
< _LOOKUP_SCOPE_MAX
);
2861 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2865 const char *config_path
= config_path_from_flags(&lp
, flags
);
2869 r
= normalize_linked_files(scope
, &lp
, names_or_paths
, &names
, &files
);
2873 /* First, we invoke the disable command with only the basename... */
2874 r
= do_unit_file_disable(&lp
, scope
, flags
, config_path
, names
, changes
, n_changes
);
2878 /* But the enable command with the full name */
2879 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2882 int unit_file_set_default(
2884 UnitFileFlags flags
,
2885 const char *root_dir
,
2887 UnitFileChange
**changes
,
2888 size_t *n_changes
) {
2890 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2891 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2892 UnitFileInstallInfo
*info
;
2893 const char *new_path
;
2897 assert(scope
< _LOOKUP_SCOPE_MAX
);
2900 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2902 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2905 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2909 r
= install_info_discover_and_check(&ctx
, &lp
, name
, 0, &info
, changes
, n_changes
);
2913 new_path
= strjoina(lp
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2914 return create_symlink(&lp
, info
->path
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2917 int unit_file_get_default(
2919 const char *root_dir
,
2922 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2923 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2924 UnitFileInstallInfo
*info
;
2929 assert(scope
< _LOOKUP_SCOPE_MAX
);
2932 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2936 r
= install_info_discover(&ctx
, &lp
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2940 r
= install_info_may_process(info
, &lp
, NULL
, 0);
2944 n
= strdup(info
->name
);
2952 int unit_file_lookup_state(
2954 const LookupPaths
*lp
,
2956 UnitFileState
*ret
) {
2958 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2959 UnitFileInstallInfo
*info
;
2960 UnitFileState state
;
2966 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2969 r
= install_info_discover(&ctx
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2972 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2974 assert(IN_SET(info
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2975 log_debug("Found unit %s at %s (%s)", name
, strna(info
->path
),
2976 info
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2978 /* Shortcut things, if the caller just wants to know if this unit exists. */
2982 switch (info
->type
) {
2984 case UNIT_FILE_TYPE_MASKED
:
2985 r
= path_is_runtime(lp
, info
->path
, true);
2989 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2992 case UNIT_FILE_TYPE_REGULAR
:
2993 /* Check if the name we were querying is actually an alias */
2994 if (!streq(name
, basename(info
->path
)) && !unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
2995 state
= UNIT_FILE_ALIAS
;
2999 r
= path_is_generator(lp
, info
->path
);
3003 state
= UNIT_FILE_GENERATED
;
3007 r
= path_is_transient(lp
, info
->path
);
3011 state
= UNIT_FILE_TRANSIENT
;
3015 /* Check if any of the Alias= symlinks have been created.
3016 * We ignore other aliases, and only check those that would
3017 * be created by systemctl enable for this unit. */
3018 r
= find_symlinks_in_scope(scope
, lp
, info
, true, &state
);
3024 /* Check if the file is known under other names. If it is,
3025 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
3026 r
= find_symlinks_in_scope(scope
, lp
, info
, false, &state
);
3030 state
= UNIT_FILE_INDIRECT
;
3032 if (unit_file_install_info_has_rules(info
))
3033 state
= UNIT_FILE_DISABLED
;
3034 else if (unit_file_install_info_has_also(info
))
3035 state
= UNIT_FILE_INDIRECT
;
3037 state
= UNIT_FILE_STATIC
;
3043 assert_not_reached();
3050 int unit_file_get_state(
3052 const char *root_dir
,
3054 UnitFileState
*ret
) {
3056 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3060 assert(scope
< _LOOKUP_SCOPE_MAX
);
3063 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3067 return unit_file_lookup_state(scope
, &lp
, name
, ret
);
3070 int unit_file_exists(LookupScope scope
, const LookupPaths
*lp
, const char *name
) {
3071 _cleanup_(install_context_done
) InstallContext c
= { .scope
= scope
};
3077 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3080 r
= install_info_discover(&c
, lp
, name
, 0, NULL
, NULL
, NULL
);
3089 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
3090 _cleanup_strv_free_
char **instances
= NULL
;
3091 _cleanup_free_
char *unit_name
= NULL
;
3095 assert(out_instances
);
3096 assert(out_unit_name
);
3098 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
3102 /* We handle the instances logic when unit name is extracted */
3104 /* We only create instances when a rule of templated unit
3105 * is seen. A rule like enable foo@.service a b c will
3106 * result in an array of (a, b, c) as instance names */
3107 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
3110 instances
= strv_split(pattern
, WHITESPACE
);
3114 *out_instances
= TAKE_PTR(instances
);
3117 *out_unit_name
= TAKE_PTR(unit_name
);
3122 static int presets_find_config(LookupScope scope
, const char *root_dir
, char ***files
) {
3123 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
3124 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
3125 const char* const* dirs
;
3128 assert(scope
< _LOOKUP_SCOPE_MAX
);
3130 if (scope
== LOOKUP_SCOPE_SYSTEM
)
3132 else if (IN_SET(scope
, LOOKUP_SCOPE_GLOBAL
, LOOKUP_SCOPE_USER
))
3135 assert_not_reached();
3137 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
3140 static int read_presets(LookupScope scope
, const char *root_dir
, UnitFilePresets
*presets
) {
3141 _cleanup_(unit_file_presets_freep
) UnitFilePresets ps
= {};
3142 _cleanup_strv_free_
char **files
= NULL
;
3146 assert(scope
< _LOOKUP_SCOPE_MAX
);
3149 r
= presets_find_config(scope
, root_dir
, &files
);
3153 STRV_FOREACH(p
, files
) {
3154 _cleanup_fclose_
FILE *f
= NULL
;
3157 f
= fopen(*p
, "re");
3159 if (errno
== ENOENT
)
3166 _cleanup_free_
char *line
= NULL
;
3167 UnitFilePresetRule rule
= {};
3168 const char *parameter
;
3171 r
= read_line(f
, LONG_LINE_MAX
, &line
);
3182 if (strchr(COMMENTS
, *l
))
3185 parameter
= first_word(l
, "enable");
3188 char **instances
= NULL
;
3190 /* Unit_name will remain the same as parameter when no instances are specified */
3191 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
3193 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
3197 rule
= (UnitFilePresetRule
) {
3198 .pattern
= unit_name
,
3199 .action
= PRESET_ENABLE
,
3200 .instances
= instances
,
3204 parameter
= first_word(l
, "disable");
3208 pattern
= strdup(parameter
);
3212 rule
= (UnitFilePresetRule
) {
3214 .action
= PRESET_DISABLE
,
3219 if (!GREEDY_REALLOC(ps
.rules
, ps
.n_rules
+ 1))
3222 ps
.rules
[ps
.n_rules
++] = rule
;
3226 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
3230 ps
.initialized
= true;
3232 ps
= (UnitFilePresets
){};
3237 static int pattern_match_multiple_instances(
3238 const UnitFilePresetRule rule
,
3239 const char *unit_name
,
3242 _cleanup_free_
char *templated_name
= NULL
;
3245 /* If no ret is needed or the rule itself does not have instances
3246 * initialized, we return not matching */
3247 if (!ret
|| !rule
.instances
)
3250 r
= unit_name_template(unit_name
, &templated_name
);
3253 if (!streq(rule
.pattern
, templated_name
))
3256 /* Compose a list of specified instances when unit name is a template */
3257 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
3258 _cleanup_strv_free_
char **out_strv
= NULL
;
3260 STRV_FOREACH(iter
, rule
.instances
) {
3261 _cleanup_free_
char *name
= NULL
;
3263 r
= unit_name_replace_instance(unit_name
, *iter
, &name
);
3267 r
= strv_consume(&out_strv
, TAKE_PTR(name
));
3272 *ret
= TAKE_PTR(out_strv
);
3275 /* We now know the input unit name is an instance name */
3276 _cleanup_free_
char *instance_name
= NULL
;
3278 r
= unit_name_to_instance(unit_name
, &instance_name
);
3282 if (strv_find(rule
.instances
, instance_name
))
3288 static int query_presets(const char *name
, const UnitFilePresets
*presets
, char ***instance_name_list
) {
3289 PresetAction action
= PRESET_UNKNOWN
;
3291 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3294 for (size_t i
= 0; i
< presets
->n_rules
; i
++)
3295 if (pattern_match_multiple_instances(presets
->rules
[i
], name
, instance_name_list
) > 0 ||
3296 fnmatch(presets
->rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
3297 action
= presets
->rules
[i
].action
;
3302 case PRESET_UNKNOWN
:
3303 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3306 if (instance_name_list
&& *instance_name_list
)
3307 STRV_FOREACH(s
, *instance_name_list
)
3308 log_debug("Preset files say enable %s.", *s
);
3310 log_debug("Preset files say enable %s.", name
);
3312 case PRESET_DISABLE
:
3313 log_debug("Preset files say disable %s.", name
);
3316 assert_not_reached();
3320 int unit_file_query_preset(LookupScope scope
, const char *root_dir
, const char *name
, UnitFilePresets
*cached
) {
3321 _cleanup_(unit_file_presets_freep
) UnitFilePresets tmp
= {};
3326 if (!cached
->initialized
) {
3327 r
= read_presets(scope
, root_dir
, cached
);
3332 return query_presets(name
, cached
, NULL
);
3335 static int execute_preset(
3336 UnitFileFlags file_flags
,
3337 InstallContext
*plus
,
3338 InstallContext
*minus
,
3339 const LookupPaths
*lp
,
3340 const char *config_path
,
3342 UnitFilePresetMode mode
,
3343 UnitFileChange
**changes
,
3344 size_t *n_changes
) {
3351 assert(config_path
);
3353 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3354 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3356 r
= install_context_mark_for_removal(minus
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3360 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, false, changes
, n_changes
);
3364 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3367 /* Returns number of symlinks that where supposed to be installed. */
3368 q
= install_context_apply(plus
, lp
,
3369 file_flags
| UNIT_FILE_IGNORE_AUXILIARY_FAILURE
,
3371 SEARCH_LOAD
, changes
, n_changes
);
3383 static int preset_prepare_one(
3385 InstallContext
*plus
,
3386 InstallContext
*minus
,
3389 const UnitFilePresets
*presets
,
3390 UnitFileChange
**changes
,
3391 size_t *n_changes
) {
3393 _cleanup_(install_context_done
) InstallContext tmp
= { .scope
= scope
};
3394 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3395 UnitFileInstallInfo
*info
;
3398 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3401 r
= install_info_discover(&tmp
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3402 &info
, changes
, n_changes
);
3405 if (!streq(name
, info
->name
)) {
3406 log_debug("Skipping %s because it is an alias for %s.", name
, info
->name
);
3410 r
= query_presets(name
, presets
, &instance_name_list
);
3415 if (instance_name_list
)
3416 STRV_FOREACH(s
, instance_name_list
) {
3417 r
= install_info_discover_and_check(plus
, lp
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3418 &info
, changes
, n_changes
);
3423 r
= install_info_discover_and_check(plus
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3424 &info
, changes
, n_changes
);
3430 r
= install_info_discover(minus
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3431 &info
, changes
, n_changes
);
3436 int unit_file_preset(
3438 UnitFileFlags file_flags
,
3439 const char *root_dir
,
3441 UnitFilePresetMode mode
,
3442 UnitFileChange
**changes
,
3443 size_t *n_changes
) {
3445 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3446 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3447 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3448 const char *config_path
;
3452 assert(scope
< _LOOKUP_SCOPE_MAX
);
3453 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3455 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3459 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3463 r
= read_presets(scope
, root_dir
, &presets
);
3467 STRV_FOREACH(i
, files
) {
3468 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, *i
, &presets
, changes
, n_changes
);
3473 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, files
, mode
, changes
, n_changes
);
3476 int unit_file_preset_all(
3478 UnitFileFlags file_flags
,
3479 const char *root_dir
,
3480 UnitFilePresetMode mode
,
3481 UnitFileChange
**changes
,
3482 size_t *n_changes
) {
3484 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3485 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3486 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3487 const char *config_path
= NULL
;
3491 assert(scope
< _LOOKUP_SCOPE_MAX
);
3492 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3494 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3498 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3502 r
= read_presets(scope
, root_dir
, &presets
);
3506 STRV_FOREACH(i
, lp
.search_path
) {
3507 _cleanup_closedir_
DIR *d
= NULL
;
3511 if (errno
== ENOENT
)
3517 FOREACH_DIRENT(de
, d
, return -errno
) {
3519 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3522 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3525 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, de
->d_name
, &presets
, changes
, n_changes
);
3527 !IN_SET(r
, -EEXIST
, -ERFKILL
, -EADDRNOTAVAIL
, -EBADSLT
, -EIDRM
, -EUCLEAN
, -ELOOP
, -ENOENT
, -EUNATCH
, -EXDEV
))
3528 /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
3529 * Coordinate with unit_file_dump_changes() above. */
3534 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, NULL
, mode
, changes
, n_changes
);
3537 static UnitFileList
* unit_file_list_free_one(UnitFileList
*f
) {
3545 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3546 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3549 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3551 int unit_file_get_list(
3553 const char *root_dir
,
3558 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3562 assert(scope
< _LOOKUP_SCOPE_MAX
);
3565 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3569 STRV_FOREACH(dirname
, lp
.search_path
) {
3570 _cleanup_closedir_
DIR *d
= NULL
;
3572 d
= opendir(*dirname
);
3574 if (errno
== ENOENT
)
3576 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3577 log_debug_errno(errno
, "Failed to open \"%s\": %m", *dirname
);
3584 FOREACH_DIRENT(de
, d
, return -errno
) {
3585 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3587 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3590 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3593 if (hashmap_get(h
, de
->d_name
))
3596 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3599 f
= new0(UnitFileList
, 1);
3603 f
->path
= path_make_absolute(de
->d_name
, *dirname
);
3607 r
= unit_file_lookup_state(scope
, &lp
, de
->d_name
, &f
->state
);
3609 f
->state
= UNIT_FILE_BAD
;
3611 if (!strv_isempty(states
) &&
3612 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3615 r
= hashmap_put(h
, basename(f
->path
), f
);
3619 f
= NULL
; /* prevent cleanup */
3626 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3627 [UNIT_FILE_ENABLED
] = "enabled",
3628 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3629 [UNIT_FILE_LINKED
] = "linked",
3630 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3631 [UNIT_FILE_ALIAS
] = "alias",
3632 [UNIT_FILE_MASKED
] = "masked",
3633 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3634 [UNIT_FILE_STATIC
] = "static",
3635 [UNIT_FILE_DISABLED
] = "disabled",
3636 [UNIT_FILE_INDIRECT
] = "indirect",
3637 [UNIT_FILE_GENERATED
] = "generated",
3638 [UNIT_FILE_TRANSIENT
] = "transient",
3639 [UNIT_FILE_BAD
] = "bad",
3642 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3644 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3645 [UNIT_FILE_SYMLINK
] = "symlink",
3646 [UNIT_FILE_UNLINK
] = "unlink",
3647 [UNIT_FILE_IS_MASKED
] = "masked",
3648 [UNIT_FILE_IS_DANGLING
] = "dangling",
3649 [UNIT_FILE_DESTINATION_NOT_PRESENT
] = "destination not present",
3650 [UNIT_FILE_AUXILIARY_FAILED
] = "auxiliary unit failed",
3653 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, int);
3655 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3656 [UNIT_FILE_PRESET_FULL
] = "full",
3657 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3658 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3661 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);