1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
12 #include "alloc-util.h"
13 #include "chase-symlinks.h"
14 #include "conf-files.h"
15 #include "conf-parser.h"
17 #include "dirent-util.h"
18 #include "errno-list.h"
19 #include "extract-word.h"
24 #include "install-printf.h"
26 #include "locale-util.h"
29 #include "mkdir-label.h"
30 #include "path-lookup.h"
31 #include "path-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
39 #include "unit-file.h"
41 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
43 typedef enum SearchFlags
{
45 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
46 SEARCH_DROPIN
= 1 << 2,
51 OrderedHashmap
*will_process
;
52 OrderedHashmap
*have_processed
;
61 struct UnitFilePresetRule
{
67 static bool unit_file_install_info_has_rules(const UnitFileInstallInfo
*i
) {
70 return !strv_isempty(i
->aliases
) ||
71 !strv_isempty(i
->wanted_by
) ||
72 !strv_isempty(i
->required_by
);
75 static bool unit_file_install_info_has_also(const UnitFileInstallInfo
*i
) {
78 return !strv_isempty(i
->also
);
81 void unit_file_presets_freep(UnitFilePresets
*p
) {
85 for (size_t i
= 0; i
< p
->n_rules
; i
++) {
86 free(p
->rules
[i
].pattern
);
87 strv_free(p
->rules
[i
].instances
);
94 static const char *const unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
95 [UNIT_FILE_TYPE_REGULAR
] = "regular",
96 [UNIT_FILE_TYPE_LINKED
] = "linked",
97 [UNIT_FILE_TYPE_ALIAS
] = "alias",
98 [UNIT_FILE_TYPE_MASKED
] = "masked",
101 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
103 static int in_search_path(const LookupPaths
*lp
, const char *path
) {
104 _cleanup_free_
char *parent
= NULL
;
108 parent
= dirname_malloc(path
);
112 return path_strv_contains(lp
->search_path
, parent
);
115 static const char* skip_root(const char *root_dir
, const char *path
) {
121 const char *e
= path_startswith(path
, root_dir
);
125 /* Make sure the returned path starts with a slash */
127 if (e
== path
|| e
[-1] != '/')
136 static int path_is_generator(const LookupPaths
*lp
, const char *path
) {
137 _cleanup_free_
char *parent
= NULL
;
142 parent
= dirname_malloc(path
);
146 return path_equal_ptr(parent
, lp
->generator
) ||
147 path_equal_ptr(parent
, lp
->generator_early
) ||
148 path_equal_ptr(parent
, lp
->generator_late
);
151 static int path_is_transient(const LookupPaths
*lp
, const char *path
) {
152 _cleanup_free_
char *parent
= NULL
;
157 parent
= dirname_malloc(path
);
161 return path_equal_ptr(parent
, lp
->transient
);
164 static int path_is_control(const LookupPaths
*lp
, const char *path
) {
165 _cleanup_free_
char *parent
= NULL
;
170 parent
= dirname_malloc(path
);
174 return path_equal_ptr(parent
, lp
->persistent_control
) ||
175 path_equal_ptr(parent
, lp
->runtime_control
);
178 static int path_is_config(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
179 _cleanup_free_
char *parent
= NULL
;
184 /* Note that we do *not* have generic checks for /etc or /run in place, since with
185 * them we couldn't discern configuration from transient or generated units */
188 parent
= dirname_malloc(path
);
195 return path_equal_ptr(path
, lp
->persistent_config
) ||
196 path_equal_ptr(path
, lp
->runtime_config
);
199 static int path_is_runtime(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
200 _cleanup_free_
char *parent
= NULL
;
206 /* Everything in /run is considered runtime. On top of that we also add
207 * explicit checks for the various runtime directories, as safety net. */
209 rpath
= skip_root(lp
->root_dir
, path
);
210 if (rpath
&& path_startswith(rpath
, "/run"))
214 parent
= dirname_malloc(path
);
221 return path_equal_ptr(path
, lp
->runtime_config
) ||
222 path_equal_ptr(path
, lp
->generator
) ||
223 path_equal_ptr(path
, lp
->generator_early
) ||
224 path_equal_ptr(path
, lp
->generator_late
) ||
225 path_equal_ptr(path
, lp
->transient
) ||
226 path_equal_ptr(path
, lp
->runtime_control
);
229 static int path_is_vendor_or_generator(const LookupPaths
*lp
, const char *path
) {
235 rpath
= skip_root(lp
->root_dir
, path
);
239 if (path_startswith(rpath
, "/usr"))
243 if (path_startswith(rpath
, "/lib"))
247 if (path_is_generator(lp
, rpath
))
250 return path_equal(rpath
, SYSTEM_DATA_UNIT_DIR
);
253 static const char* config_path_from_flags(const LookupPaths
*lp
, UnitFileFlags flags
) {
256 if (FLAGS_SET(flags
, UNIT_FILE_PORTABLE
))
257 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_attached
: lp
->persistent_attached
;
259 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_config
: lp
->persistent_config
;
262 int unit_file_changes_add(
263 UnitFileChange
**changes
,
265 int type_or_errno
, /* UNIT_FILE_SYMLINK, _UNLINK, _IS_MASKED, _IS_DANGLING if positive or errno if negative */
267 const char *source
) {
269 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
272 assert(!changes
== !n_changes
);
274 if (type_or_errno
>= 0)
275 assert(type_or_errno
< _UNIT_FILE_CHANGE_TYPE_MAX
);
277 assert(type_or_errno
>= -ERRNO_MAX
);
282 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
303 c
[(*n_changes
)++] = (UnitFileChange
) {
304 .type_or_errno
= type_or_errno
,
306 .source
= TAKE_PTR(s
),
312 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
313 assert(changes
|| n_changes
== 0);
315 for (size_t i
= 0; i
< n_changes
; i
++) {
316 free(changes
[i
].path
);
317 free(changes
[i
].source
);
323 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
326 assert(changes
|| n_changes
== 0);
327 /* If verb is not specified, errors are not allowed! */
328 assert(verb
|| r
>= 0);
330 for (size_t i
= 0; i
< n_changes
; i
++) {
331 assert(verb
|| changes
[i
].type_or_errno
>= 0);
333 switch (changes
[i
].type_or_errno
) {
334 case UNIT_FILE_SYMLINK
:
336 log_info("Created symlink %s %s %s.",
338 special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
),
341 case UNIT_FILE_UNLINK
:
343 log_info("Removed \"%s\".", changes
[i
].path
);
345 case UNIT_FILE_IS_MASKED
:
347 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
349 case UNIT_FILE_IS_DANGLING
:
351 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
354 case UNIT_FILE_DESTINATION_NOT_PRESENT
:
356 log_warning("Unit %s is added as a dependency to a non-existent unit %s.",
357 changes
[i
].source
, changes
[i
].path
);
359 case UNIT_FILE_AUXILIARY_FAILED
:
361 log_warning("Failed to enable auxiliary unit %s, ignoring.", changes
[i
].source
);
364 if (changes
[i
].source
)
365 err
= log_error_errno(changes
[i
].type_or_errno
,
366 "Failed to %s unit, file \"%s\" already exists and is a symlink to \"%s\".",
367 verb
, changes
[i
].path
, changes
[i
].source
);
369 err
= log_error_errno(changes
[i
].type_or_errno
,
370 "Failed to %s unit, file \"%s\" already exists.",
371 verb
, changes
[i
].path
);
374 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is masked.",
375 verb
, changes
[i
].path
);
378 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s is transient or generated.",
379 verb
, changes
[i
].path
);
382 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid specifier in \"%s\".",
383 verb
, changes
[i
].path
);
386 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s %s, destination unit %s is a non-template unit.",
387 verb
, changes
[i
].source
, changes
[i
].path
);
390 err
= log_error_errno(changes
[i
].type_or_errno
,
391 "Failed to %s unit, \"%s\" is not a valid unit name.",
392 verb
, changes
[i
].path
);
395 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, refusing to operate on linked unit file %s.",
396 verb
, changes
[i
].path
);
399 if (changes
[i
].source
)
400 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot alias %s as %s.",
401 verb
, changes
[i
].source
, changes
[i
].path
);
403 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, invalid unit reference \"%s\".",
404 verb
, changes
[i
].path
);
407 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, unit %s does not exist.",
408 verb
, changes
[i
].path
);
411 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, cannot resolve specifiers in \"%s\".",
412 verb
, changes
[i
].path
);
415 assert(changes
[i
].type_or_errno
< 0);
416 err
= log_error_errno(changes
[i
].type_or_errno
, "Failed to %s unit, file \"%s\": %m",
417 verb
, changes
[i
].path
);
421 if (r
< 0 && err
>= 0)
422 log_error_errno(r
, "Failed to %s: %m.", verb
);
426 * Checks if two symlink targets (starting from src) are equivalent as far as the unit enablement logic is
427 * concerned. If the target is in the unit search path, then anything with the same name is equivalent.
428 * If outside the unit search path, paths must be identical.
430 static int chroot_unit_symlinks_equivalent(
431 const LookupPaths
*lp
,
433 const char *target_a
,
434 const char *target_b
) {
441 /* This will give incorrect results if the paths are relative and go outside
442 * of the chroot. False negatives are possible. */
444 const char *root
= lp
->root_dir
?: "/";
445 _cleanup_free_
char *dirname
= NULL
;
448 if (!path_is_absolute(target_a
) || !path_is_absolute(target_b
)) {
449 r
= path_extract_directory(src
, &dirname
);
454 _cleanup_free_
char *a
= path_join(path_is_absolute(target_a
) ? root
: dirname
, target_a
);
455 _cleanup_free_
char *b
= path_join(path_is_absolute(target_b
) ? root
: dirname
, target_b
);
459 r
= path_equal_or_files_same(a
, b
, 0);
463 _cleanup_free_
char *a_name
= NULL
, *b_name
= NULL
;
464 r
= path_extract_filename(a
, &a_name
);
467 r
= path_extract_filename(b
, &b_name
);
471 return streq(a_name
, b_name
) &&
472 path_startswith_strv(a
, lp
->search_path
) &&
473 path_startswith_strv(b
, lp
->search_path
);
476 static int create_symlink(
477 const LookupPaths
*lp
,
478 const char *old_path
,
479 const char *new_path
,
481 UnitFileChange
**changes
,
484 _cleanup_free_
char *dest
= NULL
;
491 rp
= skip_root(lp
->root_dir
, old_path
);
495 /* Actually create a symlink, and remember that we did. This function is
496 * smart enough to check if there's already a valid symlink in place.
498 * Returns 1 if a symlink was created or already exists and points to the
499 * right place, or negative on error.
502 (void) mkdir_parents_label(new_path
, 0755);
504 if (symlink(old_path
, new_path
) >= 0) {
505 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
509 if (errno
!= EEXIST
) {
510 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
514 r
= readlink_malloc(new_path
, &dest
);
516 /* translate EINVAL (non-symlink exists) to EEXIST */
520 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
524 if (chroot_unit_symlinks_equivalent(lp
, new_path
, dest
, old_path
)) {
525 log_debug("Symlink %s → %s already exists", new_path
, dest
);
530 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
534 r
= symlink_atomic(old_path
, new_path
);
536 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
540 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
541 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
546 static int mark_symlink_for_removal(
547 Set
**remove_symlinks_to
,
555 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
565 r
= set_consume(*remove_symlinks_to
, n
);
574 static int remove_marked_symlinks_fd(
575 Set
*remove_symlinks_to
,
578 const char *config_path
,
579 const LookupPaths
*lp
,
582 UnitFileChange
**changes
,
585 _cleanup_closedir_
DIR *d
= NULL
;
588 assert(remove_symlinks_to
);
603 FOREACH_DIRENT(de
, d
, return -errno
)
605 if (de
->d_type
== DT_DIR
) {
606 _cleanup_free_
char *p
= NULL
;
609 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
619 p
= path_make_absolute(de
->d_name
, path
);
625 /* This will close nfd, regardless whether it succeeds or not */
626 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
630 } else if (de
->d_type
== DT_LNK
) {
631 _cleanup_free_
char *p
= NULL
;
635 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
638 p
= path_make_absolute(de
->d_name
, path
);
643 /* We remove all links pointing to a file or path that is marked, as well as all
644 * files sharing the same name as a file that is marked, and files sharing the same
645 * name after the instance has been removed. Do path chasing only if we don't already
646 * know that we want to remove the symlink. */
647 found
= set_contains(remove_symlinks_to
, de
->d_name
);
650 _cleanup_free_
char *template = NULL
;
652 q
= unit_name_template(de
->d_name
, &template);
653 if (q
< 0 && q
!= -EINVAL
)
656 found
= set_contains(remove_symlinks_to
, template);
660 _cleanup_free_
char *dest
= NULL
;
662 q
= chase_symlinks(p
, lp
->root_dir
, CHASE_NONEXISTENT
, &dest
, NULL
);
666 log_debug_errno(q
, "Failed to resolve symlink \"%s\": %m", p
);
667 unit_file_changes_add(changes
, n_changes
, q
, p
, NULL
);
674 found
= set_contains(remove_symlinks_to
, dest
) ||
675 set_contains(remove_symlinks_to
, basename(dest
));
684 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
687 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
691 (void) rmdir_parents(p
, config_path
);
694 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
696 /* Now, remember the full path (but with the root prefix removed) of
697 * the symlink we just removed, and remove any symlinks to it, too. */
699 const char *rp
= skip_root(lp
->root_dir
, p
);
700 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
703 if (q
> 0 && !dry_run
)
710 static int remove_marked_symlinks(
711 Set
*remove_symlinks_to
,
712 const char *config_path
,
713 const LookupPaths
*lp
,
715 UnitFileChange
**changes
,
718 _cleanup_close_
int fd
= -1;
725 if (set_size(remove_symlinks_to
) <= 0)
728 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
730 return errno
== ENOENT
? 0 : -errno
;
736 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
740 /* This takes possession of cfd and closes it */
741 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
749 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
752 if (streq(name
, i
->name
))
755 if (strv_contains(i
->aliases
, name
))
758 /* Look for template symlink matching DefaultInstance */
759 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
760 _cleanup_free_
char *s
= NULL
;
762 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
767 } else if (streq(name
, s
))
774 static int find_symlinks_in_directory(
776 const char *dir_path
,
777 const char *root_dir
,
778 const UnitFileInstallInfo
*info
,
779 bool ignore_destination
,
781 bool ignore_same_name
,
782 const char *config_path
,
783 bool *same_name_link
) {
787 FOREACH_DIRENT(de
, dir
, return -errno
) {
788 bool found_path
= false, found_dest
= false, b
= false;
791 if (de
->d_type
!= DT_LNK
)
794 if (!ignore_destination
) {
795 _cleanup_free_
char *dest
= NULL
;
797 /* Acquire symlink destination */
798 q
= readlinkat_malloc(dirfd(dir
), de
->d_name
, &dest
);
808 if (!path_is_absolute(dest
)) {
811 x
= path_join(dir_path
, dest
);
815 free_and_replace(dest
, x
);
818 /* Check if what the symlink points to matches what we are looking for */
819 found_dest
= streq(basename(dest
), info
->name
);
822 assert(unit_name_is_valid(info
->name
, UNIT_NAME_ANY
));
824 /* Check if the symlink itself matches what we are looking for.
826 * If ignore_destination is specified, we only look at the source name.
828 * If ignore_same_name is specified, we are in one of the directories which
829 * have lower priority than the unit file, and even if a file or symlink with
830 * this name was found, we should ignore it. */
832 if (ignore_destination
|| !ignore_same_name
)
833 found_path
= streq(de
->d_name
, info
->name
);
835 if (!found_path
&& ignore_destination
) {
836 _cleanup_free_
char *template = NULL
;
838 q
= unit_name_template(de
->d_name
, &template);
839 if (q
< 0 && q
!= -EINVAL
)
842 found_dest
= streq(template, info
->name
);
845 if (found_path
&& found_dest
) {
846 _cleanup_free_
char *p
= NULL
, *t
= NULL
;
848 /* Filter out same name links in the main config path */
849 p
= path_make_absolute(de
->d_name
, dir_path
);
850 t
= path_make_absolute(info
->name
, config_path
);
855 b
= path_equal(p
, t
);
859 *same_name_link
= true;
860 else if (found_path
|| found_dest
) {
864 /* Check if symlink name is in the set of names used by [Install] */
865 q
= is_symlink_with_known_name(info
, de
->d_name
);
876 static int find_symlinks(
877 const char *root_dir
,
878 const UnitFileInstallInfo
*i
,
880 bool ignore_same_name
,
881 const char *config_path
,
882 bool *same_name_link
) {
884 _cleanup_closedir_
DIR *config_dir
= NULL
;
889 assert(same_name_link
);
891 config_dir
= opendir(config_path
);
893 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
898 FOREACH_DIRENT(de
, config_dir
, return -errno
) {
900 _cleanup_free_
const char *path
= NULL
;
901 _cleanup_closedir_
DIR *d
= NULL
;
903 if (de
->d_type
!= DT_DIR
)
906 suffix
= strrchr(de
->d_name
, '.');
907 if (!STRPTR_IN_SET(suffix
, ".wants", ".requires"))
910 path
= path_join(config_path
, de
->d_name
);
916 log_error_errno(errno
, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path
);
920 r
= find_symlinks_in_directory(d
, path
, root_dir
, i
,
921 /* ignore_destination= */ true,
922 /* match_name= */ match_name
,
923 /* ignore_same_name= */ ignore_same_name
,
929 log_debug_errno(r
, "Failed to look up symlinks in \"%s\": %m", path
);
932 /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
933 rewinddir(config_dir
);
934 return find_symlinks_in_directory(config_dir
, config_path
, root_dir
, i
,
935 /* ignore_destination= */ false,
936 /* match_name= */ match_name
,
937 /* ignore_same_name= */ ignore_same_name
,
942 static int find_symlinks_in_scope(
944 const LookupPaths
*lp
,
945 const UnitFileInstallInfo
*info
,
947 UnitFileState
*state
) {
949 bool same_name_link_runtime
= false, same_name_link_config
= false;
950 bool enabled_in_runtime
= false, enabled_at_all
= false;
951 bool ignore_same_name
= false;
957 /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name"
958 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
959 * effectively masked, so we should ignore them. */
961 STRV_FOREACH(p
, lp
->search_path
) {
962 bool same_name_link
= false;
964 r
= find_symlinks(lp
->root_dir
, info
, match_name
, ignore_same_name
, *p
, &same_name_link
);
968 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
970 if (path_equal_ptr(*p
, lp
->persistent_config
)) {
971 /* This is the best outcome, let's return it immediately. */
972 *state
= UNIT_FILE_ENABLED
;
976 /* look for global enablement of user units */
977 if (scope
== LOOKUP_SCOPE_USER
&& path_is_user_config_dir(*p
)) {
978 *state
= UNIT_FILE_ENABLED
;
982 r
= path_is_runtime(lp
, *p
, false);
986 enabled_in_runtime
= true;
988 enabled_at_all
= true;
990 } else if (same_name_link
) {
991 if (path_equal_ptr(*p
, lp
->persistent_config
))
992 same_name_link_config
= true;
994 r
= path_is_runtime(lp
, *p
, false);
998 same_name_link_runtime
= true;
1002 /* Check if next iteration will be "below" the unit file (either a regular file
1003 * or a symlink), and hence should be ignored */
1004 if (!ignore_same_name
&& path_startswith(info
->path
, *p
))
1005 ignore_same_name
= true;
1008 if (enabled_in_runtime
) {
1009 *state
= UNIT_FILE_ENABLED_RUNTIME
;
1013 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
1014 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
1015 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
1016 * something, and hence are a much stronger concept. */
1017 if (enabled_at_all
&& unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1018 *state
= UNIT_FILE_STATIC
;
1022 /* Hmm, we didn't find it, but maybe we found the same name
1024 if (same_name_link_config
) {
1025 *state
= UNIT_FILE_LINKED
;
1028 if (same_name_link_runtime
) {
1029 *state
= UNIT_FILE_LINKED_RUNTIME
;
1036 static void install_info_free(UnitFileInstallInfo
*i
) {
1043 strv_free(i
->aliases
);
1044 strv_free(i
->wanted_by
);
1045 strv_free(i
->required_by
);
1047 free(i
->default_instance
);
1048 free(i
->symlink_target
);
1052 static void install_context_done(InstallContext
*ctx
) {
1055 ctx
->will_process
= ordered_hashmap_free_with_destructor(ctx
->will_process
, install_info_free
);
1056 ctx
->have_processed
= ordered_hashmap_free_with_destructor(ctx
->have_processed
, install_info_free
);
1059 static UnitFileInstallInfo
*install_info_find(InstallContext
*ctx
, const char *name
) {
1060 UnitFileInstallInfo
*i
;
1062 i
= ordered_hashmap_get(ctx
->have_processed
, name
);
1066 return ordered_hashmap_get(ctx
->will_process
, name
);
1069 static int install_info_may_process(
1070 const UnitFileInstallInfo
*i
,
1071 const LookupPaths
*lp
,
1072 UnitFileChange
**changes
,
1073 size_t *n_changes
) {
1077 /* Checks whether the loaded unit file is one we should process, or is masked,
1078 * transient or generated and thus not subject to enable/disable operations. */
1080 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1081 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1084 if (path_is_generator(lp
, i
->path
) ||
1085 path_is_transient(lp
, i
->path
)) {
1086 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1087 return -EADDRNOTAVAIL
;
1094 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1095 * hashmap, or retrieves the existing one if already present.
1097 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1099 static int install_info_add(
1100 InstallContext
*ctx
,
1105 UnitFileInstallInfo
**ret
) {
1107 UnitFileInstallInfo
*i
= NULL
;
1113 /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
1114 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
1115 * but this cannot be possible in any code path (See #6119). */
1117 name
= basename(path
);
1120 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1123 i
= install_info_find(ctx
, name
);
1125 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1132 i
= new(UnitFileInstallInfo
, 1);
1136 *i
= (UnitFileInstallInfo
) {
1137 .type
= _UNIT_FILE_TYPE_INVALID
,
1138 .auxiliary
= auxiliary
,
1141 i
->name
= strdup(name
);
1148 i
->root
= strdup(root
);
1156 i
->path
= strdup(path
);
1163 r
= ordered_hashmap_ensure_put(&ctx
->will_process
, &string_hash_ops
, i
->name
, i
);
1173 install_info_free(i
);
1177 static int config_parse_alias(
1179 const char *filename
,
1181 const char *section
,
1182 unsigned section_line
,
1196 type
= unit_name_to_type(unit
);
1197 if (!unit_type_may_alias(type
))
1198 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1199 "Alias= is not allowed for %s units, ignoring.",
1200 unit_type_to_string(type
));
1202 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1203 lvalue
, ltype
, rvalue
, data
, userdata
);
1206 static int config_parse_also(
1208 const char *filename
,
1210 const char *section
,
1211 unsigned section_line
,
1218 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1219 InstallContext
*ctx
= ASSERT_PTR(data
);
1228 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1230 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1236 r
= install_name_printf(ctx
->scope
, info
, word
, &printed
);
1238 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1239 "Failed to resolve unit name in Also=\"%s\": %m", word
);
1241 r
= install_info_add(ctx
, printed
, NULL
, info
->root
, /* auxiliary= */ true, NULL
);
1245 r
= strv_push(&info
->also
, printed
);
1255 static int config_parse_default_instance(
1257 const char *filename
,
1259 const char *section
,
1260 unsigned section_line
,
1267 InstallContext
*ctx
= ASSERT_PTR(data
);
1268 UnitFileInstallInfo
*info
= ASSERT_PTR(userdata
);
1269 _cleanup_free_
char *printed
= NULL
;
1277 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1278 /* When enabling an instance, we might be using a template unit file,
1279 * but we should ignore DefaultInstance silently. */
1281 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1282 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1283 "DefaultInstance= only makes sense for template units, ignoring.");
1285 r
= install_name_printf(ctx
->scope
, info
, rvalue
, &printed
);
1287 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1288 "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue
);
1290 if (isempty(printed
))
1291 printed
= mfree(printed
);
1293 if (printed
&& !unit_instance_is_valid(printed
))
1294 return log_syntax(unit
, LOG_WARNING
, filename
, line
, SYNTHETIC_ERRNO(EINVAL
),
1295 "Invalid DefaultInstance= value \"%s\".", printed
);
1297 return free_and_replace(info
->default_instance
, printed
);
1300 static int unit_file_load(
1301 InstallContext
*ctx
,
1302 UnitFileInstallInfo
*info
,
1304 const char *root_dir
,
1305 SearchFlags flags
) {
1307 const ConfigTableItem items
[] = {
1308 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1309 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1310 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1311 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1312 { "Install", "Also", config_parse_also
, 0, ctx
},
1317 _cleanup_fclose_
FILE *f
= NULL
;
1318 _cleanup_close_
int fd
= -1;
1325 if (!(flags
& SEARCH_DROPIN
)) {
1326 /* Loading or checking for the main unit file… */
1328 type
= unit_name_to_type(info
->name
);
1331 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1332 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1333 "%s: unit type %s cannot be templated, ignoring.", path
, unit_type_to_string(type
));
1335 if (!(flags
& SEARCH_LOAD
)) {
1336 if (lstat(path
, &st
) < 0)
1339 if (null_or_empty(&st
))
1340 info
->type
= UNIT_FILE_TYPE_MASKED
;
1341 else if (S_ISREG(st
.st_mode
))
1342 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1343 else if (S_ISLNK(st
.st_mode
))
1345 else if (S_ISDIR(st
.st_mode
))
1353 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1357 /* 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. */
1359 if (!(flags
& SEARCH_LOAD
))
1362 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1367 if (fstat(fd
, &st
) < 0)
1370 if (null_or_empty(&st
)) {
1371 if ((flags
& SEARCH_DROPIN
) == 0)
1372 info
->type
= UNIT_FILE_TYPE_MASKED
;
1377 r
= stat_verify_regular(&st
);
1381 f
= take_fdopen(&fd
, "r");
1385 /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1388 r
= config_parse(info
->name
, path
, f
,
1402 config_item_table_lookup
, items
,
1406 return log_debug_errno(r
, "Failed to parse \"%s\": %m", info
->name
);
1408 if ((flags
& SEARCH_DROPIN
) == 0)
1409 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1412 (int) strv_length(info
->aliases
) +
1413 (int) strv_length(info
->wanted_by
) +
1414 (int) strv_length(info
->required_by
);
1417 static int unit_file_load_or_readlink(
1418 InstallContext
*ctx
,
1419 UnitFileInstallInfo
*info
,
1421 const LookupPaths
*lp
,
1422 SearchFlags flags
) {
1425 r
= unit_file_load(ctx
, info
, path
, lp
->root_dir
, flags
);
1426 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1429 /* This is a symlink, let's read and verify it. */
1430 r
= unit_file_resolve_symlink(lp
->root_dir
, lp
->search_path
,
1431 NULL
, AT_FDCWD
, path
,
1432 true, &info
->symlink_target
);
1435 bool outside_search_path
= r
> 0;
1437 r
= null_or_empty_path_with_root(info
->symlink_target
, lp
->root_dir
);
1438 if (r
< 0 && r
!= -ENOENT
)
1439 return log_debug_errno(r
, "Failed to stat %s: %m", info
->symlink_target
);
1441 info
->type
= UNIT_FILE_TYPE_MASKED
;
1442 else if (outside_search_path
)
1443 info
->type
= UNIT_FILE_TYPE_LINKED
;
1445 info
->type
= UNIT_FILE_TYPE_ALIAS
;
1450 static int unit_file_search(
1451 InstallContext
*ctx
,
1452 UnitFileInstallInfo
*info
,
1453 const LookupPaths
*lp
,
1454 SearchFlags flags
) {
1456 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1457 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1458 _cleanup_free_
char *template = NULL
;
1459 bool found_unit
= false;
1465 /* Was this unit already loaded? */
1466 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1470 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1474 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1475 r
= unit_name_template(info
->name
, &template);
1480 STRV_FOREACH(p
, lp
->search_path
) {
1481 _cleanup_free_
char *path
= NULL
;
1483 path
= path_join(*p
, info
->name
);
1487 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1489 info
->path
= TAKE_PTR(path
);
1493 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1497 if (!found_unit
&& template) {
1499 /* Unit file doesn't exist, however instance
1500 * enablement was requested. We will check if it is
1501 * possible to load template unit file. */
1503 STRV_FOREACH(p
, lp
->search_path
) {
1504 _cleanup_free_
char *path
= NULL
;
1506 path
= path_join(*p
, template);
1510 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1512 info
->path
= TAKE_PTR(path
);
1516 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1522 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1523 "Cannot find unit %s%s%s.",
1524 info
->name
, template ? " or " : "", strempty(template));
1526 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1529 /* Search for drop-in directories */
1531 dropin_dir_name
= strjoina(info
->name
, ".d");
1532 STRV_FOREACH(p
, lp
->search_path
) {
1535 path
= path_join(*p
, dropin_dir_name
);
1539 r
= strv_consume(&dirs
, path
);
1545 dropin_template_dir_name
= strjoina(template, ".d");
1546 STRV_FOREACH(p
, lp
->search_path
) {
1549 path
= path_join(*p
, dropin_template_dir_name
);
1553 r
= strv_consume(&dirs
, path
);
1559 /* Load drop-in conf files */
1561 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1563 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1565 STRV_FOREACH(p
, files
) {
1566 r
= unit_file_load_or_readlink(ctx
, info
, *p
, lp
, flags
| SEARCH_DROPIN
);
1568 return log_debug_errno(r
, "Failed to load conf file \"%s\": %m", *p
);
1574 static int install_info_follow(
1575 InstallContext
*ctx
,
1576 UnitFileInstallInfo
*info
,
1577 const LookupPaths
*lp
,
1579 bool ignore_different_name
) {
1584 if (!IN_SET(info
->type
, UNIT_FILE_TYPE_ALIAS
, UNIT_FILE_TYPE_LINKED
))
1586 if (!info
->symlink_target
)
1589 /* If the basename doesn't match, the caller should add a complete new entry for this. */
1591 if (!ignore_different_name
&& !streq(basename(info
->symlink_target
), info
->name
))
1594 free_and_replace(info
->path
, info
->symlink_target
);
1595 info
->type
= _UNIT_FILE_TYPE_INVALID
;
1597 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1601 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1602 * target, maybe more than once. Propagate the instance name if present.
1604 static int install_info_traverse(
1605 InstallContext
*ctx
,
1606 const LookupPaths
*lp
,
1607 UnitFileInstallInfo
*start
,
1609 UnitFileInstallInfo
**ret
) {
1611 UnitFileInstallInfo
*i
;
1619 r
= unit_file_search(ctx
, start
, lp
, flags
);
1624 while (IN_SET(i
->type
, UNIT_FILE_TYPE_ALIAS
, UNIT_FILE_TYPE_LINKED
)) {
1625 /* Follow the symlink */
1627 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1630 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1631 r
= path_is_config(lp
, i
->path
, true);
1638 r
= install_info_follow(ctx
, i
, lp
, flags
,
1639 /* If linked, don't look at the target name */
1640 /* ignore_different_name= */ i
->type
== UNIT_FILE_TYPE_LINKED
);
1642 _cleanup_free_
char *buffer
= NULL
;
1645 /* Target is an alias, create a new install info object and continue with that. */
1647 bn
= basename(i
->symlink_target
);
1649 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1650 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1652 _cleanup_free_
char *instance
= NULL
;
1654 r
= unit_name_to_instance(i
->name
, &instance
);
1658 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1662 if (streq(buffer
, i
->name
)) {
1664 /* We filled in the instance, and the target stayed the same? If so,
1665 * then let's honour the link as it is. */
1667 r
= install_info_follow(ctx
, i
, lp
, flags
, true);
1677 r
= install_info_add(ctx
, bn
, NULL
, lp
->root_dir
, /* auxiliary= */ false, &i
);
1681 /* Try again, with the new target we found. */
1682 r
= unit_file_search(ctx
, i
, lp
, flags
);
1684 /* Translate error code to highlight this specific case */
1699 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1700 * or the name (otherwise). root_dir is prepended to the path.
1702 static int install_info_add_auto(
1703 InstallContext
*ctx
,
1704 const LookupPaths
*lp
,
1705 const char *name_or_path
,
1706 UnitFileInstallInfo
**ret
) {
1709 assert(name_or_path
);
1711 if (path_is_absolute(name_or_path
)) {
1714 pp
= prefix_roota(lp
->root_dir
, name_or_path
);
1716 return install_info_add(ctx
, NULL
, pp
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1718 return install_info_add(ctx
, name_or_path
, NULL
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1721 static int install_info_discover(
1722 InstallContext
*ctx
,
1723 const LookupPaths
*lp
,
1726 UnitFileInstallInfo
**ret
,
1727 UnitFileChange
**changes
,
1728 size_t *n_changes
) {
1730 UnitFileInstallInfo
*info
;
1737 r
= install_info_add_auto(ctx
, lp
, name
, &info
);
1739 r
= install_info_traverse(ctx
, lp
, info
, flags
, ret
);
1742 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1746 static int install_info_discover_and_check(
1747 InstallContext
*ctx
,
1748 const LookupPaths
*lp
,
1751 UnitFileInstallInfo
**ret
,
1752 UnitFileChange
**changes
,
1753 size_t *n_changes
) {
1757 r
= install_info_discover(ctx
, lp
, name
, flags
, ret
, changes
, n_changes
);
1761 return install_info_may_process(ret
? *ret
: NULL
, lp
, changes
, n_changes
);
1764 int unit_file_verify_alias(
1765 const UnitFileInstallInfo
*info
,
1768 UnitFileChange
**changes
,
1769 size_t *n_changes
) {
1771 _cleanup_free_
char *dst_updated
= NULL
;
1774 /* Verify that dst is a valid either a valid alias or a valid .wants/.requires symlink for the target
1775 * unit *i. Return negative on error or if not compatible, zero on success.
1777 * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
1778 * inserted into dst. It is not normally set, even on success, so that the caller can easily
1779 * distinguish the case where instance propagation occurred.
1782 * -EXDEV when the alias doesn't match the unit,
1783 * -EUCLEAN when the name is invalid,
1784 * -ELOOP when the alias it to the unit itself.
1787 const char *path_alias
= strrchr(dst
, '/');
1789 /* This branch covers legacy Alias= function of creating .wants and .requires symlinks. */
1790 _cleanup_free_
char *dir
= NULL
;
1793 path_alias
++; /* skip over slash */
1795 dir
= dirname_malloc(dst
);
1799 p
= endswith(dir
, ".wants");
1801 p
= endswith(dir
, ".requires");
1803 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1804 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
), "Invalid path \"%s\" in alias.", dir
);
1807 *p
= '\0'; /* dir should now be a unit name */
1809 UnitNameFlags type
= unit_name_classify(dir
);
1811 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1812 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1813 "Invalid unit name component \"%s\" in alias.", dir
);
1816 const bool instance_propagation
= type
== UNIT_NAME_TEMPLATE
;
1818 /* That's the name we want to use for verification. */
1819 r
= unit_symlink_name_compatible(path_alias
, info
->name
, instance_propagation
);
1821 return log_error_errno(r
, "Failed to verify alias validity: %m");
1823 unit_file_changes_add(changes
, n_changes
, -EXDEV
, dst
, info
->name
);
1824 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1825 "Invalid unit \"%s\" symlink \"%s\".",
1830 /* If the symlink target has an instance set and the symlink source doesn't, we "propagate
1831 * the instance", i.e. instantiate the symlink source with the target instance. */
1832 if (unit_name_is_valid(dst
, UNIT_NAME_TEMPLATE
)) {
1833 _cleanup_free_
char *inst
= NULL
;
1835 UnitNameFlags type
= unit_name_to_instance(info
->name
, &inst
);
1837 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, info
->name
, NULL
);
1838 return log_debug_errno(type
, "Failed to extract instance name from \"%s\": %m", info
->name
);
1841 if (type
== UNIT_NAME_INSTANCE
) {
1842 r
= unit_name_replace_instance(dst
, inst
, &dst_updated
);
1844 return log_error_errno(r
, "Failed to build unit name from %s+%s: %m",
1849 r
= unit_validate_alias_symlink_or_warn(LOG_DEBUG
, dst_updated
?: dst
, info
->name
);
1850 if (r
== -ELOOP
) /* -ELOOP means self-alias, which we (quietly) ignore */
1853 unit_file_changes_add(changes
, n_changes
,
1854 r
== -EINVAL
? -EXDEV
: r
,
1861 *ret_dst
= TAKE_PTR(dst_updated
);
1865 static int install_info_symlink_alias(
1867 UnitFileInstallInfo
*info
,
1868 const LookupPaths
*lp
,
1869 const char *config_path
,
1871 UnitFileChange
**changes
,
1872 size_t *n_changes
) {
1878 assert(config_path
);
1880 STRV_FOREACH(s
, info
->aliases
) {
1881 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
, *dst_updated
= NULL
;
1883 q
= install_name_printf(scope
, info
, *s
, &dst
);
1885 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1890 q
= unit_file_verify_alias(info
, dst
, &dst_updated
, changes
, n_changes
);
1898 alias_path
= path_make_absolute(dst_updated
?: dst
, config_path
);
1902 q
= create_symlink(lp
, info
->path
, alias_path
, force
, changes
, n_changes
);
1909 static int install_info_symlink_wants(
1911 UnitFileFlags file_flags
,
1912 UnitFileInstallInfo
*info
,
1913 const LookupPaths
*lp
,
1914 const char *config_path
,
1917 UnitFileChange
**changes
,
1918 size_t *n_changes
) {
1920 _cleanup_free_
char *buf
= NULL
;
1921 UnitNameFlags valid_dst_type
= UNIT_NAME_ANY
;
1927 assert(config_path
);
1929 if (strv_isempty(list
))
1932 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
| UNIT_NAME_INSTANCE
))
1933 /* Not a template unit. Use the name directly. */
1936 else if (info
->default_instance
) {
1937 UnitFileInstallInfo instance
= {
1938 .type
= _UNIT_FILE_TYPE_INVALID
,
1940 _cleanup_free_
char *path
= NULL
;
1942 /* If this is a template, and we have a default instance, use it. */
1944 r
= unit_name_replace_instance(info
->name
, info
->default_instance
, &buf
);
1948 instance
.name
= buf
;
1949 r
= unit_file_search(NULL
, &instance
, lp
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1953 path
= TAKE_PTR(instance
.path
);
1955 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1956 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1963 /* We have a template, but no instance yet. When used with an instantiated unit, we will get
1964 * the instance from that unit. Cannot be used with non-instance units. */
1966 valid_dst_type
= UNIT_NAME_INSTANCE
| UNIT_NAME_TEMPLATE
;
1970 STRV_FOREACH(s
, list
) {
1971 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1973 q
= install_name_printf(scope
, info
, *s
, &dst
);
1975 unit_file_changes_add(changes
, n_changes
, q
, *s
, NULL
);
1979 if (!unit_name_is_valid(dst
, valid_dst_type
)) {
1980 /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the
1981 * template status doesn't match. If we are doing presets don't bother reporting the
1982 * error. This also covers cases like 'systemctl preset serial-getty@.service', which
1983 * has no DefaultInstance, so there is nothing we can do. At the same time,
1984 * 'systemctl enable serial-getty@.service' should fail, the user should specify an
1985 * instance like in 'systemctl enable serial-getty@ttyS0.service'.
1987 if (file_flags
& UNIT_FILE_IGNORE_AUXILIARY_FAILURE
)
1990 if (unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1991 unit_file_changes_add(changes
, n_changes
, -EIDRM
, dst
, n
);
1994 unit_file_changes_add(changes
, n_changes
, -EUCLEAN
, dst
, NULL
);
2001 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
2005 q
= create_symlink(lp
, info
->path
, path
, true, changes
, n_changes
);
2009 if (unit_file_exists(scope
, lp
, dst
) == 0)
2010 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_DESTINATION_NOT_PRESENT
, dst
, info
->path
);
2016 static int install_info_symlink_link(
2017 UnitFileInstallInfo
*info
,
2018 const LookupPaths
*lp
,
2019 const char *config_path
,
2021 UnitFileChange
**changes
,
2022 size_t *n_changes
) {
2024 _cleanup_free_
char *path
= NULL
;
2029 assert(config_path
);
2032 r
= in_search_path(lp
, info
->path
);
2038 path
= path_join(config_path
, info
->name
);
2042 return create_symlink(lp
, info
->path
, path
, force
, changes
, n_changes
);
2045 static int install_info_apply(
2047 UnitFileFlags file_flags
,
2048 UnitFileInstallInfo
*info
,
2049 const LookupPaths
*lp
,
2050 const char *config_path
,
2051 UnitFileChange
**changes
,
2052 size_t *n_changes
) {
2058 assert(config_path
);
2060 if (info
->type
!= UNIT_FILE_TYPE_REGULAR
)
2063 bool force
= file_flags
& UNIT_FILE_FORCE
;
2065 r
= install_info_symlink_link(info
, lp
, config_path
, force
, changes
, n_changes
);
2066 /* Do not count links to the unit file towards the "carries_install_info" count */
2068 /* If linking of the file failed, do not try to create other symlinks,
2069 * because they might would pointing to a non-existent or wrong unit. */
2072 r
= install_info_symlink_alias(scope
, info
, lp
, config_path
, force
, changes
, n_changes
);
2074 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->wanted_by
, ".wants/", changes
, n_changes
);
2078 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->required_by
, ".requires/", changes
, n_changes
);
2085 static int install_context_apply(
2086 InstallContext
*ctx
,
2087 const LookupPaths
*lp
,
2088 UnitFileFlags file_flags
,
2089 const char *config_path
,
2091 UnitFileChange
**changes
,
2092 size_t *n_changes
) {
2094 UnitFileInstallInfo
*i
;
2099 assert(config_path
);
2101 if (ordered_hashmap_isempty(ctx
->will_process
))
2104 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2109 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2112 q
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2116 q
= install_info_traverse(ctx
, lp
, i
, flags
, NULL
);
2119 q
= unit_file_changes_add(changes
, n_changes
, UNIT_FILE_AUXILIARY_FAILED
, NULL
, i
->name
);
2125 unit_file_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
2129 /* We can attempt to process a masked unit when a different unit
2130 * that we were processing specifies it in Also=. */
2131 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2132 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
2134 /* Assume that something *could* have been enabled here,
2135 * avoid "empty [Install] section" warning. */
2140 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
2143 q
= install_info_apply(ctx
->scope
, file_flags
, i
, lp
, config_path
, changes
, n_changes
);
2155 static int install_context_mark_for_removal(
2156 InstallContext
*ctx
,
2157 const LookupPaths
*lp
,
2158 Set
**remove_symlinks_to
,
2159 const char *config_path
,
2160 UnitFileChange
**changes
,
2161 size_t *n_changes
) {
2163 UnitFileInstallInfo
*i
;
2168 assert(config_path
);
2170 /* Marks all items for removal */
2172 if (ordered_hashmap_isempty(ctx
->will_process
))
2175 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2179 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2181 r
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2185 r
= install_info_traverse(ctx
, lp
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2186 if (r
== -ENOLINK
) {
2187 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
2188 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
2189 } else if (r
== -ENOENT
) {
2191 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
2192 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
2194 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
2195 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2199 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
2200 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2201 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2202 log_debug("Unit file %s is masked, ignoring.", i
->name
);
2203 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
2205 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
2206 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
2210 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2220 UnitFileFlags flags
,
2221 const char *root_dir
,
2223 UnitFileChange
**changes
,
2224 size_t *n_changes
) {
2226 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2227 const char *config_path
;
2231 assert(scope
< _LOOKUP_SCOPE_MAX
);
2233 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2237 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2241 STRV_FOREACH(i
, files
) {
2242 _cleanup_free_
char *path
= NULL
;
2245 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2251 path
= path_make_absolute(*i
, config_path
);
2255 q
= create_symlink(&lp
, "/dev/null", path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2256 if (q
< 0 && r
>= 0)
2263 int unit_file_unmask(
2265 UnitFileFlags flags
,
2266 const char *root_dir
,
2268 UnitFileChange
**changes
,
2269 size_t *n_changes
) {
2271 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2272 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2273 _cleanup_strv_free_
char **todo
= NULL
;
2274 const char *config_path
;
2279 assert(scope
< _LOOKUP_SCOPE_MAX
);
2281 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2285 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2289 bool dry_run
= flags
& UNIT_FILE_DRY_RUN
;
2291 STRV_FOREACH(i
, files
) {
2292 _cleanup_free_
char *path
= NULL
;
2294 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2297 path
= path_make_absolute(*i
, config_path
);
2301 r
= null_or_empty_path(path
);
2309 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2312 todo
[n_todo
] = strdup(*i
);
2322 STRV_FOREACH(i
, todo
) {
2323 _cleanup_free_
char *path
= NULL
;
2326 path
= path_make_absolute(*i
, config_path
);
2330 if (!dry_run
&& unlink(path
) < 0) {
2331 if (errno
!= ENOENT
) {
2334 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2340 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2342 rp
= skip_root(lp
.root_dir
, path
);
2343 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2348 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, dry_run
, changes
, n_changes
);
2357 UnitFileFlags flags
,
2358 const char *root_dir
,
2360 UnitFileChange
**changes
,
2361 size_t *n_changes
) {
2363 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2364 _cleanup_strv_free_
char **todo
= NULL
;
2365 const char *config_path
;
2370 assert(scope
< _LOOKUP_SCOPE_MAX
);
2372 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2376 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2380 STRV_FOREACH(i
, files
) {
2381 _cleanup_free_
char *full
= NULL
;
2385 if (!path_is_absolute(*i
))
2389 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2392 full
= path_join(lp
.root_dir
, *i
);
2396 if (lstat(full
, &st
) < 0)
2398 r
= stat_verify_regular(&st
);
2402 q
= in_search_path(&lp
, *i
);
2408 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2411 todo
[n_todo
] = strdup(*i
);
2421 STRV_FOREACH(i
, todo
) {
2422 _cleanup_free_
char *new_path
= NULL
;
2424 new_path
= path_make_absolute(basename(*i
), config_path
);
2428 q
= create_symlink(&lp
, *i
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2429 if (q
< 0 && r
>= 0)
2436 static int path_shall_revert(const LookupPaths
*lp
, const char *path
) {
2442 /* Checks whether the path is one where the drop-in directories shall be removed. */
2444 r
= path_is_config(lp
, path
, true);
2448 r
= path_is_control(lp
, path
);
2452 return path_is_transient(lp
, path
);
2455 int unit_file_revert(
2457 const char *root_dir
,
2459 UnitFileChange
**changes
,
2460 size_t *n_changes
) {
2462 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2463 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2464 _cleanup_strv_free_
char **todo
= NULL
;
2468 /* Puts a unit file back into vendor state. This means:
2470 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2471 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2473 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2474 * "config", but not in "transient" or "control" or even "generated").
2476 * We remove all that in both the runtime and the persistent directories, if that applies.
2479 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2483 STRV_FOREACH(i
, files
) {
2484 bool has_vendor
= false;
2486 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2489 STRV_FOREACH(p
, lp
.search_path
) {
2490 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2493 path
= path_make_absolute(*i
, *p
);
2497 r
= lstat(path
, &st
);
2499 if (errno
!= ENOENT
)
2501 } else if (S_ISREG(st
.st_mode
)) {
2502 /* Check if there's a vendor version */
2503 r
= path_is_vendor_or_generator(&lp
, path
);
2510 dropin
= strjoin(path
, ".d");
2514 r
= lstat(dropin
, &st
);
2516 if (errno
!= ENOENT
)
2518 } else if (S_ISDIR(st
.st_mode
)) {
2519 /* Remove the drop-ins */
2520 r
= path_shall_revert(&lp
, dropin
);
2524 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2527 todo
[n_todo
++] = TAKE_PTR(dropin
);
2535 /* OK, there's a vendor version, hence drop all configuration versions */
2536 STRV_FOREACH(p
, lp
.search_path
) {
2537 _cleanup_free_
char *path
= NULL
;
2540 path
= path_make_absolute(*i
, *p
);
2544 r
= lstat(path
, &st
);
2546 if (errno
!= ENOENT
)
2548 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2549 r
= path_is_config(&lp
, path
, true);
2553 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2556 todo
[n_todo
++] = TAKE_PTR(path
);
2565 STRV_FOREACH(i
, todo
) {
2566 _cleanup_strv_free_
char **fs
= NULL
;
2569 (void) get_files_in_directory(*i
, &fs
);
2571 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2572 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2577 STRV_FOREACH(j
, fs
) {
2578 _cleanup_free_
char *t
= NULL
;
2580 t
= path_join(*i
, *j
);
2584 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2587 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2589 rp
= skip_root(lp
.root_dir
, *i
);
2590 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2595 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.runtime_config
, &lp
, false, changes
, n_changes
);
2599 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.persistent_config
, &lp
, false, changes
, n_changes
);
2606 int unit_file_add_dependency(
2608 UnitFileFlags file_flags
,
2609 const char *root_dir
,
2613 UnitFileChange
**changes
,
2614 size_t *n_changes
) {
2616 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2617 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2618 UnitFileInstallInfo
*info
, *target_info
;
2619 const char *config_path
;
2623 assert(scope
< _LOOKUP_SCOPE_MAX
);
2626 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2629 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2632 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2636 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2640 r
= install_info_discover_and_check(&ctx
, &lp
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2641 &target_info
, changes
, n_changes
);
2645 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2647 STRV_FOREACH(f
, files
) {
2650 r
= install_info_discover_and_check(&ctx
, &lp
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2651 &info
, changes
, n_changes
);
2655 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2657 /* We didn't actually load anything from the unit
2658 * file, but instead just add in our new symlink to
2661 if (dep
== UNIT_WANTS
)
2662 l
= &info
->wanted_by
;
2664 l
= &info
->required_by
;
2667 *l
= strv_new(target_info
->name
);
2672 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2673 SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2676 static int do_unit_file_enable(
2677 const LookupPaths
*lp
,
2679 UnitFileFlags flags
,
2680 const char *config_path
,
2682 UnitFileChange
**changes
,
2683 size_t *n_changes
) {
2685 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2686 UnitFileInstallInfo
*info
;
2689 STRV_FOREACH(f
, files
) {
2690 r
= install_info_discover_and_check(&ctx
, lp
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2691 &info
, changes
, n_changes
);
2695 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2698 /* This will return the number of symlink rules that were
2699 supposed to be created, not the ones actually created. This
2700 is useful to determine whether the passed files had any
2701 installation data at all. */
2703 return install_context_apply(&ctx
, lp
, flags
, config_path
,
2704 SEARCH_LOAD
, changes
, n_changes
);
2707 int unit_file_enable(
2709 UnitFileFlags flags
,
2710 const char *root_dir
,
2712 UnitFileChange
**changes
,
2713 size_t *n_changes
) {
2715 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2719 assert(scope
< _LOOKUP_SCOPE_MAX
);
2721 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2725 const char *config_path
= config_path_from_flags(&lp
, flags
);
2729 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2732 static int do_unit_file_disable(
2733 const LookupPaths
*lp
,
2735 UnitFileFlags flags
,
2736 const char *config_path
,
2738 UnitFileChange
**changes
,
2739 size_t *n_changes
) {
2741 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2742 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2745 STRV_FOREACH(i
, files
) {
2746 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2749 r
= install_info_add(&ctx
, *i
, NULL
, lp
->root_dir
, /* auxiliary= */ false, NULL
);
2754 r
= install_context_mark_for_removal(&ctx
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2758 return remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, flags
& UNIT_FILE_DRY_RUN
, changes
, n_changes
);
2762 int unit_file_disable(
2764 UnitFileFlags flags
,
2765 const char *root_dir
,
2767 UnitFileChange
**changes
,
2768 size_t *n_changes
) {
2770 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2774 assert(scope
< _LOOKUP_SCOPE_MAX
);
2776 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2780 const char *config_path
= config_path_from_flags(&lp
, flags
);
2784 return do_unit_file_disable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2787 static int normalize_linked_files(
2789 const LookupPaths
*lp
,
2790 char **names_or_paths
,
2792 char ***ret_files
) {
2794 /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/,
2795 * but operates on real unit names. For each argument we we look up the actual path
2796 * where the unit is found. This way linked units can be re-enabled successfully. */
2798 _cleanup_strv_free_
char **files
= NULL
, **names
= NULL
;
2801 STRV_FOREACH(a
, names_or_paths
) {
2802 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2803 UnitFileInstallInfo
*i
= NULL
;
2804 _cleanup_free_
char *n
= NULL
;
2806 r
= path_extract_filename(*a
, &n
);
2809 if (r
== O_DIRECTORY
)
2810 return log_debug_errno(SYNTHETIC_ERRNO(EISDIR
),
2811 "Unexpected path to a directory \"%s\", refusing.", *a
);
2814 r
= install_info_discover(&ctx
, lp
, n
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
, NULL
, NULL
);
2816 log_debug_errno(r
, "Failed to discover unit \"%s\", operating on name: %m", n
);
2819 r
= strv_consume(&names
, TAKE_PTR(n
));
2823 const char *p
= NULL
;
2824 if (i
&& i
->path
&& i
->root
)
2825 /* Use startswith here, because we know that paths are normalized, and
2826 * path_startswith() would give us a relative path, but we need an absolute path
2827 * relative to i->root.
2829 * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service
2830 * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute"
2831 * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/.
2833 p
= startswith(i
->path
, i
->root
);
2835 r
= strv_extend(&files
, p
?: *a
);
2840 *ret_names
= TAKE_PTR(names
);
2841 *ret_files
= TAKE_PTR(files
);
2845 int unit_file_reenable(
2847 UnitFileFlags flags
,
2848 const char *root_dir
,
2849 char **names_or_paths
,
2850 UnitFileChange
**changes
,
2851 size_t *n_changes
) {
2853 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2854 _cleanup_strv_free_
char **names
= NULL
, **files
= NULL
;
2858 assert(scope
< _LOOKUP_SCOPE_MAX
);
2860 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2864 const char *config_path
= config_path_from_flags(&lp
, flags
);
2868 r
= normalize_linked_files(scope
, &lp
, names_or_paths
, &names
, &files
);
2872 /* First, we invoke the disable command with only the basename... */
2873 r
= do_unit_file_disable(&lp
, scope
, flags
, config_path
, names
, changes
, n_changes
);
2877 /* But the enable command with the full name */
2878 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2881 int unit_file_set_default(
2883 UnitFileFlags flags
,
2884 const char *root_dir
,
2886 UnitFileChange
**changes
,
2887 size_t *n_changes
) {
2889 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2890 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2891 UnitFileInstallInfo
*info
;
2892 const char *new_path
;
2896 assert(scope
< _LOOKUP_SCOPE_MAX
);
2899 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2901 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2904 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2908 r
= install_info_discover_and_check(&ctx
, &lp
, name
, 0, &info
, changes
, n_changes
);
2912 new_path
= strjoina(lp
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2913 return create_symlink(&lp
, info
->path
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2916 int unit_file_get_default(
2918 const char *root_dir
,
2921 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2922 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2923 UnitFileInstallInfo
*info
;
2928 assert(scope
< _LOOKUP_SCOPE_MAX
);
2931 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2935 r
= install_info_discover(&ctx
, &lp
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2939 r
= install_info_may_process(info
, &lp
, NULL
, 0);
2943 n
= strdup(info
->name
);
2951 int unit_file_lookup_state(
2953 const LookupPaths
*lp
,
2955 UnitFileState
*ret
) {
2957 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2958 UnitFileInstallInfo
*info
;
2959 UnitFileState state
;
2965 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2968 r
= install_info_discover(&ctx
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2971 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2973 assert(IN_SET(info
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2974 log_debug("Found unit %s at %s (%s)", name
, strna(info
->path
),
2975 info
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2977 /* Shortcut things, if the caller just wants to know if this unit exists. */
2981 switch (info
->type
) {
2983 case UNIT_FILE_TYPE_MASKED
:
2984 r
= path_is_runtime(lp
, info
->path
, true);
2988 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2991 case UNIT_FILE_TYPE_REGULAR
:
2992 /* Check if the name we were querying is actually an alias */
2993 if (!streq(name
, basename(info
->path
)) && !unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
2994 state
= UNIT_FILE_ALIAS
;
2998 r
= path_is_generator(lp
, info
->path
);
3002 state
= UNIT_FILE_GENERATED
;
3006 r
= path_is_transient(lp
, info
->path
);
3010 state
= UNIT_FILE_TRANSIENT
;
3014 /* Check if any of the Alias= symlinks have been created.
3015 * We ignore other aliases, and only check those that would
3016 * be created by systemctl enable for this unit. */
3017 r
= find_symlinks_in_scope(scope
, lp
, info
, true, &state
);
3023 /* Check if the file is known under other names. If it is,
3024 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
3025 r
= find_symlinks_in_scope(scope
, lp
, info
, false, &state
);
3029 state
= UNIT_FILE_INDIRECT
;
3031 if (unit_file_install_info_has_rules(info
))
3032 state
= UNIT_FILE_DISABLED
;
3033 else if (unit_file_install_info_has_also(info
))
3034 state
= UNIT_FILE_INDIRECT
;
3036 state
= UNIT_FILE_STATIC
;
3042 assert_not_reached();
3049 int unit_file_get_state(
3051 const char *root_dir
,
3053 UnitFileState
*ret
) {
3055 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3059 assert(scope
< _LOOKUP_SCOPE_MAX
);
3062 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3066 return unit_file_lookup_state(scope
, &lp
, name
, ret
);
3069 int unit_file_exists(LookupScope scope
, const LookupPaths
*lp
, const char *name
) {
3070 _cleanup_(install_context_done
) InstallContext c
= { .scope
= scope
};
3076 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3079 r
= install_info_discover(&c
, lp
, name
, 0, NULL
, NULL
, NULL
);
3088 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
3089 _cleanup_strv_free_
char **instances
= NULL
;
3090 _cleanup_free_
char *unit_name
= NULL
;
3094 assert(out_instances
);
3095 assert(out_unit_name
);
3097 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
3101 /* We handle the instances logic when unit name is extracted */
3103 /* We only create instances when a rule of templated unit
3104 * is seen. A rule like enable foo@.service a b c will
3105 * result in an array of (a, b, c) as instance names */
3106 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
3109 instances
= strv_split(pattern
, WHITESPACE
);
3113 *out_instances
= TAKE_PTR(instances
);
3116 *out_unit_name
= TAKE_PTR(unit_name
);
3121 static int presets_find_config(LookupScope scope
, const char *root_dir
, char ***files
) {
3122 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
3123 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
3124 const char* const* dirs
;
3127 assert(scope
< _LOOKUP_SCOPE_MAX
);
3129 if (scope
== LOOKUP_SCOPE_SYSTEM
)
3131 else if (IN_SET(scope
, LOOKUP_SCOPE_GLOBAL
, LOOKUP_SCOPE_USER
))
3134 assert_not_reached();
3136 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
3139 static int read_presets(LookupScope scope
, const char *root_dir
, UnitFilePresets
*presets
) {
3140 _cleanup_(unit_file_presets_freep
) UnitFilePresets ps
= {};
3141 _cleanup_strv_free_
char **files
= NULL
;
3145 assert(scope
< _LOOKUP_SCOPE_MAX
);
3148 r
= presets_find_config(scope
, root_dir
, &files
);
3152 STRV_FOREACH(p
, files
) {
3153 _cleanup_fclose_
FILE *f
= NULL
;
3156 f
= fopen(*p
, "re");
3158 if (errno
== ENOENT
)
3165 _cleanup_free_
char *line
= NULL
;
3166 UnitFilePresetRule rule
= {};
3167 const char *parameter
;
3170 r
= read_line(f
, LONG_LINE_MAX
, &line
);
3181 if (strchr(COMMENTS
, *l
))
3184 parameter
= first_word(l
, "enable");
3187 char **instances
= NULL
;
3189 /* Unit_name will remain the same as parameter when no instances are specified */
3190 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
3192 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
3196 rule
= (UnitFilePresetRule
) {
3197 .pattern
= unit_name
,
3198 .action
= PRESET_ENABLE
,
3199 .instances
= instances
,
3203 parameter
= first_word(l
, "disable");
3207 pattern
= strdup(parameter
);
3211 rule
= (UnitFilePresetRule
) {
3213 .action
= PRESET_DISABLE
,
3218 if (!GREEDY_REALLOC(ps
.rules
, ps
.n_rules
+ 1))
3221 ps
.rules
[ps
.n_rules
++] = rule
;
3225 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
3229 ps
.initialized
= true;
3231 ps
= (UnitFilePresets
){};
3236 static int pattern_match_multiple_instances(
3237 const UnitFilePresetRule rule
,
3238 const char *unit_name
,
3241 _cleanup_free_
char *templated_name
= NULL
;
3244 /* If no ret is needed or the rule itself does not have instances
3245 * initialized, we return not matching */
3246 if (!ret
|| !rule
.instances
)
3249 r
= unit_name_template(unit_name
, &templated_name
);
3252 if (!streq(rule
.pattern
, templated_name
))
3255 /* Compose a list of specified instances when unit name is a template */
3256 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
3257 _cleanup_strv_free_
char **out_strv
= NULL
;
3259 STRV_FOREACH(iter
, rule
.instances
) {
3260 _cleanup_free_
char *name
= NULL
;
3262 r
= unit_name_replace_instance(unit_name
, *iter
, &name
);
3266 r
= strv_consume(&out_strv
, TAKE_PTR(name
));
3271 *ret
= TAKE_PTR(out_strv
);
3274 /* We now know the input unit name is an instance name */
3275 _cleanup_free_
char *instance_name
= NULL
;
3277 r
= unit_name_to_instance(unit_name
, &instance_name
);
3281 if (strv_find(rule
.instances
, instance_name
))
3287 static int query_presets(const char *name
, const UnitFilePresets
*presets
, char ***instance_name_list
) {
3288 PresetAction action
= PRESET_UNKNOWN
;
3290 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3293 for (size_t i
= 0; i
< presets
->n_rules
; i
++)
3294 if (pattern_match_multiple_instances(presets
->rules
[i
], name
, instance_name_list
) > 0 ||
3295 fnmatch(presets
->rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
3296 action
= presets
->rules
[i
].action
;
3301 case PRESET_UNKNOWN
:
3302 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3305 if (instance_name_list
&& *instance_name_list
)
3306 STRV_FOREACH(s
, *instance_name_list
)
3307 log_debug("Preset files say enable %s.", *s
);
3309 log_debug("Preset files say enable %s.", name
);
3311 case PRESET_DISABLE
:
3312 log_debug("Preset files say disable %s.", name
);
3315 assert_not_reached();
3319 int unit_file_query_preset(LookupScope scope
, const char *root_dir
, const char *name
, UnitFilePresets
*cached
) {
3320 _cleanup_(unit_file_presets_freep
) UnitFilePresets tmp
= {};
3325 if (!cached
->initialized
) {
3326 r
= read_presets(scope
, root_dir
, cached
);
3331 return query_presets(name
, cached
, NULL
);
3334 static int execute_preset(
3335 UnitFileFlags file_flags
,
3336 InstallContext
*plus
,
3337 InstallContext
*minus
,
3338 const LookupPaths
*lp
,
3339 const char *config_path
,
3341 UnitFilePresetMode mode
,
3342 UnitFileChange
**changes
,
3343 size_t *n_changes
) {
3350 assert(config_path
);
3352 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3353 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3355 r
= install_context_mark_for_removal(minus
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3359 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, false, changes
, n_changes
);
3363 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3366 /* Returns number of symlinks that where supposed to be installed. */
3367 q
= install_context_apply(plus
, lp
,
3368 file_flags
| UNIT_FILE_IGNORE_AUXILIARY_FAILURE
,
3370 SEARCH_LOAD
, changes
, n_changes
);
3382 static int preset_prepare_one(
3384 InstallContext
*plus
,
3385 InstallContext
*minus
,
3388 const UnitFilePresets
*presets
,
3389 UnitFileChange
**changes
,
3390 size_t *n_changes
) {
3392 _cleanup_(install_context_done
) InstallContext tmp
= { .scope
= scope
};
3393 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3394 UnitFileInstallInfo
*info
;
3397 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3400 r
= install_info_discover(&tmp
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3401 &info
, changes
, n_changes
);
3404 if (!streq(name
, info
->name
)) {
3405 log_debug("Skipping %s because it is an alias for %s.", name
, info
->name
);
3409 r
= query_presets(name
, presets
, &instance_name_list
);
3414 if (instance_name_list
)
3415 STRV_FOREACH(s
, instance_name_list
) {
3416 r
= install_info_discover_and_check(plus
, lp
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3417 &info
, changes
, n_changes
);
3422 r
= install_info_discover_and_check(plus
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3423 &info
, changes
, n_changes
);
3429 r
= install_info_discover(minus
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3430 &info
, changes
, n_changes
);
3435 int unit_file_preset(
3437 UnitFileFlags file_flags
,
3438 const char *root_dir
,
3440 UnitFilePresetMode mode
,
3441 UnitFileChange
**changes
,
3442 size_t *n_changes
) {
3444 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3445 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3446 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3447 const char *config_path
;
3451 assert(scope
< _LOOKUP_SCOPE_MAX
);
3452 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3454 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3458 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3462 r
= read_presets(scope
, root_dir
, &presets
);
3466 STRV_FOREACH(i
, files
) {
3467 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, *i
, &presets
, changes
, n_changes
);
3472 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, files
, mode
, changes
, n_changes
);
3475 int unit_file_preset_all(
3477 UnitFileFlags file_flags
,
3478 const char *root_dir
,
3479 UnitFilePresetMode mode
,
3480 UnitFileChange
**changes
,
3481 size_t *n_changes
) {
3483 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3484 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3485 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3486 const char *config_path
= NULL
;
3490 assert(scope
< _LOOKUP_SCOPE_MAX
);
3491 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3493 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3497 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3501 r
= read_presets(scope
, root_dir
, &presets
);
3505 STRV_FOREACH(i
, lp
.search_path
) {
3506 _cleanup_closedir_
DIR *d
= NULL
;
3510 if (errno
== ENOENT
)
3516 FOREACH_DIRENT(de
, d
, return -errno
) {
3518 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3521 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3524 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, de
->d_name
, &presets
, changes
, n_changes
);
3526 !IN_SET(r
, -EEXIST
, -ERFKILL
, -EADDRNOTAVAIL
, -EBADSLT
, -EIDRM
, -EUCLEAN
, -ELOOP
, -ENOENT
, -EUNATCH
, -EXDEV
))
3527 /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
3528 * Coordinate with unit_file_dump_changes() above. */
3533 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, NULL
, mode
, changes
, n_changes
);
3536 static UnitFileList
* unit_file_list_free_one(UnitFileList
*f
) {
3544 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3545 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3548 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3550 int unit_file_get_list(
3552 const char *root_dir
,
3557 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3561 assert(scope
< _LOOKUP_SCOPE_MAX
);
3564 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3568 STRV_FOREACH(dirname
, lp
.search_path
) {
3569 _cleanup_closedir_
DIR *d
= NULL
;
3571 d
= opendir(*dirname
);
3573 if (errno
== ENOENT
)
3575 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3576 log_debug_errno(errno
, "Failed to open \"%s\": %m", *dirname
);
3583 FOREACH_DIRENT(de
, d
, return -errno
) {
3584 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3586 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3589 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3592 if (hashmap_get(h
, de
->d_name
))
3595 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3598 f
= new0(UnitFileList
, 1);
3602 f
->path
= path_make_absolute(de
->d_name
, *dirname
);
3606 r
= unit_file_lookup_state(scope
, &lp
, de
->d_name
, &f
->state
);
3608 f
->state
= UNIT_FILE_BAD
;
3610 if (!strv_isempty(states
) &&
3611 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3614 r
= hashmap_put(h
, basename(f
->path
), f
);
3618 f
= NULL
; /* prevent cleanup */
3625 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3626 [UNIT_FILE_ENABLED
] = "enabled",
3627 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3628 [UNIT_FILE_LINKED
] = "linked",
3629 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3630 [UNIT_FILE_ALIAS
] = "alias",
3631 [UNIT_FILE_MASKED
] = "masked",
3632 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3633 [UNIT_FILE_STATIC
] = "static",
3634 [UNIT_FILE_DISABLED
] = "disabled",
3635 [UNIT_FILE_INDIRECT
] = "indirect",
3636 [UNIT_FILE_GENERATED
] = "generated",
3637 [UNIT_FILE_TRANSIENT
] = "transient",
3638 [UNIT_FILE_BAD
] = "bad",
3641 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3643 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3644 [UNIT_FILE_SYMLINK
] = "symlink",
3645 [UNIT_FILE_UNLINK
] = "unlink",
3646 [UNIT_FILE_IS_MASKED
] = "masked",
3647 [UNIT_FILE_IS_DANGLING
] = "dangling",
3648 [UNIT_FILE_DESTINATION_NOT_PRESENT
] = "destination not present",
3649 [UNIT_FILE_AUXILIARY_FAILED
] = "auxiliary unit failed",
3652 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, int);
3654 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3655 [UNIT_FILE_PRESET_FULL
] = "full",
3656 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3657 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3660 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);