1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include "alloc-util.h"
16 #include "conf-files.h"
17 #include "conf-parser.h"
18 #include "dirent-util.h"
19 #include "extract-word.h"
24 #include "install-printf.h"
26 #include "locale-util.h"
30 #include "path-lookup.h"
31 #include "path-util.h"
35 #include "stat-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
39 #include "unit-name.h"
41 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
43 typedef enum SearchFlags
{
45 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
46 SEARCH_DROPIN
= 1 << 2,
50 OrderedHashmap
*will_process
;
51 OrderedHashmap
*have_processed
;
71 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
74 return !strv_isempty(i
->aliases
) ||
75 !strv_isempty(i
->wanted_by
) ||
76 !strv_isempty(i
->required_by
);
79 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
82 return !strv_isempty(i
->also
);
85 static inline void presets_freep(Presets
*p
) {
91 for (i
= 0; i
< p
->n_rules
; i
++) {
92 free(p
->rules
[i
].pattern
);
93 strv_free(p
->rules
[i
].instances
);
100 bool unit_type_may_alias(UnitType type
) {
110 bool unit_type_may_template(UnitType type
) {
119 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
120 [UNIT_FILE_TYPE_REGULAR
] = "regular",
121 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
122 [UNIT_FILE_TYPE_MASKED
] = "masked",
125 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
127 static int in_search_path(const LookupPaths
*p
, const char *path
) {
128 _cleanup_free_
char *parent
= NULL
;
133 parent
= dirname_malloc(path
);
137 STRV_FOREACH(i
, p
->search_path
)
138 if (path_equal(parent
, *i
))
144 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
153 e
= path_startswith(path
, p
->root_dir
);
157 /* Make sure the returned path starts with a slash */
159 if (e
== path
|| e
[-1] != '/')
168 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
169 _cleanup_free_
char *parent
= NULL
;
174 parent
= dirname_malloc(path
);
178 return path_equal_ptr(parent
, p
->generator
) ||
179 path_equal_ptr(parent
, p
->generator_early
) ||
180 path_equal_ptr(parent
, p
->generator_late
);
183 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
184 _cleanup_free_
char *parent
= NULL
;
189 parent
= dirname_malloc(path
);
193 return path_equal_ptr(parent
, p
->transient
);
196 static int path_is_control(const LookupPaths
*p
, const char *path
) {
197 _cleanup_free_
char *parent
= NULL
;
202 parent
= dirname_malloc(path
);
206 return path_equal_ptr(parent
, p
->persistent_control
) ||
207 path_equal_ptr(parent
, p
->runtime_control
);
210 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
211 _cleanup_free_
char *parent
= NULL
;
216 /* Note that we do *not* have generic checks for /etc or /run in place, since with
217 * them we couldn't discern configuration from transient or generated units */
220 parent
= dirname_malloc(path
);
227 return path_equal_ptr(path
, p
->persistent_config
) ||
228 path_equal_ptr(path
, p
->runtime_config
);
231 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
232 _cleanup_free_
char *parent
= NULL
;
238 /* Everything in /run is considered runtime. On top of that we also add
239 * explicit checks for the various runtime directories, as safety net. */
241 rpath
= skip_root(p
, path
);
242 if (rpath
&& path_startswith(rpath
, "/run"))
246 parent
= dirname_malloc(path
);
253 return path_equal_ptr(path
, p
->runtime_config
) ||
254 path_equal_ptr(path
, p
->generator
) ||
255 path_equal_ptr(path
, p
->generator_early
) ||
256 path_equal_ptr(path
, p
->generator_late
) ||
257 path_equal_ptr(path
, p
->transient
) ||
258 path_equal_ptr(path
, p
->runtime_control
);
261 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
267 rpath
= skip_root(p
, path
);
271 if (path_startswith(rpath
, "/usr"))
275 if (path_startswith(rpath
, "/lib"))
279 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
282 int unit_file_changes_add(
283 UnitFileChange
**changes
,
285 UnitFileChangeType type
,
287 const char *source
) {
289 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
293 assert(!changes
== !n_changes
);
298 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
307 if (!p
|| (source
&& !s
))
310 path_simplify(p
, false);
312 path_simplify(s
, false);
314 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
320 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
323 assert(changes
|| n_changes
== 0);
325 for (i
= 0; i
< n_changes
; i
++) {
326 free(changes
[i
].path
);
327 free(changes
[i
].source
);
333 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
337 assert(changes
|| n_changes
== 0);
338 /* If verb is not specified, errors are not allowed! */
339 assert(verb
|| r
>= 0);
341 for (i
= 0; i
< n_changes
; i
++) {
342 assert(verb
|| changes
[i
].type
>= 0);
344 switch(changes
[i
].type
) {
345 case UNIT_FILE_SYMLINK
:
347 log_info("Created symlink %s %s %s.",
349 special_glyph(ARROW
),
352 case UNIT_FILE_UNLINK
:
354 log_info("Removed %s.", changes
[i
].path
);
356 case UNIT_FILE_IS_MASKED
:
358 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
360 case UNIT_FILE_IS_DANGLING
:
362 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
366 if (changes
[i
].source
)
367 log_error_errno(changes
[i
].type
,
368 "Failed to %s unit, file %s already exists and is a symlink to %s.",
369 verb
, changes
[i
].path
, changes
[i
].source
);
371 log_error_errno(changes
[i
].type
,
372 "Failed to %s unit, file %s already exists.",
373 verb
, changes
[i
].path
);
377 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
378 verb
, changes
[i
].path
);
382 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
383 verb
, changes
[i
].path
);
387 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
388 verb
, changes
[i
].path
);
393 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
398 assert(changes
[i
].type
< 0);
399 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
400 verb
, changes
[i
].path
);
405 if (r
< 0 && !logged
)
406 log_error_errno(r
, "Failed to %s: %m.", verb
);
410 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
411 * wc should be the full path in the host file system.
413 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
414 assert(path_is_absolute(wd
));
416 /* This will give incorrect results if the paths are relative and go outside
417 * of the chroot. False negatives are possible. */
422 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
423 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
424 return path_equal_or_files_same(a
, b
, 0);
427 static int create_symlink(
428 const LookupPaths
*paths
,
429 const char *old_path
,
430 const char *new_path
,
432 UnitFileChange
**changes
,
435 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
442 rp
= skip_root(paths
, old_path
);
446 /* Actually create a symlink, and remember that we did. Is
447 * smart enough to check if there's already a valid symlink in
450 * Returns 1 if a symlink was created or already exists and points to
451 * the right place, or negative on error.
454 mkdir_parents_label(new_path
, 0755);
456 if (symlink(old_path
, new_path
) >= 0) {
457 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
461 if (errno
!= EEXIST
) {
462 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
466 r
= readlink_malloc(new_path
, &dest
);
468 /* translate EINVAL (non-symlink exists) to EEXIST */
472 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
476 dirname
= dirname_malloc(new_path
);
480 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
484 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
488 r
= symlink_atomic(old_path
, new_path
);
490 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
494 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
495 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
500 static int mark_symlink_for_removal(
501 Set
**remove_symlinks_to
,
509 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
517 path_simplify(n
, false);
519 r
= set_consume(*remove_symlinks_to
, n
);
528 static int remove_marked_symlinks_fd(
529 Set
*remove_symlinks_to
,
532 const char *config_path
,
533 const LookupPaths
*lp
,
536 UnitFileChange
**changes
,
539 _cleanup_closedir_
DIR *d
= NULL
;
543 assert(remove_symlinks_to
);
558 FOREACH_DIRENT(de
, d
, return -errno
) {
560 dirent_ensure_type(d
, de
);
562 if (de
->d_type
== DT_DIR
) {
563 _cleanup_free_
char *p
= NULL
;
566 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
576 p
= path_make_absolute(de
->d_name
, path
);
582 /* This will close nfd, regardless whether it succeeds or not */
583 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
587 } else if (de
->d_type
== DT_LNK
) {
588 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
593 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
596 p
= path_make_absolute(de
->d_name
, path
);
599 path_simplify(p
, false);
601 q
= readlink_malloc(p
, &dest
);
610 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
611 * the same name as a file that is marked. */
613 found
= set_contains(remove_symlinks_to
, dest
) ||
614 set_contains(remove_symlinks_to
, basename(dest
)) ||
615 set_contains(remove_symlinks_to
, de
->d_name
);
621 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
624 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
628 (void) rmdir_parents(p
, config_path
);
631 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
633 /* Now, remember the full path (but with the root prefix removed) of
634 * the symlink we just removed, and remove any symlinks to it, too. */
636 rp
= skip_root(lp
, p
);
637 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
640 if (q
> 0 && !dry_run
)
648 static int remove_marked_symlinks(
649 Set
*remove_symlinks_to
,
650 const char *config_path
,
651 const LookupPaths
*lp
,
653 UnitFileChange
**changes
,
656 _cleanup_close_
int fd
= -1;
663 if (set_size(remove_symlinks_to
) <= 0)
666 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
668 return errno
== ENOENT
? 0 : -errno
;
674 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
678 /* This takes possession of cfd and closes it */
679 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
687 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
690 if (streq(name
, i
->name
))
693 if (strv_contains(i
->aliases
, name
))
696 /* Look for template symlink matching DefaultInstance */
697 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
698 _cleanup_free_
char *s
= NULL
;
700 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
705 } else if (streq(name
, s
))
712 static int find_symlinks_fd(
713 const char *root_dir
,
714 UnitFileInstallInfo
*i
,
718 const char *config_path
,
719 bool *same_name_link
) {
721 _cleanup_closedir_
DIR *d
= NULL
;
729 assert(same_name_link
);
737 FOREACH_DIRENT(de
, d
, return -errno
) {
739 dirent_ensure_type(d
, de
);
741 if (de
->d_type
== DT_DIR
) {
742 _cleanup_free_
char *p
= NULL
;
745 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
755 p
= path_make_absolute(de
->d_name
, path
);
761 /* This will close nfd, regardless whether it succeeds or not */
762 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
763 p
, config_path
, same_name_link
);
769 } else if (de
->d_type
== DT_LNK
) {
770 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
771 bool found_path
, found_dest
, b
= false;
774 /* Acquire symlink name */
775 p
= path_make_absolute(de
->d_name
, path
);
779 /* Acquire symlink destination */
780 q
= readlink_malloc(p
, &dest
);
790 if (!path_is_absolute(dest
)) {
793 x
= prefix_root(root_dir
, dest
);
801 /* Check if the symlink itself matches what we
803 if (path_is_absolute(i
->name
))
804 found_path
= path_equal(p
, i
->name
);
806 found_path
= streq(de
->d_name
, i
->name
);
808 /* Check if what the symlink points to
809 * matches what we are looking for */
810 if (path_is_absolute(i
->name
))
811 found_dest
= path_equal(dest
, i
->name
);
813 found_dest
= streq(basename(dest
), i
->name
);
815 if (found_path
&& found_dest
) {
816 _cleanup_free_
char *t
= NULL
;
818 /* Filter out same name links in the main
820 t
= path_make_absolute(i
->name
, config_path
);
824 b
= path_equal(t
, p
);
828 *same_name_link
= true;
829 else if (found_path
|| found_dest
) {
833 /* Check if symlink name is in the set of names used by [Install] */
834 q
= is_symlink_with_known_name(i
, de
->d_name
);
846 static int find_symlinks(
847 const char *root_dir
,
848 UnitFileInstallInfo
*i
,
850 const char *config_path
,
851 bool *same_name_link
) {
857 assert(same_name_link
);
859 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
861 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
866 /* This takes possession of fd and closes it */
867 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
868 config_path
, config_path
, same_name_link
);
871 static int find_symlinks_in_scope(
873 const LookupPaths
*paths
,
874 UnitFileInstallInfo
*i
,
876 UnitFileState
*state
) {
878 bool same_name_link_runtime
= false, same_name_link_config
= false;
879 bool enabled_in_runtime
= false, enabled_at_all
= false;
886 STRV_FOREACH(p
, paths
->search_path
) {
887 bool same_name_link
= false;
889 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
893 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
895 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
896 /* This is the best outcome, let's return it immediately. */
897 *state
= UNIT_FILE_ENABLED
;
901 /* look for global enablement of user units */
902 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
903 *state
= UNIT_FILE_ENABLED
;
907 r
= path_is_runtime(paths
, *p
, false);
911 enabled_in_runtime
= true;
913 enabled_at_all
= true;
915 } else if (same_name_link
) {
916 if (path_equal_ptr(*p
, paths
->persistent_config
))
917 same_name_link_config
= true;
919 r
= path_is_runtime(paths
, *p
, false);
923 same_name_link_runtime
= true;
928 if (enabled_in_runtime
) {
929 *state
= UNIT_FILE_ENABLED_RUNTIME
;
933 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
934 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
935 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
936 * something, and hence are a much stronger concept. */
937 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
938 *state
= UNIT_FILE_STATIC
;
942 /* Hmm, we didn't find it, but maybe we found the same name
944 if (same_name_link_config
) {
945 *state
= UNIT_FILE_LINKED
;
948 if (same_name_link_runtime
) {
949 *state
= UNIT_FILE_LINKED_RUNTIME
;
956 static void install_info_free(UnitFileInstallInfo
*i
) {
963 strv_free(i
->aliases
);
964 strv_free(i
->wanted_by
);
965 strv_free(i
->required_by
);
967 free(i
->default_instance
);
968 free(i
->symlink_target
);
972 static void install_context_done(InstallContext
*c
) {
975 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
976 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
979 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
980 UnitFileInstallInfo
*i
;
982 i
= ordered_hashmap_get(c
->have_processed
, name
);
986 return ordered_hashmap_get(c
->will_process
, name
);
989 static int install_info_may_process(
990 UnitFileInstallInfo
*i
,
991 const LookupPaths
*paths
,
992 UnitFileChange
**changes
,
997 /* Checks whether the loaded unit file is one we should process, or is masked,
998 * transient or generated and thus not subject to enable/disable operations. */
1000 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1001 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1004 if (path_is_generator(paths
, i
->path
) ||
1005 path_is_transient(paths
, i
->path
)) {
1006 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1007 return -EADDRNOTAVAIL
;
1014 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1015 * hashmap, or retrieves the existing one if already present.
1017 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1019 static int install_info_add(
1024 UnitFileInstallInfo
**ret
) {
1026 UnitFileInstallInfo
*i
= NULL
;
1030 assert(name
|| path
);
1033 name
= basename(path
);
1035 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1038 i
= install_info_find(c
, name
);
1040 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1047 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1051 i
= new0(UnitFileInstallInfo
, 1);
1054 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1055 i
->auxiliary
= auxiliary
;
1057 i
->name
= strdup(name
);
1064 i
->path
= strdup(path
);
1071 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1081 install_info_free(i
);
1085 static int config_parse_alias(
1087 const char *filename
,
1089 const char *section
,
1090 unsigned section_line
,
1104 type
= unit_name_to_type(unit
);
1105 if (!unit_type_may_alias(type
))
1106 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1107 "Alias= is not allowed for %s units, ignoring.",
1108 unit_type_to_string(type
));
1110 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1111 lvalue
, ltype
, rvalue
, data
, userdata
);
1114 static int config_parse_also(
1116 const char *filename
,
1118 const char *section
,
1119 unsigned section_line
,
1126 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1127 InstallContext
*c
= data
;
1136 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1138 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1144 r
= install_full_printf(info
, word
, &printed
);
1148 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1151 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1155 r
= strv_push(&info
->also
, printed
);
1165 static int config_parse_default_instance(
1167 const char *filename
,
1169 const char *section
,
1170 unsigned section_line
,
1177 UnitFileInstallInfo
*i
= data
;
1178 _cleanup_free_
char *printed
= NULL
;
1186 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1187 /* When enabling an instance, we might be using a template unit file,
1188 * but we should ignore DefaultInstance silently. */
1190 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1191 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1192 "DefaultInstance= only makes sense for template units, ignoring.");
1194 r
= install_full_printf(i
, rvalue
, &printed
);
1198 if (!unit_instance_is_valid(printed
))
1201 return free_and_replace(i
->default_instance
, printed
);
1204 static int unit_file_load(
1206 UnitFileInstallInfo
*info
,
1208 const char *root_dir
,
1209 SearchFlags flags
) {
1211 const ConfigTableItem items
[] = {
1212 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1213 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1214 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1215 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1216 { "Install", "Also", config_parse_also
, 0, c
},
1221 _cleanup_fclose_
FILE *f
= NULL
;
1222 _cleanup_close_
int fd
= -1;
1229 if (!(flags
& SEARCH_DROPIN
)) {
1230 /* Loading or checking for the main unit file… */
1232 type
= unit_name_to_type(info
->name
);
1235 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1236 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1240 if (!(flags
& SEARCH_LOAD
)) {
1241 r
= lstat(path
, &st
);
1245 if (null_or_empty(&st
))
1246 info
->type
= UNIT_FILE_TYPE_MASKED
;
1247 else if (S_ISREG(st
.st_mode
))
1248 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1249 else if (S_ISLNK(st
.st_mode
))
1251 else if (S_ISDIR(st
.st_mode
))
1259 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1263 /* 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. */
1265 if (!(flags
& SEARCH_LOAD
))
1268 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1273 if (fstat(fd
, &st
) < 0)
1276 if (null_or_empty(&st
)) {
1277 if ((flags
& SEARCH_DROPIN
) == 0)
1278 info
->type
= UNIT_FILE_TYPE_MASKED
;
1283 r
= stat_verify_regular(&st
);
1287 f
= fdopen(fd
, "re");
1292 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1295 r
= config_parse(info
->name
, path
, f
,
1297 config_item_table_lookup
, items
,
1298 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1300 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1302 if ((flags
& SEARCH_DROPIN
) == 0)
1303 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1306 (int) strv_length(info
->aliases
) +
1307 (int) strv_length(info
->wanted_by
) +
1308 (int) strv_length(info
->required_by
);
1311 static int unit_file_load_or_readlink(
1313 UnitFileInstallInfo
*info
,
1315 const char *root_dir
,
1316 SearchFlags flags
) {
1318 _cleanup_free_
char *target
= NULL
;
1321 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1322 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1325 /* This is a symlink, let's read it. */
1327 r
= readlink_malloc(path
, &target
);
1331 if (path_equal(target
, "/dev/null"))
1332 info
->type
= UNIT_FILE_TYPE_MASKED
;
1337 bn
= basename(target
);
1339 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1341 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1344 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1346 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1349 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1351 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1356 /* Enforce that the symlink destination does not
1357 * change the unit file type. */
1359 a
= unit_name_to_type(info
->name
);
1360 b
= unit_name_to_type(bn
);
1361 if (a
< 0 || b
< 0 || a
!= b
)
1364 if (path_is_absolute(target
))
1365 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1366 info
->symlink_target
= prefix_root(root_dir
, target
);
1368 /* This is a relative path, take it relative to the dir the symlink is located in. */
1369 info
->symlink_target
= file_in_same_dir(path
, target
);
1370 if (!info
->symlink_target
)
1373 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1379 static int unit_file_search(
1381 UnitFileInstallInfo
*info
,
1382 const LookupPaths
*paths
,
1383 SearchFlags flags
) {
1385 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1386 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1387 _cleanup_free_
char *template = NULL
;
1388 bool found_unit
= false;
1395 /* Was this unit already loaded? */
1396 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1400 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1404 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1405 r
= unit_name_template(info
->name
, &template);
1410 STRV_FOREACH(p
, paths
->search_path
) {
1411 _cleanup_free_
char *path
= NULL
;
1413 path
= strjoin(*p
, "/", info
->name
);
1417 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1419 info
->path
= TAKE_PTR(path
);
1423 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1427 if (!found_unit
&& template) {
1429 /* Unit file doesn't exist, however instance
1430 * enablement was requested. We will check if it is
1431 * possible to load template unit file. */
1433 STRV_FOREACH(p
, paths
->search_path
) {
1434 _cleanup_free_
char *path
= NULL
;
1436 path
= strjoin(*p
, "/", template);
1440 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1442 info
->path
= TAKE_PTR(path
);
1446 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1452 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1456 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1459 /* Search for drop-in directories */
1461 dropin_dir_name
= strjoina(info
->name
, ".d");
1462 STRV_FOREACH(p
, paths
->search_path
) {
1465 path
= path_join(NULL
, *p
, dropin_dir_name
);
1469 r
= strv_consume(&dirs
, path
);
1475 dropin_template_dir_name
= strjoina(template, ".d");
1476 STRV_FOREACH(p
, paths
->search_path
) {
1479 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1483 r
= strv_consume(&dirs
, path
);
1489 /* Load drop-in conf files */
1491 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1493 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1495 STRV_FOREACH(p
, files
) {
1496 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1498 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1504 static int install_info_follow(
1506 UnitFileInstallInfo
*i
,
1507 const char *root_dir
,
1509 bool ignore_different_name
) {
1514 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1516 if (!i
->symlink_target
)
1519 /* If the basename doesn't match, the caller should add a
1520 * complete new entry for this. */
1522 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1525 free_and_replace(i
->path
, i
->symlink_target
);
1526 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1528 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1532 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1533 * target, maybe more than once. Propagate the instance name if present.
1535 static int install_info_traverse(
1536 UnitFileScope scope
,
1538 const LookupPaths
*paths
,
1539 UnitFileInstallInfo
*start
,
1541 UnitFileInstallInfo
**ret
) {
1543 UnitFileInstallInfo
*i
;
1551 r
= unit_file_search(c
, start
, paths
, flags
);
1556 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1557 /* Follow the symlink */
1559 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1562 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1563 r
= path_is_config(paths
, i
->path
, true);
1570 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1572 _cleanup_free_
char *buffer
= NULL
;
1575 /* Target has a different name, create a new
1576 * install info object for that, and continue
1579 bn
= basename(i
->symlink_target
);
1581 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1582 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1584 _cleanup_free_
char *instance
= NULL
;
1586 r
= unit_name_to_instance(i
->name
, &instance
);
1590 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1594 if (streq(buffer
, i
->name
)) {
1596 /* We filled in the instance, and the target stayed the same? If so, then let's
1597 * honour the link as it is. */
1599 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1609 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1613 /* Try again, with the new target we found. */
1614 r
= unit_file_search(c
, i
, paths
, flags
);
1616 /* Translate error code to highlight this specific case */
1631 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1632 * or the name (otherwise). root_dir is prepended to the path.
1634 static int install_info_add_auto(
1636 const LookupPaths
*paths
,
1637 const char *name_or_path
,
1638 UnitFileInstallInfo
**ret
) {
1641 assert(name_or_path
);
1643 if (path_is_absolute(name_or_path
)) {
1646 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1648 return install_info_add(c
, NULL
, pp
, false, ret
);
1650 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1653 static int install_info_discover(
1654 UnitFileScope scope
,
1656 const LookupPaths
*paths
,
1659 UnitFileInstallInfo
**ret
,
1660 UnitFileChange
**changes
,
1661 size_t *n_changes
) {
1663 UnitFileInstallInfo
*i
;
1670 r
= install_info_add_auto(c
, paths
, name
, &i
);
1672 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1675 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1679 static int install_info_discover_and_check(
1680 UnitFileScope scope
,
1682 const LookupPaths
*paths
,
1685 UnitFileInstallInfo
**ret
,
1686 UnitFileChange
**changes
,
1687 size_t *n_changes
) {
1691 r
= install_info_discover(scope
, c
, paths
, name
, flags
, ret
, changes
, n_changes
);
1695 return install_info_may_process(ret
? *ret
: NULL
, paths
, changes
, n_changes
);
1698 static int install_info_symlink_alias(
1699 UnitFileInstallInfo
*i
,
1700 const LookupPaths
*paths
,
1701 const char *config_path
,
1703 UnitFileChange
**changes
,
1704 size_t *n_changes
) {
1711 assert(config_path
);
1713 STRV_FOREACH(s
, i
->aliases
) {
1714 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1716 q
= install_full_printf(i
, *s
, &dst
);
1720 alias_path
= path_make_absolute(dst
, config_path
);
1724 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1732 static int install_info_symlink_wants(
1733 UnitFileInstallInfo
*i
,
1734 const LookupPaths
*paths
,
1735 const char *config_path
,
1738 UnitFileChange
**changes
,
1739 size_t *n_changes
) {
1741 _cleanup_free_
char *buf
= NULL
;
1748 assert(config_path
);
1750 if (strv_isempty(list
))
1753 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1754 UnitFileInstallInfo instance
= {
1755 .type
= _UNIT_FILE_TYPE_INVALID
,
1757 _cleanup_free_
char *path
= NULL
;
1759 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1763 instance
.name
= buf
;
1764 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1768 path
= TAKE_PTR(instance
.path
);
1770 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1771 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1779 STRV_FOREACH(s
, list
) {
1780 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1782 q
= install_full_printf(i
, *s
, &dst
);
1786 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1791 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1795 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1803 static int install_info_symlink_link(
1804 UnitFileInstallInfo
*i
,
1805 const LookupPaths
*paths
,
1806 const char *config_path
,
1808 UnitFileChange
**changes
,
1809 size_t *n_changes
) {
1811 _cleanup_free_
char *path
= NULL
;
1816 assert(config_path
);
1819 r
= in_search_path(paths
, i
->path
);
1825 path
= strjoin(config_path
, "/", i
->name
);
1829 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1832 static int install_info_apply(
1833 UnitFileInstallInfo
*i
,
1834 const LookupPaths
*paths
,
1835 const char *config_path
,
1837 UnitFileChange
**changes
,
1838 size_t *n_changes
) {
1844 assert(config_path
);
1846 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1849 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1851 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1855 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1859 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1860 /* Do not count links to the unit file towards the "carries_install_info" count */
1861 if (r
== 0 && q
< 0)
1867 static int install_context_apply(
1868 UnitFileScope scope
,
1870 const LookupPaths
*paths
,
1871 const char *config_path
,
1874 UnitFileChange
**changes
,
1875 size_t *n_changes
) {
1877 UnitFileInstallInfo
*i
;
1882 assert(config_path
);
1884 if (ordered_hashmap_isempty(c
->will_process
))
1887 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1892 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1895 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1899 q
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1901 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1905 /* We can attempt to process a masked unit when a different unit
1906 * that we were processing specifies it in Also=. */
1907 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1908 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1910 /* Assume that something *could* have been enabled here,
1911 * avoid "empty [Install] section" warning. */
1916 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1919 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1931 static int install_context_mark_for_removal(
1932 UnitFileScope scope
,
1934 const LookupPaths
*paths
,
1935 Set
**remove_symlinks_to
,
1936 UnitFileChange
**changes
,
1937 size_t *n_changes
) {
1939 UnitFileInstallInfo
*i
;
1945 /* Marks all items for removal */
1947 if (ordered_hashmap_isempty(c
->will_process
))
1950 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1954 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1956 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1960 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1961 if (r
== -ENOLINK
) {
1962 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1963 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1964 } else if (r
== -ENOENT
) {
1966 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1967 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1969 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1970 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1974 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1975 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1976 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1977 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1978 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1980 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1981 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1985 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1994 UnitFileScope scope
,
1995 UnitFileFlags flags
,
1996 const char *root_dir
,
1998 UnitFileChange
**changes
,
1999 size_t *n_changes
) {
2001 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2002 const char *config_path
;
2007 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2009 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2013 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2017 STRV_FOREACH(i
, files
) {
2018 _cleanup_free_
char *path
= NULL
;
2021 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2027 path
= path_make_absolute(*i
, config_path
);
2031 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2032 if (q
< 0 && r
>= 0)
2039 int unit_file_unmask(
2040 UnitFileScope scope
,
2041 UnitFileFlags flags
,
2042 const char *root_dir
,
2044 UnitFileChange
**changes
,
2045 size_t *n_changes
) {
2047 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2048 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2049 _cleanup_strv_free_
char **todo
= NULL
;
2050 size_t n_todo
= 0, n_allocated
= 0;
2051 const char *config_path
;
2053 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2057 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2059 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2063 STRV_FOREACH(i
, files
) {
2064 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2067 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2068 _cleanup_free_
char *path
= NULL
;
2070 path
= path_make_absolute(*i
, config_path
);
2074 r
= null_or_empty_path(path
);
2082 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2085 todo
[n_todo
] = strdup(*i
);
2096 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2097 STRV_FOREACH(i
, todo
) {
2098 _cleanup_free_
char *path
= NULL
;
2101 path
= path_make_absolute(*i
, config_path
);
2105 if (!dry_run
&& unlink(path
) < 0) {
2106 if (errno
!= ENOENT
) {
2109 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2115 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2117 rp
= skip_root(&paths
, path
);
2118 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2123 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2132 UnitFileScope scope
,
2133 UnitFileFlags flags
,
2134 const char *root_dir
,
2136 UnitFileChange
**changes
,
2137 size_t *n_changes
) {
2139 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2140 _cleanup_strv_free_
char **todo
= NULL
;
2141 size_t n_todo
= 0, n_allocated
= 0;
2142 const char *config_path
;
2147 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2149 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2153 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2157 STRV_FOREACH(i
, files
) {
2158 _cleanup_free_
char *full
= NULL
;
2162 if (!path_is_absolute(*i
))
2166 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2169 full
= prefix_root(paths
.root_dir
, *i
);
2173 if (lstat(full
, &st
) < 0)
2175 r
= stat_verify_regular(&st
);
2179 q
= in_search_path(&paths
, *i
);
2185 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2188 todo
[n_todo
] = strdup(*i
);
2198 STRV_FOREACH(i
, todo
) {
2199 _cleanup_free_
char *new_path
= NULL
;
2201 new_path
= path_make_absolute(basename(*i
), config_path
);
2205 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2206 if (q
< 0 && r
>= 0)
2213 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2219 /* Checks whether the path is one where the drop-in directories shall be removed. */
2221 r
= path_is_config(paths
, path
, true);
2225 r
= path_is_control(paths
, path
);
2229 return path_is_transient(paths
, path
);
2232 int unit_file_revert(
2233 UnitFileScope scope
,
2234 const char *root_dir
,
2236 UnitFileChange
**changes
,
2237 size_t *n_changes
) {
2239 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2240 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2241 _cleanup_strv_free_
char **todo
= NULL
;
2242 size_t n_todo
= 0, n_allocated
= 0;
2246 /* Puts a unit file back into vendor state. This means:
2248 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2249 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2251 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2252 * "config", but not in "transient" or "control" or even "generated").
2254 * We remove all that in both the runtime and the persistent directories, if that applies.
2257 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2261 STRV_FOREACH(i
, files
) {
2262 bool has_vendor
= false;
2265 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2268 STRV_FOREACH(p
, paths
.search_path
) {
2269 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2272 path
= path_make_absolute(*i
, *p
);
2276 r
= lstat(path
, &st
);
2278 if (errno
!= ENOENT
)
2280 } else if (S_ISREG(st
.st_mode
)) {
2281 /* Check if there's a vendor version */
2282 r
= path_is_vendor(&paths
, path
);
2289 dropin
= strappend(path
, ".d");
2293 r
= lstat(dropin
, &st
);
2295 if (errno
!= ENOENT
)
2297 } else if (S_ISDIR(st
.st_mode
)) {
2298 /* Remove the drop-ins */
2299 r
= path_shall_revert(&paths
, dropin
);
2303 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2306 todo
[n_todo
++] = TAKE_PTR(dropin
);
2314 /* OK, there's a vendor version, hence drop all configuration versions */
2315 STRV_FOREACH(p
, paths
.search_path
) {
2316 _cleanup_free_
char *path
= NULL
;
2319 path
= path_make_absolute(*i
, *p
);
2323 r
= lstat(path
, &st
);
2325 if (errno
!= ENOENT
)
2327 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2328 r
= path_is_config(&paths
, path
, true);
2332 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2335 todo
[n_todo
++] = TAKE_PTR(path
);
2344 STRV_FOREACH(i
, todo
) {
2345 _cleanup_strv_free_
char **fs
= NULL
;
2349 (void) get_files_in_directory(*i
, &fs
);
2351 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2352 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2357 STRV_FOREACH(j
, fs
) {
2358 _cleanup_free_
char *t
= NULL
;
2360 t
= strjoin(*i
, "/", *j
);
2364 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2367 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2369 rp
= skip_root(&paths
, *i
);
2370 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2375 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2379 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2386 int unit_file_add_dependency(
2387 UnitFileScope scope
,
2388 UnitFileFlags flags
,
2389 const char *root_dir
,
2393 UnitFileChange
**changes
,
2394 size_t *n_changes
) {
2396 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2397 _cleanup_(install_context_done
) InstallContext c
= {};
2398 UnitFileInstallInfo
*i
, *target_info
;
2399 const char *config_path
;
2404 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2407 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2410 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2413 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2417 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2421 r
= install_info_discover_and_check(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2422 &target_info
, changes
, n_changes
);
2426 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2428 STRV_FOREACH(f
, files
) {
2431 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2432 &i
, changes
, n_changes
);
2436 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2438 /* We didn't actually load anything from the unit
2439 * file, but instead just add in our new symlink to
2442 if (dep
== UNIT_WANTS
)
2445 l
= &i
->required_by
;
2448 *l
= strv_new(target_info
->name
);
2453 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2456 int unit_file_enable(
2457 UnitFileScope scope
,
2458 UnitFileFlags flags
,
2459 const char *root_dir
,
2461 UnitFileChange
**changes
,
2462 size_t *n_changes
) {
2464 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2465 _cleanup_(install_context_done
) InstallContext c
= {};
2466 const char *config_path
;
2467 UnitFileInstallInfo
*i
;
2472 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2474 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2478 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2482 STRV_FOREACH(f
, files
) {
2483 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2484 &i
, changes
, n_changes
);
2488 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2491 /* This will return the number of symlink rules that were
2492 supposed to be created, not the ones actually created. This
2493 is useful to determine whether the passed files had any
2494 installation data at all. */
2496 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2499 int unit_file_disable(
2500 UnitFileScope scope
,
2501 UnitFileFlags flags
,
2502 const char *root_dir
,
2504 UnitFileChange
**changes
,
2505 size_t *n_changes
) {
2507 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2508 _cleanup_(install_context_done
) InstallContext c
= {};
2509 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2510 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2511 const char *config_path
;
2516 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2518 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2522 STRV_FOREACH(i
, files
) {
2523 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2526 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2531 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2535 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2536 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, 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
,
2663 /* Shortcut things, if the caller just wants to know if this unit exists. */
2669 case UNIT_FILE_TYPE_MASKED
:
2670 r
= path_is_runtime(paths
, i
->path
, true);
2674 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2677 case UNIT_FILE_TYPE_REGULAR
:
2678 r
= path_is_generator(paths
, i
->path
);
2682 state
= UNIT_FILE_GENERATED
;
2686 r
= path_is_transient(paths
, i
->path
);
2690 state
= UNIT_FILE_TRANSIENT
;
2694 /* Check if any of the Alias= symlinks have been created.
2695 * We ignore other aliases, and only check those that would
2696 * be created by systemctl enable for this unit. */
2697 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2703 /* Check if the file is known under other names. If it is,
2704 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2705 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2709 state
= UNIT_FILE_INDIRECT
;
2711 if (unit_file_install_info_has_rules(i
))
2712 state
= UNIT_FILE_DISABLED
;
2713 else if (unit_file_install_info_has_also(i
))
2714 state
= UNIT_FILE_INDIRECT
;
2716 state
= UNIT_FILE_STATIC
;
2722 assert_not_reached("Unexpect unit file type.");
2729 int unit_file_get_state(
2730 UnitFileScope scope
,
2731 const char *root_dir
,
2733 UnitFileState
*ret
) {
2735 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2739 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2742 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2746 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2749 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2750 _cleanup_(install_context_done
) InstallContext c
= {};
2756 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2759 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2768 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2769 _cleanup_strv_free_
char **instances
= NULL
;
2770 _cleanup_free_
char *unit_name
= NULL
;
2774 assert(out_instances
);
2775 assert(out_unit_name
);
2777 r
= extract_first_word(&pattern
, &unit_name
, NULL
, 0);
2781 /* We handle the instances logic when unit name is extracted */
2783 /* We only create instances when a rule of templated unit
2784 * is seen. A rule like enable foo@.service a b c will
2785 * result in an array of (a, b, c) as instance names */
2786 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2789 instances
= strv_split(pattern
, WHITESPACE
);
2793 *out_instances
= TAKE_PTR(instances
);
2796 *out_unit_name
= TAKE_PTR(unit_name
);
2801 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2802 _cleanup_(presets_freep
) Presets ps
= {};
2803 size_t n_allocated
= 0;
2804 _cleanup_strv_free_
char **files
= NULL
;
2809 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2813 case UNIT_FILE_SYSTEM
:
2814 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2815 "/etc/systemd/system-preset",
2816 "/run/systemd/system-preset",
2817 "/usr/local/lib/systemd/system-preset",
2818 "/usr/lib/systemd/system-preset",
2820 "/lib/systemd/system-preset",
2825 case UNIT_FILE_GLOBAL
:
2826 case UNIT_FILE_USER
:
2827 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2828 "/etc/systemd/user-preset",
2829 "/run/systemd/user-preset",
2830 "/usr/local/lib/systemd/user-preset",
2831 "/usr/lib/systemd/user-preset",
2836 assert_not_reached("Invalid unit file scope");
2842 STRV_FOREACH(p
, files
) {
2843 _cleanup_fclose_
FILE *f
;
2846 f
= fopen(*p
, "re");
2848 if (errno
== ENOENT
)
2855 _cleanup_free_
char *line
= NULL
;
2856 PresetRule rule
= {};
2857 const char *parameter
;
2860 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2871 if (strchr(COMMENTS
, *l
))
2874 parameter
= first_word(l
, "enable");
2877 char **instances
= NULL
;
2879 /* Unit_name will remain the same as parameter when no instances are specified */
2880 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2882 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2886 rule
= (PresetRule
) {
2887 .pattern
= unit_name
,
2888 .action
= PRESET_ENABLE
,
2889 .instances
= instances
,
2893 parameter
= first_word(l
, "disable");
2897 pattern
= strdup(parameter
);
2901 rule
= (PresetRule
) {
2903 .action
= PRESET_DISABLE
,
2908 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2911 ps
.rules
[ps
.n_rules
++] = rule
;
2915 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2925 static int pattern_match_multiple_instances(
2926 const PresetRule rule
,
2927 const char *unit_name
,
2930 _cleanup_free_
char *templated_name
= NULL
;
2933 /* If no ret is needed or the rule itself does not have instances
2934 * initalized, we return not matching */
2935 if (!ret
|| !rule
.instances
)
2938 r
= unit_name_template(unit_name
, &templated_name
);
2941 if (!streq(rule
.pattern
, templated_name
))
2944 /* Compose a list of specified instances when unit name is a template */
2945 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
2946 _cleanup_free_
char *prefix
= NULL
;
2947 _cleanup_strv_free_
char **out_strv
= NULL
;
2950 r
= unit_name_to_prefix(unit_name
, &prefix
);
2954 STRV_FOREACH(iter
, rule
.instances
) {
2955 _cleanup_free_
char *name
= NULL
;
2956 r
= unit_name_build(prefix
, *iter
, ".service", &name
);
2959 r
= strv_extend(&out_strv
, name
);
2964 *ret
= TAKE_PTR(out_strv
);
2967 /* We now know the input unit name is an instance name */
2968 _cleanup_free_
char *instance_name
= NULL
;
2970 r
= unit_name_to_instance(unit_name
, &instance_name
);
2974 if (strv_find(rule
.instances
, instance_name
))
2980 static int query_presets(const char *name
, const Presets presets
, char ***instance_name_list
) {
2981 PresetAction action
= PRESET_UNKNOWN
;
2984 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2987 for (i
= 0; i
< presets
.n_rules
; i
++)
2988 if (pattern_match_multiple_instances(presets
.rules
[i
], name
, instance_name_list
) > 0 ||
2989 fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2990 action
= presets
.rules
[i
].action
;
2995 case PRESET_UNKNOWN
:
2996 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2999 if (instance_name_list
&& *instance_name_list
)
3000 STRV_FOREACH(s
, *instance_name_list
)
3001 log_debug("Preset files say enable %s.", *s
);
3003 log_debug("Preset files say enable %s.", name
);
3005 case PRESET_DISABLE
:
3006 log_debug("Preset files say disable %s.", name
);
3009 assert_not_reached("invalid preset action");
3013 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
3014 _cleanup_(presets_freep
) Presets presets
= {};
3017 r
= read_presets(scope
, root_dir
, &presets
);
3021 return query_presets(name
, presets
, NULL
);
3024 static int execute_preset(
3025 UnitFileScope scope
,
3026 UnitFileFlags flags
,
3027 InstallContext
*plus
,
3028 InstallContext
*minus
,
3029 const LookupPaths
*paths
,
3031 UnitFilePresetMode mode
,
3032 UnitFileChange
**changes
,
3033 size_t *n_changes
) {
3035 const char *config_path
;
3036 bool force
= !!(flags
& UNIT_FILE_FORCE
);
3037 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
3044 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3045 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3047 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
3051 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
3052 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
3058 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3059 /* Returns number of symlinks that where supposed to be installed. */
3060 q
= install_context_apply(scope
, plus
, paths
,
3061 runtime
? paths
->runtime_config
: paths
->persistent_config
,
3062 force
, SEARCH_LOAD
, changes
, n_changes
);
3070 static int preset_prepare_one(
3071 UnitFileScope scope
,
3072 InstallContext
*plus
,
3073 InstallContext
*minus
,
3077 UnitFileChange
**changes
,
3078 size_t *n_changes
) {
3080 _cleanup_(install_context_done
) InstallContext tmp
= {};
3081 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3082 UnitFileInstallInfo
*i
;
3085 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3088 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3089 &i
, changes
, n_changes
);
3092 if (!streq(name
, i
->name
)) {
3093 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3097 r
= query_presets(name
, presets
, &instance_name_list
);
3102 if (instance_name_list
) {
3104 STRV_FOREACH(s
, instance_name_list
) {
3105 r
= install_info_discover_and_check(scope
, plus
, paths
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3106 &i
, changes
, n_changes
);
3111 r
= install_info_discover_and_check(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3112 &i
, changes
, n_changes
);
3118 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3119 &i
, changes
, n_changes
);
3124 int unit_file_preset(
3125 UnitFileScope scope
,
3126 UnitFileFlags flags
,
3127 const char *root_dir
,
3129 UnitFilePresetMode mode
,
3130 UnitFileChange
**changes
,
3131 size_t *n_changes
) {
3133 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3134 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3135 _cleanup_(presets_freep
) Presets presets
= {};
3140 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3141 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3143 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3147 r
= read_presets(scope
, root_dir
, &presets
);
3151 STRV_FOREACH(i
, files
) {
3152 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3157 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3160 int unit_file_preset_all(
3161 UnitFileScope scope
,
3162 UnitFileFlags flags
,
3163 const char *root_dir
,
3164 UnitFilePresetMode mode
,
3165 UnitFileChange
**changes
,
3166 size_t *n_changes
) {
3168 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3169 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3170 _cleanup_(presets_freep
) Presets presets
= {};
3175 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3176 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3178 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3182 r
= read_presets(scope
, root_dir
, &presets
);
3186 STRV_FOREACH(i
, paths
.search_path
) {
3187 _cleanup_closedir_
DIR *d
= NULL
;
3192 if (errno
== ENOENT
)
3198 FOREACH_DIRENT(de
, d
, return -errno
) {
3199 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3202 dirent_ensure_type(d
, de
);
3204 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3207 /* we don't pass changes[] in, because we want to handle errors on our own */
3208 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3210 r
= unit_file_changes_add(changes
, n_changes
,
3211 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3212 else if (r
== -ENOLINK
)
3213 r
= unit_file_changes_add(changes
, n_changes
,
3214 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3215 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3222 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3225 static void unit_file_list_free_one(UnitFileList
*f
) {
3233 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3234 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3237 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3239 int unit_file_get_list(
3240 UnitFileScope scope
,
3241 const char *root_dir
,
3246 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3251 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3254 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3258 STRV_FOREACH(i
, paths
.search_path
) {
3259 _cleanup_closedir_
DIR *d
= NULL
;
3264 if (errno
== ENOENT
)
3266 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3267 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3274 FOREACH_DIRENT(de
, d
, return -errno
) {
3275 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3277 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3280 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3283 if (hashmap_get(h
, de
->d_name
))
3286 dirent_ensure_type(d
, de
);
3288 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3291 f
= new0(UnitFileList
, 1);
3295 f
->path
= path_make_absolute(de
->d_name
, *i
);
3299 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3301 f
->state
= UNIT_FILE_BAD
;
3303 if (!strv_isempty(states
) &&
3304 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3307 r
= hashmap_put(h
, basename(f
->path
), f
);
3311 f
= NULL
; /* prevent cleanup */
3318 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3319 [UNIT_FILE_ENABLED
] = "enabled",
3320 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3321 [UNIT_FILE_LINKED
] = "linked",
3322 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3323 [UNIT_FILE_MASKED
] = "masked",
3324 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3325 [UNIT_FILE_STATIC
] = "static",
3326 [UNIT_FILE_DISABLED
] = "disabled",
3327 [UNIT_FILE_INDIRECT
] = "indirect",
3328 [UNIT_FILE_GENERATED
] = "generated",
3329 [UNIT_FILE_TRANSIENT
] = "transient",
3330 [UNIT_FILE_BAD
] = "bad",
3333 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3335 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3336 [UNIT_FILE_SYMLINK
] = "symlink",
3337 [UNIT_FILE_UNLINK
] = "unlink",
3338 [UNIT_FILE_IS_MASKED
] = "masked",
3339 [UNIT_FILE_IS_DANGLING
] = "dangling",
3342 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3344 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3345 [UNIT_FILE_PRESET_FULL
] = "full",
3346 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3347 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3350 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);