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 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1237 "Unit type %s cannot be templated.", unit_type_to_string(type
));
1239 if (!(flags
& SEARCH_LOAD
)) {
1240 r
= lstat(path
, &st
);
1244 if (null_or_empty(&st
))
1245 info
->type
= UNIT_FILE_TYPE_MASKED
;
1246 else if (S_ISREG(st
.st_mode
))
1247 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1248 else if (S_ISLNK(st
.st_mode
))
1250 else if (S_ISDIR(st
.st_mode
))
1258 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1262 /* 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. */
1264 if (!(flags
& SEARCH_LOAD
))
1267 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1272 if (fstat(fd
, &st
) < 0)
1275 if (null_or_empty(&st
)) {
1276 if ((flags
& SEARCH_DROPIN
) == 0)
1277 info
->type
= UNIT_FILE_TYPE_MASKED
;
1282 r
= stat_verify_regular(&st
);
1286 f
= fdopen(fd
, "re");
1291 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1294 r
= config_parse(info
->name
, path
, f
,
1296 config_item_table_lookup
, items
,
1297 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1299 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1301 if ((flags
& SEARCH_DROPIN
) == 0)
1302 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1305 (int) strv_length(info
->aliases
) +
1306 (int) strv_length(info
->wanted_by
) +
1307 (int) strv_length(info
->required_by
);
1310 static int unit_file_load_or_readlink(
1312 UnitFileInstallInfo
*info
,
1314 const char *root_dir
,
1315 SearchFlags flags
) {
1317 _cleanup_free_
char *target
= NULL
;
1320 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1321 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1324 /* This is a symlink, let's read it. */
1326 r
= readlink_malloc(path
, &target
);
1330 if (path_equal(target
, "/dev/null"))
1331 info
->type
= UNIT_FILE_TYPE_MASKED
;
1336 bn
= basename(target
);
1338 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1340 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1343 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1345 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1348 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1350 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1355 /* Enforce that the symlink destination does not
1356 * change the unit file type. */
1358 a
= unit_name_to_type(info
->name
);
1359 b
= unit_name_to_type(bn
);
1360 if (a
< 0 || b
< 0 || a
!= b
)
1363 if (path_is_absolute(target
))
1364 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1365 info
->symlink_target
= prefix_root(root_dir
, target
);
1367 /* This is a relative path, take it relative to the dir the symlink is located in. */
1368 info
->symlink_target
= file_in_same_dir(path
, target
);
1369 if (!info
->symlink_target
)
1372 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1378 static int unit_file_search(
1380 UnitFileInstallInfo
*info
,
1381 const LookupPaths
*paths
,
1382 SearchFlags flags
) {
1384 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1385 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1386 _cleanup_free_
char *template = NULL
;
1387 bool found_unit
= false;
1394 /* Was this unit already loaded? */
1395 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1399 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1403 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1404 r
= unit_name_template(info
->name
, &template);
1409 STRV_FOREACH(p
, paths
->search_path
) {
1410 _cleanup_free_
char *path
= NULL
;
1412 path
= strjoin(*p
, "/", info
->name
);
1416 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1418 info
->path
= TAKE_PTR(path
);
1422 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1426 if (!found_unit
&& template) {
1428 /* Unit file doesn't exist, however instance
1429 * enablement was requested. We will check if it is
1430 * possible to load template unit file. */
1432 STRV_FOREACH(p
, paths
->search_path
) {
1433 _cleanup_free_
char *path
= NULL
;
1435 path
= strjoin(*p
, "/", template);
1439 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1441 info
->path
= TAKE_PTR(path
);
1445 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1451 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1452 "Cannot find unit %s%s%s.",
1453 info
->name
, template ? " or " : "", strempty(template));
1455 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1458 /* Search for drop-in directories */
1460 dropin_dir_name
= strjoina(info
->name
, ".d");
1461 STRV_FOREACH(p
, paths
->search_path
) {
1464 path
= path_join(NULL
, *p
, dropin_dir_name
);
1468 r
= strv_consume(&dirs
, path
);
1474 dropin_template_dir_name
= strjoina(template, ".d");
1475 STRV_FOREACH(p
, paths
->search_path
) {
1478 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1482 r
= strv_consume(&dirs
, path
);
1488 /* Load drop-in conf files */
1490 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1492 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1494 STRV_FOREACH(p
, files
) {
1495 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1497 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1503 static int install_info_follow(
1505 UnitFileInstallInfo
*i
,
1506 const char *root_dir
,
1508 bool ignore_different_name
) {
1513 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1515 if (!i
->symlink_target
)
1518 /* If the basename doesn't match, the caller should add a
1519 * complete new entry for this. */
1521 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1524 free_and_replace(i
->path
, i
->symlink_target
);
1525 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1527 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1531 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1532 * target, maybe more than once. Propagate the instance name if present.
1534 static int install_info_traverse(
1535 UnitFileScope scope
,
1537 const LookupPaths
*paths
,
1538 UnitFileInstallInfo
*start
,
1540 UnitFileInstallInfo
**ret
) {
1542 UnitFileInstallInfo
*i
;
1550 r
= unit_file_search(c
, start
, paths
, flags
);
1555 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1556 /* Follow the symlink */
1558 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1561 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1562 r
= path_is_config(paths
, i
->path
, true);
1569 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1571 _cleanup_free_
char *buffer
= NULL
;
1574 /* Target has a different name, create a new
1575 * install info object for that, and continue
1578 bn
= basename(i
->symlink_target
);
1580 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1581 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1583 _cleanup_free_
char *instance
= NULL
;
1585 r
= unit_name_to_instance(i
->name
, &instance
);
1589 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1593 if (streq(buffer
, i
->name
)) {
1595 /* We filled in the instance, and the target stayed the same? If so, then let's
1596 * honour the link as it is. */
1598 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1608 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1612 /* Try again, with the new target we found. */
1613 r
= unit_file_search(c
, i
, paths
, flags
);
1615 /* Translate error code to highlight this specific case */
1630 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1631 * or the name (otherwise). root_dir is prepended to the path.
1633 static int install_info_add_auto(
1635 const LookupPaths
*paths
,
1636 const char *name_or_path
,
1637 UnitFileInstallInfo
**ret
) {
1640 assert(name_or_path
);
1642 if (path_is_absolute(name_or_path
)) {
1645 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1647 return install_info_add(c
, NULL
, pp
, false, ret
);
1649 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1652 static int install_info_discover(
1653 UnitFileScope scope
,
1655 const LookupPaths
*paths
,
1658 UnitFileInstallInfo
**ret
,
1659 UnitFileChange
**changes
,
1660 size_t *n_changes
) {
1662 UnitFileInstallInfo
*i
;
1669 r
= install_info_add_auto(c
, paths
, name
, &i
);
1671 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1674 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1678 static int install_info_discover_and_check(
1679 UnitFileScope scope
,
1681 const LookupPaths
*paths
,
1684 UnitFileInstallInfo
**ret
,
1685 UnitFileChange
**changes
,
1686 size_t *n_changes
) {
1690 r
= install_info_discover(scope
, c
, paths
, name
, flags
, ret
, changes
, n_changes
);
1694 return install_info_may_process(ret
? *ret
: NULL
, paths
, changes
, n_changes
);
1697 static int install_info_symlink_alias(
1698 UnitFileInstallInfo
*i
,
1699 const LookupPaths
*paths
,
1700 const char *config_path
,
1702 UnitFileChange
**changes
,
1703 size_t *n_changes
) {
1710 assert(config_path
);
1712 STRV_FOREACH(s
, i
->aliases
) {
1713 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1715 q
= install_full_printf(i
, *s
, &dst
);
1719 alias_path
= path_make_absolute(dst
, config_path
);
1723 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1731 static int install_info_symlink_wants(
1732 UnitFileInstallInfo
*i
,
1733 const LookupPaths
*paths
,
1734 const char *config_path
,
1737 UnitFileChange
**changes
,
1738 size_t *n_changes
) {
1740 _cleanup_free_
char *buf
= NULL
;
1747 assert(config_path
);
1749 if (strv_isempty(list
))
1752 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1753 UnitFileInstallInfo instance
= {
1754 .type
= _UNIT_FILE_TYPE_INVALID
,
1756 _cleanup_free_
char *path
= NULL
;
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
= strjoin(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 UnitFileChange
**changes
,
1936 size_t *n_changes
) {
1938 UnitFileInstallInfo
*i
;
1944 /* Marks all items for removal */
1946 if (ordered_hashmap_isempty(c
->will_process
))
1949 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1953 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1955 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1959 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1960 if (r
== -ENOLINK
) {
1961 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1962 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1963 } else if (r
== -ENOENT
) {
1965 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1966 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1968 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1969 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1973 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1974 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1975 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1976 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1977 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1979 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1980 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1984 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1993 UnitFileScope scope
,
1994 UnitFileFlags flags
,
1995 const char *root_dir
,
1997 UnitFileChange
**changes
,
1998 size_t *n_changes
) {
2000 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2001 const char *config_path
;
2006 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2008 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2012 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2016 STRV_FOREACH(i
, files
) {
2017 _cleanup_free_
char *path
= NULL
;
2020 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2026 path
= path_make_absolute(*i
, config_path
);
2030 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2031 if (q
< 0 && r
>= 0)
2038 int unit_file_unmask(
2039 UnitFileScope scope
,
2040 UnitFileFlags flags
,
2041 const char *root_dir
,
2043 UnitFileChange
**changes
,
2044 size_t *n_changes
) {
2046 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2047 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2048 _cleanup_strv_free_
char **todo
= NULL
;
2049 size_t n_todo
= 0, n_allocated
= 0;
2050 const char *config_path
;
2052 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2056 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2058 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2062 STRV_FOREACH(i
, files
) {
2063 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2066 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2067 _cleanup_free_
char *path
= NULL
;
2069 path
= path_make_absolute(*i
, config_path
);
2073 r
= null_or_empty_path(path
);
2081 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2084 todo
[n_todo
] = strdup(*i
);
2095 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2096 STRV_FOREACH(i
, todo
) {
2097 _cleanup_free_
char *path
= NULL
;
2100 path
= path_make_absolute(*i
, config_path
);
2104 if (!dry_run
&& unlink(path
) < 0) {
2105 if (errno
!= ENOENT
) {
2108 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2114 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2116 rp
= skip_root(&paths
, path
);
2117 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2122 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2131 UnitFileScope scope
,
2132 UnitFileFlags flags
,
2133 const char *root_dir
,
2135 UnitFileChange
**changes
,
2136 size_t *n_changes
) {
2138 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2139 _cleanup_strv_free_
char **todo
= NULL
;
2140 size_t n_todo
= 0, n_allocated
= 0;
2141 const char *config_path
;
2146 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2148 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2152 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2156 STRV_FOREACH(i
, files
) {
2157 _cleanup_free_
char *full
= NULL
;
2161 if (!path_is_absolute(*i
))
2165 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2168 full
= prefix_root(paths
.root_dir
, *i
);
2172 if (lstat(full
, &st
) < 0)
2174 r
= stat_verify_regular(&st
);
2178 q
= in_search_path(&paths
, *i
);
2184 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2187 todo
[n_todo
] = strdup(*i
);
2197 STRV_FOREACH(i
, todo
) {
2198 _cleanup_free_
char *new_path
= NULL
;
2200 new_path
= path_make_absolute(basename(*i
), config_path
);
2204 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2205 if (q
< 0 && r
>= 0)
2212 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2218 /* Checks whether the path is one where the drop-in directories shall be removed. */
2220 r
= path_is_config(paths
, path
, true);
2224 r
= path_is_control(paths
, path
);
2228 return path_is_transient(paths
, path
);
2231 int unit_file_revert(
2232 UnitFileScope scope
,
2233 const char *root_dir
,
2235 UnitFileChange
**changes
,
2236 size_t *n_changes
) {
2238 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2239 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2240 _cleanup_strv_free_
char **todo
= NULL
;
2241 size_t n_todo
= 0, n_allocated
= 0;
2245 /* Puts a unit file back into vendor state. This means:
2247 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2248 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2250 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2251 * "config", but not in "transient" or "control" or even "generated").
2253 * We remove all that in both the runtime and the persistent directories, if that applies.
2256 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2260 STRV_FOREACH(i
, files
) {
2261 bool has_vendor
= false;
2264 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2267 STRV_FOREACH(p
, paths
.search_path
) {
2268 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2271 path
= path_make_absolute(*i
, *p
);
2275 r
= lstat(path
, &st
);
2277 if (errno
!= ENOENT
)
2279 } else if (S_ISREG(st
.st_mode
)) {
2280 /* Check if there's a vendor version */
2281 r
= path_is_vendor(&paths
, path
);
2288 dropin
= strappend(path
, ".d");
2292 r
= lstat(dropin
, &st
);
2294 if (errno
!= ENOENT
)
2296 } else if (S_ISDIR(st
.st_mode
)) {
2297 /* Remove the drop-ins */
2298 r
= path_shall_revert(&paths
, dropin
);
2302 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2305 todo
[n_todo
++] = TAKE_PTR(dropin
);
2313 /* OK, there's a vendor version, hence drop all configuration versions */
2314 STRV_FOREACH(p
, paths
.search_path
) {
2315 _cleanup_free_
char *path
= NULL
;
2318 path
= path_make_absolute(*i
, *p
);
2322 r
= lstat(path
, &st
);
2324 if (errno
!= ENOENT
)
2326 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2327 r
= path_is_config(&paths
, path
, true);
2331 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2334 todo
[n_todo
++] = TAKE_PTR(path
);
2343 STRV_FOREACH(i
, todo
) {
2344 _cleanup_strv_free_
char **fs
= NULL
;
2348 (void) get_files_in_directory(*i
, &fs
);
2350 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2351 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2356 STRV_FOREACH(j
, fs
) {
2357 _cleanup_free_
char *t
= NULL
;
2359 t
= strjoin(*i
, "/", *j
);
2363 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2366 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2368 rp
= skip_root(&paths
, *i
);
2369 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2374 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2378 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2385 int unit_file_add_dependency(
2386 UnitFileScope scope
,
2387 UnitFileFlags flags
,
2388 const char *root_dir
,
2392 UnitFileChange
**changes
,
2393 size_t *n_changes
) {
2395 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2396 _cleanup_(install_context_done
) InstallContext c
= {};
2397 UnitFileInstallInfo
*i
, *target_info
;
2398 const char *config_path
;
2403 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2406 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2409 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2412 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2416 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2420 r
= install_info_discover_and_check(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2421 &target_info
, changes
, n_changes
);
2425 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2427 STRV_FOREACH(f
, files
) {
2430 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2431 &i
, changes
, n_changes
);
2435 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2437 /* We didn't actually load anything from the unit
2438 * file, but instead just add in our new symlink to
2441 if (dep
== UNIT_WANTS
)
2444 l
= &i
->required_by
;
2447 *l
= strv_new(target_info
->name
);
2452 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2455 int unit_file_enable(
2456 UnitFileScope scope
,
2457 UnitFileFlags flags
,
2458 const char *root_dir
,
2460 UnitFileChange
**changes
,
2461 size_t *n_changes
) {
2463 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2464 _cleanup_(install_context_done
) InstallContext c
= {};
2465 const char *config_path
;
2466 UnitFileInstallInfo
*i
;
2471 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2473 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2477 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2481 STRV_FOREACH(f
, files
) {
2482 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2483 &i
, changes
, n_changes
);
2487 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2490 /* This will return the number of symlink rules that were
2491 supposed to be created, not the ones actually created. This
2492 is useful to determine whether the passed files had any
2493 installation data at all. */
2495 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2498 int unit_file_disable(
2499 UnitFileScope scope
,
2500 UnitFileFlags flags
,
2501 const char *root_dir
,
2503 UnitFileChange
**changes
,
2504 size_t *n_changes
) {
2506 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2507 _cleanup_(install_context_done
) InstallContext c
= {};
2508 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2509 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2510 const char *config_path
;
2515 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2517 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2521 STRV_FOREACH(i
, files
) {
2522 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2525 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2530 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2534 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2535 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2543 int unit_file_reenable(
2544 UnitFileScope scope
,
2545 UnitFileFlags flags
,
2546 const char *root_dir
,
2548 UnitFileChange
**changes
,
2549 size_t *n_changes
) {
2555 /* First, we invoke the disable command with only the basename... */
2556 l
= strv_length(files
);
2557 n
= newa(char*, l
+1);
2558 for (i
= 0; i
< l
; i
++)
2559 n
[i
] = basename(files
[i
]);
2562 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2566 /* But the enable command with the full name */
2567 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2570 int unit_file_set_default(
2571 UnitFileScope scope
,
2572 UnitFileFlags flags
,
2573 const char *root_dir
,
2575 UnitFileChange
**changes
,
2576 size_t *n_changes
) {
2578 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2579 _cleanup_(install_context_done
) InstallContext c
= {};
2580 UnitFileInstallInfo
*i
;
2581 const char *new_path
;
2585 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2588 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2590 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2593 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2597 r
= install_info_discover_and_check(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2601 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2602 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2605 int unit_file_get_default(
2606 UnitFileScope scope
,
2607 const char *root_dir
,
2610 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2611 _cleanup_(install_context_done
) InstallContext c
= {};
2612 UnitFileInstallInfo
*i
;
2617 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2620 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2624 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2628 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2632 n
= strdup(i
->name
);
2640 int unit_file_lookup_state(
2641 UnitFileScope scope
,
2642 const LookupPaths
*paths
,
2644 UnitFileState
*ret
) {
2646 _cleanup_(install_context_done
) InstallContext c
= {};
2647 UnitFileInstallInfo
*i
;
2648 UnitFileState state
;
2654 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2657 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2662 /* Shortcut things, if the caller just wants to know if this unit exists. */
2668 case UNIT_FILE_TYPE_MASKED
:
2669 r
= path_is_runtime(paths
, i
->path
, true);
2673 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2676 case UNIT_FILE_TYPE_REGULAR
:
2677 r
= path_is_generator(paths
, i
->path
);
2681 state
= UNIT_FILE_GENERATED
;
2685 r
= path_is_transient(paths
, i
->path
);
2689 state
= UNIT_FILE_TRANSIENT
;
2693 /* Check if any of the Alias= symlinks have been created.
2694 * We ignore other aliases, and only check those that would
2695 * be created by systemctl enable for this unit. */
2696 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2702 /* Check if the file is known under other names. If it is,
2703 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2704 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2708 state
= UNIT_FILE_INDIRECT
;
2710 if (unit_file_install_info_has_rules(i
))
2711 state
= UNIT_FILE_DISABLED
;
2712 else if (unit_file_install_info_has_also(i
))
2713 state
= UNIT_FILE_INDIRECT
;
2715 state
= UNIT_FILE_STATIC
;
2721 assert_not_reached("Unexpect unit file type.");
2728 int unit_file_get_state(
2729 UnitFileScope scope
,
2730 const char *root_dir
,
2732 UnitFileState
*ret
) {
2734 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2738 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2741 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2745 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2748 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2749 _cleanup_(install_context_done
) InstallContext c
= {};
2755 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2758 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2767 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2768 _cleanup_strv_free_
char **instances
= NULL
;
2769 _cleanup_free_
char *unit_name
= NULL
;
2773 assert(out_instances
);
2774 assert(out_unit_name
);
2776 r
= extract_first_word(&pattern
, &unit_name
, NULL
, 0);
2780 /* We handle the instances logic when unit name is extracted */
2782 /* We only create instances when a rule of templated unit
2783 * is seen. A rule like enable foo@.service a b c will
2784 * result in an array of (a, b, c) as instance names */
2785 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2788 instances
= strv_split(pattern
, WHITESPACE
);
2792 *out_instances
= TAKE_PTR(instances
);
2795 *out_unit_name
= TAKE_PTR(unit_name
);
2800 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2801 _cleanup_(presets_freep
) Presets ps
= {};
2802 size_t n_allocated
= 0;
2803 _cleanup_strv_free_
char **files
= NULL
;
2808 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2812 case UNIT_FILE_SYSTEM
:
2813 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2814 "/etc/systemd/system-preset",
2815 "/run/systemd/system-preset",
2816 "/usr/local/lib/systemd/system-preset",
2817 "/usr/lib/systemd/system-preset",
2819 "/lib/systemd/system-preset",
2824 case UNIT_FILE_GLOBAL
:
2825 case UNIT_FILE_USER
:
2826 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2827 "/etc/systemd/user-preset",
2828 "/run/systemd/user-preset",
2829 "/usr/local/lib/systemd/user-preset",
2830 "/usr/lib/systemd/user-preset",
2835 assert_not_reached("Invalid unit file scope");
2841 STRV_FOREACH(p
, files
) {
2842 _cleanup_fclose_
FILE *f
;
2845 f
= fopen(*p
, "re");
2847 if (errno
== ENOENT
)
2854 _cleanup_free_
char *line
= NULL
;
2855 PresetRule rule
= {};
2856 const char *parameter
;
2859 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2870 if (strchr(COMMENTS
, *l
))
2873 parameter
= first_word(l
, "enable");
2876 char **instances
= NULL
;
2878 /* Unit_name will remain the same as parameter when no instances are specified */
2879 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2881 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2885 rule
= (PresetRule
) {
2886 .pattern
= unit_name
,
2887 .action
= PRESET_ENABLE
,
2888 .instances
= instances
,
2892 parameter
= first_word(l
, "disable");
2896 pattern
= strdup(parameter
);
2900 rule
= (PresetRule
) {
2902 .action
= PRESET_DISABLE
,
2907 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2910 ps
.rules
[ps
.n_rules
++] = rule
;
2914 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2924 static int pattern_match_multiple_instances(
2925 const PresetRule rule
,
2926 const char *unit_name
,
2929 _cleanup_free_
char *templated_name
= NULL
;
2932 /* If no ret is needed or the rule itself does not have instances
2933 * initalized, we return not matching */
2934 if (!ret
|| !rule
.instances
)
2937 r
= unit_name_template(unit_name
, &templated_name
);
2940 if (!streq(rule
.pattern
, templated_name
))
2943 /* Compose a list of specified instances when unit name is a template */
2944 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
2945 _cleanup_free_
char *prefix
= NULL
;
2946 _cleanup_strv_free_
char **out_strv
= NULL
;
2949 r
= unit_name_to_prefix(unit_name
, &prefix
);
2953 STRV_FOREACH(iter
, rule
.instances
) {
2954 _cleanup_free_
char *name
= NULL
;
2955 r
= unit_name_build(prefix
, *iter
, ".service", &name
);
2958 r
= strv_extend(&out_strv
, name
);
2963 *ret
= TAKE_PTR(out_strv
);
2966 /* We now know the input unit name is an instance name */
2967 _cleanup_free_
char *instance_name
= NULL
;
2969 r
= unit_name_to_instance(unit_name
, &instance_name
);
2973 if (strv_find(rule
.instances
, instance_name
))
2979 static int query_presets(const char *name
, const Presets presets
, char ***instance_name_list
) {
2980 PresetAction action
= PRESET_UNKNOWN
;
2983 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2986 for (i
= 0; i
< presets
.n_rules
; i
++)
2987 if (pattern_match_multiple_instances(presets
.rules
[i
], name
, instance_name_list
) > 0 ||
2988 fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2989 action
= presets
.rules
[i
].action
;
2994 case PRESET_UNKNOWN
:
2995 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2998 if (instance_name_list
&& *instance_name_list
)
2999 STRV_FOREACH(s
, *instance_name_list
)
3000 log_debug("Preset files say enable %s.", *s
);
3002 log_debug("Preset files say enable %s.", name
);
3004 case PRESET_DISABLE
:
3005 log_debug("Preset files say disable %s.", name
);
3008 assert_not_reached("invalid preset action");
3012 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
3013 _cleanup_(presets_freep
) Presets presets
= {};
3016 r
= read_presets(scope
, root_dir
, &presets
);
3020 return query_presets(name
, presets
, NULL
);
3023 static int execute_preset(
3024 UnitFileScope scope
,
3025 UnitFileFlags flags
,
3026 InstallContext
*plus
,
3027 InstallContext
*minus
,
3028 const LookupPaths
*paths
,
3030 UnitFilePresetMode mode
,
3031 UnitFileChange
**changes
,
3032 size_t *n_changes
) {
3034 const char *config_path
;
3035 bool force
= !!(flags
& UNIT_FILE_FORCE
);
3036 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
3043 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3044 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3046 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
3050 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
3051 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
3057 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3058 /* Returns number of symlinks that where supposed to be installed. */
3059 q
= install_context_apply(scope
, plus
, paths
,
3060 runtime
? paths
->runtime_config
: paths
->persistent_config
,
3061 force
, SEARCH_LOAD
, changes
, n_changes
);
3069 static int preset_prepare_one(
3070 UnitFileScope scope
,
3071 InstallContext
*plus
,
3072 InstallContext
*minus
,
3076 UnitFileChange
**changes
,
3077 size_t *n_changes
) {
3079 _cleanup_(install_context_done
) InstallContext tmp
= {};
3080 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3081 UnitFileInstallInfo
*i
;
3084 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3087 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3088 &i
, changes
, n_changes
);
3091 if (!streq(name
, i
->name
)) {
3092 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3096 r
= query_presets(name
, presets
, &instance_name_list
);
3101 if (instance_name_list
) {
3103 STRV_FOREACH(s
, instance_name_list
) {
3104 r
= install_info_discover_and_check(scope
, plus
, paths
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3105 &i
, changes
, n_changes
);
3110 r
= install_info_discover_and_check(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3111 &i
, changes
, n_changes
);
3117 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3118 &i
, changes
, n_changes
);
3123 int unit_file_preset(
3124 UnitFileScope scope
,
3125 UnitFileFlags flags
,
3126 const char *root_dir
,
3128 UnitFilePresetMode mode
,
3129 UnitFileChange
**changes
,
3130 size_t *n_changes
) {
3132 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3133 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3134 _cleanup_(presets_freep
) Presets presets
= {};
3139 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3140 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3142 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3146 r
= read_presets(scope
, root_dir
, &presets
);
3150 STRV_FOREACH(i
, files
) {
3151 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3156 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3159 int unit_file_preset_all(
3160 UnitFileScope scope
,
3161 UnitFileFlags flags
,
3162 const char *root_dir
,
3163 UnitFilePresetMode mode
,
3164 UnitFileChange
**changes
,
3165 size_t *n_changes
) {
3167 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3168 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3169 _cleanup_(presets_freep
) Presets presets
= {};
3174 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3175 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3177 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3181 r
= read_presets(scope
, root_dir
, &presets
);
3185 STRV_FOREACH(i
, paths
.search_path
) {
3186 _cleanup_closedir_
DIR *d
= NULL
;
3191 if (errno
== ENOENT
)
3197 FOREACH_DIRENT(de
, d
, return -errno
) {
3198 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3201 dirent_ensure_type(d
, de
);
3203 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3206 /* we don't pass changes[] in, because we want to handle errors on our own */
3207 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3209 r
= unit_file_changes_add(changes
, n_changes
,
3210 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3211 else if (r
== -ENOLINK
)
3212 r
= unit_file_changes_add(changes
, n_changes
,
3213 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3214 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3221 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3224 static void unit_file_list_free_one(UnitFileList
*f
) {
3232 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3233 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3236 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3238 int unit_file_get_list(
3239 UnitFileScope scope
,
3240 const char *root_dir
,
3245 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3250 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3253 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3257 STRV_FOREACH(i
, paths
.search_path
) {
3258 _cleanup_closedir_
DIR *d
= NULL
;
3263 if (errno
== ENOENT
)
3265 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3266 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3273 FOREACH_DIRENT(de
, d
, return -errno
) {
3274 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3276 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3279 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3282 if (hashmap_get(h
, de
->d_name
))
3285 dirent_ensure_type(d
, de
);
3287 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3290 f
= new0(UnitFileList
, 1);
3294 f
->path
= path_make_absolute(de
->d_name
, *i
);
3298 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3300 f
->state
= UNIT_FILE_BAD
;
3302 if (!strv_isempty(states
) &&
3303 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3306 r
= hashmap_put(h
, basename(f
->path
), f
);
3310 f
= NULL
; /* prevent cleanup */
3317 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3318 [UNIT_FILE_ENABLED
] = "enabled",
3319 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3320 [UNIT_FILE_LINKED
] = "linked",
3321 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3322 [UNIT_FILE_MASKED
] = "masked",
3323 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3324 [UNIT_FILE_STATIC
] = "static",
3325 [UNIT_FILE_DISABLED
] = "disabled",
3326 [UNIT_FILE_INDIRECT
] = "indirect",
3327 [UNIT_FILE_GENERATED
] = "generated",
3328 [UNIT_FILE_TRANSIENT
] = "transient",
3329 [UNIT_FILE_BAD
] = "bad",
3332 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3334 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3335 [UNIT_FILE_SYMLINK
] = "symlink",
3336 [UNIT_FILE_UNLINK
] = "unlink",
3337 [UNIT_FILE_IS_MASKED
] = "masked",
3338 [UNIT_FILE_IS_DANGLING
] = "dangling",
3341 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3343 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3344 [UNIT_FILE_PRESET_FULL
] = "full",
3345 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3346 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3349 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);