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 err
= 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 err
= log_error_errno(changes
[i
].type_or_errno
,
369 "Failed to %s unit, file \"%s\" already exists.",
370 verb
, changes
[i
].path
);
373 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is masked.",
374 verb
, changes
[i
].path
);
377 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is transient or generated.",
378 verb
, changes
[i
].path
);
381 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid specifier in \"%s\".",
382 verb
, changes
[i
].path
);
385 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s %s, destination unit %s is a non-template unit.",
386 verb
, changes
[i
].source
, changes
[i
].path
);
389 err
= log_error_errno(changes
[i
].type_or_errno
,
390 "Failed to %s unit, \"%s\" is not a valid unit name.",
391 verb
, changes
[i
].path
);
394 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, refusing to operate on linked unit file %s.",
395 verb
, changes
[i
].path
);
398 if (changes
[i
].source
)
399 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot alias %s as %s.",
400 verb
, changes
[i
].source
, changes
[i
].path
);
402 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid unit reference \"%s\".",
403 verb
, changes
[i
].path
);
406 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s does not exist.",
407 verb
, changes
[i
].path
);
410 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot resolve specifiers in \"%s\".",
411 verb
, changes
[i
].path
);
414 assert(changes
[i
].type_or_errno
< 0);
415 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, file \"%s\": %m",
416 verb
, changes
[i
].path
);
420 if (r
< 0 && err
>= 0)
421 log_error_errno(r
, "Failed to %s: %m.", verb
);
425 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
426 * wc should be the full path in the host file system.
428 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
429 assert(path_is_absolute(wd
));
431 /* This will give incorrect results if the paths are relative and go outside
432 * of the chroot. False negatives are possible. */
437 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
438 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
439 return path_equal_or_files_same(a
, b
, 0);
442 static int create_symlink(
443 const LookupPaths
*lp
,
444 const char *old_path
,
445 const char *new_path
,
447 UnitFileChange
**changes
,
450 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
457 rp
= skip_root(lp
->root_dir
, old_path
);
461 /* Actually create a symlink, and remember that we did. This function is
462 * smart enough to check if there's already a valid symlink in place.
464 * Returns 1 if a symlink was created or already exists and points to the
465 * right place, or negative on error.
468 (void) mkdir_parents_label(new_path
, 0755);
470 if (symlink(old_path
, new_path
) >= 0) {
471 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
475 if (errno
!= EEXIST
) {
476 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
480 r
= readlink_malloc(new_path
, &dest
);
482 /* translate EINVAL (non-symlink exists) to EEXIST */
486 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
490 dirname
= dirname_malloc(new_path
);
494 if (chroot_symlinks_same(lp
->root_dir
, dirname
, dest
, old_path
)) {
495 log_debug("Symlink %s → %s already exists", new_path
, dest
);
500 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
504 r
= symlink_atomic(old_path
, new_path
);
506 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
510 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
511 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
516 static int mark_symlink_for_removal(
517 Set
**remove_symlinks_to
,
525 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
535 r
= set_consume(*remove_symlinks_to
, n
);
544 static int remove_marked_symlinks_fd(
545 Set
*remove_symlinks_to
,
548 const char *config_path
,
549 const LookupPaths
*lp
,
552 UnitFileChange
**changes
,
555 _cleanup_closedir_
DIR *d
= NULL
;
558 assert(remove_symlinks_to
);
573 FOREACH_DIRENT(de
, d
, return -errno
)
575 if (de
->d_type
== DT_DIR
) {
576 _cleanup_free_
char *p
= NULL
;
579 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
589 p
= path_make_absolute(de
->d_name
, path
);
595 /* This will close nfd, regardless whether it succeeds or not */
596 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
600 } else if (de
->d_type
== DT_LNK
) {
601 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
606 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
609 p
= path_make_absolute(de
->d_name
, path
);
614 q
= chase_symlinks(p
, lp
->root_dir
, CHASE_NONEXISTENT
, &dest
, NULL
);
618 log_debug_errno(q
, "Failed to resolve symlink \"%s\": %m", p
);
619 unit_file_changes_add(changes
, n_changes
, q
, p
, NULL
);
626 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
627 * the same name as a file that is marked. */
629 found
= set_contains(remove_symlinks_to
, dest
) ||
630 set_contains(remove_symlinks_to
, basename(dest
)) ||
631 set_contains(remove_symlinks_to
, de
->d_name
);
637 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
640 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
644 (void) rmdir_parents(p
, config_path
);
647 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
649 /* Now, remember the full path (but with the root prefix removed) of
650 * the symlink we just removed, and remove any symlinks to it, too. */
652 rp
= skip_root(lp
->root_dir
, p
);
653 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
656 if (q
> 0 && !dry_run
)
663 static int remove_marked_symlinks(
664 Set
*remove_symlinks_to
,
665 const char *config_path
,
666 const LookupPaths
*lp
,
668 UnitFileChange
**changes
,
671 _cleanup_close_
int fd
= -1;
678 if (set_size(remove_symlinks_to
) <= 0)
681 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
683 return errno
== ENOENT
? 0 : -errno
;
689 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
693 /* This takes possession of cfd and closes it */
694 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
702 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
705 if (streq(name
, i
->name
))
708 if (strv_contains(i
->aliases
, name
))
711 /* Look for template symlink matching DefaultInstance */
712 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
713 _cleanup_free_
char *s
= NULL
;
715 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
720 } else if (streq(name
, s
))
727 static int find_symlinks_in_directory(
729 const char *dir_path
,
730 const char *root_dir
,
731 const UnitFileInstallInfo
*info
,
733 bool ignore_same_name
,
734 const char *config_path
,
735 bool *same_name_link
) {
739 FOREACH_DIRENT(de
, dir
, return -errno
) {
740 _cleanup_free_
char *dest
= NULL
;
741 bool found_path
= false, found_dest
, b
= false;
744 if (de
->d_type
!= DT_LNK
)
747 /* Acquire symlink destination */
748 q
= readlinkat_malloc(dirfd(dir
), de
->d_name
, &dest
);
758 if (!path_is_absolute(dest
)) {
761 x
= path_join(dir_path
, dest
);
765 free_and_replace(dest
, x
);
768 assert(unit_name_is_valid(info
->name
, UNIT_NAME_ANY
));
769 if (!ignore_same_name
)
770 /* Check if the symlink itself matches what we are looking for.
772 * If ignore_same_name is specified, we are in one of the directories which
773 * have lower priority than the unit file, and even if a file or symlink with
774 * this name was found, we should ignore it. */
775 found_path
= streq(de
->d_name
, info
->name
);
777 /* Check if what the symlink points to matches what we are looking for */
778 found_dest
= streq(basename(dest
), info
->name
);
780 if (found_path
&& found_dest
) {
781 _cleanup_free_
char *p
= NULL
, *t
= NULL
;
783 /* Filter out same name links in the main
785 p
= path_make_absolute(de
->d_name
, dir_path
);
786 t
= path_make_absolute(info
->name
, config_path
);
791 b
= path_equal(p
, t
);
795 *same_name_link
= true;
796 else if (found_path
|| found_dest
) {
800 /* Check if symlink name is in the set of names used by [Install] */
801 q
= is_symlink_with_known_name(info
, de
->d_name
);
812 static int find_symlinks(
813 const char *root_dir
,
814 const UnitFileInstallInfo
*i
,
816 bool ignore_same_name
,
817 const char *config_path
,
818 bool *same_name_link
) {
820 _cleanup_closedir_
DIR *config_dir
= NULL
;
825 assert(same_name_link
);
827 config_dir
= opendir(config_path
);
829 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
834 FOREACH_DIRENT(de
, config_dir
, return -errno
) {
836 _cleanup_free_
const char *path
= NULL
;
837 _cleanup_closedir_
DIR *d
= NULL
;
839 if (de
->d_type
!= DT_DIR
)
842 suffix
= strrchr(de
->d_name
, '.');
843 if (!STRPTR_IN_SET(suffix
, ".wants", ".requires"))
846 path
= path_join(config_path
, de
->d_name
);
852 log_error_errno(errno
, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path
);
856 r
= find_symlinks_in_directory(d
, path
, root_dir
, i
, match_name
, ignore_same_name
, config_path
, same_name_link
);
860 log_debug_errno(r
, "Failed to look up symlinks in \"%s\": %m", path
);
863 /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
864 rewinddir(config_dir
);
865 return find_symlinks_in_directory(config_dir
, config_path
, root_dir
, i
, match_name
, ignore_same_name
, config_path
, same_name_link
);
868 static int find_symlinks_in_scope(
870 const LookupPaths
*lp
,
871 const UnitFileInstallInfo
*info
,
873 UnitFileState
*state
) {
875 bool same_name_link_runtime
= false, same_name_link_config
= false;
876 bool enabled_in_runtime
= false, enabled_at_all
= false;
877 bool ignore_same_name
= false;
883 /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name"
884 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
885 * effectively masked, so we should ignore them. */
887 STRV_FOREACH(p
, lp
->search_path
) {
888 bool same_name_link
= false;
890 r
= find_symlinks(lp
->root_dir
, info
, match_name
, ignore_same_name
, *p
, &same_name_link
);
894 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
896 if (path_equal_ptr(*p
, lp
->persistent_config
)) {
897 /* This is the best outcome, let's return it immediately. */
898 *state
= UNIT_FILE_ENABLED
;
902 /* look for global enablement of user units */
903 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
904 *state
= UNIT_FILE_ENABLED
;
908 r
= path_is_runtime(lp
, *p
, false);
912 enabled_in_runtime
= true;
914 enabled_at_all
= true;
916 } else if (same_name_link
) {
917 if (path_equal_ptr(*p
, lp
->persistent_config
))
918 same_name_link_config
= true;
920 r
= path_is_runtime(lp
, *p
, false);
924 same_name_link_runtime
= true;
928 /* Check if next iteration will be "below" the unit file (either a regular file
929 * or a symlink), and hence should be ignored */
930 if (!ignore_same_name
&& path_startswith(info
->path
, *p
))
931 ignore_same_name
= true;
934 if (enabled_in_runtime
) {
935 *state
= UNIT_FILE_ENABLED_RUNTIME
;
939 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
940 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
941 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
942 * something, and hence are a much stronger concept. */
943 if (enabled_at_all
&& unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
944 *state
= UNIT_FILE_STATIC
;
948 /* Hmm, we didn't find it, but maybe we found the same name
950 if (same_name_link_config
) {
951 *state
= UNIT_FILE_LINKED
;
954 if (same_name_link_runtime
) {
955 *state
= UNIT_FILE_LINKED_RUNTIME
;
962 static void install_info_free(UnitFileInstallInfo
*i
) {
969 strv_free(i
->aliases
);
970 strv_free(i
->wanted_by
);
971 strv_free(i
->required_by
);
973 free(i
->default_instance
);
974 free(i
->symlink_target
);
978 static void install_context_done(InstallContext
*ctx
) {
981 ctx
->will_process
= ordered_hashmap_free_with_destructor(ctx
->will_process
, install_info_free
);
982 ctx
->have_processed
= ordered_hashmap_free_with_destructor(ctx
->have_processed
, install_info_free
);
985 static UnitFileInstallInfo
*install_info_find(InstallContext
*ctx
, const char *name
) {
986 UnitFileInstallInfo
*i
;
988 i
= ordered_hashmap_get(ctx
->have_processed
, name
);
992 return ordered_hashmap_get(ctx
->will_process
, name
);
995 static int install_info_may_process(
996 const UnitFileInstallInfo
*i
,
997 const LookupPaths
*lp
,
998 UnitFileChange
**changes
,
1003 /* Checks whether the loaded unit file is one we should process, or is masked,
1004 * transient or generated and thus not subject to enable/disable operations. */
1006 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1007 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1010 if (path_is_generator(lp
, i
->path
) ||
1011 path_is_transient(lp
, i
->path
)) {
1012 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1013 return -EADDRNOTAVAIL
;
1020 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1021 * hashmap, or retrieves the existing one if already present.
1023 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1025 static int install_info_add(
1026 InstallContext
*ctx
,
1031 UnitFileInstallInfo
**ret
) {
1033 UnitFileInstallInfo
*i
= NULL
;
1039 /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
1040 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
1041 * but this cannot be possible in any code path (See #6119). */
1043 name
= basename(path
);
1046 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1049 i
= install_info_find(ctx
, name
);
1051 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1058 i
= new(UnitFileInstallInfo
, 1);
1062 *i
= (UnitFileInstallInfo
) {
1063 .type
= _UNIT_FILE_TYPE_INVALID
,
1064 .auxiliary
= auxiliary
,
1067 i
->name
= strdup(name
);
1074 i
->root
= strdup(root
);
1082 i
->path
= strdup(path
);
1089 r
= ordered_hashmap_ensure_put(&ctx
->will_process
, &string_hash_ops
, i
->name
, i
);
1099 install_info_free(i
);
1103 static int config_parse_alias(
1105 const char *filename
,
1107 const char *section
,
1108 unsigned section_line
,
1122 type
= unit_name_to_type(unit
);
1123 if (!unit_type_may_alias(type
))
1124 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1125 "Alias= is not allowed for %s units, ignoring.",
1126 unit_type_to_string(type
));
1128 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1129 lvalue
, ltype
, rvalue
, data
, userdata
);
1132 static int config_parse_also(
1134 const char *filename
,
1136 const char *section
,
1137 unsigned section_line
,
1144 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1145 InstallContext
*ctx
= ASSERT_PTR(data
);
1154 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1156 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1162 r
= install_name_printf(ctx
->scope
, info
, word
, info
->root
, &printed
);
1164 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1165 "Failed to resolve unit name in Also=\"%s\": %m", word
);
1167 r
= install_info_add(ctx
, printed
, NULL
, info
->root
, /* auxiliary= */ true, NULL
);
1171 r
= strv_push(&info
->also
, printed
);
1181 static int config_parse_default_instance(
1183 const char *filename
,
1185 const char *section
,
1186 unsigned section_line
,
1193 InstallContext
*ctx
= ASSERT_PTR(data
);
1194 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1195 _cleanup_free_
char *printed
= NULL
;
1203 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1204 /* When enabling an instance, we might be using a template unit file,
1205 * but we should ignore DefaultInstance silently. */
1207 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1208 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1209 "DefaultInstance= only makes sense for template units, ignoring.");
1211 r
= install_name_printf(ctx
->scope
, info
, rvalue
, info
->root
, &printed
);
1213 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1214 "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue
);
1216 if (isempty(printed
))
1217 printed
= mfree(printed
);
1219 if (printed
&& !unit_instance_is_valid(printed
))
1220 return log_syntax(unit
, LOG_WARNING
, filename
, line
, SYNTHETIC_ERRNO(EINVAL
),
1221 "Invalid DefaultInstance= value \"%s\".", printed
);
1223 return free_and_replace(info
->default_instance
, printed
);
1226 static int unit_file_load(
1227 InstallContext
*ctx
,
1228 UnitFileInstallInfo
*info
,
1230 const char *root_dir
,
1231 SearchFlags flags
) {
1233 const ConfigTableItem items
[] = {
1234 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1235 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1236 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1237 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1238 { "Install", "Also", config_parse_also
, 0, ctx
},
1243 _cleanup_fclose_
FILE *f
= NULL
;
1244 _cleanup_close_
int fd
= -1;
1251 if (!(flags
& SEARCH_DROPIN
)) {
1252 /* Loading or checking for the main unit file… */
1254 type
= unit_name_to_type(info
->name
);
1257 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1258 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1259 "%s: unit type %s cannot be templated, ignoring.", path
, unit_type_to_string(type
));
1261 if (!(flags
& SEARCH_LOAD
)) {
1262 if (lstat(path
, &st
) < 0)
1265 if (null_or_empty(&st
))
1266 info
->type
= UNIT_FILE_TYPE_MASKED
;
1267 else if (S_ISREG(st
.st_mode
))
1268 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1269 else if (S_ISLNK(st
.st_mode
))
1271 else if (S_ISDIR(st
.st_mode
))
1279 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1283 /* 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. */
1285 if (!(flags
& SEARCH_LOAD
))
1288 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1293 if (fstat(fd
, &st
) < 0)
1296 if (null_or_empty(&st
)) {
1297 if ((flags
& SEARCH_DROPIN
) == 0)
1298 info
->type
= UNIT_FILE_TYPE_MASKED
;
1303 r
= stat_verify_regular(&st
);
1307 f
= take_fdopen(&fd
, "r");
1311 /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1314 r
= config_parse(info
->name
, path
, f
,
1328 config_item_table_lookup
, items
,
1332 return log_debug_errno(r
, "Failed to parse \"%s\": %m", info
->name
);
1334 if ((flags
& SEARCH_DROPIN
) == 0)
1335 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1338 (int) strv_length(info
->aliases
) +
1339 (int) strv_length(info
->wanted_by
) +
1340 (int) strv_length(info
->required_by
);
1343 static int unit_file_load_or_readlink(
1344 InstallContext
*ctx
,
1345 UnitFileInstallInfo
*info
,
1347 const LookupPaths
*lp
,
1348 SearchFlags flags
) {
1351 r
= unit_file_load(ctx
, info
, path
, lp
->root_dir
, flags
);
1352 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1355 /* This is a symlink, let's read and verify it. */
1356 r
= unit_file_resolve_symlink(lp
->root_dir
, lp
->search_path
,
1357 NULL
, AT_FDCWD
, path
,
1358 true, &info
->symlink_target
);
1362 r
= null_or_empty_path_with_root(info
->symlink_target
, lp
->root_dir
);
1363 if (r
< 0 && r
!= -ENOENT
)
1364 return log_debug_errno(r
, "Failed to stat %s: %m", info
->symlink_target
);
1366 info
->type
= UNIT_FILE_TYPE_MASKED
;
1368 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1373 static int unit_file_search(
1374 InstallContext
*ctx
,
1375 UnitFileInstallInfo
*info
,
1376 const LookupPaths
*lp
,
1377 SearchFlags flags
) {
1379 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1380 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1381 _cleanup_free_
char *template = NULL
;
1382 bool found_unit
= false;
1388 /* Was this unit already loaded? */
1389 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1393 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1397 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1398 r
= unit_name_template(info
->name
, &template);
1403 STRV_FOREACH(p
, lp
->search_path
) {
1404 _cleanup_free_
char *path
= NULL
;
1406 path
= path_join(*p
, info
->name
);
1410 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1412 info
->path
= TAKE_PTR(path
);
1416 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1420 if (!found_unit
&& template) {
1422 /* Unit file doesn't exist, however instance
1423 * enablement was requested. We will check if it is
1424 * possible to load template unit file. */
1426 STRV_FOREACH(p
, lp
->search_path
) {
1427 _cleanup_free_
char *path
= NULL
;
1429 path
= path_join(*p
, template);
1433 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1435 info
->path
= TAKE_PTR(path
);
1439 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1445 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1446 "Cannot find unit %s%s%s.",
1447 info
->name
, template ? " or " : "", strempty(template));
1449 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1452 /* Search for drop-in directories */
1454 dropin_dir_name
= strjoina(info
->name
, ".d");
1455 STRV_FOREACH(p
, lp
->search_path
) {
1458 path
= path_join(*p
, dropin_dir_name
);
1462 r
= strv_consume(&dirs
, path
);
1468 dropin_template_dir_name
= strjoina(template, ".d");
1469 STRV_FOREACH(p
, lp
->search_path
) {
1472 path
= path_join(*p
, dropin_template_dir_name
);
1476 r
= strv_consume(&dirs
, path
);
1482 /* Load drop-in conf files */
1484 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1486 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1488 STRV_FOREACH(p
, files
) {
1489 r
= unit_file_load_or_readlink(ctx
, info
, *p
, lp
, flags
| SEARCH_DROPIN
);
1491 return log_debug_errno(r
, "Failed to load conf file \"%s\": %m", *p
);
1497 static int install_info_follow(
1498 InstallContext
*ctx
,
1499 UnitFileInstallInfo
*info
,
1500 const LookupPaths
*lp
,
1502 bool ignore_different_name
) {
1507 if (info
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1509 if (!info
->symlink_target
)
1512 /* If the basename doesn't match, the caller should add a complete new entry for this. */
1514 if (!ignore_different_name
&& !streq(basename(info
->symlink_target
), info
->name
))
1517 free_and_replace(info
->path
, info
->symlink_target
);
1518 info
->type
= _UNIT_FILE_TYPE_INVALID
;
1520 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1524 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1525 * target, maybe more than once. Propagate the instance name if present.
1527 static int install_info_traverse(
1528 InstallContext
*ctx
,
1529 const LookupPaths
*lp
,
1530 UnitFileInstallInfo
*start
,
1532 UnitFileInstallInfo
**ret
) {
1534 UnitFileInstallInfo
*i
;
1542 r
= unit_file_search(ctx
, start
, lp
, flags
);
1547 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1548 /* Follow the symlink */
1550 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1553 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1554 r
= path_is_config(lp
, i
->path
, true);
1561 r
= install_info_follow(ctx
, i
, lp
, flags
, false);
1563 _cleanup_free_
char *buffer
= NULL
;
1566 /* Target is an alias, create a new install info object and continue with that. */
1568 bn
= basename(i
->symlink_target
);
1570 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1571 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1573 _cleanup_free_
char *instance
= NULL
;
1575 r
= unit_name_to_instance(i
->name
, &instance
);
1579 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1583 if (streq(buffer
, i
->name
)) {
1585 /* We filled in the instance, and the target stayed the same? If so,
1586 * then let's honour the link as it is. */
1588 r
= install_info_follow(ctx
, i
, lp
, flags
, true);
1598 r
= install_info_add(ctx
, bn
, NULL
, lp
->root_dir
, /* auxiliary= */ false, &i
);
1602 /* Try again, with the new target we found. */
1603 r
= unit_file_search(ctx
, i
, lp
, flags
);
1605 /* Translate error code to highlight this specific case */
1620 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1621 * or the name (otherwise). root_dir is prepended to the path.
1623 static int install_info_add_auto(
1624 InstallContext
*ctx
,
1625 const LookupPaths
*lp
,
1626 const char *name_or_path
,
1627 UnitFileInstallInfo
**ret
) {
1630 assert(name_or_path
);
1632 if (path_is_absolute(name_or_path
)) {
1635 pp
= prefix_roota(lp
->root_dir
, name_or_path
);
1637 return install_info_add(ctx
, NULL
, pp
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1639 return install_info_add(ctx
, name_or_path
, NULL
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1642 static int install_info_discover(
1643 InstallContext
*ctx
,
1644 const LookupPaths
*lp
,
1647 UnitFileInstallInfo
**ret
,
1648 UnitFileChange
**changes
,
1649 size_t *n_changes
) {
1651 UnitFileInstallInfo
*info
;
1658 r
= install_info_add_auto(ctx
, lp
, name
, &info
);
1660 r
= install_info_traverse(ctx
, lp
, info
, flags
, ret
);
1663 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1667 static int install_info_discover_and_check(
1668 InstallContext
*ctx
,
1669 const LookupPaths
*lp
,
1672 UnitFileInstallInfo
**ret
,
1673 UnitFileChange
**changes
,
1674 size_t *n_changes
) {
1678 r
= install_info_discover(ctx
, lp
, name
, flags
, ret
, changes
, n_changes
);
1682 return install_info_may_process(ret
? *ret
: NULL
, lp
, changes
, n_changes
);
1685 int unit_file_verify_alias(
1686 const UnitFileInstallInfo
*info
,
1689 UnitFileChange
**changes
,
1690 size_t *n_changes
) {
1692 _cleanup_free_
char *dst_updated
= NULL
;
1695 /* Verify that dst is a valid either a valid alias or a valid .wants/.requires symlink for the target
1696 * unit *i. Return negative on error or if not compatible, zero on success.
1698 * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
1699 * inserted into dst. It is not normally set, even on success, so that the caller can easily
1700 * distinguish the case where instance propagation occurred.
1703 * -EXDEV when the alias doesn't match the unit,
1704 * -EUCLEAN when the name is invalid,
1705 * -ELOOP when the alias it to the unit itself.
1708 const char *path_alias
= strrchr(dst
, '/');
1710 /* This branch covers legacy Alias= function of creating .wants and .requires symlinks. */
1711 _cleanup_free_
char *dir
= NULL
;
1714 path_alias
++; /* skip over slash */
1716 dir
= dirname_malloc(dst
);
1720 p
= endswith(dir
, ".wants");
1722 p
= endswith(dir
, ".requires");
1724 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1725 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
), "Invalid path \"%s\" in alias.", dir
);
1728 *p
= '\0'; /* dir should now be a unit name */
1730 UnitNameFlags type
= unit_name_classify(dir
);
1732 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1733 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1734 "Invalid unit name component \"%s\" in alias.", dir
);
1737 const bool instance_propagation
= type
== UNIT_NAME_TEMPLATE
;
1739 /* That's the name we want to use for verification. */
1740 r
= unit_symlink_name_compatible(path_alias
, info
->name
, instance_propagation
);
1742 return log_error_errno(r
, "Failed to verify alias validity: %m");
1744 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, info
->name
);
1745 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1746 "Invalid unit \"%s\" symlink \"%s\".",
1751 /* If the symlink target has an instance set and the symlink source doesn't, we "propagate
1752 * the instance", i.e. instantiate the symlink source with the target instance. */
1753 if (unit_name_is_valid(dst
, UNIT_NAME_TEMPLATE
)) {
1754 _cleanup_free_
char *inst
= NULL
;
1756 UnitNameFlags type
= unit_name_to_instance(info
->name
, &inst
);
1758 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, info
->name
, NULL
);
1759 return log_debug_errno(type
, "Failed to extract instance name from \"%s\": %m", info
->name
);
1762 if (type
== UNIT_NAME_INSTANCE
) {
1763 r
= unit_name_replace_instance(dst
, inst
, &dst_updated
);
1765 return log_error_errno(r
, "Failed to build unit name from %s+%s: %m",
1770 r
= unit_validate_alias_symlink_or_warn(LOG_DEBUG
, dst_updated
?: dst
, info
->name
);
1771 if (r
== -ELOOP
) /* -ELOOP means self-alias, which we (quietly) ignore */
1774 unit_file_changes_add(changes
, n_changes
,
1775 r
== -EINVAL
? -EXDEV
: r
,
1782 *ret_dst
= TAKE_PTR(dst_updated
);
1786 static int install_info_symlink_alias(
1787 UnitFileScope scope
,
1788 UnitFileInstallInfo
*info
,
1789 const LookupPaths
*lp
,
1790 const char *config_path
,
1792 UnitFileChange
**changes
,
1793 size_t *n_changes
) {
1799 assert(config_path
);
1801 STRV_FOREACH(s
, info
->aliases
) {
1802 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
, *dst_updated
= NULL
;
1804 q
= install_name_printf(scope
, info
, *s
, info
->root
, &dst
);
1806 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1811 q
= unit_file_verify_alias(info
, dst
, &dst_updated
, changes
, n_changes
);
1819 alias_path
= path_make_absolute(dst_updated
?: dst
, config_path
);
1823 q
= create_symlink(lp
, info
->path
, alias_path
, force
, changes
, n_changes
);
1830 static int install_info_symlink_wants(
1831 UnitFileScope scope
,
1832 UnitFileFlags file_flags
,
1833 UnitFileInstallInfo
*info
,
1834 const LookupPaths
*lp
,
1835 const char *config_path
,
1838 UnitFileChange
**changes
,
1839 size_t *n_changes
) {
1841 _cleanup_free_
char *buf
= NULL
;
1842 UnitNameFlags valid_dst_type
= UNIT_NAME_ANY
;
1848 assert(config_path
);
1850 if (strv_isempty(list
))
1853 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
| UNIT_NAME_INSTANCE
))
1854 /* Not a template unit. Use the name directly. */
1857 else if (info
->default_instance
) {
1858 UnitFileInstallInfo instance
= {
1859 .type
= _UNIT_FILE_TYPE_INVALID
,
1861 _cleanup_free_
char *path
= NULL
;
1863 /* If this is a template, and we have a default instance, use it. */
1865 r
= unit_name_replace_instance(info
->name
, info
->default_instance
, &buf
);
1869 instance
.name
= buf
;
1870 r
= unit_file_search(NULL
, &instance
, lp
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1874 path
= TAKE_PTR(instance
.path
);
1876 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1877 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1884 /* We have a template, but no instance yet. When used with an instantiated unit, we will get
1885 * the instance from that unit. Cannot be used with non-instance units. */
1887 valid_dst_type
= UNIT_NAME_INSTANCE
| UNIT_NAME_TEMPLATE
;
1891 STRV_FOREACH(s
, list
) {
1892 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1894 q
= install_name_printf(scope
, info
, *s
, info
->root
, &dst
);
1896 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1900 if (!unit_name_is_valid(dst
, valid_dst_type
)) {
1901 /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the
1902 * template status doesn't match. If we are doing presets don't bother reporting the
1903 * error. This also covers cases like 'systemctl preset serial-getty@.service', which
1904 * has no DefaultInstance, so there is nothing we can do. At the same time,
1905 * 'systemctl enable serial-getty@.service' should fail, the user should specify an
1906 * instance like in 'systemctl enable serial-getty@ttyS0.service'.
1908 if (file_flags
& UNIT_FILE_IGNORE_AUXILIARY_FAILURE
)
1911 if (unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1912 unit_file_changes_add(changes
, n_changes
, -EIDRM
, dst
, n
);
1915 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, dst
, NULL
);
1922 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1926 q
= create_symlink(lp
, info
->path
, path
, true, changes
, n_changes
);
1930 if (unit_file_exists(scope
, lp
, dst
) == 0)
1931 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_DESTINATION_NOT_PRESENT
, dst
, info
->path
);
1937 static int install_info_symlink_link(
1938 UnitFileInstallInfo
*info
,
1939 const LookupPaths
*lp
,
1940 const char *config_path
,
1942 UnitFileChange
**changes
,
1943 size_t *n_changes
) {
1945 _cleanup_free_
char *path
= NULL
;
1950 assert(config_path
);
1953 r
= in_search_path(lp
, info
->path
);
1959 path
= path_join(config_path
, info
->name
);
1963 return create_symlink(lp
, info
->path
, path
, force
, changes
, n_changes
);
1966 static int install_info_apply(
1967 UnitFileScope scope
,
1968 UnitFileFlags file_flags
,
1969 UnitFileInstallInfo
*info
,
1970 const LookupPaths
*lp
,
1971 const char *config_path
,
1972 UnitFileChange
**changes
,
1973 size_t *n_changes
) {
1979 assert(config_path
);
1981 if (info
->type
!= UNIT_FILE_TYPE_REGULAR
)
1984 bool force
= file_flags
& UNIT_FILE_FORCE
;
1986 r
= install_info_symlink_link(info
, lp
, config_path
, force
, changes
, n_changes
);
1987 /* Do not count links to the unit file towards the "carries_install_info" count */
1989 /* If linking of the file failed, do not try to create other symlinks,
1990 * because they might would pointing to a non-existent or wrong unit. */
1993 r
= install_info_symlink_alias(scope
, info
, lp
, config_path
, force
, changes
, n_changes
);
1995 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->wanted_by
, ".wants/", changes
, n_changes
);
1999 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->required_by
, ".requires/", changes
, n_changes
);
2006 static int install_context_apply(
2007 InstallContext
*ctx
,
2008 const LookupPaths
*lp
,
2009 UnitFileFlags file_flags
,
2010 const char *config_path
,
2012 UnitFileChange
**changes
,
2013 size_t *n_changes
) {
2015 UnitFileInstallInfo
*i
;
2020 assert(config_path
);
2022 if (ordered_hashmap_isempty(ctx
->will_process
))
2025 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2030 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2033 q
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2037 q
= install_info_traverse(ctx
, lp
, i
, flags
, NULL
);
2040 q
= unit_file_changes_add(changes
, n_changes
, UNIT_FILE_AUXILIARY_FAILED
, NULL
, i
->name
);
2046 unit_file_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
2050 /* We can attempt to process a masked unit when a different unit
2051 * that we were processing specifies it in Also=. */
2052 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2053 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
2055 /* Assume that something *could* have been enabled here,
2056 * avoid "empty [Install] section" warning. */
2061 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
2064 q
= install_info_apply(ctx
->scope
, file_flags
, i
, lp
, config_path
, changes
, n_changes
);
2076 static int install_context_mark_for_removal(
2077 InstallContext
*ctx
,
2078 const LookupPaths
*lp
,
2079 Set
**remove_symlinks_to
,
2080 const char *config_path
,
2081 UnitFileChange
**changes
,
2082 size_t *n_changes
) {
2084 UnitFileInstallInfo
*i
;
2089 assert(config_path
);
2091 /* Marks all items for removal */
2093 if (ordered_hashmap_isempty(ctx
->will_process
))
2096 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2100 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2102 r
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2106 r
= install_info_traverse(ctx
, lp
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2107 if (r
== -ENOLINK
) {
2108 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
2109 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
2110 } else if (r
== -ENOENT
) {
2112 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
2113 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
2115 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
2116 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2120 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
2121 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2122 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2123 log_debug("Unit file %s is masked, ignoring.", i
->name
);
2124 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
2126 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
2127 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
2131 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2140 UnitFileScope scope
,
2141 UnitFileFlags flags
,
2142 const char *root_dir
,
2144 UnitFileChange
**changes
,
2145 size_t *n_changes
) {
2147 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2148 const char *config_path
;
2152 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2154 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2158 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2162 STRV_FOREACH(i
, files
) {
2163 _cleanup_free_
char *path
= NULL
;
2166 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2172 path
= path_make_absolute(*i
, config_path
);
2176 q
= create_symlink(&lp
, "/dev/null", path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2177 if (q
< 0 && r
>= 0)
2184 int unit_file_unmask(
2185 UnitFileScope scope
,
2186 UnitFileFlags flags
,
2187 const char *root_dir
,
2189 UnitFileChange
**changes
,
2190 size_t *n_changes
) {
2192 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2193 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2194 _cleanup_strv_free_
char **todo
= NULL
;
2195 const char *config_path
;
2200 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2202 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2206 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2210 bool dry_run
= flags
& UNIT_FILE_DRY_RUN
;
2212 STRV_FOREACH(i
, files
) {
2213 _cleanup_free_
char *path
= NULL
;
2215 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2218 path
= path_make_absolute(*i
, config_path
);
2222 r
= null_or_empty_path(path
);
2230 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2233 todo
[n_todo
] = strdup(*i
);
2243 STRV_FOREACH(i
, todo
) {
2244 _cleanup_free_
char *path
= NULL
;
2247 path
= path_make_absolute(*i
, config_path
);
2251 if (!dry_run
&& unlink(path
) < 0) {
2252 if (errno
!= ENOENT
) {
2255 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2261 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2263 rp
= skip_root(lp
.root_dir
, path
);
2264 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2269 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, dry_run
, changes
, n_changes
);
2277 UnitFileScope scope
,
2278 UnitFileFlags flags
,
2279 const char *root_dir
,
2281 UnitFileChange
**changes
,
2282 size_t *n_changes
) {
2284 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2285 _cleanup_strv_free_
char **todo
= NULL
;
2286 const char *config_path
;
2291 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2293 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2297 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2301 STRV_FOREACH(i
, files
) {
2302 _cleanup_free_
char *full
= NULL
;
2306 if (!path_is_absolute(*i
))
2310 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2313 full
= path_join(lp
.root_dir
, *i
);
2317 if (lstat(full
, &st
) < 0)
2319 r
= stat_verify_regular(&st
);
2323 q
= in_search_path(&lp
, *i
);
2329 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2332 todo
[n_todo
] = strdup(*i
);
2342 STRV_FOREACH(i
, todo
) {
2343 _cleanup_free_
char *new_path
= NULL
;
2345 new_path
= path_make_absolute(basename(*i
), config_path
);
2349 q
= create_symlink(&lp
, *i
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2350 if (q
< 0 && r
>= 0)
2357 static int path_shall_revert(const LookupPaths
*lp
, const char *path
) {
2363 /* Checks whether the path is one where the drop-in directories shall be removed. */
2365 r
= path_is_config(lp
, path
, true);
2369 r
= path_is_control(lp
, path
);
2373 return path_is_transient(lp
, path
);
2376 int unit_file_revert(
2377 UnitFileScope scope
,
2378 const char *root_dir
,
2380 UnitFileChange
**changes
,
2381 size_t *n_changes
) {
2383 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2384 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2385 _cleanup_strv_free_
char **todo
= NULL
;
2389 /* Puts a unit file back into vendor state. This means:
2391 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2392 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2394 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2395 * "config", but not in "transient" or "control" or even "generated").
2397 * We remove all that in both the runtime and the persistent directories, if that applies.
2400 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2404 STRV_FOREACH(i
, files
) {
2405 bool has_vendor
= false;
2407 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2410 STRV_FOREACH(p
, lp
.search_path
) {
2411 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2414 path
= path_make_absolute(*i
, *p
);
2418 r
= lstat(path
, &st
);
2420 if (errno
!= ENOENT
)
2422 } else if (S_ISREG(st
.st_mode
)) {
2423 /* Check if there's a vendor version */
2424 r
= path_is_vendor_or_generator(&lp
, path
);
2431 dropin
= strjoin(path
, ".d");
2435 r
= lstat(dropin
, &st
);
2437 if (errno
!= ENOENT
)
2439 } else if (S_ISDIR(st
.st_mode
)) {
2440 /* Remove the drop-ins */
2441 r
= path_shall_revert(&lp
, dropin
);
2445 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2448 todo
[n_todo
++] = TAKE_PTR(dropin
);
2456 /* OK, there's a vendor version, hence drop all configuration versions */
2457 STRV_FOREACH(p
, lp
.search_path
) {
2458 _cleanup_free_
char *path
= NULL
;
2461 path
= path_make_absolute(*i
, *p
);
2465 r
= lstat(path
, &st
);
2467 if (errno
!= ENOENT
)
2469 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2470 r
= path_is_config(&lp
, path
, true);
2474 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2477 todo
[n_todo
++] = TAKE_PTR(path
);
2486 STRV_FOREACH(i
, todo
) {
2487 _cleanup_strv_free_
char **fs
= NULL
;
2490 (void) get_files_in_directory(*i
, &fs
);
2492 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2493 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2498 STRV_FOREACH(j
, fs
) {
2499 _cleanup_free_
char *t
= NULL
;
2501 t
= path_join(*i
, *j
);
2505 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2508 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2510 rp
= skip_root(lp
.root_dir
, *i
);
2511 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2516 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.runtime_config
, &lp
, false, changes
, n_changes
);
2520 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.persistent_config
, &lp
, false, changes
, n_changes
);
2527 int unit_file_add_dependency(
2528 UnitFileScope scope
,
2529 UnitFileFlags file_flags
,
2530 const char *root_dir
,
2534 UnitFileChange
**changes
,
2535 size_t *n_changes
) {
2537 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2538 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2539 UnitFileInstallInfo
*info
, *target_info
;
2540 const char *config_path
;
2544 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2547 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2550 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2553 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2557 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2561 r
= install_info_discover_and_check(&ctx
, &lp
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2562 &target_info
, changes
, n_changes
);
2566 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2568 STRV_FOREACH(f
, files
) {
2571 r
= install_info_discover_and_check(&ctx
, &lp
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2572 &info
, changes
, n_changes
);
2576 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2578 /* We didn't actually load anything from the unit
2579 * file, but instead just add in our new symlink to
2582 if (dep
== UNIT_WANTS
)
2583 l
= &info
->wanted_by
;
2585 l
= &info
->required_by
;
2588 *l
= strv_new(target_info
->name
);
2593 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2594 SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2597 static int do_unit_file_enable(
2598 const LookupPaths
*lp
,
2599 UnitFileScope scope
,
2600 UnitFileFlags flags
,
2601 const char *config_path
,
2603 UnitFileChange
**changes
,
2604 size_t *n_changes
) {
2606 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2607 UnitFileInstallInfo
*info
;
2610 STRV_FOREACH(f
, files
) {
2611 r
= install_info_discover_and_check(&ctx
, lp
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2612 &info
, changes
, n_changes
);
2616 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2619 /* This will return the number of symlink rules that were
2620 supposed to be created, not the ones actually created. This
2621 is useful to determine whether the passed files had any
2622 installation data at all. */
2624 return install_context_apply(&ctx
, lp
, flags
, config_path
,
2625 SEARCH_LOAD
, changes
, n_changes
);
2628 int unit_file_enable(
2629 UnitFileScope scope
,
2630 UnitFileFlags flags
,
2631 const char *root_dir
,
2633 UnitFileChange
**changes
,
2634 size_t *n_changes
) {
2636 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2640 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2642 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2646 const char *config_path
= config_path_from_flags(&lp
, flags
);
2650 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2653 static int do_unit_file_disable(
2654 const LookupPaths
*lp
,
2655 UnitFileScope scope
,
2656 UnitFileFlags flags
,
2657 const char *config_path
,
2659 UnitFileChange
**changes
,
2660 size_t *n_changes
) {
2662 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2663 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2666 STRV_FOREACH(i
, files
) {
2667 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2670 r
= install_info_add(&ctx
, *i
, NULL
, lp
->root_dir
, /* auxiliary= */ false, NULL
);
2675 r
= install_context_mark_for_removal(&ctx
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2679 return remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, flags
& UNIT_FILE_DRY_RUN
, changes
, n_changes
);
2683 int unit_file_disable(
2684 UnitFileScope scope
,
2685 UnitFileFlags flags
,
2686 const char *root_dir
,
2688 UnitFileChange
**changes
,
2689 size_t *n_changes
) {
2691 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2695 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2697 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2701 const char *config_path
= config_path_from_flags(&lp
, flags
);
2705 return do_unit_file_disable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2708 static int normalize_linked_files(
2709 UnitFileScope scope
,
2710 const LookupPaths
*lp
,
2711 char **names_or_paths
,
2713 char ***ret_files
) {
2715 /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/,
2716 * but operates on real unit names. For each argument we we look up the actual path
2717 * where the unit is found. This way linked units can be reenabled successfully. */
2719 _cleanup_free_
char **files
= NULL
, **names
= NULL
;
2722 STRV_FOREACH(a
, names_or_paths
) {
2723 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2724 UnitFileInstallInfo
*i
= NULL
;
2725 _cleanup_free_
char *n
= NULL
;
2727 r
= path_extract_filename(*a
, &n
);
2730 if (r
== O_DIRECTORY
)
2731 return log_debug_errno(SYNTHETIC_ERRNO(EISDIR
),
2732 "Unexpected path to a directory \"%s\", refusing.", *a
);
2735 r
= install_info_discover(&ctx
, lp
, n
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
, NULL
, NULL
);
2737 log_debug_errno(r
, "Failed to discover unit \"%s\", operating on name: %m", n
);
2740 r
= strv_consume(&names
, TAKE_PTR(n
));
2744 const char *p
= NULL
;
2746 /* Use startswith here, because we know that paths are normalized, and
2747 * path_startswith() would give us a relative path, but we need an absolute path
2748 * relative to i->root.
2750 * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service
2751 * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute"
2752 * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/.
2754 p
= startswith(i
->path
, i
->root
);
2756 r
= strv_extend(&files
, p
?: *a
);
2761 *ret_names
= TAKE_PTR(names
);
2762 *ret_files
= TAKE_PTR(files
);
2766 int unit_file_reenable(
2767 UnitFileScope scope
,
2768 UnitFileFlags flags
,
2769 const char *root_dir
,
2770 char **names_or_paths
,
2771 UnitFileChange
**changes
,
2772 size_t *n_changes
) {
2774 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2775 _cleanup_strv_free_
char **names
= NULL
, **files
= NULL
;
2779 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2781 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2785 const char *config_path
= config_path_from_flags(&lp
, flags
);
2789 r
= normalize_linked_files(scope
, &lp
, names_or_paths
, &names
, &files
);
2793 /* First, we invoke the disable command with only the basename... */
2794 r
= do_unit_file_disable(&lp
, scope
, flags
, config_path
, names
, changes
, n_changes
);
2798 /* But the enable command with the full name */
2799 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2802 int unit_file_set_default(
2803 UnitFileScope scope
,
2804 UnitFileFlags flags
,
2805 const char *root_dir
,
2807 UnitFileChange
**changes
,
2808 size_t *n_changes
) {
2810 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2811 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2812 UnitFileInstallInfo
*info
;
2813 const char *new_path
;
2817 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2820 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2822 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2825 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2829 r
= install_info_discover_and_check(&ctx
, &lp
, name
, 0, &info
, changes
, n_changes
);
2833 new_path
= strjoina(lp
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2834 return create_symlink(&lp
, info
->path
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2837 int unit_file_get_default(
2838 UnitFileScope scope
,
2839 const char *root_dir
,
2842 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2843 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2844 UnitFileInstallInfo
*info
;
2849 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2852 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2856 r
= install_info_discover(&ctx
, &lp
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2860 r
= install_info_may_process(info
, &lp
, NULL
, 0);
2864 n
= strdup(info
->name
);
2872 int unit_file_lookup_state(
2873 UnitFileScope scope
,
2874 const LookupPaths
*lp
,
2876 UnitFileState
*ret
) {
2878 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2879 UnitFileInstallInfo
*info
;
2880 UnitFileState state
;
2886 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2889 r
= install_info_discover(&ctx
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2892 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2894 assert(IN_SET(info
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2895 log_debug("Found unit %s at %s (%s)", name
, strna(info
->path
),
2896 info
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2898 /* Shortcut things, if the caller just wants to know if this unit exists. */
2902 switch (info
->type
) {
2904 case UNIT_FILE_TYPE_MASKED
:
2905 r
= path_is_runtime(lp
, info
->path
, true);
2909 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2912 case UNIT_FILE_TYPE_REGULAR
:
2913 /* Check if the name we were querying is actually an alias */
2914 if (!streq(name
, basename(info
->path
)) && !unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
2915 state
= UNIT_FILE_ALIAS
;
2919 r
= path_is_generator(lp
, info
->path
);
2923 state
= UNIT_FILE_GENERATED
;
2927 r
= path_is_transient(lp
, info
->path
);
2931 state
= UNIT_FILE_TRANSIENT
;
2935 /* Check if any of the Alias= symlinks have been created.
2936 * We ignore other aliases, and only check those that would
2937 * be created by systemctl enable for this unit. */
2938 r
= find_symlinks_in_scope(scope
, lp
, info
, true, &state
);
2944 /* Check if the file is known under other names. If it is,
2945 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2946 r
= find_symlinks_in_scope(scope
, lp
, info
, false, &state
);
2950 state
= UNIT_FILE_INDIRECT
;
2952 if (unit_file_install_info_has_rules(info
))
2953 state
= UNIT_FILE_DISABLED
;
2954 else if (unit_file_install_info_has_also(info
))
2955 state
= UNIT_FILE_INDIRECT
;
2957 state
= UNIT_FILE_STATIC
;
2963 assert_not_reached();
2970 int unit_file_get_state(
2971 UnitFileScope scope
,
2972 const char *root_dir
,
2974 UnitFileState
*ret
) {
2976 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2980 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2983 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2987 return unit_file_lookup_state(scope
, &lp
, name
, ret
);
2990 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*lp
, const char *name
) {
2991 _cleanup_(install_context_done
) InstallContext c
= { .scope
= scope
};
2997 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3000 r
= install_info_discover(&c
, lp
, name
, 0, NULL
, NULL
, NULL
);
3009 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
3010 _cleanup_strv_free_
char **instances
= NULL
;
3011 _cleanup_free_
char *unit_name
= NULL
;
3015 assert(out_instances
);
3016 assert(out_unit_name
);
3018 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
3022 /* We handle the instances logic when unit name is extracted */
3024 /* We only create instances when a rule of templated unit
3025 * is seen. A rule like enable foo@.service a b c will
3026 * result in an array of (a, b, c) as instance names */
3027 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
3030 instances
= strv_split(pattern
, WHITESPACE
);
3034 *out_instances
= TAKE_PTR(instances
);
3037 *out_unit_name
= TAKE_PTR(unit_name
);
3042 static int presets_find_config(UnitFileScope scope
, const char *root_dir
, char ***files
) {
3043 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
3044 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
3045 const char* const* dirs
;
3048 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3050 if (scope
== UNIT_FILE_SYSTEM
)
3052 else if (IN_SET(scope
, UNIT_FILE_GLOBAL
, UNIT_FILE_USER
))
3055 assert_not_reached();
3057 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
3060 static int read_presets(UnitFileScope scope
, const char *root_dir
, UnitFilePresets
*presets
) {
3061 _cleanup_(unit_file_presets_freep
) UnitFilePresets ps
= {};
3062 _cleanup_strv_free_
char **files
= NULL
;
3066 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3069 r
= presets_find_config(scope
, root_dir
, &files
);
3073 STRV_FOREACH(p
, files
) {
3074 _cleanup_fclose_
FILE *f
= NULL
;
3077 f
= fopen(*p
, "re");
3079 if (errno
== ENOENT
)
3086 _cleanup_free_
char *line
= NULL
;
3087 UnitFilePresetRule rule
= {};
3088 const char *parameter
;
3091 r
= read_line(f
, LONG_LINE_MAX
, &line
);
3102 if (strchr(COMMENTS
, *l
))
3105 parameter
= first_word(l
, "enable");
3108 char **instances
= NULL
;
3110 /* Unit_name will remain the same as parameter when no instances are specified */
3111 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
3113 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
3117 rule
= (UnitFilePresetRule
) {
3118 .pattern
= unit_name
,
3119 .action
= PRESET_ENABLE
,
3120 .instances
= instances
,
3124 parameter
= first_word(l
, "disable");
3128 pattern
= strdup(parameter
);
3132 rule
= (UnitFilePresetRule
) {
3134 .action
= PRESET_DISABLE
,
3139 if (!GREEDY_REALLOC(ps
.rules
, ps
.n_rules
+ 1))
3142 ps
.rules
[ps
.n_rules
++] = rule
;
3146 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
3150 ps
.initialized
= true;
3152 ps
= (UnitFilePresets
){};
3157 static int pattern_match_multiple_instances(
3158 const UnitFilePresetRule rule
,
3159 const char *unit_name
,
3162 _cleanup_free_
char *templated_name
= NULL
;
3165 /* If no ret is needed or the rule itself does not have instances
3166 * initialized, we return not matching */
3167 if (!ret
|| !rule
.instances
)
3170 r
= unit_name_template(unit_name
, &templated_name
);
3173 if (!streq(rule
.pattern
, templated_name
))
3176 /* Compose a list of specified instances when unit name is a template */
3177 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
3178 _cleanup_strv_free_
char **out_strv
= NULL
;
3180 STRV_FOREACH(iter
, rule
.instances
) {
3181 _cleanup_free_
char *name
= NULL
;
3183 r
= unit_name_replace_instance(unit_name
, *iter
, &name
);
3187 r
= strv_consume(&out_strv
, TAKE_PTR(name
));
3192 *ret
= TAKE_PTR(out_strv
);
3195 /* We now know the input unit name is an instance name */
3196 _cleanup_free_
char *instance_name
= NULL
;
3198 r
= unit_name_to_instance(unit_name
, &instance_name
);
3202 if (strv_find(rule
.instances
, instance_name
))
3208 static int query_presets(const char *name
, const UnitFilePresets
*presets
, char ***instance_name_list
) {
3209 PresetAction action
= PRESET_UNKNOWN
;
3211 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3214 for (size_t i
= 0; i
< presets
->n_rules
; i
++)
3215 if (pattern_match_multiple_instances(presets
->rules
[i
], name
, instance_name_list
) > 0 ||
3216 fnmatch(presets
->rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
3217 action
= presets
->rules
[i
].action
;
3222 case PRESET_UNKNOWN
:
3223 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3226 if (instance_name_list
&& *instance_name_list
)
3227 STRV_FOREACH(s
, *instance_name_list
)
3228 log_debug("Preset files say enable %s.", *s
);
3230 log_debug("Preset files say enable %s.", name
);
3232 case PRESET_DISABLE
:
3233 log_debug("Preset files say disable %s.", name
);
3236 assert_not_reached();
3240 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
, UnitFilePresets
*cached
) {
3241 _cleanup_(unit_file_presets_freep
) UnitFilePresets tmp
= {};
3246 if (!cached
->initialized
) {
3247 r
= read_presets(scope
, root_dir
, cached
);
3252 return query_presets(name
, cached
, NULL
);
3255 static int execute_preset(
3256 UnitFileFlags file_flags
,
3257 InstallContext
*plus
,
3258 InstallContext
*minus
,
3259 const LookupPaths
*lp
,
3260 const char *config_path
,
3262 UnitFilePresetMode mode
,
3263 UnitFileChange
**changes
,
3264 size_t *n_changes
) {
3271 assert(config_path
);
3273 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3274 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3276 r
= install_context_mark_for_removal(minus
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3280 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, false, changes
, n_changes
);
3284 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3287 /* Returns number of symlinks that where supposed to be installed. */
3288 q
= install_context_apply(plus
, lp
,
3289 file_flags
| UNIT_FILE_IGNORE_AUXILIARY_FAILURE
,
3291 SEARCH_LOAD
, changes
, n_changes
);
3303 static int preset_prepare_one(
3304 UnitFileScope scope
,
3305 InstallContext
*plus
,
3306 InstallContext
*minus
,
3309 const UnitFilePresets
*presets
,
3310 UnitFileChange
**changes
,
3311 size_t *n_changes
) {
3313 _cleanup_(install_context_done
) InstallContext tmp
= { .scope
= scope
};
3314 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3315 UnitFileInstallInfo
*info
;
3318 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3321 r
= install_info_discover(&tmp
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3322 &info
, changes
, n_changes
);
3325 if (!streq(name
, info
->name
)) {
3326 log_debug("Skipping %s because it is an alias for %s.", name
, info
->name
);
3330 r
= query_presets(name
, presets
, &instance_name_list
);
3335 if (instance_name_list
)
3336 STRV_FOREACH(s
, instance_name_list
) {
3337 r
= install_info_discover_and_check(plus
, lp
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3338 &info
, changes
, n_changes
);
3343 r
= install_info_discover_and_check(plus
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3344 &info
, changes
, n_changes
);
3350 r
= install_info_discover(minus
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3351 &info
, changes
, n_changes
);
3356 int unit_file_preset(
3357 UnitFileScope scope
,
3358 UnitFileFlags file_flags
,
3359 const char *root_dir
,
3361 UnitFilePresetMode mode
,
3362 UnitFileChange
**changes
,
3363 size_t *n_changes
) {
3365 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3366 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3367 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3368 const char *config_path
;
3372 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3373 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3375 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3379 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3383 r
= read_presets(scope
, root_dir
, &presets
);
3387 STRV_FOREACH(i
, files
) {
3388 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, *i
, &presets
, changes
, n_changes
);
3393 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, files
, mode
, changes
, n_changes
);
3396 int unit_file_preset_all(
3397 UnitFileScope scope
,
3398 UnitFileFlags file_flags
,
3399 const char *root_dir
,
3400 UnitFilePresetMode mode
,
3401 UnitFileChange
**changes
,
3402 size_t *n_changes
) {
3404 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3405 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3406 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3407 const char *config_path
= NULL
;
3411 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3412 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3414 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3418 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3422 r
= read_presets(scope
, root_dir
, &presets
);
3426 STRV_FOREACH(i
, lp
.search_path
) {
3427 _cleanup_closedir_
DIR *d
= NULL
;
3431 if (errno
== ENOENT
)
3437 FOREACH_DIRENT(de
, d
, return -errno
) {
3439 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3442 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3445 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, de
->d_name
, &presets
, changes
, n_changes
);
3447 !IN_SET(r
, -EEXIST
, -ERFKILL
, -EADDRNOTAVAIL
, -EBADSLT
, -EIDRM
, -EUCLEAN
, -ELOOP
, -ENOENT
, -EUNATCH
, -EXDEV
))
3448 /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
3449 * Coordinate with unit_file_dump_changes() above. */
3454 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, NULL
, mode
, changes
, n_changes
);
3457 static UnitFileList
* unit_file_list_free_one(UnitFileList
*f
) {
3465 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3466 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3469 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3471 int unit_file_get_list(
3472 UnitFileScope scope
,
3473 const char *root_dir
,
3478 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3482 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3485 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3489 STRV_FOREACH(dirname
, lp
.search_path
) {
3490 _cleanup_closedir_
DIR *d
= NULL
;
3492 d
= opendir(*dirname
);
3494 if (errno
== ENOENT
)
3496 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3497 log_debug_errno(errno
, "Failed to open \"%s\": %m", *dirname
);
3504 FOREACH_DIRENT(de
, d
, return -errno
) {
3505 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3507 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3510 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3513 if (hashmap_get(h
, de
->d_name
))
3516 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3519 f
= new0(UnitFileList
, 1);
3523 f
->path
= path_make_absolute(de
->d_name
, *dirname
);
3527 r
= unit_file_lookup_state(scope
, &lp
, de
->d_name
, &f
->state
);
3529 f
->state
= UNIT_FILE_BAD
;
3531 if (!strv_isempty(states
) &&
3532 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3535 r
= hashmap_put(h
, basename(f
->path
), f
);
3539 f
= NULL
; /* prevent cleanup */
3546 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3547 [UNIT_FILE_ENABLED
] = "enabled",
3548 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3549 [UNIT_FILE_LINKED
] = "linked",
3550 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3551 [UNIT_FILE_ALIAS
] = "alias",
3552 [UNIT_FILE_MASKED
] = "masked",
3553 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3554 [UNIT_FILE_STATIC
] = "static",
3555 [UNIT_FILE_DISABLED
] = "disabled",
3556 [UNIT_FILE_INDIRECT
] = "indirect",
3557 [UNIT_FILE_GENERATED
] = "generated",
3558 [UNIT_FILE_TRANSIENT
] = "transient",
3559 [UNIT_FILE_BAD
] = "bad",
3562 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3564 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3565 [UNIT_FILE_SYMLINK
] = "symlink",
3566 [UNIT_FILE_UNLINK
] = "unlink",
3567 [UNIT_FILE_IS_MASKED
] = "masked",
3568 [UNIT_FILE_IS_DANGLING
] = "dangling",
3569 [UNIT_FILE_DESTINATION_NOT_PRESENT
] = "destination not present",
3570 [UNIT_FILE_AUXILIARY_FAILED
] = "auxiliary unit failed",
3573 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, int);
3575 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3576 [UNIT_FILE_PRESET_FULL
] = "full",
3577 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3578 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3581 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);