1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
12 #include "alloc-util.h"
13 #include "bus-common-errors.h"
15 #include "conf-files.h"
16 #include "conf-parser.h"
17 #include "constants.h"
18 #include "dirent-util.h"
19 #include "errno-list.h"
20 #include "extract-word.h"
25 #include "install-printf.h"
27 #include "locale-util.h"
30 #include "mkdir-label.h"
31 #include "path-lookup.h"
32 #include "path-util.h"
36 #include "stat-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
40 #include "unit-file.h"
42 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
44 typedef enum SearchFlags
{
46 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
47 SEARCH_DROPIN
= 1 << 2,
52 OrderedHashmap
*will_process
;
53 OrderedHashmap
*have_processed
;
56 struct UnitFilePresetRule
{
62 /* NB! strings use past tense. */
63 static const char *const preset_action_past_tense_table
[_PRESET_ACTION_MAX
] = {
64 [PRESET_UNKNOWN
] = "unknown",
65 [PRESET_ENABLE
] = "enabled",
66 [PRESET_DISABLE
] = "disabled",
67 [PRESET_IGNORE
] = "ignored",
70 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(preset_action_past_tense
, PresetAction
);
72 static bool install_info_has_rules(const InstallInfo
*i
) {
75 return !strv_isempty(i
->aliases
) ||
76 !strv_isempty(i
->wanted_by
) ||
77 !strv_isempty(i
->required_by
) ||
78 !strv_isempty(i
->upheld_by
);
81 static bool install_info_has_also(const InstallInfo
*i
) {
84 return !strv_isempty(i
->also
);
87 static void unit_file_preset_rule_done(UnitFilePresetRule
*rule
) {
91 strv_free(rule
->instances
);
94 void unit_file_presets_done(UnitFilePresets
*p
) {
98 FOREACH_ARRAY(rule
, p
->rules
, p
->n_rules
)
99 unit_file_preset_rule_done(rule
);
105 static const char *const install_mode_table
[_INSTALL_MODE_MAX
] = {
106 [INSTALL_MODE_REGULAR
] = "regular",
107 [INSTALL_MODE_LINKED
] = "linked",
108 [INSTALL_MODE_ALIAS
] = "alias",
109 [INSTALL_MODE_MASKED
] = "masked",
112 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(install_mode
, InstallMode
);
114 static int in_search_path(const LookupPaths
*lp
, const char *path
) {
115 _cleanup_free_
char *parent
= NULL
;
118 /* Check if 'path' is in lp->search_path. */
120 r
= path_extract_directory(ASSERT_PTR(path
), &parent
);
124 return path_strv_contains(ASSERT_PTR(lp
)->search_path
, parent
);
127 static int underneath_search_path(const LookupPaths
*lp
, const char *path
) {
128 /* Check if 'path' is underneath lp->search_path. */
130 return !!path_startswith_strv(ASSERT_PTR(path
), ASSERT_PTR(lp
)->search_path
);
133 static const char* skip_root(const char *root_dir
, const char *path
) {
139 const char *e
= path_startswith(path
, root_dir
);
143 /* Make sure the returned path starts with a slash */
145 if (e
== path
|| e
[-1] != '/')
154 static int path_is_generator(const LookupPaths
*lp
, const char *path
) {
155 _cleanup_free_
char *parent
= NULL
;
161 r
= path_extract_directory(path
, &parent
);
165 return PATH_IN_SET(parent
,
171 static int path_is_transient(const LookupPaths
*lp
, const char *path
) {
172 _cleanup_free_
char *parent
= NULL
;
178 r
= path_extract_directory(path
, &parent
);
182 return path_equal(parent
, lp
->transient
);
185 static int path_is_control(const LookupPaths
*lp
, const char *path
) {
186 _cleanup_free_
char *parent
= NULL
;
192 r
= path_extract_directory(path
, &parent
);
196 return PATH_IN_SET(parent
,
197 lp
->persistent_control
,
198 lp
->runtime_control
);
201 static int path_is_config(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
202 _cleanup_free_
char *parent
= NULL
;
208 /* Note that we do *not* have generic checks for /etc or /run in place, since with
209 * them we couldn't discern configuration from transient or generated units */
212 r
= path_extract_directory(path
, &parent
);
219 return PATH_IN_SET(path
,
220 lp
->persistent_config
,
224 static int path_is_runtime(const LookupPaths
*lp
, const char *path
, bool check_parent
) {
225 _cleanup_free_
char *parent
= NULL
;
232 /* Everything in /run is considered runtime. On top of that we also add
233 * explicit checks for the various runtime directories, as safety net. */
235 rpath
= skip_root(lp
->root_dir
, path
);
236 if (rpath
&& path_startswith(rpath
, "/run"))
240 r
= path_extract_directory(path
, &parent
);
247 return PATH_IN_SET(path
,
253 lp
->runtime_control
);
256 static int path_is_vendor_or_generator(const LookupPaths
*lp
, const char *path
) {
262 rpath
= skip_root(lp
->root_dir
, path
);
266 if (path_startswith(rpath
, "/usr"))
269 if (path_is_generator(lp
, rpath
))
272 return path_equal(rpath
, SYSTEM_DATA_UNIT_DIR
);
275 static const char* config_path_from_flags(const LookupPaths
*lp
, UnitFileFlags flags
) {
278 if (FLAGS_SET(flags
, UNIT_FILE_PORTABLE
))
279 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_attached
: lp
->persistent_attached
;
281 return FLAGS_SET(flags
, UNIT_FILE_RUNTIME
) ? lp
->runtime_config
: lp
->persistent_config
;
284 InstallChangeType
install_changes_add(
285 InstallChange
**changes
,
287 InstallChangeType type
, /* INSTALL_CHANGE_SYMLINK, _UNLINK, _IS_MASKED, _IS_DANGLING, … if positive or errno if negative */
289 const char *source
) {
291 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
295 assert(!changes
== !n_changes
);
296 assert(INSTALL_CHANGE_TYPE_VALID(type
));
298 /* Message formatting requires <path> to be set. */
301 /* Register a change or error. Note that the return value may be the error
302 * that was passed in, or -ENOMEM generated internally. */
307 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(InstallChange
));
312 r
= path_simplify_alloc(path
, &p
);
316 r
= path_simplify_alloc(source
, &s
);
320 c
[(*n_changes
)++] = (InstallChange
) {
323 .source
= TAKE_PTR(s
),
329 void install_changes_free(InstallChange
*changes
, size_t n_changes
) {
330 assert(changes
|| n_changes
== 0);
332 FOREACH_ARRAY(i
, changes
, n_changes
) {
340 static void install_change_dump_success(const InstallChange
*change
) {
342 assert(change
->path
);
344 switch (change
->type
) {
346 case INSTALL_CHANGE_SYMLINK
:
347 return log_info("Created symlink '%s' %s '%s'.",
348 change
->path
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
), change
->source
);
350 case INSTALL_CHANGE_UNLINK
:
351 return log_info("Removed '%s'.", change
->path
);
353 case INSTALL_CHANGE_IS_MASKED
:
354 return log_info("Unit %s is masked, ignoring.", change
->path
);
356 case INSTALL_CHANGE_IS_MASKED_GENERATOR
:
357 return log_info("Unit %s is masked via a generator and cannot be unmasked, skipping.", change
->path
);
359 case INSTALL_CHANGE_IS_DANGLING
:
360 return log_info("Unit %s is an alias to a non-existent unit, ignoring.", change
->path
);
362 case INSTALL_CHANGE_DESTINATION_NOT_PRESENT
:
363 return log_warning("Unit %s is added as a dependency to a non-existent unit %s.",
364 change
->source
, change
->path
);
366 case INSTALL_CHANGE_AUXILIARY_FAILED
:
367 return log_warning("Failed to enable auxiliary unit %s, ignoring.", change
->path
);
370 assert_not_reached();
374 int install_change_dump_error(const InstallChange
*change
, char **ret_errmsg
, const char **ret_bus_error
) {
376 const char *bus_error
;
378 /* Returns 0: known error and ret_errmsg formatted
379 * < 0: non-recognizable error */
382 assert(change
->path
);
383 assert(change
->type
< 0);
386 switch (change
->type
) {
389 m
= strjoin("File '", change
->path
, "' already exists",
390 change
->source
? " and is a symlink to " : NULL
, change
->source
);
391 bus_error
= BUS_ERROR_UNIT_EXISTS
;
395 m
= strjoin("Unit ", change
->path
, " is masked");
396 bus_error
= BUS_ERROR_UNIT_MASKED
;
400 m
= strjoin("Unit ", change
->path
, " is transient or generated");
401 bus_error
= BUS_ERROR_UNIT_GENERATED
;
405 m
= strjoin("File '", change
->path
, "' is under the systemd unit hierarchy already");
406 bus_error
= BUS_ERROR_UNIT_BAD_PATH
;
410 m
= strjoin("Invalid specifier in unit ", change
->path
);
411 bus_error
= BUS_ERROR_BAD_UNIT_SETTING
;
415 m
= strjoin("Refusing to operate on template unit ", change
->source
,
416 " when destination unit ", change
->path
, " is a non-template unit");
417 bus_error
= BUS_ERROR_BAD_UNIT_SETTING
;
421 m
= strjoin("Invalid unit name ", change
->path
);
422 bus_error
= BUS_ERROR_BAD_UNIT_SETTING
;
426 m
= strjoin("Refusing to operate on linked unit file ", change
->path
);
427 bus_error
= BUS_ERROR_UNIT_LINKED
;
432 m
= strjoin("Cannot alias ", change
->source
, " as ", change
->path
);
434 m
= strjoin("Invalid unit reference ", change
->path
);
435 bus_error
= BUS_ERROR_BAD_UNIT_SETTING
;
439 m
= strjoin("Unit ", change
->path
, " does not exist");
440 bus_error
= BUS_ERROR_NO_SUCH_UNIT
;
444 m
= strjoin("Unit ", change
->path
, " is an unresolvable alias");
445 bus_error
= BUS_ERROR_NO_SUCH_UNIT
;
449 m
= strjoin("Cannot resolve specifiers in unit ", change
->path
);
450 bus_error
= BUS_ERROR_BAD_UNIT_SETTING
;
461 *ret_bus_error
= bus_error
;
466 void install_changes_dump(
469 const InstallChange
*changes
,
473 bool err_logged
= false;
476 /* If verb is not specified, errors are not allowed! */
477 assert(verb
|| error
>= 0);
478 assert(changes
|| n_changes
== 0);
480 FOREACH_ARRAY(i
, changes
, n_changes
)
483 install_change_dump_success(i
);
485 _cleanup_free_
char *err_message
= NULL
;
489 r
= install_change_dump_error(i
, &err_message
, /* ret_bus_error = */ NULL
);
491 return (void) log_oom();
493 log_error_errno(r
, "Failed to %s unit %s: %m", verb
, i
->path
);
495 log_error_errno(i
->type
, "Failed to %s unit: %s", verb
, err_message
);
500 if (error
< 0 && !err_logged
)
501 log_error_errno(error
, "Failed to %s unit: %m.", verb
);
505 * Checks if two symlink targets (starting from src) are equivalent as far as the unit enablement logic is
506 * concerned. If the target is in the unit search path, then anything with the same name is equivalent.
507 * If outside the unit search path, paths must be identical.
509 static int chroot_unit_symlinks_equivalent(
510 const LookupPaths
*lp
,
512 const char *target_a
,
513 const char *target_b
) {
520 /* This will give incorrect results if the paths are relative and go outside
521 * of the chroot. False negatives are possible. */
523 const char *root
= lp
->root_dir
?: "/";
524 _cleanup_free_
char *dirname
= NULL
;
527 if (!path_is_absolute(target_a
) || !path_is_absolute(target_b
)) {
528 r
= path_extract_directory(src
, &dirname
);
533 _cleanup_free_
char *a
= path_join(path_is_absolute(target_a
) ? root
: dirname
, target_a
);
534 _cleanup_free_
char *b
= path_join(path_is_absolute(target_b
) ? root
: dirname
, target_b
);
538 r
= path_equal_or_inode_same(a
, b
, 0);
542 _cleanup_free_
char *a_name
= NULL
, *b_name
= NULL
;
543 r
= path_extract_filename(a
, &a_name
);
546 r
= path_extract_filename(b
, &b_name
);
550 return streq(a_name
, b_name
) &&
551 path_startswith_strv(a
, lp
->search_path
) &&
552 path_startswith_strv(b
, lp
->search_path
);
555 static int create_symlink(
556 const LookupPaths
*lp
,
557 const char *old_path
,
558 const char *new_path
,
560 InstallChange
**changes
,
563 _cleanup_free_
char *dest
= NULL
;
570 rp
= skip_root(lp
->root_dir
, old_path
);
574 /* Actually create a symlink, and remember that we did. This function is
575 * smart enough to check if there's already a valid symlink in place.
577 * Returns 1 if a symlink was created or already exists and points to the
578 * right place, or negative on error.
581 (void) mkdir_parents_label(new_path
, 0755);
583 if (symlink(old_path
, new_path
) >= 0) {
584 r
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_SYMLINK
, new_path
, old_path
);
591 return install_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
593 r
= readlink_malloc(new_path
, &dest
);
595 /* translate EINVAL (non-symlink exists) to EEXIST */
599 return install_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
602 if (chroot_unit_symlinks_equivalent(lp
, new_path
, dest
, old_path
)) {
603 log_debug("Symlink %s %s %s already exists",
604 new_path
, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
), dest
);
609 return install_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
611 r
= symlink_atomic(old_path
, new_path
);
613 return install_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
615 r
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_UNLINK
, new_path
, NULL
);
618 r
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_SYMLINK
, new_path
, old_path
);
625 static int mark_symlink_for_removal(
626 Set
**remove_symlinks_to
,
634 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
638 r
= path_simplify_alloc(p
, &n
);
642 r
= set_consume(*remove_symlinks_to
, n
);
651 static int remove_marked_symlinks_fd(
652 Set
*remove_symlinks_to
,
655 const char *config_path
,
656 const LookupPaths
*lp
,
659 InstallChange
**changes
,
662 _cleanup_closedir_
DIR *d
= NULL
;
665 assert(remove_symlinks_to
);
680 FOREACH_DIRENT(de
, d
, return -errno
)
682 if (de
->d_type
== DT_DIR
) {
683 _cleanup_free_
char *p
= NULL
;
686 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
696 p
= path_make_absolute(de
->d_name
, path
);
702 /* This will close nfd, regardless whether it succeeds or not */
703 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
707 } else if (de
->d_type
== DT_LNK
) {
708 _cleanup_free_
char *p
= NULL
;
712 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
715 p
= path_make_absolute(de
->d_name
, path
);
720 /* We remove all links pointing to a file or path that is marked, as well as all
721 * files sharing the same name as a file that is marked, and files sharing the same
722 * name after the instance has been removed. Do path chasing only if we don't already
723 * know that we want to remove the symlink. */
724 found
= set_contains(remove_symlinks_to
, de
->d_name
);
727 _cleanup_free_
char *template = NULL
;
729 q
= unit_name_template(de
->d_name
, &template);
730 if (q
< 0 && q
!= -EINVAL
)
733 found
= set_contains(remove_symlinks_to
, template);
737 _cleanup_free_
char *dest
= NULL
;
739 q
= chase(p
, lp
->root_dir
, CHASE_NONEXISTENT
, &dest
, NULL
);
743 log_debug_errno(q
, "Failed to resolve symlink \"%s\": %m", p
);
744 install_changes_add(changes
, n_changes
, q
, p
, NULL
);
751 found
= set_contains(remove_symlinks_to
, dest
) ||
752 set_contains(remove_symlinks_to
, basename(dest
));
761 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
764 install_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
768 (void) rmdir_parents(p
, config_path
);
771 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_UNLINK
, p
, NULL
);
775 /* Now, remember the full path (but with the root prefix removed) of
776 * the symlink we just removed, and remove any symlinks to it, too. */
778 const char *rp
= skip_root(lp
->root_dir
, p
);
779 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
782 if (q
> 0 && !dry_run
)
789 static int remove_marked_symlinks(
790 Set
*remove_symlinks_to
,
791 const char *config_path
,
792 const LookupPaths
*lp
,
794 InstallChange
**changes
,
797 _cleanup_close_
int fd
= -EBADF
;
804 if (set_isempty(remove_symlinks_to
))
807 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
809 return errno
== ENOENT
? 0 : -errno
;
815 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
819 /* This takes possession of cfd and closes it */
820 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
828 static int is_symlink_with_known_name(const InstallInfo
*i
, const char *name
) {
831 if (streq(name
, i
->name
))
834 if (strv_contains(i
->aliases
, name
))
837 /* Look for template symlink matching DefaultInstance */
838 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
839 _cleanup_free_
char *s
= NULL
;
841 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
846 } else if (streq(name
, s
))
853 static int find_symlinks_in_directory(
855 const char *dir_path
,
856 const char *root_dir
,
857 const InstallInfo
*info
,
858 bool ignore_destination
,
860 bool ignore_same_name
,
861 const char *config_path
,
862 bool *same_name_link
) {
866 FOREACH_DIRENT(de
, dir
, return -errno
) {
867 bool found_path
= false, found_dest
= false, b
= false;
870 if (de
->d_type
!= DT_LNK
)
873 if (!ignore_destination
) {
874 _cleanup_free_
char *dest
= NULL
;
876 /* Acquire symlink destination */
877 q
= readlinkat_malloc(dirfd(dir
), de
->d_name
, &dest
);
887 if (!path_is_absolute(dest
)) {
890 x
= path_join(dir_path
, dest
);
894 free_and_replace(dest
, x
);
897 /* Check if what the symlink points to matches what we are looking for */
898 found_dest
= streq(basename(dest
), info
->name
);
901 assert(unit_name_is_valid(info
->name
, UNIT_NAME_ANY
));
903 /* Check if the symlink itself matches what we are looking for.
905 * If ignore_destination is specified, we only look at the source name.
907 * If ignore_same_name is specified, we are in one of the directories which
908 * have lower priority than the unit file, and even if a file or symlink with
909 * this name was found, we should ignore it. */
911 if (ignore_destination
|| !ignore_same_name
)
912 found_path
= streq(de
->d_name
, info
->name
);
914 if (!found_path
&& ignore_destination
) {
915 _cleanup_free_
char *template = NULL
;
917 q
= unit_name_template(de
->d_name
, &template);
918 if (q
< 0 && q
!= -EINVAL
)
921 found_dest
= streq(template, info
->name
);
924 if (found_path
&& found_dest
) {
925 _cleanup_free_
char *p
= NULL
, *t
= NULL
;
927 /* Filter out same name links in the main config path */
928 p
= path_make_absolute(de
->d_name
, dir_path
);
929 t
= path_make_absolute(info
->name
, config_path
);
934 b
= path_equal(p
, t
);
938 *same_name_link
= true;
939 else if (found_path
|| found_dest
) {
943 /* Check if symlink name is in the set of names used by [Install] */
944 q
= is_symlink_with_known_name(info
, de
->d_name
);
955 static int find_symlinks(
956 const char *root_dir
,
957 const InstallInfo
*i
,
959 bool ignore_same_name
,
960 const char *config_path
,
961 bool *same_name_link
) {
963 _cleanup_closedir_
DIR *config_dir
= NULL
;
968 assert(same_name_link
);
970 config_dir
= opendir(config_path
);
972 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
977 FOREACH_DIRENT(de
, config_dir
, return -errno
) {
979 _cleanup_free_
const char *path
= NULL
;
980 _cleanup_closedir_
DIR *d
= NULL
;
982 if (de
->d_type
!= DT_DIR
)
985 suffix
= strrchr(de
->d_name
, '.');
986 if (!STRPTR_IN_SET(suffix
, ".wants", ".requires", ".upholds"))
989 path
= path_join(config_path
, de
->d_name
);
995 log_error_errno(errno
, "Failed to open directory \"%s\" while scanning for symlinks, ignoring: %m", path
);
999 r
= find_symlinks_in_directory(d
, path
, root_dir
, i
,
1000 /* ignore_destination= */ true,
1001 /* match_name= */ match_name
,
1002 /* ignore_same_name= */ ignore_same_name
,
1008 log_debug_errno(r
, "Failed to look up symlinks in \"%s\": %m", path
);
1011 /* We didn't find any suitable symlinks in .wants, .requires or .upholds directories,
1012 * let's look for linked unit files in this directory. */
1013 rewinddir(config_dir
);
1014 return find_symlinks_in_directory(config_dir
, config_path
, root_dir
, i
,
1015 /* ignore_destination= */ false,
1016 /* match_name= */ match_name
,
1017 /* ignore_same_name= */ ignore_same_name
,
1022 static int find_symlinks_in_scope(
1024 const LookupPaths
*lp
,
1025 const InstallInfo
*info
,
1027 UnitFileState
*state
) {
1029 bool same_name_link_runtime
= false, same_name_link_config
= false;
1030 bool enabled_in_runtime
= false, enabled_at_all
= false;
1031 bool ignore_same_name
= false;
1037 /* As we iterate over the list of search paths in lp->search_path, we may encounter "same name"
1038 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
1039 * effectively masked, so we should ignore them. */
1041 STRV_FOREACH(p
, lp
->search_path
) {
1042 bool same_name_link
= false;
1044 r
= find_symlinks(lp
->root_dir
, info
, match_name
, ignore_same_name
, *p
, &same_name_link
);
1048 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
1050 if (path_equal(*p
, lp
->persistent_config
)) {
1051 /* This is the best outcome, let's return it immediately. */
1052 *state
= UNIT_FILE_ENABLED
;
1056 /* look for global enablement of user units */
1057 if (scope
== RUNTIME_SCOPE_USER
&& path_is_user_config_dir(*p
)) {
1058 *state
= UNIT_FILE_ENABLED
;
1062 r
= path_is_runtime(lp
, *p
, false);
1066 enabled_in_runtime
= true;
1068 enabled_at_all
= true;
1070 } else if (same_name_link
) {
1071 if (path_equal(*p
, lp
->persistent_config
))
1072 same_name_link_config
= true;
1074 r
= path_is_runtime(lp
, *p
, false);
1078 same_name_link_runtime
= true;
1082 /* Check if next iteration will be "below" the unit file (either a regular file
1083 * or a symlink), and hence should be ignored */
1084 if (!ignore_same_name
&& path_startswith(info
->path
, *p
))
1085 ignore_same_name
= true;
1088 if (enabled_in_runtime
) {
1089 *state
= UNIT_FILE_ENABLED_RUNTIME
;
1093 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
1094 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
1095 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
1096 * something, and hence are a much stronger concept. */
1097 if (enabled_at_all
&& unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1098 *state
= UNIT_FILE_STATIC
;
1102 /* Hmm, we didn't find it, but maybe we found the same name
1104 if (same_name_link_config
) {
1105 *state
= UNIT_FILE_LINKED
;
1108 if (same_name_link_runtime
) {
1109 *state
= UNIT_FILE_LINKED_RUNTIME
;
1116 static void install_info_clear(InstallInfo
*i
) {
1120 i
->name
= mfree(i
->name
);
1121 i
->path
= mfree(i
->path
);
1122 i
->root
= mfree(i
->root
);
1123 i
->aliases
= strv_free(i
->aliases
);
1124 i
->wanted_by
= strv_free(i
->wanted_by
);
1125 i
->required_by
= strv_free(i
->required_by
);
1126 i
->upheld_by
= strv_free(i
->upheld_by
);
1127 i
->also
= strv_free(i
->also
);
1128 i
->default_instance
= mfree(i
->default_instance
);
1129 i
->symlink_target
= mfree(i
->symlink_target
);
1132 static InstallInfo
* install_info_free(InstallInfo
*i
) {
1133 install_info_clear(i
);
1137 DEFINE_TRIVIAL_CLEANUP_FUNC(InstallInfo
*, install_info_free
);
1139 static void install_context_done(InstallContext
*ctx
) {
1142 ctx
->will_process
= ordered_hashmap_free_with_destructor(ctx
->will_process
, install_info_free
);
1143 ctx
->have_processed
= ordered_hashmap_free_with_destructor(ctx
->have_processed
, install_info_free
);
1146 static InstallInfo
*install_info_find(InstallContext
*ctx
, const char *name
) {
1149 i
= ordered_hashmap_get(ctx
->have_processed
, name
);
1153 return ordered_hashmap_get(ctx
->will_process
, name
);
1156 static int install_info_may_process(
1157 const InstallInfo
*i
,
1158 const LookupPaths
*lp
,
1159 InstallChange
**changes
,
1160 size_t *n_changes
) {
1164 /* Checks whether the loaded unit file is one we should process, or is masked,
1165 * transient or generated and thus not subject to enable/disable operations. */
1167 if (i
->install_mode
== INSTALL_MODE_MASKED
)
1168 return install_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1169 if (path_is_generator(lp
, i
->path
) ||
1170 path_is_transient(lp
, i
->path
))
1171 return install_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1177 * Adds a new InstallInfo entry under name in the InstallContext.will_process
1178 * hashmap, or retrieves the existing one if already present.
1180 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1182 static int install_info_add(
1183 InstallContext
*ctx
,
1188 InstallInfo
**ret
) {
1195 /* 'name' and 'path' must not both be null. Check here 'path' using assert_se() to
1196 * workaround a bug in gcc that generates a -Wnonnull warning when calling basename(),
1197 * but this cannot be possible in any code path (See #6119). */
1199 name
= basename(path
);
1202 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1205 InstallInfo
*i
= install_info_find(ctx
, name
);
1207 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1214 _cleanup_(install_info_freep
) InstallInfo
*alloc
= new(InstallInfo
, 1);
1218 *alloc
= (InstallInfo
) {
1219 .install_mode
= _INSTALL_MODE_INVALID
,
1220 .auxiliary
= auxiliary
,
1223 alloc
->name
= strdup(name
);
1228 alloc
->root
= strdup(root
);
1234 alloc
->path
= strdup(path
);
1239 r
= ordered_hashmap_ensure_put(&ctx
->will_process
, &string_hash_ops
, alloc
->name
, alloc
);
1242 i
= TAKE_PTR(alloc
);
1249 static int config_parse_alias(
1251 const char *filename
,
1253 const char *section
,
1254 unsigned section_line
,
1268 type
= unit_name_to_type(unit
);
1269 if (!unit_type_may_alias(type
))
1270 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1271 "Alias= is not allowed for %s units, ignoring.",
1272 unit_type_to_string(type
));
1274 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1275 lvalue
, ltype
, rvalue
, data
, userdata
);
1278 static int config_parse_also(
1280 const char *filename
,
1282 const char *section
,
1283 unsigned section_line
,
1290 InstallInfo
*info
= ASSERT_PTR(userdata
);
1291 InstallContext
*ctx
= ASSERT_PTR(data
);
1300 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1302 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1308 r
= install_name_printf(ctx
->scope
, info
, word
, &printed
);
1310 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1311 "Failed to resolve unit name in Also=\"%s\": %m", word
);
1313 r
= install_info_add(ctx
, printed
, NULL
, info
->root
, /* auxiliary= */ true, NULL
);
1317 r
= strv_push(&info
->also
, printed
);
1327 static int config_parse_default_instance(
1329 const char *filename
,
1331 const char *section
,
1332 unsigned section_line
,
1339 InstallContext
*ctx
= ASSERT_PTR(data
);
1340 InstallInfo
*info
= ASSERT_PTR(userdata
);
1341 _cleanup_free_
char *printed
= NULL
;
1349 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1350 /* When enabling an instance, we might be using a template unit file,
1351 * but we should ignore DefaultInstance silently. */
1353 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1354 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1355 "DefaultInstance= only makes sense for template units, ignoring.");
1357 r
= install_name_printf(ctx
->scope
, info
, rvalue
, &printed
);
1359 return log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1360 "Failed to resolve instance name in DefaultInstance=\"%s\": %m", rvalue
);
1362 if (isempty(printed
))
1363 printed
= mfree(printed
);
1365 if (printed
&& !unit_instance_is_valid(printed
))
1366 return log_syntax(unit
, LOG_WARNING
, filename
, line
, SYNTHETIC_ERRNO(EINVAL
),
1367 "Invalid DefaultInstance= value \"%s\".", printed
);
1369 return free_and_replace(info
->default_instance
, printed
);
1372 static int unit_file_load(
1373 InstallContext
*ctx
,
1376 const char *root_dir
,
1377 SearchFlags flags
) {
1379 const ConfigTableItem items
[] = {
1380 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1381 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1382 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1383 { "Install", "UpheldBy", config_parse_strv
, 0, &info
->upheld_by
},
1384 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1385 { "Install", "Also", config_parse_also
, 0, ctx
},
1390 _cleanup_fclose_
FILE *f
= NULL
;
1391 _cleanup_close_
int fd
= -EBADF
;
1398 if (!(flags
& SEARCH_DROPIN
)) {
1399 /* Loading or checking for the main unit file… */
1401 type
= unit_name_to_type(info
->name
);
1404 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1405 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1406 "%s: unit type %s cannot be templated, ignoring.", path
, unit_type_to_string(type
));
1408 if (!(flags
& SEARCH_LOAD
)) {
1409 if (lstat(path
, &st
) < 0)
1412 if (null_or_empty(&st
))
1413 info
->install_mode
= INSTALL_MODE_MASKED
;
1414 else if (S_ISREG(st
.st_mode
))
1415 info
->install_mode
= INSTALL_MODE_REGULAR
;
1416 else if (S_ISLNK(st
.st_mode
))
1418 else if (S_ISDIR(st
.st_mode
))
1426 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1430 /* 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. */
1432 if (!(flags
& SEARCH_LOAD
))
1435 fd
= chase_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1440 if (fstat(fd
, &st
) < 0)
1443 if (null_or_empty(&st
)) {
1444 if ((flags
& SEARCH_DROPIN
) == 0)
1445 info
->install_mode
= INSTALL_MODE_MASKED
;
1450 r
= stat_verify_regular(&st
);
1454 f
= take_fdopen(&fd
, "r");
1458 /* ctx is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1461 r
= config_parse(info
->name
, path
, f
,
1475 config_item_table_lookup
, items
,
1479 return log_debug_errno(r
, "Failed to parse \"%s\": %m", info
->name
);
1481 if ((flags
& SEARCH_DROPIN
) == 0)
1482 info
->install_mode
= INSTALL_MODE_REGULAR
;
1485 (int) strv_length(info
->aliases
) +
1486 (int) strv_length(info
->wanted_by
) +
1487 (int) strv_length(info
->required_by
) +
1488 (int) strv_length(info
->upheld_by
);
1491 static int unit_file_load_or_readlink(
1492 InstallContext
*ctx
,
1495 const LookupPaths
*lp
,
1496 SearchFlags flags
) {
1499 r
= unit_file_load(ctx
, info
, path
, lp
->root_dir
, flags
);
1500 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1503 /* This is a symlink, let's read and verify it. */
1504 r
= unit_file_resolve_symlink(lp
->root_dir
, lp
->search_path
,
1505 NULL
, AT_FDCWD
, path
,
1506 true, &info
->symlink_target
);
1509 bool outside_search_path
= r
> 0;
1511 r
= null_or_empty_path_with_root(info
->symlink_target
, lp
->root_dir
);
1512 if (r
< 0 && r
!= -ENOENT
)
1513 return log_debug_errno(r
, "Failed to stat %s: %m", info
->symlink_target
);
1515 info
->install_mode
= INSTALL_MODE_MASKED
;
1516 else if (outside_search_path
)
1517 info
->install_mode
= INSTALL_MODE_LINKED
;
1519 info
->install_mode
= INSTALL_MODE_ALIAS
;
1524 static int unit_file_search(
1525 InstallContext
*ctx
,
1527 const LookupPaths
*lp
,
1528 SearchFlags flags
) {
1530 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1531 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1532 _cleanup_free_
char *template = NULL
;
1533 bool found_unit
= false;
1539 /* Was this unit already loaded? */
1540 if (info
->install_mode
!= _INSTALL_MODE_INVALID
)
1544 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1548 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1549 r
= unit_name_template(info
->name
, &template);
1554 STRV_FOREACH(p
, lp
->search_path
) {
1555 _cleanup_free_
char *path
= NULL
;
1557 path
= path_join(*p
, info
->name
);
1561 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1563 info
->path
= TAKE_PTR(path
);
1567 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1571 if (!found_unit
&& template) {
1573 /* Unit file doesn't exist, however instance
1574 * enablement was requested. We will check if it is
1575 * possible to load template unit file. */
1577 STRV_FOREACH(p
, lp
->search_path
) {
1578 _cleanup_free_
char *path
= NULL
;
1580 path
= path_join(*p
, template);
1584 r
= unit_file_load_or_readlink(ctx
, info
, path
, lp
, flags
);
1586 info
->path
= TAKE_PTR(path
);
1590 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1596 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1597 "Cannot find unit %s%s%s.",
1598 info
->name
, template ? " or " : "", strempty(template));
1600 if (info
->install_mode
== INSTALL_MODE_MASKED
)
1603 /* Search for drop-in directories */
1605 dropin_dir_name
= strjoina(info
->name
, ".d");
1606 STRV_FOREACH(p
, lp
->search_path
) {
1609 path
= path_join(*p
, dropin_dir_name
);
1613 r
= strv_consume(&dirs
, path
);
1619 dropin_template_dir_name
= strjoina(template, ".d");
1620 STRV_FOREACH(p
, lp
->search_path
) {
1623 path
= path_join(*p
, dropin_template_dir_name
);
1627 r
= strv_consume(&dirs
, path
);
1633 /* Load drop-in conf files */
1635 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1637 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1639 STRV_FOREACH(p
, files
) {
1640 r
= unit_file_load_or_readlink(ctx
, info
, *p
, lp
, flags
| SEARCH_DROPIN
);
1642 return log_debug_errno(r
, "Failed to load conf file \"%s\": %m", *p
);
1648 static int install_info_follow(
1649 InstallContext
*ctx
,
1651 const LookupPaths
*lp
,
1653 bool ignore_different_name
) {
1658 if (!IN_SET(info
->install_mode
, INSTALL_MODE_ALIAS
, INSTALL_MODE_LINKED
))
1660 if (!info
->symlink_target
)
1663 /* If the basename doesn't match, the caller should add a complete new entry for this. */
1665 if (!ignore_different_name
&& !streq(basename(info
->symlink_target
), info
->name
))
1668 free_and_replace(info
->path
, info
->symlink_target
);
1669 info
->install_mode
= _INSTALL_MODE_INVALID
;
1671 return unit_file_load_or_readlink(ctx
, info
, info
->path
, lp
, flags
);
1675 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1676 * target, maybe more than once. Propagate the instance name if present.
1678 static int install_info_traverse(
1679 InstallContext
*ctx
,
1680 const LookupPaths
*lp
,
1683 InstallInfo
**ret
) {
1693 r
= unit_file_search(ctx
, start
, lp
, flags
);
1698 while (IN_SET(i
->install_mode
, INSTALL_MODE_ALIAS
, INSTALL_MODE_LINKED
)) {
1699 /* Follow the symlink */
1701 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1704 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1705 r
= path_is_config(lp
, i
->path
, true);
1712 r
= install_info_follow(ctx
, i
, lp
, flags
,
1713 /* If linked, don't look at the target name */
1714 /* ignore_different_name= */ i
->install_mode
== INSTALL_MODE_LINKED
);
1715 if (r
== -EXDEV
&& i
->symlink_target
) {
1716 _cleanup_free_
char *buffer
= NULL
;
1719 /* Target is an alias, create a new install info object and continue with that. */
1721 bn
= basename(i
->symlink_target
);
1723 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1724 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1726 _cleanup_free_
char *instance
= NULL
;
1728 r
= unit_name_to_instance(i
->name
, &instance
);
1732 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1736 if (streq(buffer
, i
->name
)) {
1738 /* We filled in the instance, and the target stayed the same? If so,
1739 * then let's honour the link as it is. */
1741 r
= install_info_follow(ctx
, i
, lp
, flags
, true);
1751 r
= install_info_add(ctx
, bn
, NULL
, lp
->root_dir
, /* auxiliary= */ false, &i
);
1755 /* Try again, with the new target we found. */
1756 r
= unit_file_search(ctx
, i
, lp
, flags
);
1758 /* Translate error code to highlight this specific case */
1773 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1774 * or the name (otherwise). root_dir is prepended to the path.
1776 static int install_info_add_auto(
1777 InstallContext
*ctx
,
1778 const LookupPaths
*lp
,
1779 const char *name_or_path
,
1780 InstallInfo
**ret
) {
1783 assert(name_or_path
);
1785 if (path_is_absolute(name_or_path
)) {
1788 pp
= prefix_roota(lp
->root_dir
, name_or_path
);
1790 return install_info_add(ctx
, NULL
, pp
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1792 return install_info_add(ctx
, name_or_path
, NULL
, lp
->root_dir
, /* auxiliary= */ false, ret
);
1795 static int install_info_discover(
1796 InstallContext
*ctx
,
1797 const LookupPaths
*lp
,
1798 const char *name_or_path
,
1801 InstallChange
**changes
,
1802 size_t *n_changes
) {
1809 assert(name_or_path
);
1811 r
= install_info_add_auto(ctx
, lp
, name_or_path
, &info
);
1813 r
= install_info_traverse(ctx
, lp
, info
, flags
, ret
);
1816 install_changes_add(changes
, n_changes
, r
, name_or_path
, NULL
);
1820 static int install_info_discover_and_check(
1821 InstallContext
*ctx
,
1822 const LookupPaths
*lp
,
1823 const char *name_or_path
,
1826 InstallChange
**changes
,
1827 size_t *n_changes
) {
1831 r
= install_info_discover(ctx
, lp
, name_or_path
, flags
, ret
, changes
, n_changes
);
1835 return install_info_may_process(ret
? *ret
: NULL
, lp
, changes
, n_changes
);
1838 int unit_file_verify_alias(
1839 const InstallInfo
*info
,
1842 InstallChange
**changes
,
1843 size_t *n_changes
) {
1845 _cleanup_free_
char *dst_updated
= NULL
;
1848 /* Verify that dst is a valid either a valid alias or a valid .wants/.requires symlink for the target
1849 * unit *i. Return negative on error or if not compatible, zero on success.
1851 * ret_dst is set in cases where "instance propagation" happens, i.e. when the instance part is
1852 * inserted into dst. It is not normally set, even on success, so that the caller can easily
1853 * distinguish the case where instance propagation occurred.
1856 * -EXDEV when the alias doesn't match the unit,
1857 * -EUCLEAN when the name is invalid,
1858 * -ELOOP when the alias it to the unit itself.
1861 const char *path_alias
= strrchr(dst
, '/');
1863 /* This branch covers legacy Alias= function of creating .wants and .requires symlinks. */
1864 _cleanup_free_
char *dir
= NULL
;
1867 path_alias
++; /* skip over slash */
1869 r
= path_extract_directory(dst
, &dir
);
1871 return log_error_errno(r
, "Failed to extract parent directory from '%s': %m", dst
);
1873 p
= endswith(dir
, ".wants");
1875 p
= endswith(dir
, ".requires");
1877 install_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1878 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
), "Invalid path \"%s\" in alias.", dir
);
1881 *p
= '\0'; /* dir should now be a unit name */
1883 UnitNameFlags type
= unit_name_classify(dir
);
1885 install_changes_add(changes
, n_changes
, -EXDEV
, dst
, NULL
);
1886 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1887 "Invalid unit name component \"%s\" in alias.", dir
);
1890 const bool instance_propagation
= type
== UNIT_NAME_TEMPLATE
;
1892 /* That's the name we want to use for verification. */
1893 r
= unit_symlink_name_compatible(path_alias
, info
->name
, instance_propagation
);
1895 return log_error_errno(r
, "Failed to verify alias validity: %m");
1897 install_changes_add(changes
, n_changes
, -EXDEV
, dst
, info
->name
);
1898 return log_debug_errno(SYNTHETIC_ERRNO(EXDEV
),
1899 "Invalid unit \"%s\" symlink \"%s\".",
1904 /* If the symlink target has an instance set and the symlink source doesn't, we "propagate
1905 * the instance", i.e. instantiate the symlink source with the target instance. */
1906 if (unit_name_is_valid(dst
, UNIT_NAME_TEMPLATE
)) {
1907 _cleanup_free_
char *inst
= NULL
;
1909 UnitNameFlags type
= unit_name_to_instance(info
->name
, &inst
);
1911 install_changes_add(changes
, n_changes
, -EUCLEAN
, info
->name
, NULL
);
1912 return log_debug_errno(type
, "Failed to extract instance name from \"%s\": %m", info
->name
);
1915 if (type
== UNIT_NAME_INSTANCE
) {
1916 r
= unit_name_replace_instance(dst
, inst
, &dst_updated
);
1918 return log_error_errno(r
, "Failed to build unit name from %s+%s: %m",
1923 r
= unit_validate_alias_symlink_or_warn(LOG_DEBUG
, dst_updated
?: dst
, info
->name
);
1924 if (r
== -ELOOP
) /* -ELOOP means self-alias, which we (quietly) ignore */
1927 return install_changes_add(changes
, n_changes
,
1928 r
== -EINVAL
? -EXDEV
: r
,
1933 *ret_dst
= TAKE_PTR(dst_updated
);
1937 static int install_info_symlink_alias(
1940 const LookupPaths
*lp
,
1941 const char *config_path
,
1943 InstallChange
**changes
,
1944 size_t *n_changes
) {
1950 assert(config_path
);
1952 STRV_FOREACH(s
, info
->aliases
) {
1953 _cleanup_free_
char *alias_path
= NULL
, *alias_target
= NULL
, *dst
= NULL
, *dst_updated
= NULL
;
1955 r
= install_name_printf(scope
, info
, *s
, &dst
);
1957 RET_GATHER(ret
, install_changes_add(changes
, n_changes
, r
, *s
, NULL
));
1961 r
= unit_file_verify_alias(info
, dst
, &dst_updated
, changes
, n_changes
);
1968 alias_path
= path_make_absolute(dst_updated
?: dst
, config_path
);
1972 r
= in_search_path(lp
, info
->path
);
1976 /* The unit path itself is outside of the search path. To
1977 * correctly apply the alias, we need the alias symlink to
1978 * point to the symlink that was created in the search path. */
1979 alias_target
= path_join(config_path
, info
->name
);
1985 r
= chase(alias_path
, lp
->root_dir
, CHASE_NONEXISTENT
, /* ret_path = */ NULL
, /* ret_fd = */ NULL
);
1986 if (r
< 0 && r
!= -ENOENT
) {
1990 broken
= r
== 0; /* symlink target does not exist? */
1992 RET_GATHER(ret
, create_symlink(lp
, alias_target
?: info
->path
, alias_path
, force
|| broken
, changes
, n_changes
));
1998 static int install_info_symlink_wants(
2000 UnitFileFlags file_flags
,
2002 const LookupPaths
*lp
,
2003 const char *config_path
,
2006 InstallChange
**changes
,
2007 size_t *n_changes
) {
2009 _cleanup_(install_info_clear
) InstallInfo instance
= {
2010 .install_mode
= _INSTALL_MODE_INVALID
,
2013 UnitNameFlags valid_dst_type
= UNIT_NAME_ANY
;
2019 assert(config_path
);
2021 if (strv_isempty(list
))
2024 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
| UNIT_NAME_INSTANCE
))
2025 /* Not a template unit. Use the name directly. */
2028 else if (info
->default_instance
) {
2029 /* If this is a template, and we have a default instance, use it. */
2031 r
= unit_name_replace_instance(info
->name
, info
->default_instance
, &instance
.name
);
2035 r
= unit_file_search(NULL
, &instance
, lp
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
2039 if (instance
.install_mode
== INSTALL_MODE_MASKED
)
2040 return install_changes_add(changes
, n_changes
, -ERFKILL
, instance
.path
, NULL
);
2045 /* We have a template, but no instance yet. When used with an instantiated unit, we will get
2046 * the instance from that unit. Cannot be used with non-instance units. */
2048 valid_dst_type
= UNIT_NAME_INSTANCE
| UNIT_NAME_TEMPLATE
;
2053 STRV_FOREACH(s
, list
) {
2054 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
2056 q
= install_name_printf(scope
, info
, *s
, &dst
);
2058 RET_GATHER(r
, install_changes_add(changes
, n_changes
, q
, *s
, NULL
));
2062 if (!unit_name_is_valid(dst
, valid_dst_type
)) {
2063 /* Generate a proper error here: EUCLEAN if the name is generally bad, EIDRM if the
2064 * template status doesn't match. If we are doing presets don't bother reporting the
2065 * error. This also covers cases like 'systemctl preset serial-getty@.service', which
2066 * has no DefaultInstance, so there is nothing we can do. At the same time,
2067 * 'systemctl enable serial-getty@.service' should fail, the user should specify an
2068 * instance like in 'systemctl enable serial-getty@ttyS0.service'.
2070 if (FLAGS_SET(file_flags
, UNIT_FILE_IGNORE_AUXILIARY_FAILURE
))
2073 if (unit_name_is_valid(dst
, UNIT_NAME_ANY
))
2074 RET_GATHER(r
, install_changes_add(changes
, n_changes
, -EIDRM
, dst
, n
));
2076 RET_GATHER(r
, install_changes_add(changes
, n_changes
, -EUCLEAN
, dst
, NULL
));
2081 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
2085 q
= create_symlink(lp
, info
->path
, path
, /* force = */ true, changes
, n_changes
);
2086 if ((q
< 0 && r
>= 0) || r
== 0)
2089 if (unit_file_exists(scope
, lp
, dst
) == 0) {
2090 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_DESTINATION_NOT_PRESENT
, dst
, info
->path
);
2099 static int install_info_symlink_link(
2101 const LookupPaths
*lp
,
2102 const char *config_path
,
2104 InstallChange
**changes
,
2105 size_t *n_changes
) {
2107 _cleanup_free_
char *path
= NULL
;
2112 assert(config_path
);
2115 r
= in_search_path(lp
, info
->path
);
2121 path
= path_join(config_path
, info
->name
);
2125 return create_symlink(lp
, info
->path
, path
, force
, changes
, n_changes
);
2128 static int install_info_apply(
2130 UnitFileFlags file_flags
,
2132 const LookupPaths
*lp
,
2133 const char *config_path
,
2134 InstallChange
**changes
,
2135 size_t *n_changes
) {
2141 assert(config_path
);
2143 if (info
->install_mode
!= INSTALL_MODE_REGULAR
)
2146 bool force
= file_flags
& UNIT_FILE_FORCE
;
2148 r
= install_info_symlink_link(info
, lp
, config_path
, force
, changes
, n_changes
);
2149 /* Do not count links to the unit file towards the "carries_install_info" count */
2151 /* If linking of the file failed, do not try to create other symlinks,
2152 * because they might would pointing to a non-existent or wrong unit. */
2155 r
= install_info_symlink_alias(scope
, info
, lp
, config_path
, force
, changes
, n_changes
);
2157 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->wanted_by
, ".wants/", changes
, n_changes
);
2161 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->required_by
, ".requires/", changes
, n_changes
);
2165 q
= install_info_symlink_wants(scope
, file_flags
, info
, lp
, config_path
, info
->upheld_by
, ".upholds/", changes
, n_changes
);
2172 static int install_context_apply(
2173 InstallContext
*ctx
,
2174 const LookupPaths
*lp
,
2175 UnitFileFlags file_flags
,
2176 const char *config_path
,
2178 InstallChange
**changes
,
2179 size_t *n_changes
) {
2186 assert(config_path
);
2188 if (ordered_hashmap_isempty(ctx
->will_process
))
2191 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2196 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2199 q
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2203 q
= install_info_traverse(ctx
, lp
, i
, flags
, NULL
);
2206 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_AUXILIARY_FAILED
, i
->name
, NULL
);
2212 return install_changes_add(changes
, n_changes
, q
, i
->name
, NULL
);
2215 /* We can attempt to process a masked unit when a different unit
2216 * that we were processing specifies it in Also=. */
2217 if (i
->install_mode
== INSTALL_MODE_MASKED
) {
2218 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_IS_MASKED
, i
->path
, NULL
);
2222 /* Assume that something *could* have been enabled here,
2223 * avoid "empty [Install] section" warning. */
2228 if (i
->install_mode
!= INSTALL_MODE_REGULAR
)
2231 q
= install_info_apply(ctx
->scope
, file_flags
, i
, lp
, config_path
, changes
, n_changes
);
2243 static int install_context_mark_for_removal(
2244 InstallContext
*ctx
,
2245 const LookupPaths
*lp
,
2246 Set
**remove_symlinks_to
,
2247 const char *config_path
,
2248 InstallChange
**changes
,
2249 size_t *n_changes
) {
2256 assert(config_path
);
2258 /* Marks all items for removal */
2260 if (ordered_hashmap_isempty(ctx
->will_process
))
2263 r
= ordered_hashmap_ensure_allocated(&ctx
->have_processed
, &string_hash_ops
);
2267 while ((i
= ordered_hashmap_first(ctx
->will_process
))) {
2269 r
= ordered_hashmap_move_one(ctx
->have_processed
, ctx
->will_process
, i
->name
);
2273 r
= install_info_traverse(ctx
, lp
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2274 if (r
== -ENOLINK
) {
2275 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
2276 r
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
2279 } else if (r
== -ENOENT
) {
2280 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
2281 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
2283 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
2284 r
= install_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2289 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
2290 install_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
2291 } else if (i
->install_mode
== INSTALL_MODE_MASKED
) {
2292 log_debug("Unit file %s is masked, ignoring.", i
->name
);
2293 install_changes_add(changes
, n_changes
, INSTALL_CHANGE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
2295 } else if (i
->install_mode
!= INSTALL_MODE_REGULAR
) {
2296 log_debug("Unit %s has install mode %s, ignoring.",
2297 i
->name
, install_mode_to_string(i
->install_mode
) ?: "invalid");
2301 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2311 UnitFileFlags flags
,
2312 const char *root_dir
,
2314 InstallChange
**changes
,
2315 size_t *n_changes
) {
2317 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2318 const char *config_path
;
2322 assert(scope
< _RUNTIME_SCOPE_MAX
);
2324 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2328 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2334 STRV_FOREACH(name
, names
) {
2335 _cleanup_free_
char *path
= NULL
;
2337 if (!unit_name_is_valid(*name
, UNIT_NAME_ANY
)) {
2338 RET_GATHER(r
, -EINVAL
);
2342 path
= path_make_absolute(*name
, config_path
);
2346 RET_GATHER(r
, create_symlink(&lp
, "/dev/null", path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
));
2352 int unit_file_unmask(
2354 UnitFileFlags flags
,
2355 const char *root_dir
,
2357 InstallChange
**changes
,
2358 size_t *n_changes
) {
2360 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2361 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2362 _cleanup_strv_free_
char **todo
= NULL
;
2363 const char *config_path
;
2368 assert(scope
< _RUNTIME_SCOPE_MAX
);
2370 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2374 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2378 bool dry_run
= flags
& UNIT_FILE_DRY_RUN
;
2380 STRV_FOREACH(name
, names
) {
2381 if (!unit_name_is_valid(*name
, UNIT_NAME_ANY
))
2384 /* If root_dir is set, we don't care about kernel command line or generators.
2385 * But if it is not set, we need to check for interference. */
2387 _cleanup_(install_info_clear
) InstallInfo info
= {
2388 .name
= *name
, /* We borrow *name temporarily… */
2389 .install_mode
= _INSTALL_MODE_INVALID
,
2392 r
= unit_file_search(NULL
, &info
, &lp
, 0);
2395 log_debug_errno(r
, "Failed to look up unit %s, ignoring: %m", info
.name
);
2396 } else if (info
.install_mode
== INSTALL_MODE_MASKED
&&
2397 path_is_generator(&lp
, info
.path
)) {
2398 r
= install_changes_add(changes
, n_changes
,
2399 INSTALL_CHANGE_IS_MASKED_GENERATOR
, info
.name
, info
.path
);
2404 TAKE_PTR(info
.name
); /* … and give it back here */
2407 _cleanup_free_
char *path
= path_make_absolute(*name
, config_path
);
2411 r
= null_or_empty_path(path
);
2419 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2422 todo
[n_todo
] = strdup(*name
);
2432 STRV_FOREACH(i
, todo
) {
2433 _cleanup_free_
char *path
= NULL
;
2436 path
= path_make_absolute(*i
, config_path
);
2440 if (!dry_run
&& unlink(path
) < 0) {
2441 if (errno
!= ENOENT
) {
2442 RET_GATHER(r
, -errno
);
2443 install_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2449 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_UNLINK
, path
, NULL
);
2453 rp
= skip_root(lp
.root_dir
, path
);
2454 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2459 RET_GATHER(r
, remove_marked_symlinks(remove_symlinks_to
, config_path
, &lp
, dry_run
, changes
, n_changes
));
2466 UnitFileFlags flags
,
2467 const char *root_dir
,
2469 InstallChange
**changes
,
2470 size_t *n_changes
) {
2472 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2473 _cleanup_strv_free_
char **todo
= NULL
;
2474 const char *config_path
;
2479 assert(scope
< _RUNTIME_SCOPE_MAX
);
2481 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2485 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2489 STRV_FOREACH(file
, files
) {
2490 _cleanup_free_
char *full
= NULL
;
2494 if (!path_is_absolute(*file
))
2495 return install_changes_add(changes
, n_changes
, -EINVAL
, *file
, NULL
);
2497 fn
= basename(*file
);
2498 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2499 return install_changes_add(changes
, n_changes
, -EUCLEAN
, *file
, NULL
);
2501 full
= path_join(lp
.root_dir
, *file
);
2505 if (lstat(full
, &st
) < 0)
2506 return install_changes_add(changes
, n_changes
, -errno
, *file
, NULL
);
2508 r
= stat_verify_regular(&st
);
2510 return install_changes_add(changes
, n_changes
, r
, *file
, NULL
);
2512 r
= in_search_path(&lp
, *file
);
2514 return install_changes_add(changes
, n_changes
, r
, *file
, NULL
);
2516 /* A silent noop if the file is already in the search path. */
2519 r
= underneath_search_path(&lp
, *file
);
2523 return install_changes_add(changes
, n_changes
, r
, *file
, NULL
);
2525 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2528 todo
[n_todo
] = strdup(*file
);
2538 STRV_FOREACH(i
, todo
) {
2539 _cleanup_free_
char *new_path
= NULL
;
2541 new_path
= path_make_absolute(basename(*i
), config_path
);
2545 RET_GATHER(r
, create_symlink(&lp
, *i
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
));
2551 static int path_shall_revert(const LookupPaths
*lp
, const char *path
) {
2557 /* Checks whether the path is one where the drop-in directories shall be removed. */
2559 r
= path_is_config(lp
, path
, true);
2563 r
= path_is_control(lp
, path
);
2567 return path_is_transient(lp
, path
);
2570 int unit_file_revert(
2572 const char *root_dir
,
2574 InstallChange
**changes
,
2575 size_t *n_changes
) {
2577 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2578 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2579 _cleanup_strv_free_
char **todo
= NULL
;
2583 /* Puts a unit file back into vendor state. This means:
2585 * a) we remove all drop-in snippets added by the user ("config"), add to transient units
2586 * ("transient"), and added via "systemctl set-property" ("control"), but not if the drop-in is
2587 * generated ("generated").
2589 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files
2590 * (i.e. in "config", but not in "transient" or "control" or even "generated").
2592 * We remove all that in both the runtime and the persistent directories, if that applies.
2595 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2599 STRV_FOREACH(name
, names
) {
2600 bool has_vendor
= false;
2602 if (!unit_name_is_valid(*name
, UNIT_NAME_ANY
))
2605 STRV_FOREACH(p
, lp
.search_path
) {
2606 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2609 path
= path_make_absolute(*name
, *p
);
2613 r
= RET_NERRNO(lstat(path
, &st
));
2616 return install_changes_add(changes
, n_changes
, r
, path
, NULL
);
2617 } else if (S_ISREG(st
.st_mode
)) {
2618 /* Check if there's a vendor version */
2619 r
= path_is_vendor_or_generator(&lp
, path
);
2621 return install_changes_add(changes
, n_changes
, r
, path
, NULL
);
2626 dropin
= strjoin(path
, ".d");
2630 r
= RET_NERRNO(lstat(dropin
, &st
));
2633 return install_changes_add(changes
, n_changes
, r
, dropin
, NULL
);
2634 } else if (S_ISDIR(st
.st_mode
)) {
2635 /* Remove the drop-ins */
2636 r
= path_shall_revert(&lp
, dropin
);
2638 return install_changes_add(changes
, n_changes
, r
, dropin
, NULL
);
2640 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2643 todo
[n_todo
++] = TAKE_PTR(dropin
);
2651 /* OK, there's a vendor version, hence drop all configuration versions */
2652 STRV_FOREACH(p
, lp
.search_path
) {
2653 _cleanup_free_
char *path
= NULL
;
2656 path
= path_make_absolute(*name
, *p
);
2660 r
= RET_NERRNO(lstat(path
, &st
));
2663 return install_changes_add(changes
, n_changes
, r
, path
, NULL
);
2664 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2665 r
= path_is_config(&lp
, path
, true);
2667 return install_changes_add(changes
, n_changes
, r
, path
, NULL
);
2669 if (!GREEDY_REALLOC0(todo
, n_todo
+ 2))
2672 todo
[n_todo
++] = TAKE_PTR(path
);
2681 STRV_FOREACH(i
, todo
) {
2682 _cleanup_strv_free_
char **fs
= NULL
;
2685 (void) get_files_in_directory(*i
, &fs
);
2687 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2688 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2693 STRV_FOREACH(j
, fs
) {
2694 _cleanup_free_
char *t
= NULL
;
2696 t
= path_join(*i
, *j
);
2700 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_UNLINK
, t
, NULL
);
2705 q
= install_changes_add(changes
, n_changes
, INSTALL_CHANGE_UNLINK
, *i
, NULL
);
2709 rp
= skip_root(lp
.root_dir
, *i
);
2710 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2715 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.runtime_config
, &lp
, false, changes
, n_changes
);
2719 q
= remove_marked_symlinks(remove_symlinks_to
, lp
.persistent_config
, &lp
, false, changes
, n_changes
);
2726 int unit_file_add_dependency(
2728 UnitFileFlags file_flags
,
2729 const char *root_dir
,
2733 InstallChange
**changes
,
2734 size_t *n_changes
) {
2736 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2737 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2738 InstallInfo
*info
, *target_info
;
2739 const char *config_path
;
2743 assert(scope
< _RUNTIME_SCOPE_MAX
);
2745 assert(IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
));
2747 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2748 return install_changes_add(changes
, n_changes
, -EUCLEAN
, target
, NULL
);
2750 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2754 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
2758 r
= install_info_discover_and_check(&ctx
, &lp
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2759 &target_info
, changes
, n_changes
);
2763 assert(target_info
->install_mode
== INSTALL_MODE_REGULAR
);
2765 STRV_FOREACH(name
, names
) {
2768 r
= install_info_discover_and_check(&ctx
, &lp
, *name
,
2769 SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2770 &info
, changes
, n_changes
);
2774 assert(info
->install_mode
== INSTALL_MODE_REGULAR
);
2776 /* We didn't actually load anything from the unit
2777 * file, but instead just add in our new symlink to
2780 if (dep
== UNIT_WANTS
)
2781 l
= &info
->wanted_by
;
2782 else if (dep
== UNIT_REQUIRES
)
2783 l
= &info
->required_by
;
2785 l
= &info
->upheld_by
;
2788 *l
= strv_new(target_info
->name
);
2793 return install_context_apply(&ctx
, &lp
, file_flags
, config_path
,
2794 SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2797 static int do_unit_file_enable(
2798 const LookupPaths
*lp
,
2800 UnitFileFlags flags
,
2801 const char *config_path
,
2802 char **names_or_paths
,
2803 InstallChange
**changes
,
2804 size_t *n_changes
) {
2806 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2810 STRV_FOREACH(name
, names_or_paths
) {
2811 r
= install_info_discover_and_check(&ctx
, lp
, *name
,
2812 SEARCH_LOAD
| SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2813 &info
, changes
, n_changes
);
2817 assert(info
->install_mode
== INSTALL_MODE_REGULAR
);
2820 /* This will return the number of symlink rules that were
2821 supposed to be created, not the ones actually created. This
2822 is useful to determine whether the passed units had any
2823 installation data at all. */
2825 return install_context_apply(&ctx
, lp
, flags
, config_path
,
2826 SEARCH_LOAD
, changes
, n_changes
);
2829 int unit_file_enable(
2831 UnitFileFlags flags
,
2832 const char *root_dir
,
2833 char **names_or_paths
,
2834 InstallChange
**changes
,
2835 size_t *n_changes
) {
2837 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2841 assert(scope
< _RUNTIME_SCOPE_MAX
);
2843 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2847 const char *config_path
= config_path_from_flags(&lp
, flags
);
2851 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, names_or_paths
, changes
, n_changes
);
2854 static int do_unit_file_disable(
2855 const LookupPaths
*lp
,
2857 UnitFileFlags flags
,
2858 const char *config_path
,
2860 InstallChange
**changes
,
2861 size_t *n_changes
) {
2863 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2864 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2865 bool has_install_info
= false;
2868 STRV_FOREACH(name
, names
) {
2871 if (!unit_name_is_valid(*name
, UNIT_NAME_ANY
))
2872 return install_changes_add(changes
, n_changes
, -EUCLEAN
, *name
, NULL
);
2874 r
= install_info_add(&ctx
, *name
, NULL
, lp
->root_dir
, /* auxiliary= */ false, &info
);
2876 r
= install_info_traverse(&ctx
, lp
, info
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
2879 return install_changes_add(changes
, n_changes
, r
, *name
, NULL
);
2881 /* If we enable multiple units, some with install info and others without,
2882 * the "empty [Install] section" warning is not shown. Let's make the behavior
2883 * of disable align with that. */
2884 has_install_info
= has_install_info
|| install_info_has_rules(info
) || install_info_has_also(info
);
2887 r
= install_context_mark_for_removal(&ctx
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2889 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, flags
& UNIT_FILE_DRY_RUN
, changes
, n_changes
);
2893 /* The warning is shown only if it's a no-op */
2894 return install_changes_have_modification(*changes
, *n_changes
) || has_install_info
;
2897 int unit_file_disable(
2899 UnitFileFlags flags
,
2900 const char *root_dir
,
2902 InstallChange
**changes
,
2903 size_t *n_changes
) {
2905 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2909 assert(scope
< _RUNTIME_SCOPE_MAX
);
2911 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2915 const char *config_path
= config_path_from_flags(&lp
, flags
);
2919 return do_unit_file_disable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
2922 static int normalize_linked_files(
2924 const LookupPaths
*lp
,
2925 char **names_or_paths
,
2927 char ***ret_files
) {
2929 /* This is similar to normalize_filenames()/normalize_names() in src/systemctl/,
2930 * but operates on real unit names. For each argument we look up the actual path
2931 * where the unit is found. This way linked units can be re-enabled successfully. */
2933 _cleanup_strv_free_
char **files
= NULL
, **names
= NULL
;
2936 STRV_FOREACH(a
, names_or_paths
) {
2937 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
2938 InstallInfo
*i
= NULL
;
2939 _cleanup_free_
char *n
= NULL
;
2941 r
= path_extract_filename(*a
, &n
);
2944 if (r
== O_DIRECTORY
)
2945 return log_debug_errno(SYNTHETIC_ERRNO(EISDIR
),
2946 "Unexpected path to a directory \"%s\", refusing.", *a
);
2948 if (!is_path(*a
) && !unit_name_is_valid(*a
, UNIT_NAME_INSTANCE
)) {
2949 r
= install_info_discover(&ctx
, lp
, n
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
, NULL
, NULL
);
2951 log_debug_errno(r
, "Failed to discover unit \"%s\", operating on name: %m", n
);
2954 r
= strv_consume(&names
, TAKE_PTR(n
));
2958 const char *p
= NULL
;
2959 if (i
&& i
->path
&& i
->root
)
2960 /* Use startswith here, because we know that paths are normalized, and
2961 * path_startswith() would give us a relative path, but we need an absolute path
2962 * relative to i->root.
2964 * In other words: /var/tmp/instroot.1234/etc/systemd/system/frobnicator.service
2965 * is replaced by /etc/systemd/system/frobnicator.service, which is "absolute"
2966 * in a sense, but only makes sense "relative" to /var/tmp/instroot.1234/.
2968 p
= startswith(i
->path
, i
->root
);
2970 r
= strv_extend(&files
, p
?: *a
);
2975 *ret_names
= TAKE_PTR(names
);
2976 *ret_files
= TAKE_PTR(files
);
2980 int unit_file_reenable(
2982 UnitFileFlags flags
,
2983 const char *root_dir
,
2984 char **names_or_paths
,
2985 InstallChange
**changes
,
2986 size_t *n_changes
) {
2988 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
2989 _cleanup_strv_free_
char **names
= NULL
, **files
= NULL
;
2993 assert(scope
< _RUNTIME_SCOPE_MAX
);
2995 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
2999 const char *config_path
= config_path_from_flags(&lp
, flags
);
3003 r
= normalize_linked_files(scope
, &lp
, names_or_paths
, &names
, &files
);
3007 /* First, we invoke the disable command with only the basename... */
3008 r
= do_unit_file_disable(&lp
, scope
, flags
, config_path
, names
, changes
, n_changes
);
3012 /* But the enable command with the full name */
3013 return do_unit_file_enable(&lp
, scope
, flags
, config_path
, files
, changes
, n_changes
);
3016 int unit_file_set_default(
3018 UnitFileFlags flags
,
3019 const char *root_dir
,
3021 InstallChange
**changes
,
3022 size_t *n_changes
) {
3024 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
3025 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
3027 const char *new_path
;
3031 assert(scope
< _RUNTIME_SCOPE_MAX
);
3034 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
3036 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
3039 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3043 r
= install_info_discover_and_check(&ctx
, &lp
, name
, 0, &info
, changes
, n_changes
);
3047 new_path
= strjoina(lp
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
3048 return create_symlink(&lp
, info
->path
, new_path
, flags
& UNIT_FILE_FORCE
, changes
, n_changes
);
3051 int unit_file_get_default(
3053 const char *root_dir
,
3056 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
3057 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
3062 assert(scope
< _RUNTIME_SCOPE_MAX
);
3065 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3069 r
= install_info_discover(&ctx
, &lp
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3074 return strdup_to(ret
, info
->name
);
3077 int unit_file_lookup_state(
3079 const LookupPaths
*lp
,
3081 UnitFileState
*ret
) {
3083 _cleanup_(install_context_done
) InstallContext ctx
= { .scope
= scope
};
3085 UnitFileState state
;
3091 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3094 r
= install_info_discover(&ctx
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3097 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
3099 assert(IN_SET(info
->install_mode
, INSTALL_MODE_REGULAR
, INSTALL_MODE_MASKED
));
3100 log_debug("Found unit %s at %s (%s)", name
, strna(info
->path
),
3101 info
->install_mode
== INSTALL_MODE_REGULAR
? "regular file" : "mask");
3103 /* Shortcut things, if the caller just wants to know if this unit exists. */
3107 switch (info
->install_mode
) {
3109 case INSTALL_MODE_MASKED
:
3110 r
= path_is_runtime(lp
, info
->path
, true);
3114 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
3117 case INSTALL_MODE_REGULAR
:
3118 /* Check if the name we were querying is actually an alias */
3119 if (!streq(name
, basename(info
->path
)) && !unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
3120 state
= UNIT_FILE_ALIAS
;
3124 r
= path_is_generator(lp
, info
->path
);
3128 state
= UNIT_FILE_GENERATED
;
3132 r
= path_is_transient(lp
, info
->path
);
3136 state
= UNIT_FILE_TRANSIENT
;
3140 /* Check if any of the Alias= symlinks have been created.
3141 * We ignore other aliases, and only check those that would
3142 * be created by systemctl enable for this unit. */
3143 r
= find_symlinks_in_scope(scope
, lp
, info
, true, &state
);
3149 /* Check if the file is known under other names. If it is,
3150 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
3151 r
= find_symlinks_in_scope(scope
, lp
, info
, false, &state
);
3155 state
= UNIT_FILE_INDIRECT
;
3157 if (install_info_has_rules(info
))
3158 state
= UNIT_FILE_DISABLED
;
3159 else if (install_info_has_also(info
))
3160 state
= UNIT_FILE_INDIRECT
;
3162 state
= UNIT_FILE_STATIC
;
3168 assert_not_reached();
3175 int unit_file_get_state(
3177 const char *root_dir
,
3179 UnitFileState
*ret
) {
3181 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
3185 assert(scope
< _RUNTIME_SCOPE_MAX
);
3188 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3192 return unit_file_lookup_state(scope
, &lp
, name
, ret
);
3195 int unit_file_exists_full(RuntimeScope scope
, const LookupPaths
*lp
, const char *name
, char **ret_path
) {
3196 _cleanup_(install_context_done
) InstallContext c
= {
3204 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3207 InstallInfo
*info
= NULL
;
3208 r
= install_info_discover(
3213 ret_path
? &info
: NULL
,
3214 /* changes= */ NULL
,
3215 /* n_changes= */ NULL
);
3227 r
= strdup_to(ret_path
, info
->path
);
3235 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
3236 _cleanup_strv_free_
char **instances
= NULL
;
3237 _cleanup_free_
char *unit_name
= NULL
;
3241 assert(out_instances
);
3242 assert(out_unit_name
);
3244 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
3248 /* We handle the instances logic when unit name is extracted */
3250 /* We only create instances when a rule of templated unit
3251 * is seen. A rule like enable foo@.service a b c will
3252 * result in an array of (a, b, c) as instance names */
3253 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
3256 instances
= strv_split(pattern
, WHITESPACE
);
3260 *out_instances
= TAKE_PTR(instances
);
3263 *out_unit_name
= TAKE_PTR(unit_name
);
3268 static int presets_find_config(RuntimeScope scope
, const char *root_dir
, char ***files
) {
3269 static const char* const system_dirs
[] = { CONF_PATHS("systemd/system-preset"), NULL
};
3270 static const char* const user_dirs
[] = { CONF_PATHS("systemd/user-preset"), NULL
};
3271 const char* const* dirs
;
3274 assert(scope
< _RUNTIME_SCOPE_MAX
);
3276 if (scope
== RUNTIME_SCOPE_SYSTEM
)
3278 else if (IN_SET(scope
, RUNTIME_SCOPE_GLOBAL
, RUNTIME_SCOPE_USER
))
3281 assert_not_reached();
3283 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
3286 static int read_presets(RuntimeScope scope
, const char *root_dir
, UnitFilePresets
*presets
) {
3287 _cleanup_(unit_file_presets_done
) UnitFilePresets ps
= {};
3288 _cleanup_strv_free_
char **files
= NULL
;
3292 assert(scope
< _RUNTIME_SCOPE_MAX
);
3295 r
= presets_find_config(scope
, root_dir
, &files
);
3299 STRV_FOREACH(p
, files
) {
3300 _cleanup_fclose_
FILE *f
= NULL
;
3303 f
= fopen(*p
, "re");
3305 if (errno
== ENOENT
)
3312 _cleanup_free_
char *line
= NULL
;
3313 _cleanup_(unit_file_preset_rule_done
) UnitFilePresetRule rule
= {};
3314 const char *parameter
;
3316 r
= read_stripped_line(f
, LONG_LINE_MAX
, &line
);
3326 if (strchr(COMMENTS
, line
[0]))
3329 parameter
= first_word(line
, "enable");
3332 char **instances
= NULL
;
3334 /* Unit_name will remain the same as parameter when no instances are specified */
3335 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
3337 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
3341 rule
= (UnitFilePresetRule
) {
3342 .pattern
= unit_name
,
3343 .action
= PRESET_ENABLE
,
3344 .instances
= instances
,
3348 parameter
= first_word(line
, "disable");
3352 pattern
= strdup(parameter
);
3356 rule
= (UnitFilePresetRule
) {
3358 .action
= PRESET_DISABLE
,
3362 parameter
= first_word(line
, "ignore");
3366 pattern
= strdup(parameter
);
3370 rule
= (UnitFilePresetRule
) {
3372 .action
= PRESET_IGNORE
,
3377 if (!GREEDY_REALLOC(ps
.rules
, ps
.n_rules
+ 1))
3380 ps
.rules
[ps
.n_rules
++] = TAKE_STRUCT(rule
);
3384 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
3388 ps
.initialized
= true;
3389 *presets
= TAKE_STRUCT(ps
);
3394 static int pattern_match_multiple_instances(
3395 const UnitFilePresetRule rule
,
3396 const char *unit_name
,
3399 _cleanup_free_
char *templated_name
= NULL
;
3402 /* If no ret is needed or the rule itself does not have instances
3403 * initialized, we return not matching */
3404 if (!ret
|| !rule
.instances
)
3407 r
= unit_name_template(unit_name
, &templated_name
);
3410 if (!streq(rule
.pattern
, templated_name
))
3413 /* Compose a list of specified instances when unit name is a template */
3414 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
3415 _cleanup_strv_free_
char **out_strv
= NULL
;
3417 STRV_FOREACH(iter
, rule
.instances
) {
3418 _cleanup_free_
char *name
= NULL
;
3420 r
= unit_name_replace_instance(unit_name
, *iter
, &name
);
3424 r
= strv_consume(&out_strv
, TAKE_PTR(name
));
3429 *ret
= TAKE_PTR(out_strv
);
3432 /* We now know the input unit name is an instance name */
3433 _cleanup_free_
char *instance_name
= NULL
;
3435 r
= unit_name_to_instance(unit_name
, &instance_name
);
3439 if (strv_find(rule
.instances
, instance_name
))
3445 static int query_presets(const char *name
, const UnitFilePresets
*presets
, char ***instance_name_list
) {
3446 PresetAction action
= PRESET_UNKNOWN
;
3448 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
3451 for (size_t i
= 0; i
< presets
->n_rules
; i
++)
3452 if (pattern_match_multiple_instances(presets
->rules
[i
], name
, instance_name_list
) > 0 ||
3453 fnmatch(presets
->rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
3454 action
= presets
->rules
[i
].action
;
3459 case PRESET_UNKNOWN
:
3460 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3461 return PRESET_ENABLE
;
3463 if (instance_name_list
&& *instance_name_list
)
3464 STRV_FOREACH(s
, *instance_name_list
)
3465 log_debug("Preset files say enable %s.", *s
);
3467 log_debug("Preset files say enable %s.", name
);
3468 return PRESET_ENABLE
;
3469 case PRESET_DISABLE
:
3470 log_debug("Preset files say disable %s.", name
);
3471 return PRESET_DISABLE
;
3473 log_debug("Preset files say ignore %s.", name
);
3474 return PRESET_IGNORE
;
3476 assert_not_reached();
3480 PresetAction
unit_file_query_preset(RuntimeScope scope
, const char *root_dir
, const char *name
, UnitFilePresets
*cached
) {
3481 _cleanup_(unit_file_presets_done
) UnitFilePresets tmp
= {};
3486 if (!cached
->initialized
) {
3487 r
= read_presets(scope
, root_dir
, cached
);
3492 return query_presets(name
, cached
, NULL
);
3495 static int execute_preset(
3496 UnitFileFlags file_flags
,
3497 InstallContext
*plus
,
3498 InstallContext
*minus
,
3499 const LookupPaths
*lp
,
3500 const char *config_path
,
3502 UnitFilePresetMode mode
,
3503 InstallChange
**changes
,
3504 size_t *n_changes
) {
3511 assert(config_path
);
3513 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3514 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3516 r
= install_context_mark_for_removal(minus
, lp
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3520 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, lp
, false, changes
, n_changes
);
3524 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3527 /* Returns number of symlinks that where supposed to be installed. */
3528 q
= install_context_apply(plus
, lp
,
3529 file_flags
| UNIT_FILE_IGNORE_AUXILIARY_FAILURE
,
3531 SEARCH_LOAD
, changes
, n_changes
);
3543 static int preset_prepare_one(
3545 InstallContext
*plus
,
3546 InstallContext
*minus
,
3549 const UnitFilePresets
*presets
,
3550 InstallChange
**changes
,
3551 size_t *n_changes
) {
3553 _cleanup_(install_context_done
) InstallContext tmp
= { .scope
= scope
};
3554 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3558 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3561 r
= install_info_discover(&tmp
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3562 &info
, changes
, n_changes
);
3565 if (!streq(name
, info
->name
)) {
3566 log_debug("Skipping %s because it is an alias for %s.", name
, info
->name
);
3570 r
= query_presets(name
, presets
, &instance_name_list
);
3574 if (r
== PRESET_ENABLE
) {
3575 if (instance_name_list
)
3576 STRV_FOREACH(s
, instance_name_list
) {
3577 r
= install_info_discover_and_check(plus
, lp
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3578 &info
, changes
, n_changes
);
3583 r
= install_info_discover_and_check(plus
, lp
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3584 &info
, changes
, n_changes
);
3589 } else if (r
== PRESET_DISABLE
)
3590 r
= install_info_discover(minus
, lp
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3591 &info
, changes
, n_changes
);
3596 int unit_file_preset(
3598 UnitFileFlags file_flags
,
3599 const char *root_dir
,
3601 UnitFilePresetMode mode
,
3602 InstallChange
**changes
,
3603 size_t *n_changes
) {
3605 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3606 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
3607 _cleanup_(unit_file_presets_done
) UnitFilePresets presets
= {};
3608 const char *config_path
;
3612 assert(scope
< _RUNTIME_SCOPE_MAX
);
3613 assert(mode
< _UNIT_FILE_PRESET_MODE_MAX
);
3615 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3619 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3623 r
= read_presets(scope
, root_dir
, &presets
);
3627 STRV_FOREACH(name
, names
) {
3628 r
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, *name
, &presets
, changes
, n_changes
);
3633 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, names
, mode
, changes
, n_changes
);
3636 int unit_file_preset_all(
3638 UnitFileFlags file_flags
,
3639 const char *root_dir
,
3640 UnitFilePresetMode mode
,
3641 InstallChange
**changes
,
3642 size_t *n_changes
) {
3644 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3645 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
3646 _cleanup_(unit_file_presets_done
) UnitFilePresets presets
= {};
3647 const char *config_path
= NULL
;
3651 assert(scope
< _RUNTIME_SCOPE_MAX
);
3652 assert(mode
< _UNIT_FILE_PRESET_MODE_MAX
);
3654 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3658 config_path
= (file_flags
& UNIT_FILE_RUNTIME
) ? lp
.runtime_config
: lp
.persistent_config
;
3662 r
= read_presets(scope
, root_dir
, &presets
);
3667 STRV_FOREACH(i
, lp
.search_path
) {
3668 _cleanup_closedir_
DIR *d
= NULL
;
3672 if (errno
!= ENOENT
)
3673 RET_GATHER(r
, -errno
);
3677 FOREACH_DIRENT(de
, d
, RET_GATHER(r
, -errno
)) {
3680 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3683 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3686 k
= preset_prepare_one(scope
, &plus
, &minus
, &lp
, de
->d_name
, &presets
, changes
, n_changes
);
3700 /* Ignore generated/transient/missing/invalid units when applying preset, propagate other errors.
3701 * Coordinate with install_change_dump_error() above. */
3706 return execute_preset(file_flags
, &plus
, &minus
, &lp
, config_path
, NULL
, mode
, changes
, n_changes
);
3709 static UnitFileList
* unit_file_list_free(UnitFileList
*f
) {
3717 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free
);
3719 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
3720 unit_file_list_hash_ops_free
,
3723 string_compare_func
,
3725 unit_file_list_free
);
3727 int unit_file_get_list(
3729 const char *root_dir
,
3734 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
3738 assert(scope
< _RUNTIME_SCOPE_MAX
);
3741 r
= lookup_paths_init(&lp
, scope
, 0, root_dir
);
3745 STRV_FOREACH(dirname
, lp
.search_path
) {
3746 _cleanup_closedir_
DIR *d
= NULL
;
3748 d
= opendir(*dirname
);
3750 if (errno
== ENOENT
)
3752 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3753 log_debug_errno(errno
, "Failed to open \"%s\": %m", *dirname
);
3760 FOREACH_DIRENT(de
, d
, return -errno
) {
3761 _cleanup_(unit_file_list_freep
) UnitFileList
*f
= NULL
;
3763 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3766 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3769 if (hashmap_get(h
, de
->d_name
))
3772 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3775 f
= new0(UnitFileList
, 1);
3779 f
->path
= path_make_absolute(de
->d_name
, *dirname
);
3783 r
= unit_file_lookup_state(scope
, &lp
, de
->d_name
, &f
->state
);
3785 f
->state
= UNIT_FILE_BAD
;
3787 if (!strv_isempty(states
) &&
3788 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3791 r
= hashmap_put(h
, basename(f
->path
), f
);
3795 f
= NULL
; /* prevent cleanup */
3802 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3803 [UNIT_FILE_ENABLED
] = "enabled",
3804 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3805 [UNIT_FILE_LINKED
] = "linked",
3806 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3807 [UNIT_FILE_ALIAS
] = "alias",
3808 [UNIT_FILE_MASKED
] = "masked",
3809 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3810 [UNIT_FILE_STATIC
] = "static",
3811 [UNIT_FILE_DISABLED
] = "disabled",
3812 [UNIT_FILE_INDIRECT
] = "indirect",
3813 [UNIT_FILE_GENERATED
] = "generated",
3814 [UNIT_FILE_TRANSIENT
] = "transient",
3815 [UNIT_FILE_BAD
] = "bad",
3818 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3820 static const char* const install_change_type_table
[_INSTALL_CHANGE_TYPE_MAX
] = {
3821 [INSTALL_CHANGE_SYMLINK
] = "symlink",
3822 [INSTALL_CHANGE_UNLINK
] = "unlink",
3823 [INSTALL_CHANGE_IS_MASKED
] = "masked",
3824 [INSTALL_CHANGE_IS_MASKED_GENERATOR
] = "masked by generator",
3825 [INSTALL_CHANGE_IS_DANGLING
] = "dangling",
3826 [INSTALL_CHANGE_DESTINATION_NOT_PRESENT
] = "destination not present",
3827 [INSTALL_CHANGE_AUXILIARY_FAILED
] = "auxiliary unit failed",
3830 DEFINE_STRING_TABLE_LOOKUP(install_change_type
, InstallChangeType
);
3832 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MODE_MAX
] = {
3833 [UNIT_FILE_PRESET_FULL
] = "full",
3834 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3835 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3838 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);