1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include "alloc-util.h"
16 #include "conf-files.h"
17 #include "conf-parser.h"
19 #include "dirent-util.h"
20 #include "extract-word.h"
25 #include "install-printf.h"
27 #include "locale-util.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,
51 OrderedHashmap
*will_process
;
52 OrderedHashmap
*have_processed
;
72 static bool unit_file_install_info_has_rules(const UnitFileInstallInfo
*i
) {
75 return !strv_isempty(i
->aliases
) ||
76 !strv_isempty(i
->wanted_by
) ||
77 !strv_isempty(i
->required_by
);
80 static bool unit_file_install_info_has_also(const UnitFileInstallInfo
*i
) {
83 return !strv_isempty(i
->also
);
86 static void presets_freep(Presets
*p
) {
92 for (i
= 0; i
< p
->n_rules
; i
++) {
93 free(p
->rules
[i
].pattern
);
94 strv_free(p
->rules
[i
].instances
);
101 static const char *const unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
102 [UNIT_FILE_TYPE_REGULAR
] = "regular",
103 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
104 [UNIT_FILE_TYPE_MASKED
] = "masked",
107 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
109 static int in_search_path(const LookupPaths
*p
, const char *path
) {
110 _cleanup_free_
char *parent
= NULL
;
115 parent
= dirname_malloc(path
);
119 STRV_FOREACH(i
, p
->search_path
)
120 if (path_equal(parent
, *i
))
126 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
135 e
= path_startswith(path
, p
->root_dir
);
139 /* Make sure the returned path starts with a slash */
141 if (e
== path
|| e
[-1] != '/')
150 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
151 _cleanup_free_
char *parent
= NULL
;
156 parent
= dirname_malloc(path
);
160 return path_equal_ptr(parent
, p
->generator
) ||
161 path_equal_ptr(parent
, p
->generator_early
) ||
162 path_equal_ptr(parent
, p
->generator_late
);
165 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
166 _cleanup_free_
char *parent
= NULL
;
171 parent
= dirname_malloc(path
);
175 return path_equal_ptr(parent
, p
->transient
);
178 static int path_is_control(const LookupPaths
*p
, const char *path
) {
179 _cleanup_free_
char *parent
= NULL
;
184 parent
= dirname_malloc(path
);
188 return path_equal_ptr(parent
, p
->persistent_control
) ||
189 path_equal_ptr(parent
, p
->runtime_control
);
192 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
193 _cleanup_free_
char *parent
= NULL
;
198 /* Note that we do *not* have generic checks for /etc or /run in place, since with
199 * them we couldn't discern configuration from transient or generated units */
202 parent
= dirname_malloc(path
);
209 return path_equal_ptr(path
, p
->persistent_config
) ||
210 path_equal_ptr(path
, p
->runtime_config
);
213 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
214 _cleanup_free_
char *parent
= NULL
;
220 /* Everything in /run is considered runtime. On top of that we also add
221 * explicit checks for the various runtime directories, as safety net. */
223 rpath
= skip_root(p
, path
);
224 if (rpath
&& path_startswith(rpath
, "/run"))
228 parent
= dirname_malloc(path
);
235 return path_equal_ptr(path
, p
->runtime_config
) ||
236 path_equal_ptr(path
, p
->generator
) ||
237 path_equal_ptr(path
, p
->generator_early
) ||
238 path_equal_ptr(path
, p
->generator_late
) ||
239 path_equal_ptr(path
, p
->transient
) ||
240 path_equal_ptr(path
, p
->runtime_control
);
243 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
249 rpath
= skip_root(p
, path
);
253 if (path_startswith(rpath
, "/usr"))
257 if (path_startswith(rpath
, "/lib"))
261 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
264 int unit_file_changes_add(
265 UnitFileChange
**changes
,
267 UnitFileChangeType type
,
269 const char *source
) {
271 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
275 assert(!changes
== !n_changes
);
280 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
289 if (!p
|| (source
&& !s
))
292 path_simplify(p
, false);
294 path_simplify(s
, false);
296 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
302 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
305 assert(changes
|| n_changes
== 0);
307 for (i
= 0; i
< n_changes
; i
++) {
308 free(changes
[i
].path
);
309 free(changes
[i
].source
);
315 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
319 assert(changes
|| n_changes
== 0);
320 /* If verb is not specified, errors are not allowed! */
321 assert(verb
|| r
>= 0);
323 for (i
= 0; i
< n_changes
; i
++) {
324 assert(verb
|| changes
[i
].type
>= 0);
326 switch(changes
[i
].type
) {
327 case UNIT_FILE_SYMLINK
:
329 log_info("Created symlink %s %s %s.",
331 special_glyph(SPECIAL_GLYPH_ARROW
),
334 case UNIT_FILE_UNLINK
:
336 log_info("Removed %s.", changes
[i
].path
);
338 case UNIT_FILE_IS_MASKED
:
340 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
342 case UNIT_FILE_IS_DANGLING
:
344 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
348 if (changes
[i
].source
)
349 log_error_errno(changes
[i
].type
,
350 "Failed to %s unit, file %s already exists and is a symlink to %s.",
351 verb
, changes
[i
].path
, changes
[i
].source
);
353 log_error_errno(changes
[i
].type
,
354 "Failed to %s unit, file %s already exists.",
355 verb
, changes
[i
].path
);
359 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
360 verb
, changes
[i
].path
);
364 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
365 verb
, changes
[i
].path
);
369 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
370 verb
, changes
[i
].path
);
375 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
380 assert(changes
[i
].type
< 0);
381 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
382 verb
, changes
[i
].path
);
387 if (r
< 0 && !logged
)
388 log_error_errno(r
, "Failed to %s: %m.", verb
);
392 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
393 * wc should be the full path in the host file system.
395 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
396 assert(path_is_absolute(wd
));
398 /* This will give incorrect results if the paths are relative and go outside
399 * of the chroot. False negatives are possible. */
404 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
405 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
406 return path_equal_or_files_same(a
, b
, 0);
409 static int create_symlink(
410 const LookupPaths
*paths
,
411 const char *old_path
,
412 const char *new_path
,
414 UnitFileChange
**changes
,
417 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
424 rp
= skip_root(paths
, old_path
);
428 /* Actually create a symlink, and remember that we did. Is
429 * smart enough to check if there's already a valid symlink in
432 * Returns 1 if a symlink was created or already exists and points to
433 * the right place, or negative on error.
436 mkdir_parents_label(new_path
, 0755);
438 if (symlink(old_path
, new_path
) >= 0) {
439 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
443 if (errno
!= EEXIST
) {
444 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
448 r
= readlink_malloc(new_path
, &dest
);
450 /* translate EINVAL (non-symlink exists) to EEXIST */
454 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
458 dirname
= dirname_malloc(new_path
);
462 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
)) {
463 log_debug("Symlink %s → %s already exists", new_path
, dest
);
468 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
472 r
= symlink_atomic(old_path
, new_path
);
474 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
478 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
479 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
484 static int mark_symlink_for_removal(
485 Set
**remove_symlinks_to
,
493 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
501 path_simplify(n
, false);
503 r
= set_consume(*remove_symlinks_to
, n
);
512 static int remove_marked_symlinks_fd(
513 Set
*remove_symlinks_to
,
516 const char *config_path
,
517 const LookupPaths
*lp
,
520 UnitFileChange
**changes
,
523 _cleanup_closedir_
DIR *d
= NULL
;
527 assert(remove_symlinks_to
);
542 FOREACH_DIRENT(de
, d
, return -errno
) {
544 dirent_ensure_type(d
, de
);
546 if (de
->d_type
== DT_DIR
) {
547 _cleanup_free_
char *p
= NULL
;
550 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
560 p
= path_make_absolute(de
->d_name
, path
);
566 /* This will close nfd, regardless whether it succeeds or not */
567 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
571 } else if (de
->d_type
== DT_LNK
) {
572 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
577 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
580 p
= path_make_absolute(de
->d_name
, path
);
583 path_simplify(p
, false);
585 q
= readlink_malloc(p
, &dest
);
594 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
595 * the same name as a file that is marked. */
597 found
= set_contains(remove_symlinks_to
, dest
) ||
598 set_contains(remove_symlinks_to
, basename(dest
)) ||
599 set_contains(remove_symlinks_to
, de
->d_name
);
605 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
608 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
612 (void) rmdir_parents(p
, config_path
);
615 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
617 /* Now, remember the full path (but with the root prefix removed) of
618 * the symlink we just removed, and remove any symlinks to it, too. */
620 rp
= skip_root(lp
, p
);
621 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
624 if (q
> 0 && !dry_run
)
632 static int remove_marked_symlinks(
633 Set
*remove_symlinks_to
,
634 const char *config_path
,
635 const LookupPaths
*lp
,
637 UnitFileChange
**changes
,
640 _cleanup_close_
int fd
= -1;
647 if (set_size(remove_symlinks_to
) <= 0)
650 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
652 return errno
== ENOENT
? 0 : -errno
;
658 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
662 /* This takes possession of cfd and closes it */
663 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
671 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
674 if (streq(name
, i
->name
))
677 if (strv_contains(i
->aliases
, name
))
680 /* Look for template symlink matching DefaultInstance */
681 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
682 _cleanup_free_
char *s
= NULL
;
684 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
689 } else if (streq(name
, s
))
696 static int find_symlinks_fd(
697 const char *root_dir
,
698 const UnitFileInstallInfo
*i
,
700 bool ignore_same_name
,
703 const char *config_path
,
704 bool *same_name_link
) {
706 _cleanup_closedir_
DIR *d
= NULL
;
714 assert(same_name_link
);
722 FOREACH_DIRENT(de
, d
, return -errno
) {
724 dirent_ensure_type(d
, de
);
726 if (de
->d_type
== DT_DIR
) {
727 _cleanup_free_
char *p
= NULL
;
730 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
740 p
= path_make_absolute(de
->d_name
, path
);
746 /* This will close nfd, regardless whether it succeeds or not */
747 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, ignore_same_name
, nfd
,
748 p
, config_path
, same_name_link
);
754 } else if (de
->d_type
== DT_LNK
) {
755 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
756 bool found_path
= false, found_dest
, b
= false;
759 /* Acquire symlink name */
760 p
= path_make_absolute(de
->d_name
, path
);
764 /* Acquire symlink destination */
765 q
= readlink_malloc(p
, &dest
);
775 if (!path_is_absolute(dest
)) {
778 x
= path_join(root_dir
, dest
);
782 free_and_replace(dest
, x
);
785 assert(unit_name_is_valid(i
->name
, UNIT_NAME_ANY
));
786 if (!ignore_same_name
)
787 /* Check if the symlink itself matches what we are looking for.
789 * If ignore_same_name is specified, we are in one of the directories which
790 * have lower priority than the unit file, and even if a file or symlink with
791 * this name was found, we should ignore it. */
792 found_path
= streq(de
->d_name
, i
->name
);
794 /* Check if what the symlink points to matches what we are looking for */
795 found_dest
= streq(basename(dest
), i
->name
);
797 if (found_path
&& found_dest
) {
798 _cleanup_free_
char *t
= NULL
;
800 /* Filter out same name links in the main
802 t
= path_make_absolute(i
->name
, config_path
);
806 b
= path_equal(t
, p
);
810 *same_name_link
= true;
811 else if (found_path
|| found_dest
) {
815 /* Check if symlink name is in the set of names used by [Install] */
816 q
= is_symlink_with_known_name(i
, de
->d_name
);
828 static int find_symlinks(
829 const char *root_dir
,
830 const UnitFileInstallInfo
*i
,
832 bool ignore_same_name
,
833 const char *config_path
,
834 bool *same_name_link
) {
840 assert(same_name_link
);
842 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
844 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
849 /* This takes possession of fd and closes it */
850 return find_symlinks_fd(root_dir
, i
, match_name
, ignore_same_name
, fd
,
851 config_path
, config_path
, same_name_link
);
854 static int find_symlinks_in_scope(
856 const LookupPaths
*paths
,
857 const UnitFileInstallInfo
*i
,
859 UnitFileState
*state
) {
861 bool same_name_link_runtime
= false, same_name_link_config
= false;
862 bool enabled_in_runtime
= false, enabled_at_all
= false;
863 bool ignore_same_name
= false;
870 /* As we iterate over the list of search paths in paths->search_path, we may encounter "same name"
871 * symlinks. The ones which are "below" (i.e. have lower priority) than the unit file itself are
872 * effectively masked, so we should ignore them. */
874 STRV_FOREACH(p
, paths
->search_path
) {
875 bool same_name_link
= false;
877 r
= find_symlinks(paths
->root_dir
, i
, match_name
, ignore_same_name
, *p
, &same_name_link
);
881 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
883 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
884 /* This is the best outcome, let's return it immediately. */
885 *state
= UNIT_FILE_ENABLED
;
889 /* look for global enablement of user units */
890 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
891 *state
= UNIT_FILE_ENABLED
;
895 r
= path_is_runtime(paths
, *p
, false);
899 enabled_in_runtime
= true;
901 enabled_at_all
= true;
903 } else if (same_name_link
) {
904 if (path_equal_ptr(*p
, paths
->persistent_config
))
905 same_name_link_config
= true;
907 r
= path_is_runtime(paths
, *p
, false);
911 same_name_link_runtime
= true;
915 /* Check if next iteration will be "below" the unit file (either a regular file
916 * or a symlink), and hence should be ignored */
917 if (!ignore_same_name
&& path_startswith(i
->path
, *p
))
918 ignore_same_name
= true;
921 if (enabled_in_runtime
) {
922 *state
= UNIT_FILE_ENABLED_RUNTIME
;
926 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
927 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
928 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
929 * something, and hence are a much stronger concept. */
930 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
931 *state
= UNIT_FILE_STATIC
;
935 /* Hmm, we didn't find it, but maybe we found the same name
937 if (same_name_link_config
) {
938 *state
= UNIT_FILE_LINKED
;
941 if (same_name_link_runtime
) {
942 *state
= UNIT_FILE_LINKED_RUNTIME
;
949 static void install_info_free(UnitFileInstallInfo
*i
) {
956 strv_free(i
->aliases
);
957 strv_free(i
->wanted_by
);
958 strv_free(i
->required_by
);
960 free(i
->default_instance
);
961 free(i
->symlink_target
);
965 static void install_context_done(InstallContext
*c
) {
968 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
969 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
972 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
973 UnitFileInstallInfo
*i
;
975 i
= ordered_hashmap_get(c
->have_processed
, name
);
979 return ordered_hashmap_get(c
->will_process
, name
);
982 static int install_info_may_process(
983 const UnitFileInstallInfo
*i
,
984 const LookupPaths
*paths
,
985 UnitFileChange
**changes
,
990 /* Checks whether the loaded unit file is one we should process, or is masked,
991 * transient or generated and thus not subject to enable/disable operations. */
993 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
994 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
997 if (path_is_generator(paths
, i
->path
) ||
998 path_is_transient(paths
, i
->path
)) {
999 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1000 return -EADDRNOTAVAIL
;
1007 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1008 * hashmap, or retrieves the existing one if already present.
1010 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1012 static int install_info_add(
1017 UnitFileInstallInfo
**ret
) {
1019 UnitFileInstallInfo
*i
= NULL
;
1023 assert(name
|| path
);
1026 name
= basename(path
);
1028 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1031 i
= install_info_find(c
, name
);
1033 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1040 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1044 i
= new(UnitFileInstallInfo
, 1);
1048 *i
= (UnitFileInstallInfo
) {
1049 .type
= _UNIT_FILE_TYPE_INVALID
,
1050 .auxiliary
= auxiliary
,
1053 i
->name
= strdup(name
);
1060 i
->path
= strdup(path
);
1067 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1077 install_info_free(i
);
1081 static int config_parse_alias(
1083 const char *filename
,
1085 const char *section
,
1086 unsigned section_line
,
1100 type
= unit_name_to_type(unit
);
1101 if (!unit_type_may_alias(type
))
1102 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1103 "Alias= is not allowed for %s units, ignoring.",
1104 unit_type_to_string(type
));
1106 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1107 lvalue
, ltype
, rvalue
, data
, userdata
);
1110 static int config_parse_also(
1112 const char *filename
,
1114 const char *section
,
1115 unsigned section_line
,
1122 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1123 InstallContext
*c
= data
;
1132 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1134 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1140 r
= install_full_printf(info
, word
, &printed
);
1144 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1147 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1151 r
= strv_push(&info
->also
, printed
);
1161 static int config_parse_default_instance(
1163 const char *filename
,
1165 const char *section
,
1166 unsigned section_line
,
1173 UnitFileInstallInfo
*i
= data
;
1174 _cleanup_free_
char *printed
= NULL
;
1182 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1183 /* When enabling an instance, we might be using a template unit file,
1184 * but we should ignore DefaultInstance silently. */
1186 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1187 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1188 "DefaultInstance= only makes sense for template units, ignoring.");
1190 r
= install_full_printf(i
, rvalue
, &printed
);
1194 if (!unit_instance_is_valid(printed
))
1197 return free_and_replace(i
->default_instance
, printed
);
1200 static int unit_file_load(
1202 UnitFileInstallInfo
*info
,
1204 const char *root_dir
,
1205 SearchFlags flags
) {
1207 const ConfigTableItem items
[] = {
1208 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1209 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1210 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1211 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1212 { "Install", "Also", config_parse_also
, 0, c
},
1217 _cleanup_fclose_
FILE *f
= NULL
;
1218 _cleanup_close_
int fd
= -1;
1225 if (!(flags
& SEARCH_DROPIN
)) {
1226 /* Loading or checking for the main unit file… */
1228 type
= unit_name_to_type(info
->name
);
1231 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1232 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1233 "Unit type %s cannot be templated.", unit_type_to_string(type
));
1235 if (!(flags
& SEARCH_LOAD
)) {
1236 r
= lstat(path
, &st
);
1240 if (null_or_empty(&st
))
1241 info
->type
= UNIT_FILE_TYPE_MASKED
;
1242 else if (S_ISREG(st
.st_mode
))
1243 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1244 else if (S_ISLNK(st
.st_mode
))
1246 else if (S_ISDIR(st
.st_mode
))
1254 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1258 /* 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. */
1260 if (!(flags
& SEARCH_LOAD
))
1263 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1268 if (fstat(fd
, &st
) < 0)
1271 if (null_or_empty(&st
)) {
1272 if ((flags
& SEARCH_DROPIN
) == 0)
1273 info
->type
= UNIT_FILE_TYPE_MASKED
;
1278 r
= stat_verify_regular(&st
);
1282 f
= fdopen(fd
, "r");
1287 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1290 r
= config_parse(info
->name
, path
, f
,
1292 config_item_table_lookup
, items
,
1293 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1295 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1297 if ((flags
& SEARCH_DROPIN
) == 0)
1298 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1301 (int) strv_length(info
->aliases
) +
1302 (int) strv_length(info
->wanted_by
) +
1303 (int) strv_length(info
->required_by
);
1306 static int unit_file_load_or_readlink(
1308 UnitFileInstallInfo
*info
,
1310 const char *root_dir
,
1311 SearchFlags flags
) {
1313 _cleanup_free_
char *target
= NULL
;
1316 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1317 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1320 /* This is a symlink, let's read it. */
1322 r
= readlink_malloc(path
, &target
);
1326 if (path_equal(target
, "/dev/null"))
1327 info
->type
= UNIT_FILE_TYPE_MASKED
;
1332 bn
= basename(target
);
1334 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1336 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1339 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1341 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1344 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1346 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1351 /* Enforce that the symlink destination does not
1352 * change the unit file type. */
1354 a
= unit_name_to_type(info
->name
);
1355 b
= unit_name_to_type(bn
);
1356 if (a
< 0 || b
< 0 || a
!= b
)
1359 if (path_is_absolute(target
))
1360 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1361 info
->symlink_target
= path_join(root_dir
, target
);
1363 /* This is a relative path, take it relative to the dir the symlink is located in. */
1364 info
->symlink_target
= file_in_same_dir(path
, target
);
1365 if (!info
->symlink_target
)
1368 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1374 static int unit_file_search(
1376 UnitFileInstallInfo
*info
,
1377 const LookupPaths
*paths
,
1378 SearchFlags flags
) {
1380 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1381 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1382 _cleanup_free_
char *template = NULL
;
1383 bool found_unit
= false;
1390 /* Was this unit already loaded? */
1391 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1395 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1399 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1400 r
= unit_name_template(info
->name
, &template);
1405 STRV_FOREACH(p
, paths
->search_path
) {
1406 _cleanup_free_
char *path
= NULL
;
1408 path
= path_join(*p
, info
->name
);
1412 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1414 info
->path
= TAKE_PTR(path
);
1418 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1422 if (!found_unit
&& template) {
1424 /* Unit file doesn't exist, however instance
1425 * enablement was requested. We will check if it is
1426 * possible to load template unit file. */
1428 STRV_FOREACH(p
, paths
->search_path
) {
1429 _cleanup_free_
char *path
= NULL
;
1431 path
= path_join(*p
, template);
1435 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1437 info
->path
= TAKE_PTR(path
);
1441 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1447 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1448 "Cannot find unit %s%s%s.",
1449 info
->name
, template ? " or " : "", strempty(template));
1451 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1454 /* Search for drop-in directories */
1456 dropin_dir_name
= strjoina(info
->name
, ".d");
1457 STRV_FOREACH(p
, paths
->search_path
) {
1460 path
= path_join(*p
, dropin_dir_name
);
1464 r
= strv_consume(&dirs
, path
);
1470 dropin_template_dir_name
= strjoina(template, ".d");
1471 STRV_FOREACH(p
, paths
->search_path
) {
1474 path
= path_join(*p
, dropin_template_dir_name
);
1478 r
= strv_consume(&dirs
, path
);
1484 /* Load drop-in conf files */
1486 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1488 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1490 STRV_FOREACH(p
, files
) {
1491 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1493 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1499 static int install_info_follow(
1501 UnitFileInstallInfo
*i
,
1502 const char *root_dir
,
1504 bool ignore_different_name
) {
1509 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1511 if (!i
->symlink_target
)
1514 /* If the basename doesn't match, the caller should add a
1515 * complete new entry for this. */
1517 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1520 free_and_replace(i
->path
, i
->symlink_target
);
1521 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1523 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1527 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1528 * target, maybe more than once. Propagate the instance name if present.
1530 static int install_info_traverse(
1531 UnitFileScope scope
,
1533 const LookupPaths
*paths
,
1534 UnitFileInstallInfo
*start
,
1536 UnitFileInstallInfo
**ret
) {
1538 UnitFileInstallInfo
*i
;
1546 r
= unit_file_search(c
, start
, paths
, flags
);
1551 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1552 /* Follow the symlink */
1554 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1557 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1558 r
= path_is_config(paths
, i
->path
, true);
1565 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1567 _cleanup_free_
char *buffer
= NULL
;
1570 /* Target has a different name, create a new
1571 * install info object for that, and continue
1574 bn
= basename(i
->symlink_target
);
1576 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1577 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1579 _cleanup_free_
char *instance
= NULL
;
1581 r
= unit_name_to_instance(i
->name
, &instance
);
1585 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1589 if (streq(buffer
, i
->name
)) {
1591 /* We filled in the instance, and the target stayed the same? If so, then let's
1592 * honour the link as it is. */
1594 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1604 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1608 /* Try again, with the new target we found. */
1609 r
= unit_file_search(c
, i
, paths
, flags
);
1611 /* Translate error code to highlight this specific case */
1626 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1627 * or the name (otherwise). root_dir is prepended to the path.
1629 static int install_info_add_auto(
1631 const LookupPaths
*paths
,
1632 const char *name_or_path
,
1633 UnitFileInstallInfo
**ret
) {
1636 assert(name_or_path
);
1638 if (path_is_absolute(name_or_path
)) {
1641 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1643 return install_info_add(c
, NULL
, pp
, false, ret
);
1645 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1648 static int install_info_discover(
1649 UnitFileScope scope
,
1651 const LookupPaths
*paths
,
1654 UnitFileInstallInfo
**ret
,
1655 UnitFileChange
**changes
,
1656 size_t *n_changes
) {
1658 UnitFileInstallInfo
*i
;
1665 r
= install_info_add_auto(c
, paths
, name
, &i
);
1667 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1670 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1674 static int install_info_discover_and_check(
1675 UnitFileScope scope
,
1677 const LookupPaths
*paths
,
1680 UnitFileInstallInfo
**ret
,
1681 UnitFileChange
**changes
,
1682 size_t *n_changes
) {
1686 r
= install_info_discover(scope
, c
, paths
, name
, flags
, ret
, changes
, n_changes
);
1690 return install_info_may_process(ret
? *ret
: NULL
, paths
, changes
, n_changes
);
1693 static int install_info_symlink_alias(
1694 UnitFileInstallInfo
*i
,
1695 const LookupPaths
*paths
,
1696 const char *config_path
,
1698 UnitFileChange
**changes
,
1699 size_t *n_changes
) {
1706 assert(config_path
);
1708 STRV_FOREACH(s
, i
->aliases
) {
1709 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1711 q
= install_full_printf(i
, *s
, &dst
);
1715 alias_path
= path_make_absolute(dst
, config_path
);
1719 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1727 static int install_info_symlink_wants(
1728 UnitFileInstallInfo
*i
,
1729 const LookupPaths
*paths
,
1730 const char *config_path
,
1733 UnitFileChange
**changes
,
1734 size_t *n_changes
) {
1736 _cleanup_free_
char *buf
= NULL
;
1743 assert(config_path
);
1745 if (strv_isempty(list
))
1748 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1749 UnitFileInstallInfo instance
= {
1750 .type
= _UNIT_FILE_TYPE_INVALID
,
1752 _cleanup_free_
char *path
= NULL
;
1754 /* If this is a template, and we have no instance, don't do anything */
1755 if (!i
->default_instance
)
1758 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1762 instance
.name
= buf
;
1763 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1767 path
= TAKE_PTR(instance
.path
);
1769 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1770 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1778 STRV_FOREACH(s
, list
) {
1779 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1781 q
= install_full_printf(i
, *s
, &dst
);
1785 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1790 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1794 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1802 static int install_info_symlink_link(
1803 UnitFileInstallInfo
*i
,
1804 const LookupPaths
*paths
,
1805 const char *config_path
,
1807 UnitFileChange
**changes
,
1808 size_t *n_changes
) {
1810 _cleanup_free_
char *path
= NULL
;
1815 assert(config_path
);
1818 r
= in_search_path(paths
, i
->path
);
1824 path
= path_join(config_path
, i
->name
);
1828 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1831 static int install_info_apply(
1832 UnitFileInstallInfo
*i
,
1833 const LookupPaths
*paths
,
1834 const char *config_path
,
1836 UnitFileChange
**changes
,
1837 size_t *n_changes
) {
1843 assert(config_path
);
1845 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1848 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1850 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1854 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1858 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1859 /* Do not count links to the unit file towards the "carries_install_info" count */
1860 if (r
== 0 && q
< 0)
1866 static int install_context_apply(
1867 UnitFileScope scope
,
1869 const LookupPaths
*paths
,
1870 const char *config_path
,
1873 UnitFileChange
**changes
,
1874 size_t *n_changes
) {
1876 UnitFileInstallInfo
*i
;
1881 assert(config_path
);
1883 if (ordered_hashmap_isempty(c
->will_process
))
1886 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1891 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1894 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1898 q
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1900 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1904 /* We can attempt to process a masked unit when a different unit
1905 * that we were processing specifies it in Also=. */
1906 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1907 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1909 /* Assume that something *could* have been enabled here,
1910 * avoid "empty [Install] section" warning. */
1915 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1918 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1930 static int install_context_mark_for_removal(
1931 UnitFileScope scope
,
1933 const LookupPaths
*paths
,
1934 Set
**remove_symlinks_to
,
1935 const char *config_path
,
1936 UnitFileChange
**changes
,
1937 size_t *n_changes
) {
1939 UnitFileInstallInfo
*i
;
1944 assert(config_path
);
1946 /* Marks all items for removal */
1948 if (ordered_hashmap_isempty(c
->will_process
))
1951 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1955 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1957 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1961 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1962 if (r
== -ENOLINK
) {
1963 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1964 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1965 } else if (r
== -ENOENT
) {
1967 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1968 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1970 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1971 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1975 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1976 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1977 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1978 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1979 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1981 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1982 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1986 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1995 UnitFileScope scope
,
1996 UnitFileFlags flags
,
1997 const char *root_dir
,
1999 UnitFileChange
**changes
,
2000 size_t *n_changes
) {
2002 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2003 const char *config_path
;
2008 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2010 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2014 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2018 STRV_FOREACH(i
, files
) {
2019 _cleanup_free_
char *path
= NULL
;
2022 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2028 path
= path_make_absolute(*i
, config_path
);
2032 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2033 if (q
< 0 && r
>= 0)
2040 int unit_file_unmask(
2041 UnitFileScope scope
,
2042 UnitFileFlags flags
,
2043 const char *root_dir
,
2045 UnitFileChange
**changes
,
2046 size_t *n_changes
) {
2048 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2049 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2050 _cleanup_strv_free_
char **todo
= NULL
;
2051 size_t n_todo
= 0, n_allocated
= 0;
2052 const char *config_path
;
2058 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2060 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2064 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2068 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2070 STRV_FOREACH(i
, files
) {
2071 _cleanup_free_
char *path
= NULL
;
2073 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2076 path
= path_make_absolute(*i
, config_path
);
2080 r
= null_or_empty_path(path
);
2088 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2091 todo
[n_todo
] = strdup(*i
);
2101 STRV_FOREACH(i
, todo
) {
2102 _cleanup_free_
char *path
= NULL
;
2105 path
= path_make_absolute(*i
, config_path
);
2109 if (!dry_run
&& unlink(path
) < 0) {
2110 if (errno
!= ENOENT
) {
2113 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2119 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2121 rp
= skip_root(&paths
, path
);
2122 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2127 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2135 UnitFileScope scope
,
2136 UnitFileFlags flags
,
2137 const char *root_dir
,
2139 UnitFileChange
**changes
,
2140 size_t *n_changes
) {
2142 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2143 _cleanup_strv_free_
char **todo
= NULL
;
2144 size_t n_todo
= 0, n_allocated
= 0;
2145 const char *config_path
;
2150 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2152 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2156 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2160 STRV_FOREACH(i
, files
) {
2161 _cleanup_free_
char *full
= NULL
;
2165 if (!path_is_absolute(*i
))
2169 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2172 full
= path_join(paths
.root_dir
, *i
);
2176 if (lstat(full
, &st
) < 0)
2178 r
= stat_verify_regular(&st
);
2182 q
= in_search_path(&paths
, *i
);
2188 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2191 todo
[n_todo
] = strdup(*i
);
2201 STRV_FOREACH(i
, todo
) {
2202 _cleanup_free_
char *new_path
= NULL
;
2204 new_path
= path_make_absolute(basename(*i
), config_path
);
2208 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2209 if (q
< 0 && r
>= 0)
2216 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2222 /* Checks whether the path is one where the drop-in directories shall be removed. */
2224 r
= path_is_config(paths
, path
, true);
2228 r
= path_is_control(paths
, path
);
2232 return path_is_transient(paths
, path
);
2235 int unit_file_revert(
2236 UnitFileScope scope
,
2237 const char *root_dir
,
2239 UnitFileChange
**changes
,
2240 size_t *n_changes
) {
2242 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2243 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2244 _cleanup_strv_free_
char **todo
= NULL
;
2245 size_t n_todo
= 0, n_allocated
= 0;
2249 /* Puts a unit file back into vendor state. This means:
2251 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2252 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2254 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2255 * "config", but not in "transient" or "control" or even "generated").
2257 * We remove all that in both the runtime and the persistent directories, if that applies.
2260 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2264 STRV_FOREACH(i
, files
) {
2265 bool has_vendor
= false;
2268 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2271 STRV_FOREACH(p
, paths
.search_path
) {
2272 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2275 path
= path_make_absolute(*i
, *p
);
2279 r
= lstat(path
, &st
);
2281 if (errno
!= ENOENT
)
2283 } else if (S_ISREG(st
.st_mode
)) {
2284 /* Check if there's a vendor version */
2285 r
= path_is_vendor(&paths
, path
);
2292 dropin
= strjoin(path
, ".d");
2296 r
= lstat(dropin
, &st
);
2298 if (errno
!= ENOENT
)
2300 } else if (S_ISDIR(st
.st_mode
)) {
2301 /* Remove the drop-ins */
2302 r
= path_shall_revert(&paths
, dropin
);
2306 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2309 todo
[n_todo
++] = TAKE_PTR(dropin
);
2317 /* OK, there's a vendor version, hence drop all configuration versions */
2318 STRV_FOREACH(p
, paths
.search_path
) {
2319 _cleanup_free_
char *path
= NULL
;
2322 path
= path_make_absolute(*i
, *p
);
2326 r
= lstat(path
, &st
);
2328 if (errno
!= ENOENT
)
2330 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2331 r
= path_is_config(&paths
, path
, true);
2335 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2338 todo
[n_todo
++] = TAKE_PTR(path
);
2347 STRV_FOREACH(i
, todo
) {
2348 _cleanup_strv_free_
char **fs
= NULL
;
2352 (void) get_files_in_directory(*i
, &fs
);
2354 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2355 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2360 STRV_FOREACH(j
, fs
) {
2361 _cleanup_free_
char *t
= NULL
;
2363 t
= path_join(*i
, *j
);
2367 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2370 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2372 rp
= skip_root(&paths
, *i
);
2373 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2378 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2382 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2389 int unit_file_add_dependency(
2390 UnitFileScope scope
,
2391 UnitFileFlags flags
,
2392 const char *root_dir
,
2396 UnitFileChange
**changes
,
2397 size_t *n_changes
) {
2399 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2400 _cleanup_(install_context_done
) InstallContext c
= {};
2401 UnitFileInstallInfo
*i
, *target_info
;
2402 const char *config_path
;
2407 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2410 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2413 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2416 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2420 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2424 r
= install_info_discover_and_check(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2425 &target_info
, changes
, n_changes
);
2429 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2431 STRV_FOREACH(f
, files
) {
2434 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2435 &i
, changes
, n_changes
);
2439 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2441 /* We didn't actually load anything from the unit
2442 * file, but instead just add in our new symlink to
2445 if (dep
== UNIT_WANTS
)
2448 l
= &i
->required_by
;
2451 *l
= strv_new(target_info
->name
);
2456 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2459 int unit_file_enable(
2460 UnitFileScope scope
,
2461 UnitFileFlags flags
,
2462 const char *root_dir
,
2464 UnitFileChange
**changes
,
2465 size_t *n_changes
) {
2467 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2468 _cleanup_(install_context_done
) InstallContext c
= {};
2469 const char *config_path
;
2470 UnitFileInstallInfo
*i
;
2475 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2477 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2481 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2485 STRV_FOREACH(f
, files
) {
2486 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2487 &i
, changes
, n_changes
);
2491 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2494 /* This will return the number of symlink rules that were
2495 supposed to be created, not the ones actually created. This
2496 is useful to determine whether the passed files had any
2497 installation data at all. */
2499 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2502 int unit_file_disable(
2503 UnitFileScope scope
,
2504 UnitFileFlags flags
,
2505 const char *root_dir
,
2507 UnitFileChange
**changes
,
2508 size_t *n_changes
) {
2510 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2511 _cleanup_(install_context_done
) InstallContext c
= {};
2512 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2513 const char *config_path
;
2518 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2520 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2524 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2528 STRV_FOREACH(i
, files
) {
2529 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2532 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2537 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2541 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2544 int unit_file_reenable(
2545 UnitFileScope scope
,
2546 UnitFileFlags flags
,
2547 const char *root_dir
,
2549 UnitFileChange
**changes
,
2550 size_t *n_changes
) {
2556 /* First, we invoke the disable command with only the basename... */
2557 l
= strv_length(files
);
2558 n
= newa(char*, l
+1);
2559 for (i
= 0; i
< l
; i
++)
2560 n
[i
] = basename(files
[i
]);
2563 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2567 /* But the enable command with the full name */
2568 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2571 int unit_file_set_default(
2572 UnitFileScope scope
,
2573 UnitFileFlags flags
,
2574 const char *root_dir
,
2576 UnitFileChange
**changes
,
2577 size_t *n_changes
) {
2579 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2580 _cleanup_(install_context_done
) InstallContext c
= {};
2581 UnitFileInstallInfo
*i
;
2582 const char *new_path
;
2586 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2589 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2591 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2594 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2598 r
= install_info_discover_and_check(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2602 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2603 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2606 int unit_file_get_default(
2607 UnitFileScope scope
,
2608 const char *root_dir
,
2611 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2612 _cleanup_(install_context_done
) InstallContext c
= {};
2613 UnitFileInstallInfo
*i
;
2618 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2621 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2625 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2629 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2633 n
= strdup(i
->name
);
2641 int unit_file_lookup_state(
2642 UnitFileScope scope
,
2643 const LookupPaths
*paths
,
2645 UnitFileState
*ret
) {
2647 _cleanup_(install_context_done
) InstallContext c
= {};
2648 UnitFileInstallInfo
*i
;
2649 UnitFileState state
;
2655 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2658 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2661 return log_debug_errno(r
, "Failed to discover unit %s: %m", name
);
2663 assert(IN_SET(i
->type
, UNIT_FILE_TYPE_REGULAR
, UNIT_FILE_TYPE_MASKED
));
2664 log_debug("Found unit %s at %s (%s)", name
, strna(i
->path
),
2665 i
->type
== UNIT_FILE_TYPE_REGULAR
? "regular file" : "mask");
2667 /* Shortcut things, if the caller just wants to know if this unit exists. */
2673 case UNIT_FILE_TYPE_MASKED
:
2674 r
= path_is_runtime(paths
, i
->path
, true);
2678 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2681 case UNIT_FILE_TYPE_REGULAR
:
2682 r
= path_is_generator(paths
, i
->path
);
2686 state
= UNIT_FILE_GENERATED
;
2690 r
= path_is_transient(paths
, i
->path
);
2694 state
= UNIT_FILE_TRANSIENT
;
2698 /* Check if any of the Alias= symlinks have been created.
2699 * We ignore other aliases, and only check those that would
2700 * be created by systemctl enable for this unit. */
2701 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2707 /* Check if the file is known under other names. If it is,
2708 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2709 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2713 state
= UNIT_FILE_INDIRECT
;
2715 if (unit_file_install_info_has_rules(i
))
2716 state
= UNIT_FILE_DISABLED
;
2717 else if (unit_file_install_info_has_also(i
))
2718 state
= UNIT_FILE_INDIRECT
;
2720 state
= UNIT_FILE_STATIC
;
2726 assert_not_reached("Unexpect unit file type.");
2733 int unit_file_get_state(
2734 UnitFileScope scope
,
2735 const char *root_dir
,
2737 UnitFileState
*ret
) {
2739 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2743 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2746 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2750 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2753 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2754 _cleanup_(install_context_done
) InstallContext c
= {};
2760 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2763 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2772 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2773 _cleanup_strv_free_
char **instances
= NULL
;
2774 _cleanup_free_
char *unit_name
= NULL
;
2778 assert(out_instances
);
2779 assert(out_unit_name
);
2781 r
= extract_first_word(&pattern
, &unit_name
, NULL
, EXTRACT_RETAIN_ESCAPE
);
2785 /* We handle the instances logic when unit name is extracted */
2787 /* We only create instances when a rule of templated unit
2788 * is seen. A rule like enable foo@.service a b c will
2789 * result in an array of (a, b, c) as instance names */
2790 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2793 instances
= strv_split(pattern
, WHITESPACE
);
2797 *out_instances
= TAKE_PTR(instances
);
2800 *out_unit_name
= TAKE_PTR(unit_name
);
2805 static int presets_find_config(UnitFileScope scope
, const char *root_dir
, char ***files
) {
2806 static const char* const system_dirs
[] = {CONF_PATHS("systemd/system-preset"), NULL
};
2807 static const char* const user_dirs
[] = {CONF_PATHS_USR("systemd/user-preset"), NULL
};
2808 const char* const* dirs
;
2811 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2813 if (scope
== UNIT_FILE_SYSTEM
)
2815 else if (IN_SET(scope
, UNIT_FILE_GLOBAL
, UNIT_FILE_USER
))
2818 assert_not_reached("Invalid unit file scope");
2820 return conf_files_list_strv(files
, ".preset", root_dir
, 0, dirs
);
2823 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2824 _cleanup_(presets_freep
) Presets ps
= {};
2825 size_t n_allocated
= 0;
2826 _cleanup_strv_free_
char **files
= NULL
;
2831 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2834 r
= presets_find_config(scope
, root_dir
, &files
);
2838 STRV_FOREACH(p
, files
) {
2839 _cleanup_fclose_
FILE *f
;
2842 f
= fopen(*p
, "re");
2844 if (errno
== ENOENT
)
2851 _cleanup_free_
char *line
= NULL
;
2852 PresetRule rule
= {};
2853 const char *parameter
;
2856 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2867 if (strchr(COMMENTS
, *l
))
2870 parameter
= first_word(l
, "enable");
2873 char **instances
= NULL
;
2875 /* Unit_name will remain the same as parameter when no instances are specified */
2876 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2878 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2882 rule
= (PresetRule
) {
2883 .pattern
= unit_name
,
2884 .action
= PRESET_ENABLE
,
2885 .instances
= instances
,
2889 parameter
= first_word(l
, "disable");
2893 pattern
= strdup(parameter
);
2897 rule
= (PresetRule
) {
2899 .action
= PRESET_DISABLE
,
2904 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2907 ps
.rules
[ps
.n_rules
++] = rule
;
2911 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2921 static int pattern_match_multiple_instances(
2922 const PresetRule rule
,
2923 const char *unit_name
,
2926 _cleanup_free_
char *templated_name
= NULL
;
2929 /* If no ret is needed or the rule itself does not have instances
2930 * initialized, we return not matching */
2931 if (!ret
|| !rule
.instances
)
2934 r
= unit_name_template(unit_name
, &templated_name
);
2937 if (!streq(rule
.pattern
, templated_name
))
2940 /* Compose a list of specified instances when unit name is a template */
2941 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
2942 _cleanup_free_
char *prefix
= NULL
;
2943 _cleanup_strv_free_
char **out_strv
= NULL
;
2946 r
= unit_name_to_prefix(unit_name
, &prefix
);
2950 STRV_FOREACH(iter
, rule
.instances
) {
2951 _cleanup_free_
char *name
= NULL
;
2952 r
= unit_name_build(prefix
, *iter
, ".service", &name
);
2955 r
= strv_extend(&out_strv
, name
);
2960 *ret
= TAKE_PTR(out_strv
);
2963 /* We now know the input unit name is an instance name */
2964 _cleanup_free_
char *instance_name
= NULL
;
2966 r
= unit_name_to_instance(unit_name
, &instance_name
);
2970 if (strv_find(rule
.instances
, instance_name
))
2976 static int query_presets(const char *name
, const Presets presets
, char ***instance_name_list
) {
2977 PresetAction action
= PRESET_UNKNOWN
;
2980 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2983 for (i
= 0; i
< presets
.n_rules
; i
++)
2984 if (pattern_match_multiple_instances(presets
.rules
[i
], name
, instance_name_list
) > 0 ||
2985 fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2986 action
= presets
.rules
[i
].action
;
2991 case PRESET_UNKNOWN
:
2992 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2995 if (instance_name_list
&& *instance_name_list
)
2996 STRV_FOREACH(s
, *instance_name_list
)
2997 log_debug("Preset files say enable %s.", *s
);
2999 log_debug("Preset files say enable %s.", name
);
3001 case PRESET_DISABLE
:
3002 log_debug("Preset files say disable %s.", name
);
3005 assert_not_reached("invalid preset action");
3009 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
3010 _cleanup_(presets_freep
) Presets presets
= {};
3013 r
= read_presets(scope
, root_dir
, &presets
);
3017 return query_presets(name
, presets
, NULL
);
3020 static int execute_preset(
3021 UnitFileScope scope
,
3022 InstallContext
*plus
,
3023 InstallContext
*minus
,
3024 const LookupPaths
*paths
,
3025 const char *config_path
,
3027 UnitFilePresetMode mode
,
3029 UnitFileChange
**changes
,
3030 size_t *n_changes
) {
3037 assert(config_path
);
3039 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3040 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3042 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
3046 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
3050 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3053 /* Returns number of symlinks that where supposed to be installed. */
3054 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
3066 static int preset_prepare_one(
3067 UnitFileScope scope
,
3068 InstallContext
*plus
,
3069 InstallContext
*minus
,
3073 UnitFileChange
**changes
,
3074 size_t *n_changes
) {
3076 _cleanup_(install_context_done
) InstallContext tmp
= {};
3077 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3078 UnitFileInstallInfo
*i
;
3081 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3084 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3085 &i
, changes
, n_changes
);
3088 if (!streq(name
, i
->name
)) {
3089 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3093 r
= query_presets(name
, presets
, &instance_name_list
);
3098 if (instance_name_list
) {
3100 STRV_FOREACH(s
, instance_name_list
) {
3101 r
= install_info_discover_and_check(scope
, plus
, paths
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3102 &i
, changes
, n_changes
);
3107 r
= install_info_discover_and_check(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3108 &i
, changes
, n_changes
);
3114 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3115 &i
, changes
, n_changes
);
3120 int unit_file_preset(
3121 UnitFileScope scope
,
3122 UnitFileFlags flags
,
3123 const char *root_dir
,
3125 UnitFilePresetMode mode
,
3126 UnitFileChange
**changes
,
3127 size_t *n_changes
) {
3129 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3130 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3131 _cleanup_(presets_freep
) Presets presets
= {};
3132 const char *config_path
;
3137 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3138 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3140 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3144 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3148 r
= read_presets(scope
, root_dir
, &presets
);
3152 STRV_FOREACH(i
, files
) {
3153 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3158 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3161 int unit_file_preset_all(
3162 UnitFileScope scope
,
3163 UnitFileFlags flags
,
3164 const char *root_dir
,
3165 UnitFilePresetMode mode
,
3166 UnitFileChange
**changes
,
3167 size_t *n_changes
) {
3169 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3170 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3171 _cleanup_(presets_freep
) Presets presets
= {};
3172 const char *config_path
= NULL
;
3177 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3178 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3180 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3184 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3188 r
= read_presets(scope
, root_dir
, &presets
);
3192 STRV_FOREACH(i
, paths
.search_path
) {
3193 _cleanup_closedir_
DIR *d
= NULL
;
3198 if (errno
== ENOENT
)
3204 FOREACH_DIRENT(de
, d
, return -errno
) {
3206 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3209 dirent_ensure_type(d
, de
);
3211 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3214 /* we don't pass changes[] in, because we want to handle errors on our own */
3215 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3217 r
= unit_file_changes_add(changes
, n_changes
,
3218 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3219 else if (r
== -ENOLINK
)
3220 r
= unit_file_changes_add(changes
, n_changes
,
3221 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3222 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3229 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3232 static void unit_file_list_free_one(UnitFileList
*f
) {
3240 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3241 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3244 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3246 int unit_file_get_list(
3247 UnitFileScope scope
,
3248 const char *root_dir
,
3253 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3258 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3261 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3265 STRV_FOREACH(i
, paths
.search_path
) {
3266 _cleanup_closedir_
DIR *d
= NULL
;
3271 if (errno
== ENOENT
)
3273 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3274 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3281 FOREACH_DIRENT(de
, d
, return -errno
) {
3282 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3284 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3287 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3290 if (hashmap_get(h
, de
->d_name
))
3293 dirent_ensure_type(d
, de
);
3295 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3298 f
= new0(UnitFileList
, 1);
3302 f
->path
= path_make_absolute(de
->d_name
, *i
);
3306 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3308 f
->state
= UNIT_FILE_BAD
;
3310 if (!strv_isempty(states
) &&
3311 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3314 r
= hashmap_put(h
, basename(f
->path
), f
);
3318 f
= NULL
; /* prevent cleanup */
3325 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3326 [UNIT_FILE_ENABLED
] = "enabled",
3327 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3328 [UNIT_FILE_LINKED
] = "linked",
3329 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3330 [UNIT_FILE_MASKED
] = "masked",
3331 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3332 [UNIT_FILE_STATIC
] = "static",
3333 [UNIT_FILE_DISABLED
] = "disabled",
3334 [UNIT_FILE_INDIRECT
] = "indirect",
3335 [UNIT_FILE_GENERATED
] = "generated",
3336 [UNIT_FILE_TRANSIENT
] = "transient",
3337 [UNIT_FILE_BAD
] = "bad",
3340 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3342 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3343 [UNIT_FILE_SYMLINK
] = "symlink",
3344 [UNIT_FILE_UNLINK
] = "unlink",
3345 [UNIT_FILE_IS_MASKED
] = "masked",
3346 [UNIT_FILE_IS_DANGLING
] = "dangling",
3349 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3351 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3352 [UNIT_FILE_PRESET_FULL
] = "full",
3353 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3354 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3357 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);