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
->name
, 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 *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 _cleanup_free_
char *path
= strjoin(config_path
, "/", dst
, suffix
, n
);
2005 _cleanup_free_
char *target
= strjoin("../", info
->name
);
2009 q
= create_symlink(lp
, target
, path
, true, changes
, n_changes
);
2013 if (unit_file_exists(scope
, lp
, dst
) == 0)
2014 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_DESTINATION_NOT_PRESENT
, dst
, info
->path
);
2020 static int install_info_symlink_link(
2021 UnitFileInstallInfo
*info
,
2022 const LookupPaths
*lp
,
2023 const char *config_path
,
2025 UnitFileChange
**changes
,
2026 size_t *n_changes
) {
2028 _cleanup_free_
char *path
= NULL
;
2033 assert(config_path
);
2036 r
= in_search_path(lp
, info
->path
);
2042 path
= path_join(config_path
, info
->name
);
2046 return create_symlink(lp
, info
->path
, path
, force
, changes
, n_changes
);
2049 static int install_info_apply(
2051 UnitFileFlags file_flags
,
2052 UnitFileInstallInfo
*info
,
2053 const LookupPaths
*lp
,
2054 const char *config_path
,
2055 UnitFileChange
**changes
,
2056 size_t *n_changes
) {
2062 assert(config_path
);
2064 if (info
->type
!= UNIT_FILE_TYPE_REGULAR
)
2067 bool force
= file_flags
& UNIT_FILE_FORCE
;
2069 r
= install_info_symlink_link(info
, lp
, config_path
, force
, changes
, n_changes
);
2070 /* Do not count links to the unit file towards the "carries_install_info" count */
2072 /* If linking of the file failed, do not try to create other symlinks,
2073 * because they might would pointing to a non-existent or wrong unit. */
2076 r
= install_info_symlink_alias(scope
, info
, lp
, config_path
, force
, changes
, n_changes
);
2078 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->wanted_by
, ".wants/", changes
, n_changes
);
2082 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->required_by
, ".requires/", changes
, n_changes
);
2089 static int install_context_apply(
2090 InstallContext
*ctx
,
2091 const LookupPaths
*lp
,
2092 UnitFileFlags file_flags
,
2093 const char *config_path
,
2095 UnitFileChange
**changes
,
2096 size_t *n_changes
) {
2098 UnitFileInstallInfo
*i
;
2103 assert(config_path
);
2105 if (ordered_hashmap_isempty(ctx
->will_process
))
2108 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2113 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2116 q
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2120 q
= install_info_traverse(ctx
, lp
, i
, flags
, NULL
);
2123 q
= unit_file_changes_add(changes
, n_changes
, UNIT_FILE_AUXILIARY_FAILED
, NULL
, i
->name
);
2129 unit_file_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
2133 /* We can attempt to process a masked unit when a different unit
2134 * that we were processing specifies it in Also=. */
2135 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2136 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
2138 /* Assume that something *could* have been enabled here,
2139 * avoid "empty [Install] section" warning. */
2144 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
2147 q
= install_info_apply(ctx
->scope
, file_flags
, i
, lp
, config_path
, changes
, n_changes
);
2159 static int install_context_mark_for_removal(
2160 InstallContext
*ctx
,
2161 const LookupPaths
*lp
,
2162 Set
**remove_symlinks_to
,
2163 const char *config_path
,
2164 UnitFileChange
**changes
,
2165 size_t *n_changes
) {
2167 UnitFileInstallInfo
*i
;
2172 assert(config_path
);
2174 /* Marks all items for removal */
2176 if (ordered_hashmap_isempty(ctx
->will_process
))
2179 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2183 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2185 r
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2189 r
= install_info_traverse(ctx
, lp
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2190 if (r
== -ENOLINK
) {
2191 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
2192 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
2193 } else if (r
== -ENOENT
) {
2195 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
2196 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
2198 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
2199 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2203 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
2204 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2205 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
2206 log_debug("Unit file %s is masked, ignoring.", i
->name
);
2207 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
2209 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
2210 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
2214 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2224 UnitFileFlags flags
,
2225 const char *root_dir
,
2227 UnitFileChange
**changes
,
2228 size_t *n_changes
) {
2230 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2231 const char *config_path
;
2235 assert(scope
< _LOOKUP_SCOPE_MAX
);
2237 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2241 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2245 STRV_FOREACH(i
, files
) {
2246 _cleanup_free_
char *path
= NULL
;
2249 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2255 path
= path_make_absolute(*i
, config_path
);
2259 q
= create_symlink(&lp
, "/dev/null", path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2260 if (q
< 0 && r
>= 0)
2267 int unit_file_unmask(
2269 UnitFileFlags flags
,
2270 const char *root_dir
,
2272 UnitFileChange
**changes
,
2273 size_t *n_changes
) {
2275 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2276 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2277 _cleanup_strv_free_
char **todo
= NULL
;
2278 const char *config_path
;
2283 assert(scope
< _LOOKUP_SCOPE_MAX
);
2285 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2289 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2293 bool dry_run
= flags
& UNIT_FILE_DRY_RUN
;
2295 STRV_FOREACH(i
, files
) {
2296 _cleanup_free_
char *path
= NULL
;
2298 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2301 path
= path_make_absolute(*i
, config_path
);
2305 r
= null_or_empty_path(path
);
2313 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2316 todo
[n_todo
] = strdup(*i
);
2326 STRV_FOREACH(i
, todo
) {
2327 _cleanup_free_
char *path
= NULL
;
2330 path
= path_make_absolute(*i
, config_path
);
2334 if (!dry_run
&& unlink(path
) < 0) {
2335 if (errno
!= ENOENT
) {
2338 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2344 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2346 rp
= skip_root(lp
.root_dir
, path
);
2347 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2352 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, dry_run
, changes
, n_changes
);
2361 UnitFileFlags flags
,
2362 const char *root_dir
,
2364 UnitFileChange
**changes
,
2365 size_t *n_changes
) {
2367 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2368 _cleanup_strv_free_
char **todo
= NULL
;
2369 const char *config_path
;
2374 assert(scope
< _LOOKUP_SCOPE_MAX
);
2376 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2380 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2384 STRV_FOREACH(i
, files
) {
2385 _cleanup_free_
char *full
= NULL
;
2389 if (!path_is_absolute(*i
))
2393 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2396 full
= path_join(lp
.root_dir
, *i
);
2400 if (lstat(full
, &st
) < 0)
2402 r
= stat_verify_regular(&st
);
2406 q
= in_search_path(&lp
, *i
);
2412 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2415 todo
[n_todo
] = strdup(*i
);
2425 STRV_FOREACH(i
, todo
) {
2426 _cleanup_free_
char *new_path
= NULL
;
2428 new_path
= path_make_absolute(basename(*i
), config_path
);
2432 q
= create_symlink(&lp
, *i
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2433 if (q
< 0 && r
>= 0)
2440 static int path_shall_revert(const LookupPaths
*lp
, const char *path
) {
2446 /* Checks whether the path is one where the drop-in directories shall be removed. */
2448 r
= path_is_config(lp
, path
, true);
2452 r
= path_is_control(lp
, path
);
2456 return path_is_transient(lp
, path
);
2459 int unit_file_revert(
2461 const char *root_dir
,
2463 UnitFileChange
**changes
,
2464 size_t *n_changes
) {
2466 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2467 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2468 _cleanup_strv_free_
char **todo
= NULL
;
2472 /* Puts a unit file back into vendor state. This means:
2474 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2475 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2477 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2478 * "config", but not in "transient" or "control" or even "generated").
2480 * We remove all that in both the runtime and the persistent directories, if that applies.
2483 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2487 STRV_FOREACH(i
, files
) {
2488 bool has_vendor
= false;
2490 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2493 STRV_FOREACH(p
, lp
.search_path
) {
2494 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2497 path
= path_make_absolute(*i
, *p
);
2501 r
= lstat(path
, &st
);
2503 if (errno
!= ENOENT
)
2505 } else if (S_ISREG(st
.st_mode
)) {
2506 /* Check if there's a vendor version */
2507 r
= path_is_vendor_or_generator(&lp
, path
);
2514 dropin
= strjoin(path
, ".d");
2518 r
= lstat(dropin
, &st
);
2520 if (errno
!= ENOENT
)
2522 } else if (S_ISDIR(st
.st_mode
)) {
2523 /* Remove the drop-ins */
2524 r
= path_shall_revert(&lp
, dropin
);
2528 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2531 todo
[n_todo
++] = TAKE_PTR(dropin
);
2539 /* OK, there's a vendor version, hence drop all configuration versions */
2540 STRV_FOREACH(p
, lp
.search_path
) {
2541 _cleanup_free_
char *path
= NULL
;
2544 path
= path_make_absolute(*i
, *p
);
2548 r
= lstat(path
, &st
);
2550 if (errno
!= ENOENT
)
2552 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2553 r
= path_is_config(&lp
, path
, true);
2557 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2560 todo
[n_todo
++] = TAKE_PTR(path
);
2569 STRV_FOREACH(i
, todo
) {
2570 _cleanup_strv_free_
char **fs
= NULL
;
2573 (void) get_files_in_directory(*i
, &fs
);
2575 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2576 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2581 STRV_FOREACH(j
, fs
) {
2582 _cleanup_free_
char *t
= NULL
;
2584 t
= path_join(*i
, *j
);
2588 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2591 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2593 rp
= skip_root(lp
.root_dir
, *i
);
2594 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2599 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.runtime_config
, &lp
, false, changes
, n_changes
);
2603 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.persistent_config
, &lp
, false, changes
, n_changes
);
2610 int unit_file_add_dependency(
2612 UnitFileFlags file_flags
,
2613 const char *root_dir
,
2617 UnitFileChange
**changes
,
2618 size_t *n_changes
) {
2620 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2621 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2622 UnitFileInstallInfo
*info
, *target_info
;
2623 const char *config_path
;
2627 assert(scope
< _LOOKUP_SCOPE_MAX
);
2630 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2633 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2636 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2640 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2644 r
= install_info_discover_and_check(&ctx
, &lp
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2645 &target_info
, changes
, n_changes
);
2649 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2651 STRV_FOREACH(f
, files
) {
2654 r
= install_info_discover_and_check(&ctx
, &lp
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2655 &info
, changes
, n_changes
);
2659 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2661 /* We didn't actually load anything from the unit
2662 * file, but instead just add in our new symlink to
2665 if (dep
== UNIT_WANTS
)
2666 l
= &info
->wanted_by
;
2668 l
= &info
->required_by
;
2671 *l
= strv_new(target_info
->name
);
2676 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2677 SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2680 static int do_unit_file_enable(
2681 const LookupPaths
*lp
,
2683 UnitFileFlags flags
,
2684 const char *config_path
,
2686 UnitFileChange
**changes
,
2687 size_t *n_changes
) {
2689 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2690 UnitFileInstallInfo
*info
;
2693 STRV_FOREACH(f
, files
) {
2694 r
= install_info_discover_and_check(&ctx
, lp
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2695 &info
, changes
, n_changes
);
2699 assert(info
->type
== UNIT_FILE_TYPE_REGULAR
);
2702 /* This will return the number of symlink rules that were
2703 supposed to be created, not the ones actually created. This
2704 is useful to determine whether the passed files had any
2705 installation data at all. */
2707 return install_context_apply(&ctx
, lp
, flags
, config_path
,
2708 SEARCH_LOAD
, changes
, n_changes
);
2711 int unit_file_enable(
2713 UnitFileFlags flags
,
2714 const char *root_dir
,
2716 UnitFileChange
**changes
,
2717 size_t *n_changes
) {
2719 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2723 assert(scope
< _LOOKUP_SCOPE_MAX
);
2725 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2729 const char *config_path
= config_path_from_flags(&lp
, flags
);
2733 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2736 static int do_unit_file_disable(
2737 const LookupPaths
*lp
,
2739 UnitFileFlags flags
,
2740 const char *config_path
,
2742 UnitFileChange
**changes
,
2743 size_t *n_changes
) {
2745 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2746 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2749 STRV_FOREACH(i
, files
) {
2750 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2753 r
= install_info_add(&ctx
, *i
, NULL
, lp
->root_dir
, /* auxiliary= */ false, NULL
);
2758 r
= install_context_mark_for_removal(&ctx
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2762 return remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, flags
& UNIT_FILE_DRY_RUN
, changes
, n_changes
);
2766 int unit_file_disable(
2768 UnitFileFlags flags
,
2769 const char *root_dir
,
2771 UnitFileChange
**changes
,
2772 size_t *n_changes
) {
2774 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2778 assert(scope
< _LOOKUP_SCOPE_MAX
);
2780 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2784 const char *config_path
= config_path_from_flags(&lp
, flags
);
2788 return do_unit_file_disable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2791 static int normalize_linked_files(
2793 const LookupPaths
*lp
,
2794 char **names_or_paths
,
2796 char ***ret_files
) {
2798 /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/,
2799 * but operates on real unit names. For each argument we we look up the actual path
2800 * where the unit is found. This way linked units can be re-enabled successfully. */
2802 _cleanup_free_
char **files
= NULL
, **names
= NULL
;
2805 STRV_FOREACH(a
, names_or_paths
) {
2806 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2807 UnitFileInstallInfo
*i
= NULL
;
2808 _cleanup_free_
char *n
= NULL
;
2810 r
= path_extract_filename(*a
, &n
);
2813 if (r
== O_DIRECTORY
)
2814 return log_debug_errno(SYNTHETIC_ERRNO(EISDIR
),
2815 "Unexpected path to a directory \"%s\", refusing.", *a
);
2818 r
= install_info_discover(&ctx
, lp
, n
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
, NULL
, NULL
);
2820 log_debug_errno(r
, "Failed to discover unit \"%s\", operating on name: %m", n
);
2823 r
= strv_consume(&names
, TAKE_PTR(n
));
2827 const char *p
= NULL
;
2829 /* Use startswith here, because we know that paths are normalized, and
2830 * path_startswith() would give us a relative path, but we need an absolute path
2831 * relative to i->root.
2833 * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service
2834 * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute"
2835 * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/.
2837 p
= startswith(i
->path
, i
->root
);
2839 r
= strv_extend(&files
, p
?: *a
);
2844 *ret_names
= TAKE_PTR(names
);
2845 *ret_files
= TAKE_PTR(files
);
2849 int unit_file_reenable(
2851 UnitFileFlags flags
,
2852 const char *root_dir
,
2853 char **names_or_paths
,
2854 UnitFileChange
**changes
,
2855 size_t *n_changes
) {
2857 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2858 _cleanup_strv_free_
char **names
= NULL
, **files
= NULL
;
2862 assert(scope
< _LOOKUP_SCOPE_MAX
);
2864 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2868 const char *config_path
= config_path_from_flags(&lp
, flags
);
2872 r
= normalize_linked_files(scope
, &lp
, names_or_paths
, &names
, &files
);
2876 /* First, we invoke the disable command with only the basename... */
2877 r
= do_unit_file_disable(&lp
, scope
, flags
, config_path
, names
, changes
, n_changes
);
2881 /* But the enable command with the full name */
2882 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2885 int unit_file_set_default(
2887 UnitFileFlags flags
,
2888 const char *root_dir
,
2890 UnitFileChange
**changes
,
2891 size_t *n_changes
) {
2893 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2894 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2895 UnitFileInstallInfo
*info
;
2896 const char *new_path
;
2900 assert(scope
< _LOOKUP_SCOPE_MAX
);
2903 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2905 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2908 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2912 r
= install_info_discover_and_check(&ctx
, &lp
, name
, 0, &info
, changes
, n_changes
);
2916 new_path
= strjoina(lp
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2917 return create_symlink(&lp
, info
->name
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
2920 int unit_file_get_default(
2922 const char *root_dir
,
2925 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
2926 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2927 UnitFileInstallInfo
*info
;
2932 assert(scope
< _LOOKUP_SCOPE_MAX
);
2935 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2939 r
= install_info_discover(&ctx
, &lp
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2943 r
= install_info_may_process(info
, &lp
, NULL
, 0);
2947 n
= strdup(info
->name
);
2955 int unit_file_lookup_state(
2957 const LookupPaths
*lp
,
2959 UnitFileState
*ret
) {
2961 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2962 UnitFileInstallInfo
*info
;
2963 UnitFileState state
;
2969 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2972 r
= install_info_discover(&ctx
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2975 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2977 assert(IN_SET(info
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2978 log_debug("Found unit %s at %s (%s)", name
, strna(info
->path
),
2979 info
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2981 /* Shortcut things, if the caller just wants to know if this unit exists. */
2985 switch (info
->type
) {
2987 case UNIT_FILE_TYPE_MASKED
:
2988 r
= path_is_runtime(lp
, info
->path
, true);
2992 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2995 case UNIT_FILE_TYPE_REGULAR
:
2996 /* Check if the name we were querying is actually an alias */
2997 if (!streq(name
, basename(info
->path
)) && !unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
2998 state
= UNIT_FILE_ALIAS
;
3002 r
= path_is_generator(lp
, info
->path
);
3006 state
= UNIT_FILE_GENERATED
;
3010 r
= path_is_transient(lp
, info
->path
);
3014 state
= UNIT_FILE_TRANSIENT
;
3018 /* Check if any of the Alias= symlinks have been created.
3019 * We ignore other aliases, and only check those that would
3020 * be created by systemctl enable for this unit. */
3021 r
= find_symlinks_in_scope(scope
, lp
, info
, true, &state
);
3027 /* Check if the file is known under other names. If it is,
3028 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
3029 r
= find_symlinks_in_scope(scope
, lp
, info
, false, &state
);
3033 state
= UNIT_FILE_INDIRECT
;
3035 if (unit_file_install_info_has_rules(info
))
3036 state
= UNIT_FILE_DISABLED
;
3037 else if (unit_file_install_info_has_also(info
))
3038 state
= UNIT_FILE_INDIRECT
;
3040 state
= UNIT_FILE_STATIC
;
3046 assert_not_reached();
3053 int unit_file_get_state(
3055 const char *root_dir
,
3057 UnitFileState
*ret
) {
3059 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3063 assert(scope
< _LOOKUP_SCOPE_MAX
);
3066 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3070 return unit_file_lookup_state(scope
, &lp
, name
, ret
);
3073 int unit_file_exists(LookupScope scope
, const LookupPaths
*lp
, const char *name
) {
3074 _cleanup_(install_context_done
) InstallContext c
= { .scope
= scope
};
3080 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3083 r
= install_info_discover(&c
, lp
, name
, 0, NULL
, NULL
, NULL
);
3092 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
3093 _cleanup_strv_free_
char **instances
= NULL
;
3094 _cleanup_free_
char *unit_name
= NULL
;
3098 assert(out_instances
);
3099 assert(out_unit_name
);
3101 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
3105 /* We handle the instances logic when unit name is extracted */
3107 /* We only create instances when a rule of templated unit
3108 * is seen. A rule like enable foo@.service a b c will
3109 * result in an array of (a, b, c) as instance names */
3110 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
3113 instances
= strv_split(pattern
, WHITESPACE
);
3117 *out_instances
= TAKE_PTR(instances
);
3120 *out_unit_name
= TAKE_PTR(unit_name
);
3125 static int presets_find_config(LookupScope scope
, const char *root_dir
, char ***files
) {
3126 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
3127 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
3128 const char* const* dirs
;
3131 assert(scope
< _LOOKUP_SCOPE_MAX
);
3133 if (scope
== LOOKUP_SCOPE_SYSTEM
)
3135 else if (IN_SET(scope
, LOOKUP_SCOPE_GLOBAL
, LOOKUP_SCOPE_USER
))
3138 assert_not_reached();
3140 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
3143 static int read_presets(LookupScope scope
, const char *root_dir
, UnitFilePresets
*presets
) {
3144 _cleanup_(unit_file_presets_freep
) UnitFilePresets ps
= {};
3145 _cleanup_strv_free_
char **files
= NULL
;
3149 assert(scope
< _LOOKUP_SCOPE_MAX
);
3152 r
= presets_find_config(scope
, root_dir
, &files
);
3156 STRV_FOREACH(p
, files
) {
3157 _cleanup_fclose_
FILE *f
= NULL
;
3160 f
= fopen(*p
, "re");
3162 if (errno
== ENOENT
)
3169 _cleanup_free_
char *line
= NULL
;
3170 UnitFilePresetRule rule
= {};
3171 const char *parameter
;
3174 r
= read_line(f
, LONG_LINE_MAX
, &line
);
3185 if (strchr(COMMENTS
, *l
))
3188 parameter
= first_word(l
, "enable");
3191 char **instances
= NULL
;
3193 /* Unit_name will remain the same as parameter when no instances are specified */
3194 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
3196 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
3200 rule
= (UnitFilePresetRule
) {
3201 .pattern
= unit_name
,
3202 .action
= PRESET_ENABLE
,
3203 .instances
= instances
,
3207 parameter
= first_word(l
, "disable");
3211 pattern
= strdup(parameter
);
3215 rule
= (UnitFilePresetRule
) {
3217 .action
= PRESET_DISABLE
,
3222 if (!GREEDY_REALLOC(ps
.rules
, ps
.n_rules
+ 1))
3225 ps
.rules
[ps
.n_rules
++] = rule
;
3229 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
3233 ps
.initialized
= true;
3235 ps
= (UnitFilePresets
){};
3240 static int pattern_match_multiple_instances(
3241 const UnitFilePresetRule rule
,
3242 const char *unit_name
,
3245 _cleanup_free_
char *templated_name
= NULL
;
3248 /* If no ret is needed or the rule itself does not have instances
3249 * initialized, we return not matching */
3250 if (!ret
|| !rule
.instances
)
3253 r
= unit_name_template(unit_name
, &templated_name
);
3256 if (!streq(rule
.pattern
, templated_name
))
3259 /* Compose a list of specified instances when unit name is a template */
3260 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
3261 _cleanup_strv_free_
char **out_strv
= NULL
;
3263 STRV_FOREACH(iter
, rule
.instances
) {
3264 _cleanup_free_
char *name
= NULL
;
3266 r
= unit_name_replace_instance(unit_name
, *iter
, &name
);
3270 r
= strv_consume(&out_strv
, TAKE_PTR(name
));
3275 *ret
= TAKE_PTR(out_strv
);
3278 /* We now know the input unit name is an instance name */
3279 _cleanup_free_
char *instance_name
= NULL
;
3281 r
= unit_name_to_instance(unit_name
, &instance_name
);
3285 if (strv_find(rule
.instances
, instance_name
))
3291 static int query_presets(const char *name
, const UnitFilePresets
*presets
, char ***instance_name_list
) {
3292 PresetAction action
= PRESET_UNKNOWN
;
3294 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3297 for (size_t i
= 0; i
< presets
->n_rules
; i
++)
3298 if (pattern_match_multiple_instances(presets
->rules
[i
], name
, instance_name_list
) > 0 ||
3299 fnmatch(presets
->rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
3300 action
= presets
->rules
[i
].action
;
3305 case PRESET_UNKNOWN
:
3306 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3309 if (instance_name_list
&& *instance_name_list
)
3310 STRV_FOREACH(s
, *instance_name_list
)
3311 log_debug("Preset files say enable %s.", *s
);
3313 log_debug("Preset files say enable %s.", name
);
3315 case PRESET_DISABLE
:
3316 log_debug("Preset files say disable %s.", name
);
3319 assert_not_reached();
3323 int unit_file_query_preset(LookupScope scope
, const char *root_dir
, const char *name
, UnitFilePresets
*cached
) {
3324 _cleanup_(unit_file_presets_freep
) UnitFilePresets tmp
= {};
3329 if (!cached
->initialized
) {
3330 r
= read_presets(scope
, root_dir
, cached
);
3335 return query_presets(name
, cached
, NULL
);
3338 static int execute_preset(
3339 UnitFileFlags file_flags
,
3340 InstallContext
*plus
,
3341 InstallContext
*minus
,
3342 const LookupPaths
*lp
,
3343 const char *config_path
,
3345 UnitFilePresetMode mode
,
3346 UnitFileChange
**changes
,
3347 size_t *n_changes
) {
3354 assert(config_path
);
3356 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3357 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3359 r
= install_context_mark_for_removal(minus
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3363 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, false, changes
, n_changes
);
3367 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3370 /* Returns number of symlinks that where supposed to be installed. */
3371 q
= install_context_apply(plus
, lp
,
3372 file_flags
| UNIT_FILE_IGNORE_AUXILIARY_FAILURE
,
3374 SEARCH_LOAD
, changes
, n_changes
);
3386 static int preset_prepare_one(
3388 InstallContext
*plus
,
3389 InstallContext
*minus
,
3392 const UnitFilePresets
*presets
,
3393 UnitFileChange
**changes
,
3394 size_t *n_changes
) {
3396 _cleanup_(install_context_done
) InstallContext tmp
= { .scope
= scope
};
3397 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3398 UnitFileInstallInfo
*info
;
3401 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3404 r
= install_info_discover(&tmp
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3405 &info
, changes
, n_changes
);
3408 if (!streq(name
, info
->name
)) {
3409 log_debug("Skipping %s because it is an alias for %s.", name
, info
->name
);
3413 r
= query_presets(name
, presets
, &instance_name_list
);
3418 if (instance_name_list
)
3419 STRV_FOREACH(s
, instance_name_list
) {
3420 r
= install_info_discover_and_check(plus
, lp
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3421 &info
, changes
, n_changes
);
3426 r
= install_info_discover_and_check(plus
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3427 &info
, changes
, n_changes
);
3433 r
= install_info_discover(minus
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3434 &info
, changes
, n_changes
);
3439 int unit_file_preset(
3441 UnitFileFlags file_flags
,
3442 const char *root_dir
,
3444 UnitFilePresetMode mode
,
3445 UnitFileChange
**changes
,
3446 size_t *n_changes
) {
3448 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3449 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3450 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3451 const char *config_path
;
3455 assert(scope
< _LOOKUP_SCOPE_MAX
);
3456 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3458 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3462 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3466 r
= read_presets(scope
, root_dir
, &presets
);
3470 STRV_FOREACH(i
, files
) {
3471 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, *i
, &presets
, changes
, n_changes
);
3476 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, files
, mode
, changes
, n_changes
);
3479 int unit_file_preset_all(
3481 UnitFileFlags file_flags
,
3482 const char *root_dir
,
3483 UnitFilePresetMode mode
,
3484 UnitFileChange
**changes
,
3485 size_t *n_changes
) {
3487 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3488 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3489 _cleanup_(unit_file_presets_freep
) UnitFilePresets presets
= {};
3490 const char *config_path
= NULL
;
3494 assert(scope
< _LOOKUP_SCOPE_MAX
);
3495 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3497 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3501 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3505 r
= read_presets(scope
, root_dir
, &presets
);
3509 STRV_FOREACH(i
, lp
.search_path
) {
3510 _cleanup_closedir_
DIR *d
= NULL
;
3514 if (errno
== ENOENT
)
3520 FOREACH_DIRENT(de
, d
, return -errno
) {
3522 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3525 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3528 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, de
->d_name
, &presets
, changes
, n_changes
);
3530 !IN_SET(r
, -EEXIST
, -ERFKILL
, -EADDRNOTAVAIL
, -EBADSLT
, -EIDRM
, -EUCLEAN
, -ELOOP
, -ENOENT
, -EUNATCH
, -EXDEV
))
3531 /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
3532 * Coordinate with unit_file_dump_changes() above. */
3537 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, NULL
, mode
, changes
, n_changes
);
3540 static UnitFileList
* unit_file_list_free_one(UnitFileList
*f
) {
3548 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3549 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3552 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3554 int unit_file_get_list(
3556 const char *root_dir
,
3561 _cleanup_(lookup_paths_free
) LookupPaths lp
= {};
3565 assert(scope
< _LOOKUP_SCOPE_MAX
);
3568 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3572 STRV_FOREACH(dirname
, lp
.search_path
) {
3573 _cleanup_closedir_
DIR *d
= NULL
;
3575 d
= opendir(*dirname
);
3577 if (errno
== ENOENT
)
3579 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3580 log_debug_errno(errno
, "Failed to open \"%s\": %m", *dirname
);
3587 FOREACH_DIRENT(de
, d
, return -errno
) {
3588 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3590 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3593 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3596 if (hashmap_get(h
, de
->d_name
))
3599 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3602 f
= new0(UnitFileList
, 1);
3606 f
->path
= path_make_absolute(de
->d_name
, *dirname
);
3610 r
= unit_file_lookup_state(scope
, &lp
, de
->d_name
, &f
->state
);
3612 f
->state
= UNIT_FILE_BAD
;
3614 if (!strv_isempty(states
) &&
3615 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3618 r
= hashmap_put(h
, basename(f
->path
), f
);
3622 f
= NULL
; /* prevent cleanup */
3629 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3630 [UNIT_FILE_ENABLED
] = "enabled",
3631 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3632 [UNIT_FILE_LINKED
] = "linked",
3633 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3634 [UNIT_FILE_ALIAS
] = "alias",
3635 [UNIT_FILE_MASKED
] = "masked",
3636 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3637 [UNIT_FILE_STATIC
] = "static",
3638 [UNIT_FILE_DISABLED
] = "disabled",
3639 [UNIT_FILE_INDIRECT
] = "indirect",
3640 [UNIT_FILE_GENERATED
] = "generated",
3641 [UNIT_FILE_TRANSIENT
] = "transient",
3642 [UNIT_FILE_BAD
] = "bad",
3645 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3647 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3648 [UNIT_FILE_SYMLINK
] = "symlink",
3649 [UNIT_FILE_UNLINK
] = "unlink",
3650 [UNIT_FILE_IS_MASKED
] = "masked",
3651 [UNIT_FILE_IS_DANGLING
] = "dangling",
3652 [UNIT_FILE_DESTINATION_NOT_PRESENT
] = "destination not present",
3653 [UNIT_FILE_AUXILIARY_FAILED
] = "auxiliary unit failed",
3656 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, int);
3658 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3659 [UNIT_FILE_PRESET_FULL
] = "full",
3660 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3661 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3664 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);