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_SYMLINK
] = "symlink",
97 [UNIT_FILE_TYPE_MASKED
] = "masked",
100 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
102 static int in_search_path(const LookupPaths
*lp
, const char *path
) {
103 _cleanup_free_
char *parent
= NULL
;
107 parent
= dirname_malloc(path
);
111 return path_strv_contains(lp
->search_path
, parent
);
114 static const char* skip_root(const char *root_dir
, const char *path
) {
120 const char *e
= path_startswith(path
, root_dir
);
124 /* Make sure the returned path starts with a slash */
126 if (e
== path
|| e
[-1] != '/')
135 static int path_is_generator(const LookupPaths
*lp
, const char *path
) {
136 _cleanup_free_
char *parent
= NULL
;
141 parent
= dirname_malloc(path
);
145 return path_equal_ptr(parent
, lp
->generator
) ||
146 path_equal_ptr(parent
, lp
->generator_early
) ||
147 path_equal_ptr(parent
, lp
->generator_late
);
150 static int path_is_transient(const LookupPaths
*lp
, const char *path
) {
151 _cleanup_free_
char *parent
= NULL
;
156 parent
= dirname_malloc(path
);
160 return path_equal_ptr(parent
, lp
->transient
);
163 static int path_is_control(const LookupPaths
*lp
, const char *path
) {
164 _cleanup_free_
char *parent
= NULL
;
169 parent
= dirname_malloc(path
);
173 return path_equal_ptr(parent
, lp
->persistent_control
) ||
174 path_equal_ptr(parent
, lp
->runtime_control
);
177 static int path_is_config(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
178 _cleanup_free_
char *parent
= NULL
;
183 /* Note that we do *not* have generic checks for /etc or /run in place, since with
184 * them we couldn't discern configuration from transient or generated units */
187 parent
= dirname_malloc(path
);
194 return path_equal_ptr(path
, lp
->persistent_config
) ||
195 path_equal_ptr(path
, lp
->runtime_config
);
198 static int path_is_runtime(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
199 _cleanup_free_
char *parent
= NULL
;
205 /* Everything in /run is considered runtime. On top of that we also add
206 * explicit checks for the various runtime directories, as safety net. */
208 rpath
= skip_root(lp
->root_dir
, path
);
209 if (rpath
&& path_startswith(rpath
, "/run"))
213 parent
= dirname_malloc(path
);
220 return path_equal_ptr(path
, lp
->runtime_config
) ||
221 path_equal_ptr(path
, lp
->generator
) ||
222 path_equal_ptr(path
, lp
->generator_early
) ||
223 path_equal_ptr(path
, lp
->generator_late
) ||
224 path_equal_ptr(path
, lp
->transient
) ||
225 path_equal_ptr(path
, lp
->runtime_control
);
228 static int path_is_vendor_or_generator(const LookupPaths
*lp
, const char *path
) {
234 rpath
= skip_root(lp
->root_dir
, path
);
238 if (path_startswith(rpath
, "/usr"))
242 if (path_startswith(rpath
, "/lib"))
246 if (path_is_generator(lp
, rpath
))
249 return path_equal(rpath
, SYSTEM_DATA_UNIT_DIR
);
252 static const char* config_path_from_flags(const LookupPaths
*lp
, UnitFileFlags flags
) {
255 if (FLAGS_SET(flags
, UNIT_FILE_PORTABLE
))
256 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_attached
: lp
->persistent_attached
;
258 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_config
: lp
->persistent_config
;
261 int unit_file_changes_add(
262 UnitFileChange
**changes
,
264 int type_or_errno
, /* UNIT_FILE_SYMLINK, _UNLINK, _IS_MASKED, _IS_DANGLING if positive or errno if negative */
266 const char *source
) {
268 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
271 assert(!changes
== !n_changes
);
273 if (type_or_errno
>= 0)
274 assert(type_or_errno
< _UNIT_FILE_CHANGE_TYPE_MAX
);
276 assert(type_or_errno
>= -ERRNO_MAX
);
281 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
302 c
[(*n_changes
)++] = (UnitFileChange
) {
303 .type_or_errno
= type_or_errno
,
305 .source
= TAKE_PTR(s
),
311 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
312 assert(changes
|| n_changes
== 0);
314 for (size_t i
= 0; i
< n_changes
; i
++) {
315 free(changes
[i
].path
);
316 free(changes
[i
].source
);
322 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
325 assert(changes
|| n_changes
== 0);
326 /* If verb is not specified, errors are not allowed! */
327 assert(verb
|| r
>= 0);
329 for (size_t i
= 0; i
< n_changes
; i
++) {
330 assert(verb
|| changes
[i
].type_or_errno
>= 0);
332 switch(changes
[i
].type_or_errno
) {
333 case UNIT_FILE_SYMLINK
:
335 log_info("Created symlink %s %s %s.",
337 special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
),
340 case UNIT_FILE_UNLINK
:
342 log_info("Removed \"%s\".", changes
[i
].path
);
344 case UNIT_FILE_IS_MASKED
:
346 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
348 case UNIT_FILE_IS_DANGLING
:
350 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
353 case UNIT_FILE_DESTINATION_NOT_PRESENT
:
355 log_warning("Unit %s is added as a dependency to a non-existent unit %s.",
356 changes
[i
].source
, changes
[i
].path
);
358 case UNIT_FILE_AUXILIARY_FAILED
:
360 log_warning("Failed to enable auxiliary unit %s, ignoring.", changes
[i
].source
);
363 if (changes
[i
].source
)
364 log_error_errno(changes
[i
].type_or_errno
,
365 "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".",
366 verb
, changes
[i
].path
, changes
[i
].source
);
368 log_error_errno(changes
[i
].type_or_errno
,
369 "Failed to %s unit, file \"%s\" already exists.",
370 verb
, changes
[i
].path
);
374 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is masked.",
375 verb
, changes
[i
].path
);
379 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is transient or generated.",
380 verb
, changes
[i
].path
);
384 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid specifier in \"%s\".",
385 verb
, changes
[i
].path
);
389 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s %s, destination unit %s is a non-template unit.",
390 verb
, changes
[i
].source
, changes
[i
].path
);
394 log_error_errno(changes
[i
].type_or_errno
,
395 "Failed to %s unit, \"%s\" is not a valid unit name.",
396 verb
, changes
[i
].path
);
400 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, refusing to operate on linked unit file %s.",
401 verb
, changes
[i
].path
);
405 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
409 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot resolve specifiers in \"%s\".",
410 verb
, changes
[i
].path
);
414 assert(changes
[i
].type_or_errno
< 0);
415 log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, file \"%s\": %m",
416 verb
, changes
[i
].path
);
421 if (r
< 0 && !logged
)
422 log_error_errno(r
, "Failed to %s: %m.", verb
);
426 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
427 * wc should be the full path in the host file system.
429 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
430 assert(path_is_absolute(wd
));
432 /* This will give incorrect results if the paths are relative and go outside
433 * of the chroot. False negatives are possible. */
438 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
439 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
440 return path_equal_or_files_same(a
, b
, 0);
443 static int create_symlink(
444 const LookupPaths
*lp
,
445 const char *old_path
,
446 const char *new_path
,
448 UnitFileChange
**changes
,
451 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
458 rp
= skip_root(lp
->root_dir
, old_path
);
462 /* Actually create a symlink, and remember that we did. This function is
463 * smart enough to check if there's already a valid symlink in place.
465 * Returns 1 if a symlink was created or already exists and points to the
466 * right place, or negative on error.
469 (void) mkdir_parents_label(new_path
, 0755);
471 if (symlink(old_path
, new_path
) >= 0) {
472 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
476 if (errno
!= EEXIST
) {
477 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
481 r
= readlink_malloc(new_path
, &dest
);
483 /* translate EINVAL (non-symlink exists) to EEXIST */
487 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
491 dirname
= dirname_malloc(new_path
);
495 if (chroot_symlinks_same(lp
->root_dir
, dirname
, dest
, old_path
)) {
496 log_debug("Symlink %s → %s already exists", new_path
, dest
);
501 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
505 r
= symlink_atomic(old_path
, new_path
);
507 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
511 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
512 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
517 static int mark_symlink_for_removal(
518 Set
**remove_symlinks_to
,
526 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
536 r
= set_consume(*remove_symlinks_to
, n
);
545 static int remove_marked_symlinks_fd(
546 Set
*remove_symlinks_to
,
549 const char *config_path
,
550 const LookupPaths
*lp
,
553 UnitFileChange
**changes
,
556 _cleanup_closedir_
DIR *d
= NULL
;
559 assert(remove_symlinks_to
);
574 FOREACH_DIRENT(de
, d
, return -errno
)
576 if (de
->d_type
== DT_DIR
) {
577 _cleanup_free_
char *p
= NULL
;
580 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
590 p
= path_make_absolute(de
->d_name
, path
);
596 /* This will close nfd, regardless whether it succeeds or not */
597 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
601 } else if (de
->d_type
== DT_LNK
) {
602 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
607 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
610 p
= path_make_absolute(de
->d_name
, path
);
615 q
= chase_symlinks(p
, NULL
, CHASE_NONEXISTENT
, &dest
, NULL
);
624 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
625 * the same name as a file that is marked. */
627 found
= set_contains(remove_symlinks_to
, dest
) ||
628 set_contains(remove_symlinks_to
, basename(dest
)) ||
629 set_contains(remove_symlinks_to
, de
->d_name
);
635 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
638 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
642 (void) rmdir_parents(p
, config_path
);
645 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
647 /* Now, remember the full path (but with the root prefix removed) of
648 * the symlink we just removed, and remove any symlinks to it, too. */
650 rp
= skip_root(lp
->root_dir
, p
);
651 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
654 if (q
> 0 && !dry_run
)
661 static int remove_marked_symlinks(
662 Set
*remove_symlinks_to
,
663 const char *config_path
,
664 const LookupPaths
*lp
,
666 UnitFileChange
**changes
,
669 _cleanup_close_
int fd
= -1;
676 if (set_size(remove_symlinks_to
) <= 0)
679 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
681 return errno
== ENOENT
? 0 : -errno
;
687 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
691 /* This takes possession of cfd and closes it */
692 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
700 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
703 if (streq(name
, i
->name
))
706 if (strv_contains(i
->aliases
, name
))
709 /* Look for template symlink matching DefaultInstance */
710 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
711 _cleanup_free_
char *s
= NULL
;
713 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
718 } else if (streq(name
, s
))
725 static int find_symlinks_in_directory(
727 const char *dir_path
,
728 const char *root_dir
,
729 const UnitFileInstallInfo
*info
,
731 bool ignore_same_name
,
732 const char *config_path
,
733 bool *same_name_link
) {
737 FOREACH_DIRENT(de
, dir
, return -errno
) {
738 _cleanup_free_
char *dest
= NULL
;
739 bool found_path
= false, found_dest
, b
= false;
742 if (de
->d_type
!= DT_LNK
)
745 /* Acquire symlink destination */
746 q
= readlinkat_malloc(dirfd(dir
), de
->d_name
, &dest
);
756 if (!path_is_absolute(dest
)) {
759 x
= path_join(dir_path
, dest
);
763 free_and_replace(dest
, x
);
766 assert(unit_name_is_valid(info
->name
, UNIT_NAME_ANY
));
767 if (!ignore_same_name
)
768 /* Check if the symlink itself matches what we are looking for.
770 * If ignore_same_name is specified, we are in one of the directories which
771 * have lower priority than the unit file, and even if a file or symlink with
772 * this name was found, we should ignore it. */
773 found_path
= streq(de
->d_name
, info
->name
);
775 /* Check if what the symlink points to matches what we are looking for */
776 found_dest
= streq(basename(dest
), info
->name
);
778 if (found_path
&& found_dest
) {
779 _cleanup_free_
char *p
= NULL
, *t
= NULL
;
781 /* Filter out same name links in the main
783 p
= path_make_absolute(de
->d_name
, dir_path
);
784 t
= path_make_absolute(info
->name
, config_path
);
789 b
= path_equal(p
, t
);
793 *same_name_link
= true;
794 else if (found_path
|| found_dest
) {
798 /* Check if symlink name is in the set of names used by [Install] */
799 q
= is_symlink_with_known_name(info
, de
->d_name
);
810 static int find_symlinks(
811 const char *root_dir
,
812 const UnitFileInstallInfo
*i
,
814 bool ignore_same_name
,
815 const char *config_path
,
816 bool *same_name_link
) {
818 _cleanup_closedir_
DIR *config_dir
= NULL
;
823 assert(same_name_link
);
825 config_dir
= opendir(config_path
);
827 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
832 FOREACH_DIRENT(de
, config_dir
, return -errno
) {
834 _cleanup_free_
const char *path
= NULL
;
835 _cleanup_closedir_
DIR *d
= NULL
;
837 if (de
->d_type
!= DT_DIR
)
840 suffix
= strrchr(de
->d_name
, '.');
841 if (!STRPTR_IN_SET(suffix
, ".wants", ".requires"))
844 path
= path_join(config_path
, de
->d_name
);
850 log_error_errno(errno
, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path
);
854 r
= find_symlinks_in_directory(d
, path
, root_dir
, i
, match_name
, ignore_same_name
, config_path
, same_name_link
);
858 log_debug_errno(r
, "Failed to look up symlinks in \"%s\": %m", path
);
861 /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
862 rewinddir(config_dir
);
863 return find_symlinks_in_directory(config_dir
, config_path
, root_dir
, i
, match_name
, ignore_same_name
, config_path
, same_name_link
);
866 static int find_symlinks_in_scope(
868 const LookupPaths
*lp
,
869 const UnitFileInstallInfo
*info
,
871 UnitFileState
*state
) {
873 bool same_name_link_runtime
= false, same_name_link_config
= false;
874 bool enabled_in_runtime
= false, enabled_at_all
= false;
875 bool ignore_same_name
= false;
881 /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name"
882 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
883 * effectively masked, so we should ignore them. */
885 STRV_FOREACH(p
, lp
->search_path
) {
886 bool same_name_link
= false;
888 r
= find_symlinks(lp
->root_dir
, info
, match_name
, ignore_same_name
, *p
, &same_name_link
);
892 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
894 if (path_equal_ptr(*p
, lp
->persistent_config
)) {
895 /* This is the best outcome, let's return it immediately. */
896 *state
= UNIT_FILE_ENABLED
;
900 /* look for global enablement of user units */
901 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
902 *state
= UNIT_FILE_ENABLED
;
906 r
= path_is_runtime(lp
, *p
, false);
910 enabled_in_runtime
= true;
912 enabled_at_all
= true;
914 } else if (same_name_link
) {
915 if (path_equal_ptr(*p
, lp
->persistent_config
))
916 same_name_link_config
= true;
918 r
= path_is_runtime(lp
, *p
, false);
922 same_name_link_runtime
= true;
926 /* Check if next iteration will be "below" the unit file (either a regular file
927 * or a symlink), and hence should be ignored */
928 if (!ignore_same_name
&& path_startswith(info
->path
, *p
))
929 ignore_same_name
= true;
932 if (enabled_in_runtime
) {
933 *state
= UNIT_FILE_ENABLED_RUNTIME
;
937 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
938 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
939 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
940 * something, and hence are a much stronger concept. */
941 if (enabled_at_all
&& unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
942 *state
= UNIT_FILE_STATIC
;
946 /* Hmm, we didn't find it, but maybe we found the same name
948 if (same_name_link_config
) {
949 *state
= UNIT_FILE_LINKED
;
952 if (same_name_link_runtime
) {
953 *state
= UNIT_FILE_LINKED_RUNTIME
;
960 static void install_info_free(UnitFileInstallInfo
*i
) {
967 strv_free(i
->aliases
);
968 strv_free(i
->wanted_by
);
969 strv_free(i
->required_by
);
971 free(i
->default_instance
);
972 free(i
->symlink_target
);
976 static void install_context_done(InstallContext
*ctx
) {
979 ctx
->will_process
= ordered_hashmap_free_with_destructor(ctx
->will_process
, install_info_free
);
980 ctx
->have_processed
= ordered_hashmap_free_with_destructor(ctx
->have_processed
, install_info_free
);
983 static UnitFileInstallInfo
*install_info_find(InstallContext
*ctx
, const char *name
) {
984 UnitFileInstallInfo
*i
;
986 i
= ordered_hashmap_get(ctx
->have_processed
, name
);
990 return ordered_hashmap_get(ctx
->will_process
, name
);
993 static int install_info_may_process(
994 const UnitFileInstallInfo
*i
,
995 const LookupPaths
*lp
,
996 UnitFileChange
**changes
,
1001 /* Checks whether the loaded unit file is one we should process, or is masked,
1002 * transient or generated and thus not subject to enable/disable operations. */
1004 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1005 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1008 if (path_is_generator(lp
, i
->path
) ||
1009 path_is_transient(lp
, i
->path
)) {
1010 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1011 return -EADDRNOTAVAIL
;
1018 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1019 * hashmap, or retrieves the existing one if already present.
1021 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1023 static int install_info_add(
1024 InstallContext
*ctx
,
1029 UnitFileInstallInfo
**ret
) {
1031 UnitFileInstallInfo
*i
= NULL
;
1037 /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
1038 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
1039 * but this cannot be possible in any code path (See #6119). */
1041 name
= basename(path
);
1044 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1047 i
= install_info_find(ctx
, name
);
1049 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1056 i
= new(UnitFileInstallInfo
, 1);
1060 *i
= (UnitFileInstallInfo
) {
1061 .type
= _UNIT_FILE_TYPE_INVALID
,
1062 .auxiliary
= auxiliary
,
1065 i
->name
= strdup(name
);
1072 i
->root
= strdup(root
);
1080 i
->path
= strdup(path
);
1087 r
= ordered_hashmap_ensure_put(&ctx
->will_process
, &string_hash_ops
, i
->name
, i
);
1097 install_info_free(i
);
1101 static int config_parse_alias(
1103 const char *filename
,
1105 const char *section
,
1106 unsigned section_line
,
1120 type
= unit_name_to_type(unit
);
1121 if (!unit_type_may_alias(type
))
1122 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1123 "Alias= is not allowed for %s units, ignoring.",
1124 unit_type_to_string(type
));
1126 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1127 lvalue
, ltype
, rvalue
, data
, userdata
);
1130 static int config_parse_also(
1132 const char *filename
,
1134 const char *section
,
1135 unsigned section_line
,
1142 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1143 InstallContext
*ctx
= ASSERT_PTR(data
);
1152 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1154 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1160 r
= install_name_printf(ctx
->scope
, info
, word
, info
->root
, &printed
);
1162 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1163 "Failed to resolve unit name in Also=\"%s\": %m", word
);
1165 r
= install_info_add(ctx
, printed
, NULL
, info
->root
, /* auxiliary= */ true, NULL
);
1169 r
= strv_push(&info
->also
, printed
);
1179 static int config_parse_default_instance(
1181 const char *filename
,
1183 const char *section
,
1184 unsigned section_line
,
1191 InstallContext
*ctx
= ASSERT_PTR(data
);
1192 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1193 _cleanup_free_
char *printed
= NULL
;
1201 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1202 /* When enabling an instance, we might be using a template unit file,
1203 * but we should ignore DefaultInstance silently. */
1205 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1206 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1207 "DefaultInstance= only makes sense for template units, ignoring.");
1209 r
= install_name_printf(ctx
->scope
, info
, rvalue
, info
->root
, &printed
);
1211 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1212 "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue
);
1214 if (isempty(printed
))
1215 printed
= mfree(printed
);
1217 if (printed
&& !unit_instance_is_valid(printed
))
1218 return log_syntax(unit
, LOG_WARNING
, filename
, line
, SYNTHETIC_ERRNO(EINVAL
),
1219 "Invalid DefaultInstance= value \"%s\".", printed
);
1221 return free_and_replace(info
->default_instance
, printed
);
1224 static int unit_file_load(
1225 InstallContext
*ctx
,
1226 UnitFileInstallInfo
*info
,
1228 const char *root_dir
,
1229 SearchFlags flags
) {
1231 const ConfigTableItem items
[] = {
1232 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1233 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1234 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1235 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1236 { "Install", "Also", config_parse_also
, 0, ctx
},
1241 _cleanup_fclose_
FILE *f
= NULL
;
1242 _cleanup_close_
int fd
= -1;
1249 if (!(flags
& SEARCH_DROPIN
)) {
1250 /* Loading or checking for the main unit file… */
1252 type
= unit_name_to_type(info
->name
);
1255 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1256 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1257 "%s: unit type %s cannot be templated, ignoring.", path
, unit_type_to_string(type
));
1259 if (!(flags
& SEARCH_LOAD
)) {
1260 if (lstat(path
, &st
) < 0)
1263 if (null_or_empty(&st
))
1264 info
->type
= UNIT_FILE_TYPE_MASKED
;
1265 else if (S_ISREG(st
.st_mode
))
1266 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1267 else if (S_ISLNK(st
.st_mode
))
1269 else if (S_ISDIR(st
.st_mode
))
1277 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1281 /* 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. */
1283 if (!(flags
& SEARCH_LOAD
))
1286 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1291 if (fstat(fd
, &st
) < 0)
1294 if (null_or_empty(&st
)) {
1295 if ((flags
& SEARCH_DROPIN
) == 0)
1296 info
->type
= UNIT_FILE_TYPE_MASKED
;
1301 r
= stat_verify_regular(&st
);
1305 f
= take_fdopen(&fd
, "r");
1309 /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1312 r
= config_parse(info
->name
, path
, f
,
1326 config_item_table_lookup
, items
,
1330 return log_debug_errno(r
, "Failed to parse \"%s\": %m", info
->name
);
1332 if ((flags
& SEARCH_DROPIN
) == 0)
1333 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1336 (int) strv_length(info
->aliases
) +
1337 (int) strv_length(info
->wanted_by
) +
1338 (int) strv_length(info
->required_by
);
1341 static int unit_file_load_or_readlink(
1342 InstallContext
*ctx
,
1343 UnitFileInstallInfo
*info
,
1345 const LookupPaths
*lp
,
1346 SearchFlags flags
) {
1349 r
= unit_file_load(ctx
, info
, path
, lp
->root_dir
, flags
);
1350 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1353 /* This is a symlink, let's read and verify it. */
1354 r
= unit_file_resolve_symlink(lp
->root_dir
, lp
->search_path
,
1355 NULL
, AT_FDCWD
, path
,
1356 true, &info
->symlink_target
);
1360 r
= null_or_empty_path_with_root(info
->symlink_target
, lp
->root_dir
);
1361 if (r
< 0 && r
!= -ENOENT
)
1362 return log_debug_errno(r
, "Failed to stat %s: %m", info
->symlink_target
);
1364 info
->type
= UNIT_FILE_TYPE_MASKED
;
1366 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1371 static int unit_file_search(
1372 InstallContext
*ctx
,
1373 UnitFileInstallInfo
*info
,
1374 const LookupPaths
*lp
,
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;
1386 /* Was this unit already loaded? */
1387 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1391 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1395 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1396 r
= unit_name_template(info
->name
, &template);
1401 STRV_FOREACH(p
, lp
->search_path
) {
1402 _cleanup_free_
char *path
= NULL
;
1404 path
= path_join(*p
, info
->name
);
1408 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1410 info
->path
= TAKE_PTR(path
);
1414 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1418 if (!found_unit
&& template) {
1420 /* Unit file doesn't exist, however instance
1421 * enablement was requested. We will check if it is
1422 * possible to load template unit file. */
1424 STRV_FOREACH(p
, lp
->search_path
) {
1425 _cleanup_free_
char *path
= NULL
;
1427 path
= path_join(*p
, template);
1431 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1433 info
->path
= TAKE_PTR(path
);
1437 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1443 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1444 "Cannot find unit %s%s%s.",
1445 info
->name
, template ? " or " : "", strempty(template));
1447 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1450 /* Search for drop-in directories */
1452 dropin_dir_name
= strjoina(info
->name
, ".d");
1453 STRV_FOREACH(p
, lp
->search_path
) {
1456 path
= path_join(*p
, dropin_dir_name
);
1460 r
= strv_consume(&dirs
, path
);
1466 dropin_template_dir_name
= strjoina(template, ".d");
1467 STRV_FOREACH(p
, lp
->search_path
) {
1470 path
= path_join(*p
, dropin_template_dir_name
);
1474 r
= strv_consume(&dirs
, path
);
1480 /* Load drop-in conf files */
1482 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1484 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1486 STRV_FOREACH(p
, files
) {
1487 r
= unit_file_load_or_readlink(ctx
, info
, *p
, lp
, flags
| SEARCH_DROPIN
);
1489 return log_debug_errno(r
, "Failed to load conf file \"%s\": %m", *p
);
1495 static int install_info_follow(
1496 InstallContext
*ctx
,
1497 UnitFileInstallInfo
*info
,
1498 const LookupPaths
*lp
,
1500 bool ignore_different_name
) {
1505 if (info
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1507 if (!info
->symlink_target
)
1510 /* If the basename doesn't match, the caller should add a complete new entry for this. */
1512 if (!ignore_different_name
&& !streq(basename(info
->symlink_target
), info
->name
))
1515 free_and_replace(info
->path
, info
->symlink_target
);
1516 info
->type
= _UNIT_FILE_TYPE_INVALID
;
1518 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1522 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1523 * target, maybe more than once. Propagate the instance name if present.
1525 static int install_info_traverse(
1526 InstallContext
*ctx
,
1527 const LookupPaths
*lp
,
1528 UnitFileInstallInfo
*start
,
1530 UnitFileInstallInfo
**ret
) {
1532 UnitFileInstallInfo
*i
;
1540 r
= unit_file_search(ctx
, start
, lp
, flags
);
1545 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1546 /* Follow the symlink */
1548 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1551 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1552 r
= path_is_config(lp
, i
->path
, true);
1559 r
= install_info_follow(ctx
, i
, lp
, flags
, false);
1561 _cleanup_free_
char *buffer
= NULL
;
1564 /* Target is an alias, create a new install info object and continue with that. */
1566 bn
= basename(i
->symlink_target
);
1568 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1569 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1571 _cleanup_free_
char *instance
= NULL
;
1573 r
= unit_name_to_instance(i
->name
, &instance
);
1577 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1581 if (streq(buffer
, i
->name
)) {
1583 /* We filled in the instance, and the target stayed the same? If so,
1584 * then let's honour the link as it is. */
1586 r
= install_info_follow(ctx
, i
, lp
, flags
, true);
1596 r
= install_info_add(ctx
, bn
, NULL
, lp
->root_dir
, /* auxiliary= */ false, &i
);
1600 /* Try again, with the new target we found. */
1601 r
= unit_file_search(ctx
, i
, lp
, flags
);
1603 /* Translate error code to highlight this specific case */
1618 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1619 * or the name (otherwise). root_dir is prepended to the path.
1621 static int install_info_add_auto(
1622 InstallContext
*ctx
,
1623 const LookupPaths
*lp
,
1624 const char *name_or_path
,
1625 UnitFileInstallInfo
**ret
) {
1628 assert(name_or_path
);
1630 if (path_is_absolute(name_or_path
)) {
1633 pp
= prefix_roota(lp
->root_dir
, name_or_path
);
1635 return install_info_add(ctx
, NULL
, pp
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1637 return install_info_add(ctx
, name_or_path
, NULL
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1640 static int install_info_discover(
1641 InstallContext
*ctx
,
1642 const LookupPaths
*lp
,
1645 UnitFileInstallInfo
**ret
,
1646 UnitFileChange
**changes
,
1647 size_t *n_changes
) {
1649 UnitFileInstallInfo
*info
;
1656 r
= install_info_add_auto(ctx
, lp
, name
, &info
);
1658 r
= install_info_traverse(ctx
, lp
, info
, flags
, ret
);
1661 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1665 static int install_info_discover_and_check(
1666 InstallContext
*ctx
,
1667 const LookupPaths
*lp
,
1670 UnitFileInstallInfo
**ret
,
1671 UnitFileChange
**changes
,
1672 size_t *n_changes
) {
1676 r
= install_info_discover(ctx
, lp
, name
, flags
, ret
, changes
, n_changes
);
1680 return install_info_may_process(ret
? *ret
: NULL
, lp
, changes
, n_changes
);
1683 int unit_file_verify_alias(const UnitFileInstallInfo
*info
, const char *dst
, char **ret_dst
) {
1684 _cleanup_free_
char *dst_updated
= NULL
;
1687 /* Verify that dst is a valid either a valid alias or a valid .wants/.requires symlink for the target
1688 * unit *i. Return negative on error or if not compatible, zero on success.
1690 * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
1691 * inserted into dst. It is not normally set, even on success, so that the caller can easily
1692 * distinguish the case where instance propagation occurred.
1695 const char *path_alias
= strrchr(dst
, '/');
1697 /* This branch covers legacy Alias= function of creating .wants and .requires symlinks. */
1698 _cleanup_free_
char *dir
= NULL
;
1701 path_alias
++; /* skip over slash */
1703 dir
= dirname_malloc(dst
);
1707 p
= endswith(dir
, ".wants");
1709 p
= endswith(dir
, ".requires");
1711 return log_warning_errno(SYNTHETIC_ERRNO(EXDEV
),
1712 "Invalid path \"%s\" in alias.", dir
);
1713 *p
= '\0'; /* dir should now be a unit name */
1715 UnitNameFlags type
= unit_name_classify(dir
);
1717 return log_warning_errno(SYNTHETIC_ERRNO(EXDEV
),
1718 "Invalid unit name component \"%s\" in alias.", dir
);
1720 const bool instance_propagation
= type
== UNIT_NAME_TEMPLATE
;
1722 /* That's the name we want to use for verification. */
1723 r
= unit_symlink_name_compatible(path_alias
, info
->name
, instance_propagation
);
1725 return log_error_errno(r
, "Failed to verify alias validity: %m");
1727 return log_warning_errno(SYNTHETIC_ERRNO(EXDEV
),
1728 "Invalid unit \"%s\" symlink \"%s\".",
1732 /* If the symlink target has an instance set and the symlink source doesn't, we "propagate
1733 * the instance", i.e. instantiate the symlink source with the target instance. */
1734 if (unit_name_is_valid(dst
, UNIT_NAME_TEMPLATE
)) {
1735 _cleanup_free_
char *inst
= NULL
;
1737 UnitNameFlags type
= unit_name_to_instance(info
->name
, &inst
);
1739 return log_error_errno(type
, "Failed to extract instance name from \"%s\": %m", info
->name
);
1741 if (type
== UNIT_NAME_INSTANCE
) {
1742 r
= unit_name_replace_instance(dst
, inst
, &dst_updated
);
1744 return log_error_errno(r
, "Failed to build unit name from %s+%s: %m",
1749 r
= unit_validate_alias_symlink_and_warn(dst_updated
?: dst
, info
->name
);
1754 *ret_dst
= TAKE_PTR(dst_updated
);
1758 static int install_info_symlink_alias(
1759 UnitFileScope scope
,
1760 UnitFileInstallInfo
*info
,
1761 const LookupPaths
*lp
,
1762 const char *config_path
,
1764 UnitFileChange
**changes
,
1765 size_t *n_changes
) {
1771 assert(config_path
);
1773 STRV_FOREACH(s
, info
->aliases
) {
1774 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
, *dst_updated
= NULL
;
1776 q
= install_name_printf(scope
, info
, *s
, info
->root
, &dst
);
1778 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1782 q
= unit_file_verify_alias(info
, dst
, &dst_updated
);
1786 alias_path
= path_make_absolute(dst_updated
?: dst
, config_path
);
1790 q
= create_symlink(lp
, info
->path
, alias_path
, force
, changes
, n_changes
);
1798 static int install_info_symlink_wants(
1799 UnitFileScope scope
,
1800 UnitFileFlags file_flags
,
1801 UnitFileInstallInfo
*info
,
1802 const LookupPaths
*lp
,
1803 const char *config_path
,
1806 UnitFileChange
**changes
,
1807 size_t *n_changes
) {
1809 _cleanup_free_
char *buf
= NULL
;
1810 UnitNameFlags valid_dst_type
= UNIT_NAME_ANY
;
1816 assert(config_path
);
1818 if (strv_isempty(list
))
1821 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
| UNIT_NAME_INSTANCE
))
1822 /* Not a template unit. Use the name directly. */
1825 else if (info
->default_instance
) {
1826 UnitFileInstallInfo instance
= {
1827 .type
= _UNIT_FILE_TYPE_INVALID
,
1829 _cleanup_free_
char *path
= NULL
;
1831 /* If this is a template, and we have a default instance, use it. */
1833 r
= unit_name_replace_instance(info
->name
, info
->default_instance
, &buf
);
1837 instance
.name
= buf
;
1838 r
= unit_file_search(NULL
, &instance
, lp
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1842 path
= TAKE_PTR(instance
.path
);
1844 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1845 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1852 /* We have a template, but no instance yet. When used with an instantiated unit, we will get
1853 * the instance from that unit. Cannot be used with non-instance units. */
1855 valid_dst_type
= UNIT_NAME_INSTANCE
| UNIT_NAME_TEMPLATE
;
1859 STRV_FOREACH(s
, list
) {
1860 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1862 q
= install_name_printf(scope
, info
, *s
, info
->root
, &dst
);
1864 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1868 if (!unit_name_is_valid(dst
, valid_dst_type
)) {
1869 /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the
1870 * template status doesn't match. If we are doing presets don't bother reporting the
1871 * error. This also covers cases like 'systemctl preset serial-getty@.service', which
1872 * has no DefaultInstance, so there is nothing we can do. At the same time,
1873 * 'systemctl enable serial-getty@.service' should fail, the user should specify an
1874 * instance like in 'systemctl enable serial-getty@ttyS0.service'.
1876 if (file_flags
& UNIT_FILE_IGNORE_AUXILIARY_FAILURE
)
1879 if (unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1880 unit_file_changes_add(changes
, n_changes
, -EIDRM
, dst
, n
);
1883 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, dst
, NULL
);
1890 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1894 q
= create_symlink(lp
, info
->path
, path
, true, changes
, n_changes
);
1898 if (unit_file_exists(scope
, lp
, dst
) == 0)
1899 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_DESTINATION_NOT_PRESENT
, dst
, info
->path
);
1905 static int install_info_symlink_link(
1906 UnitFileInstallInfo
*info
,
1907 const LookupPaths
*lp
,
1908 const char *config_path
,
1910 UnitFileChange
**changes
,
1911 size_t *n_changes
) {
1913 _cleanup_free_
char *path
= NULL
;
1918 assert(config_path
);
1921 r
= in_search_path(lp
, info
->path
);
1927 path
= path_join(config_path
, info
->name
);
1931 return create_symlink(lp
, info
->path
, path
, force
, changes
, n_changes
);
1934 static int install_info_apply(
1935 UnitFileScope scope
,
1936 UnitFileFlags file_flags
,
1937 UnitFileInstallInfo
*info
,
1938 const LookupPaths
*lp
,
1939 const char *config_path
,
1940 UnitFileChange
**changes
,
1941 size_t *n_changes
) {
1947 assert(config_path
);
1949 if (info
->type
!= UNIT_FILE_TYPE_REGULAR
)
1952 bool force
= file_flags
& UNIT_FILE_FORCE
;
1954 r
= install_info_symlink_alias(scope
, info
, lp
, config_path
, force
, changes
, n_changes
);
1956 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->wanted_by
, ".wants/", changes
, n_changes
);
1960 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->required_by
, ".requires/", changes
, n_changes
);
1964 q
= install_info_symlink_link(info
, lp
, config_path
, force
, changes
, n_changes
);
1965 /* Do not count links to the unit file towards the "carries_install_info" count */
1966 if (r
== 0 && q
< 0)
1972 static int install_context_apply(
1973 InstallContext
*ctx
,
1974 const LookupPaths
*lp
,
1975 UnitFileFlags file_flags
,
1976 const char *config_path
,
1978 UnitFileChange
**changes
,
1979 size_t *n_changes
) {
1981 UnitFileInstallInfo
*i
;
1986 assert(config_path
);
1988 if (ordered_hashmap_isempty(ctx
->will_process
))
1991 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
1996 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
1999 q
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2003 q
= install_info_traverse(ctx
, lp
, i
, flags
, NULL
);
2006 q
= unit_file_changes_add(changes
, n_changes
, UNIT_FILE_AUXILIARY_FAILED
, NULL
, i
->name
);
2012 unit_file_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
2016 /* We can attempt to process a masked unit when a different unit
2017 * that we were processing specifies it in Also=. */
2018 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2019 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
2021 /* Assume that something *could* have been enabled here,
2022 * avoid "empty [Install] section" warning. */
2027 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
2030 q
= install_info_apply(ctx
->scope
, file_flags
, i
, lp
, config_path
, changes
, n_changes
);
2042 static int install_context_mark_for_removal(
2043 InstallContext
*ctx
,
2044 const LookupPaths
*lp
,
2045 Set
**remove_symlinks_to
,
2046 const char *config_path
,
2047 UnitFileChange
**changes
,
2048 size_t *n_changes
) {
2050 UnitFileInstallInfo
*i
;
2055 assert(config_path
);
2057 /* Marks all items for removal */
2059 if (ordered_hashmap_isempty(ctx
->will_process
))
2062 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2066 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2068 r
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2072 r
= install_info_traverse(ctx
, lp
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2073 if (r
== -ENOLINK
) {
2074 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
2075 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
2076 } else if (r
== -ENOENT
) {
2078 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
2079 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
2081 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
2082 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2086 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
2087 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2088 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2089 log_debug("Unit file %s is masked, ignoring.", i
->name
);
2090 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
2092 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
2093 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
2097 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2106 UnitFileScope scope
,
2107 UnitFileFlags flags
,
2108 const char *root_dir
,
2110 UnitFileChange
**changes
,
2111 size_t *n_changes
) {
2113 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2114 const char *config_path
;
2118 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2120 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2124 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2128 STRV_FOREACH(i
, files
) {
2129 _cleanup_free_
char *path
= NULL
;
2132 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2138 path
= path_make_absolute(*i
, config_path
);
2142 q
= create_symlink(&lp
, "/dev/null", path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2143 if (q
< 0 && r
>= 0)
2150 int unit_file_unmask(
2151 UnitFileScope scope
,
2152 UnitFileFlags flags
,
2153 const char *root_dir
,
2155 UnitFileChange
**changes
,
2156 size_t *n_changes
) {
2158 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2159 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2160 _cleanup_strv_free_
char **todo
= NULL
;
2161 const char *config_path
;
2166 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2168 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2172 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2176 bool dry_run
= flags
& UNIT_FILE_DRY_RUN
;
2178 STRV_FOREACH(i
, files
) {
2179 _cleanup_free_
char *path
= NULL
;
2181 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2184 path
= path_make_absolute(*i
, config_path
);
2188 r
= null_or_empty_path(path
);
2196 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2199 todo
[n_todo
] = strdup(*i
);
2209 STRV_FOREACH(i
, todo
) {
2210 _cleanup_free_
char *path
= NULL
;
2213 path
= path_make_absolute(*i
, config_path
);
2217 if (!dry_run
&& unlink(path
) < 0) {
2218 if (errno
!= ENOENT
) {
2221 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2227 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2229 rp
= skip_root(lp
.root_dir
, path
);
2230 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2235 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, dry_run
, changes
, n_changes
);
2243 UnitFileScope scope
,
2244 UnitFileFlags flags
,
2245 const char *root_dir
,
2247 UnitFileChange
**changes
,
2248 size_t *n_changes
) {
2250 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2251 _cleanup_strv_free_
char **todo
= NULL
;
2252 const char *config_path
;
2257 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2259 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2263 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2267 STRV_FOREACH(i
, files
) {
2268 _cleanup_free_
char *full
= NULL
;
2272 if (!path_is_absolute(*i
))
2276 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2279 full
= path_join(lp
.root_dir
, *i
);
2283 if (lstat(full
, &st
) < 0)
2285 r
= stat_verify_regular(&st
);
2289 q
= in_search_path(&lp
, *i
);
2295 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2298 todo
[n_todo
] = strdup(*i
);
2308 STRV_FOREACH(i
, todo
) {
2309 _cleanup_free_
char *new_path
= NULL
;
2311 new_path
= path_make_absolute(basename(*i
), config_path
);
2315 q
= create_symlink(&lp
, *i
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2316 if (q
< 0 && r
>= 0)
2323 static int path_shall_revert(const LookupPaths
*lp
, const char *path
) {
2329 /* Checks whether the path is one where the drop-in directories shall be removed. */
2331 r
= path_is_config(lp
, path
, true);
2335 r
= path_is_control(lp
, path
);
2339 return path_is_transient(lp
, path
);
2342 int unit_file_revert(
2343 UnitFileScope scope
,
2344 const char *root_dir
,
2346 UnitFileChange
**changes
,
2347 size_t *n_changes
) {
2349 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2350 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2351 _cleanup_strv_free_
char **todo
= NULL
;
2355 /* Puts a unit file back into vendor state. This means:
2357 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2358 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2360 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2361 * "config", but not in "transient" or "control" or even "generated").
2363 * We remove all that in both the runtime and the persistent directories, if that applies.
2366 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2370 STRV_FOREACH(i
, files
) {
2371 bool has_vendor
= false;
2373 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2376 STRV_FOREACH(p
, lp
.search_path
) {
2377 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2380 path
= path_make_absolute(*i
, *p
);
2384 r
= lstat(path
, &st
);
2386 if (errno
!= ENOENT
)
2388 } else if (S_ISREG(st
.st_mode
)) {
2389 /* Check if there's a vendor version */
2390 r
= path_is_vendor_or_generator(&lp
, path
);
2397 dropin
= strjoin(path
, ".d");
2401 r
= lstat(dropin
, &st
);
2403 if (errno
!= ENOENT
)
2405 } else if (S_ISDIR(st
.st_mode
)) {
2406 /* Remove the drop-ins */
2407 r
= path_shall_revert(&lp
, dropin
);
2411 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2414 todo
[n_todo
++] = TAKE_PTR(dropin
);
2422 /* OK, there's a vendor version, hence drop all configuration versions */
2423 STRV_FOREACH(p
, lp
.search_path
) {
2424 _cleanup_free_
char *path
= NULL
;
2427 path
= path_make_absolute(*i
, *p
);
2431 r
= lstat(path
, &st
);
2433 if (errno
!= ENOENT
)
2435 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2436 r
= path_is_config(&lp
, path
, true);
2440 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2443 todo
[n_todo
++] = TAKE_PTR(path
);
2452 STRV_FOREACH(i
, todo
) {
2453 _cleanup_strv_free_
char **fs
= NULL
;
2456 (void) get_files_in_directory(*i
, &fs
);
2458 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2459 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2464 STRV_FOREACH(j
, fs
) {
2465 _cleanup_free_
char *t
= NULL
;
2467 t
= path_join(*i
, *j
);
2471 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2474 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2476 rp
= skip_root(lp
.root_dir
, *i
);
2477 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2482 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.runtime_config
, &lp
, false, changes
, n_changes
);
2486 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.persistent_config
, &lp
, false, changes
, n_changes
);
2493 int unit_file_add_dependency(
2494 UnitFileScope scope
,
2495 UnitFileFlags file_flags
,
2496 const char *root_dir
,
2500 UnitFileChange
**changes
,
2501 size_t *n_changes
) {
2503 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2504 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2505 UnitFileInstallInfo
*info
, *target_info
;
2506 const char *config_path
;
2510 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2513 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2516 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2519 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2523 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2527 r
= install_info_discover_and_check(&ctx
, &lp
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2528 &target_info
, changes
, n_changes
);
2532 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2534 STRV_FOREACH(f
, files
) {
2537 r
= install_info_discover_and_check(&ctx
, &lp
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2538 &info
, changes
, n_changes
);
2542 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2544 /* We didn't actually load anything from the unit
2545 * file, but instead just add in our new symlink to
2548 if (dep
== UNIT_WANTS
)
2549 l
= &info
->wanted_by
;
2551 l
= &info
->required_by
;
2554 *l
= strv_new(target_info
->name
);
2559 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2560 SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2563 int unit_file_enable(
2564 UnitFileScope scope
,
2565 UnitFileFlags file_flags
,
2566 const char *root_dir
,
2568 UnitFileChange
**changes
,
2569 size_t *n_changes
) {
2571 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2572 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2573 const char *config_path
;
2574 UnitFileInstallInfo
*info
;
2578 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2580 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2584 config_path
= config_path_from_flags(&lp
, file_flags
);
2588 STRV_FOREACH(f
, files
) {
2589 r
= install_info_discover_and_check(&ctx
, &lp
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2590 &info
, changes
, n_changes
);
2594 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2597 /* This will return the number of symlink rules that were
2598 supposed to be created, not the ones actually created. This
2599 is useful to determine whether the passed files had any
2600 installation data at all. */
2602 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2603 SEARCH_LOAD
, changes
, n_changes
);
2606 int unit_file_disable(
2607 UnitFileScope scope
,
2608 UnitFileFlags flags
,
2609 const char *root_dir
,
2611 UnitFileChange
**changes
,
2612 size_t *n_changes
) {
2614 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2615 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2616 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2617 const char *config_path
;
2621 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2623 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2627 config_path
= config_path_from_flags(&lp
, flags
);
2631 STRV_FOREACH(i
, files
) {
2632 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2635 r
= install_info_add(&ctx
, *i
, NULL
, lp
.root_dir
, /* auxiliary= */ false, NULL
);
2640 r
= install_context_mark_for_removal(&ctx
, &lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2644 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, flags
& UNIT_FILE_DRY_RUN
, changes
, n_changes
);
2647 int unit_file_reenable(
2648 UnitFileScope scope
,
2649 UnitFileFlags flags
,
2650 const char *root_dir
,
2652 UnitFileChange
**changes
,
2653 size_t *n_changes
) {
2659 /* First, we invoke the disable command with only the basename... */
2660 l
= strv_length(files
);
2661 n
= newa(char*, l
+1);
2662 for (i
= 0; i
< l
; i
++)
2663 n
[i
] = basename(files
[i
]);
2666 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2670 /* But the enable command with the full name */
2671 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2674 int unit_file_set_default(
2675 UnitFileScope scope
,
2676 UnitFileFlags flags
,
2677 const char *root_dir
,
2679 UnitFileChange
**changes
,
2680 size_t *n_changes
) {
2682 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2683 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2684 UnitFileInstallInfo
*info
;
2685 const char *new_path
;
2689 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2692 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2694 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2697 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2701 r
= install_info_discover_and_check(&ctx
, &lp
, name
, 0, &info
, changes
, n_changes
);
2705 new_path
= strjoina(lp
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2706 return create_symlink(&lp
, info
->path
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2709 int unit_file_get_default(
2710 UnitFileScope scope
,
2711 const char *root_dir
,
2714 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2715 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2716 UnitFileInstallInfo
*info
;
2721 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2724 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2728 r
= install_info_discover(&ctx
, &lp
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2732 r
= install_info_may_process(info
, &lp
, NULL
, 0);
2736 n
= strdup(info
->name
);
2744 int unit_file_lookup_state(
2745 UnitFileScope scope
,
2746 const LookupPaths
*lp
,
2748 UnitFileState
*ret
) {
2750 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2751 UnitFileInstallInfo
*info
;
2752 UnitFileState state
;
2758 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2761 r
= install_info_discover(&ctx
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2764 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2766 assert(IN_SET(info
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2767 log_debug("Found unit %s at %s (%s)", name
, strna(info
->path
),
2768 info
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2770 /* Shortcut things, if the caller just wants to know if this unit exists. */
2774 switch (info
->type
) {
2776 case UNIT_FILE_TYPE_MASKED
:
2777 r
= path_is_runtime(lp
, info
->path
, true);
2781 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2784 case UNIT_FILE_TYPE_REGULAR
:
2785 /* Check if the name we were querying is actually an alias */
2786 if (!streq(name
, basename(info
->path
)) && !unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
2787 state
= UNIT_FILE_ALIAS
;
2791 r
= path_is_generator(lp
, info
->path
);
2795 state
= UNIT_FILE_GENERATED
;
2799 r
= path_is_transient(lp
, info
->path
);
2803 state
= UNIT_FILE_TRANSIENT
;
2807 /* Check if any of the Alias= symlinks have been created.
2808 * We ignore other aliases, and only check those that would
2809 * be created by systemctl enable for this unit. */
2810 r
= find_symlinks_in_scope(scope
, lp
, info
, true, &state
);
2816 /* Check if the file is known under other names. If it is,
2817 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2818 r
= find_symlinks_in_scope(scope
, lp
, info
, false, &state
);
2822 state
= UNIT_FILE_INDIRECT
;
2824 if (unit_file_install_info_has_rules(info
))
2825 state
= UNIT_FILE_DISABLED
;
2826 else if (unit_file_install_info_has_also(info
))
2827 state
= UNIT_FILE_INDIRECT
;
2829 state
= UNIT_FILE_STATIC
;
2835 assert_not_reached();
2842 int unit_file_get_state(
2843 UnitFileScope scope
,
2844 const char *root_dir
,
2846 UnitFileState
*ret
) {
2848 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2852 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2855 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2859 return unit_file_lookup_state(scope
, &lp
, name
, ret
);
2862 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*lp
, const char *name
) {
2863 _cleanup_(install_context_done
) InstallContext c
= { .scope
= scope
};
2869 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2872 r
= install_info_discover(&c
, lp
, name
, 0, NULL
, NULL
, NULL
);
2881 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2882 _cleanup_strv_free_
char **instances
= NULL
;
2883 _cleanup_free_
char *unit_name
= NULL
;
2887 assert(out_instances
);
2888 assert(out_unit_name
);
2890 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
2894 /* We handle the instances logic when unit name is extracted */
2896 /* We only create instances when a rule of templated unit
2897 * is seen. A rule like enable foo@.service a b c will
2898 * result in an array of (a, b, c) as instance names */
2899 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2902 instances
= strv_split(pattern
, WHITESPACE
);
2906 *out_instances
= TAKE_PTR(instances
);
2909 *out_unit_name
= TAKE_PTR(unit_name
);
2914 static int presets_find_config(UnitFileScope scope
, const char *root_dir
, char ***files
) {
2915 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
2916 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
2917 const char* const* dirs
;
2920 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2922 if (scope
== UNIT_FILE_SYSTEM
)
2924 else if (IN_SET(scope
, UNIT_FILE_GLOBAL
, UNIT_FILE_USER
))
2927 assert_not_reached();
2929 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
2932 static int read_presets(UnitFileScope scope
, const char *root_dir
, UnitFilePresets
*presets
) {
2933 _cleanup_(unit_file_presets_freep
) UnitFilePresets ps
= {};
2934 _cleanup_strv_free_
char **files
= NULL
;
2938 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2941 r
= presets_find_config(scope
, root_dir
, &files
);
2945 STRV_FOREACH(p
, files
) {
2946 _cleanup_fclose_
FILE *f
= NULL
;
2949 f
= fopen(*p
, "re");
2951 if (errno
== ENOENT
)
2958 _cleanup_free_
char *line
= NULL
;
2959 UnitFilePresetRule rule
= {};
2960 const char *parameter
;
2963 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2974 if (strchr(COMMENTS
, *l
))
2977 parameter
= first_word(l
, "enable");
2980 char **instances
= NULL
;
2982 /* Unit_name will remain the same as parameter when no instances are specified */
2983 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2985 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2989 rule
= (UnitFilePresetRule
) {
2990 .pattern
= unit_name
,
2991 .action
= PRESET_ENABLE
,
2992 .instances
= instances
,
2996 parameter
= first_word(l
, "disable");
3000 pattern
= strdup(parameter
);
3004 rule
= (UnitFilePresetRule
) {
3006 .action
= PRESET_DISABLE
,
3011 if (!GREEDY_REALLOC(ps
.rules
, ps
.n_rules
+ 1))
3014 ps
.rules
[ps
.n_rules
++] = rule
;
3018 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
3022 ps
.initialized
= true;
3024 ps
= (UnitFilePresets
){};
3029 static int pattern_match_multiple_instances(
3030 const UnitFilePresetRule rule
,
3031 const char *unit_name
,
3034 _cleanup_free_
char *templated_name
= NULL
;
3037 /* If no ret is needed or the rule itself does not have instances
3038 * initialized, we return not matching */
3039 if (!ret
|| !rule
.instances
)
3042 r
= unit_name_template(unit_name
, &templated_name
);
3045 if (!streq(rule
.pattern
, templated_name
))
3048 /* Compose a list of specified instances when unit name is a template */
3049 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
3050 _cleanup_strv_free_
char **out_strv
= NULL
;
3052 STRV_FOREACH(iter
, rule
.instances
) {
3053 _cleanup_free_
char *name
= NULL
;
3055 r
= unit_name_replace_instance(unit_name
, *iter
, &name
);
3059 r
= strv_consume(&out_strv
, TAKE_PTR(name
));
3064 *ret
= TAKE_PTR(out_strv
);
3067 /* We now know the input unit name is an instance name */
3068 _cleanup_free_
char *instance_name
= NULL
;
3070 r
= unit_name_to_instance(unit_name
, &instance_name
);
3074 if (strv_find(rule
.instances
, instance_name
))
3080 static int query_presets(const char *name
, const UnitFilePresets
*presets
, char ***instance_name_list
) {
3081 PresetAction action
= PRESET_UNKNOWN
;
3083 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3086 for (size_t i
= 0; i
< presets
->n_rules
; i
++)
3087 if (pattern_match_multiple_instances(presets
->rules
[i
], name
, instance_name_list
) > 0 ||
3088 fnmatch(presets
->rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
3089 action
= presets
->rules
[i
].action
;
3094 case PRESET_UNKNOWN
:
3095 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3098 if (instance_name_list
&& *instance_name_list
)
3099 STRV_FOREACH(s
, *instance_name_list
)
3100 log_debug("Preset files say enable %s.", *s
);
3102 log_debug("Preset files say enable %s.", name
);
3104 case PRESET_DISABLE
:
3105 log_debug("Preset files say disable %s.", name
);
3108 assert_not_reached();
3112 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
, UnitFilePresets
*cached
) {
3113 _cleanup_(unit_file_presets_freep
) UnitFilePresets tmp
= {};
3118 if (!cached
->initialized
) {
3119 r
= read_presets(scope
, root_dir
, cached
);
3124 return query_presets(name
, cached
, NULL
);
3127 static int execute_preset(
3128 UnitFileFlags file_flags
,
3129 InstallContext
*plus
,
3130 InstallContext
*minus
,
3131 const LookupPaths
*lp
,
3132 const char *config_path
,
3134 UnitFilePresetMode mode
,
3135 UnitFileChange
**changes
,
3136 size_t *n_changes
) {
3143 assert(config_path
);
3145 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3146 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3148 r
= install_context_mark_for_removal(minus
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3152 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, false, changes
, n_changes
);
3156 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3159 /* Returns number of symlinks that where supposed to be installed. */
3160 q
= install_context_apply(plus
, lp
,
3161 file_flags
| UNIT_FILE_IGNORE_AUXILIARY_FAILURE
,
3163 SEARCH_LOAD
, changes
, n_changes
);
3175 static int preset_prepare_one(
3176 UnitFileScope scope
,
3177 InstallContext
*plus
,
3178 InstallContext
*minus
,
3181 const UnitFilePresets
*presets
,
3182 UnitFileChange
**changes
,
3183 size_t *n_changes
) {
3185 _cleanup_(install_context_done
) InstallContext tmp
= { .scope
= scope
};
3186 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3187 UnitFileInstallInfo
*info
;
3190 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3193 r
= install_info_discover(&tmp
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3194 &info
, changes
, n_changes
);
3197 if (!streq(name
, info
->name
)) {
3198 log_debug("Skipping %s because it is an alias for %s.", name
, info
->name
);
3202 r
= query_presets(name
, presets
, &instance_name_list
);
3207 if (instance_name_list
)
3208 STRV_FOREACH(s
, instance_name_list
) {
3209 r
= install_info_discover_and_check(plus
, lp
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3210 &info
, changes
, n_changes
);
3215 r
= install_info_discover_and_check(plus
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3216 &info
, changes
, n_changes
);
3222 r
= install_info_discover(minus
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3223 &info
, changes
, n_changes
);
3228 int unit_file_preset(
3229 UnitFileScope scope
,
3230 UnitFileFlags file_flags
,
3231 const char *root_dir
,
3233 UnitFilePresetMode mode
,
3234 UnitFileChange
**changes
,
3235 size_t *n_changes
) {
3237 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3238 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3239 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3240 const char *config_path
;
3244 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3245 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3247 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3251 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3255 r
= read_presets(scope
, root_dir
, &presets
);
3259 STRV_FOREACH(i
, files
) {
3260 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, *i
, &presets
, changes
, n_changes
);
3265 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, files
, mode
, changes
, n_changes
);
3268 int unit_file_preset_all(
3269 UnitFileScope scope
,
3270 UnitFileFlags file_flags
,
3271 const char *root_dir
,
3272 UnitFilePresetMode mode
,
3273 UnitFileChange
**changes
,
3274 size_t *n_changes
) {
3276 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3277 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3278 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3279 const char *config_path
= NULL
;
3283 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3284 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3286 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3290 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3294 r
= read_presets(scope
, root_dir
, &presets
);
3298 STRV_FOREACH(i
, lp
.search_path
) {
3299 _cleanup_closedir_
DIR *d
= NULL
;
3303 if (errno
== ENOENT
)
3309 FOREACH_DIRENT(de
, d
, return -errno
) {
3311 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3314 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3317 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, de
->d_name
, &presets
, changes
, n_changes
);
3319 !IN_SET(r
, -EEXIST
, -ERFKILL
, -EADDRNOTAVAIL
, -EBADSLT
, -EIDRM
, -EUCLEAN
, -ELOOP
, -ENOENT
, -EUNATCH
))
3320 /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
3321 * Coordinate with unit_file_dump_changes() above. */
3326 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, NULL
, mode
, changes
, n_changes
);
3329 static UnitFileList
* unit_file_list_free_one(UnitFileList
*f
) {
3337 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3338 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3341 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3343 int unit_file_get_list(
3344 UnitFileScope scope
,
3345 const char *root_dir
,
3350 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3354 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3357 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3361 STRV_FOREACH(dirname
, lp
.search_path
) {
3362 _cleanup_closedir_
DIR *d
= NULL
;
3364 d
= opendir(*dirname
);
3366 if (errno
== ENOENT
)
3368 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3369 log_debug_errno(errno
, "Failed to open \"%s\": %m", *dirname
);
3376 FOREACH_DIRENT(de
, d
, return -errno
) {
3377 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3379 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3382 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3385 if (hashmap_get(h
, de
->d_name
))
3388 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3391 f
= new0(UnitFileList
, 1);
3395 f
->path
= path_make_absolute(de
->d_name
, *dirname
);
3399 r
= unit_file_lookup_state(scope
, &lp
, de
->d_name
, &f
->state
);
3401 f
->state
= UNIT_FILE_BAD
;
3403 if (!strv_isempty(states
) &&
3404 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3407 r
= hashmap_put(h
, basename(f
->path
), f
);
3411 f
= NULL
; /* prevent cleanup */
3418 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3419 [UNIT_FILE_ENABLED
] = "enabled",
3420 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3421 [UNIT_FILE_LINKED
] = "linked",
3422 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3423 [UNIT_FILE_ALIAS
] = "alias",
3424 [UNIT_FILE_MASKED
] = "masked",
3425 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3426 [UNIT_FILE_STATIC
] = "static",
3427 [UNIT_FILE_DISABLED
] = "disabled",
3428 [UNIT_FILE_INDIRECT
] = "indirect",
3429 [UNIT_FILE_GENERATED
] = "generated",
3430 [UNIT_FILE_TRANSIENT
] = "transient",
3431 [UNIT_FILE_BAD
] = "bad",
3434 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3436 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3437 [UNIT_FILE_SYMLINK
] = "symlink",
3438 [UNIT_FILE_UNLINK
] = "unlink",
3439 [UNIT_FILE_IS_MASKED
] = "masked",
3440 [UNIT_FILE_IS_DANGLING
] = "dangling",
3441 [UNIT_FILE_DESTINATION_NOT_PRESENT
] = "destination not present",
3442 [UNIT_FILE_AUXILIARY_FAILED
] = "auxiliary unit failed",
3445 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, int);
3447 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3448 [UNIT_FILE_PRESET_FULL
] = "full",
3449 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3450 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3453 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);