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
= new(UnitFileInstallInfo
, 1);
1055 *i
= (UnitFileInstallInfo
) {
1056 .type
= _UNIT_FILE_TYPE_INVALID
,
1057 .auxiliary
= auxiliary
,
1060 i
->name
= strdup(name
);
1067 i
->path
= strdup(path
);
1074 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1084 install_info_free(i
);
1088 static int config_parse_alias(
1090 const char *filename
,
1092 const char *section
,
1093 unsigned section_line
,
1107 type
= unit_name_to_type(unit
);
1108 if (!unit_type_may_alias(type
))
1109 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1110 "Alias= is not allowed for %s units, ignoring.",
1111 unit_type_to_string(type
));
1113 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1114 lvalue
, ltype
, rvalue
, data
, userdata
);
1117 static int config_parse_also(
1119 const char *filename
,
1121 const char *section
,
1122 unsigned section_line
,
1129 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1130 InstallContext
*c
= data
;
1139 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1141 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1147 r
= install_full_printf(info
, word
, &printed
);
1151 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1154 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1158 r
= strv_push(&info
->also
, printed
);
1168 static int config_parse_default_instance(
1170 const char *filename
,
1172 const char *section
,
1173 unsigned section_line
,
1180 UnitFileInstallInfo
*i
= data
;
1181 _cleanup_free_
char *printed
= NULL
;
1189 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1190 /* When enabling an instance, we might be using a template unit file,
1191 * but we should ignore DefaultInstance silently. */
1193 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1194 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1195 "DefaultInstance= only makes sense for template units, ignoring.");
1197 r
= install_full_printf(i
, rvalue
, &printed
);
1201 if (!unit_instance_is_valid(printed
))
1204 return free_and_replace(i
->default_instance
, printed
);
1207 static int unit_file_load(
1209 UnitFileInstallInfo
*info
,
1211 const char *root_dir
,
1212 SearchFlags flags
) {
1214 const ConfigTableItem items
[] = {
1215 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1216 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1217 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1218 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1219 { "Install", "Also", config_parse_also
, 0, c
},
1224 _cleanup_fclose_
FILE *f
= NULL
;
1225 _cleanup_close_
int fd
= -1;
1232 if (!(flags
& SEARCH_DROPIN
)) {
1233 /* Loading or checking for the main unit file… */
1235 type
= unit_name_to_type(info
->name
);
1238 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
))
1239 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1240 "Unit type %s cannot be templated.", unit_type_to_string(type
));
1242 if (!(flags
& SEARCH_LOAD
)) {
1243 r
= lstat(path
, &st
);
1247 if (null_or_empty(&st
))
1248 info
->type
= UNIT_FILE_TYPE_MASKED
;
1249 else if (S_ISREG(st
.st_mode
))
1250 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1251 else if (S_ISLNK(st
.st_mode
))
1253 else if (S_ISDIR(st
.st_mode
))
1261 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1265 /* 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. */
1267 if (!(flags
& SEARCH_LOAD
))
1270 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1275 if (fstat(fd
, &st
) < 0)
1278 if (null_or_empty(&st
)) {
1279 if ((flags
& SEARCH_DROPIN
) == 0)
1280 info
->type
= UNIT_FILE_TYPE_MASKED
;
1285 r
= stat_verify_regular(&st
);
1289 f
= fdopen(fd
, "re");
1294 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1297 r
= config_parse(info
->name
, path
, f
,
1299 config_item_table_lookup
, items
,
1300 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1302 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1304 if ((flags
& SEARCH_DROPIN
) == 0)
1305 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1308 (int) strv_length(info
->aliases
) +
1309 (int) strv_length(info
->wanted_by
) +
1310 (int) strv_length(info
->required_by
);
1313 static int unit_file_load_or_readlink(
1315 UnitFileInstallInfo
*info
,
1317 const char *root_dir
,
1318 SearchFlags flags
) {
1320 _cleanup_free_
char *target
= NULL
;
1323 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1324 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1327 /* This is a symlink, let's read it. */
1329 r
= readlink_malloc(path
, &target
);
1333 if (path_equal(target
, "/dev/null"))
1334 info
->type
= UNIT_FILE_TYPE_MASKED
;
1339 bn
= basename(target
);
1341 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1343 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1346 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1348 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1351 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1353 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1358 /* Enforce that the symlink destination does not
1359 * change the unit file type. */
1361 a
= unit_name_to_type(info
->name
);
1362 b
= unit_name_to_type(bn
);
1363 if (a
< 0 || b
< 0 || a
!= b
)
1366 if (path_is_absolute(target
))
1367 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1368 info
->symlink_target
= prefix_root(root_dir
, target
);
1370 /* This is a relative path, take it relative to the dir the symlink is located in. */
1371 info
->symlink_target
= file_in_same_dir(path
, target
);
1372 if (!info
->symlink_target
)
1375 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1381 static int unit_file_search(
1383 UnitFileInstallInfo
*info
,
1384 const LookupPaths
*paths
,
1385 SearchFlags flags
) {
1387 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1388 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1389 _cleanup_free_
char *template = NULL
;
1390 bool found_unit
= false;
1397 /* Was this unit already loaded? */
1398 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1402 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1406 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1407 r
= unit_name_template(info
->name
, &template);
1412 STRV_FOREACH(p
, paths
->search_path
) {
1413 _cleanup_free_
char *path
= NULL
;
1415 path
= strjoin(*p
, "/", info
->name
);
1419 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1421 info
->path
= TAKE_PTR(path
);
1425 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1429 if (!found_unit
&& template) {
1431 /* Unit file doesn't exist, however instance
1432 * enablement was requested. We will check if it is
1433 * possible to load template unit file. */
1435 STRV_FOREACH(p
, paths
->search_path
) {
1436 _cleanup_free_
char *path
= NULL
;
1438 path
= strjoin(*p
, "/", template);
1442 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1444 info
->path
= TAKE_PTR(path
);
1448 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1454 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1455 "Cannot find unit %s%s%s.",
1456 info
->name
, template ? " or " : "", strempty(template));
1458 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1461 /* Search for drop-in directories */
1463 dropin_dir_name
= strjoina(info
->name
, ".d");
1464 STRV_FOREACH(p
, paths
->search_path
) {
1467 path
= path_join(*p
, dropin_dir_name
);
1471 r
= strv_consume(&dirs
, path
);
1477 dropin_template_dir_name
= strjoina(template, ".d");
1478 STRV_FOREACH(p
, paths
->search_path
) {
1481 path
= path_join(*p
, dropin_template_dir_name
);
1485 r
= strv_consume(&dirs
, path
);
1491 /* Load drop-in conf files */
1493 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1495 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1497 STRV_FOREACH(p
, files
) {
1498 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1500 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1506 static int install_info_follow(
1508 UnitFileInstallInfo
*i
,
1509 const char *root_dir
,
1511 bool ignore_different_name
) {
1516 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1518 if (!i
->symlink_target
)
1521 /* If the basename doesn't match, the caller should add a
1522 * complete new entry for this. */
1524 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1527 free_and_replace(i
->path
, i
->symlink_target
);
1528 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1530 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1534 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1535 * target, maybe more than once. Propagate the instance name if present.
1537 static int install_info_traverse(
1538 UnitFileScope scope
,
1540 const LookupPaths
*paths
,
1541 UnitFileInstallInfo
*start
,
1543 UnitFileInstallInfo
**ret
) {
1545 UnitFileInstallInfo
*i
;
1553 r
= unit_file_search(c
, start
, paths
, flags
);
1558 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1559 /* Follow the symlink */
1561 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1564 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1565 r
= path_is_config(paths
, i
->path
, true);
1572 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1574 _cleanup_free_
char *buffer
= NULL
;
1577 /* Target has a different name, create a new
1578 * install info object for that, and continue
1581 bn
= basename(i
->symlink_target
);
1583 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1584 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1586 _cleanup_free_
char *instance
= NULL
;
1588 r
= unit_name_to_instance(i
->name
, &instance
);
1592 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1596 if (streq(buffer
, i
->name
)) {
1598 /* We filled in the instance, and the target stayed the same? If so, then let's
1599 * honour the link as it is. */
1601 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1611 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1615 /* Try again, with the new target we found. */
1616 r
= unit_file_search(c
, i
, paths
, flags
);
1618 /* Translate error code to highlight this specific case */
1633 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1634 * or the name (otherwise). root_dir is prepended to the path.
1636 static int install_info_add_auto(
1638 const LookupPaths
*paths
,
1639 const char *name_or_path
,
1640 UnitFileInstallInfo
**ret
) {
1643 assert(name_or_path
);
1645 if (path_is_absolute(name_or_path
)) {
1648 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1650 return install_info_add(c
, NULL
, pp
, false, ret
);
1652 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1655 static int install_info_discover(
1656 UnitFileScope scope
,
1658 const LookupPaths
*paths
,
1661 UnitFileInstallInfo
**ret
,
1662 UnitFileChange
**changes
,
1663 size_t *n_changes
) {
1665 UnitFileInstallInfo
*i
;
1672 r
= install_info_add_auto(c
, paths
, name
, &i
);
1674 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1677 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1681 static int install_info_discover_and_check(
1682 UnitFileScope scope
,
1684 const LookupPaths
*paths
,
1687 UnitFileInstallInfo
**ret
,
1688 UnitFileChange
**changes
,
1689 size_t *n_changes
) {
1693 r
= install_info_discover(scope
, c
, paths
, name
, flags
, ret
, changes
, n_changes
);
1697 return install_info_may_process(ret
? *ret
: NULL
, paths
, changes
, n_changes
);
1700 static int install_info_symlink_alias(
1701 UnitFileInstallInfo
*i
,
1702 const LookupPaths
*paths
,
1703 const char *config_path
,
1705 UnitFileChange
**changes
,
1706 size_t *n_changes
) {
1713 assert(config_path
);
1715 STRV_FOREACH(s
, i
->aliases
) {
1716 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1718 q
= install_full_printf(i
, *s
, &dst
);
1722 alias_path
= path_make_absolute(dst
, config_path
);
1726 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1734 static int install_info_symlink_wants(
1735 UnitFileInstallInfo
*i
,
1736 const LookupPaths
*paths
,
1737 const char *config_path
,
1740 UnitFileChange
**changes
,
1741 size_t *n_changes
) {
1743 _cleanup_free_
char *buf
= NULL
;
1750 assert(config_path
);
1752 if (strv_isempty(list
))
1755 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1756 UnitFileInstallInfo instance
= {
1757 .type
= _UNIT_FILE_TYPE_INVALID
,
1759 _cleanup_free_
char *path
= NULL
;
1761 /* If this is a template, and we have no instance, don't do anything */
1762 if (!i
->default_instance
)
1765 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1769 instance
.name
= buf
;
1770 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1774 path
= TAKE_PTR(instance
.path
);
1776 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1777 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1785 STRV_FOREACH(s
, list
) {
1786 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1788 q
= install_full_printf(i
, *s
, &dst
);
1792 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1797 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1801 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1809 static int install_info_symlink_link(
1810 UnitFileInstallInfo
*i
,
1811 const LookupPaths
*paths
,
1812 const char *config_path
,
1814 UnitFileChange
**changes
,
1815 size_t *n_changes
) {
1817 _cleanup_free_
char *path
= NULL
;
1822 assert(config_path
);
1825 r
= in_search_path(paths
, i
->path
);
1831 path
= strjoin(config_path
, "/", i
->name
);
1835 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1838 static int install_info_apply(
1839 UnitFileInstallInfo
*i
,
1840 const LookupPaths
*paths
,
1841 const char *config_path
,
1843 UnitFileChange
**changes
,
1844 size_t *n_changes
) {
1850 assert(config_path
);
1852 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1855 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1857 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1861 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1865 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1866 /* Do not count links to the unit file towards the "carries_install_info" count */
1867 if (r
== 0 && q
< 0)
1873 static int install_context_apply(
1874 UnitFileScope scope
,
1876 const LookupPaths
*paths
,
1877 const char *config_path
,
1880 UnitFileChange
**changes
,
1881 size_t *n_changes
) {
1883 UnitFileInstallInfo
*i
;
1888 assert(config_path
);
1890 if (ordered_hashmap_isempty(c
->will_process
))
1893 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1898 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1901 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1905 q
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1907 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1911 /* We can attempt to process a masked unit when a different unit
1912 * that we were processing specifies it in Also=. */
1913 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1914 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1916 /* Assume that something *could* have been enabled here,
1917 * avoid "empty [Install] section" warning. */
1922 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1925 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1937 static int install_context_mark_for_removal(
1938 UnitFileScope scope
,
1940 const LookupPaths
*paths
,
1941 Set
**remove_symlinks_to
,
1942 UnitFileChange
**changes
,
1943 size_t *n_changes
) {
1945 UnitFileInstallInfo
*i
;
1951 /* Marks all items for removal */
1953 if (ordered_hashmap_isempty(c
->will_process
))
1956 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1960 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1962 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1966 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1967 if (r
== -ENOLINK
) {
1968 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1969 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1970 } else if (r
== -ENOENT
) {
1972 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1973 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1975 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1976 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1980 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1981 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1982 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1983 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1984 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1986 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1987 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1991 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
2000 UnitFileScope scope
,
2001 UnitFileFlags flags
,
2002 const char *root_dir
,
2004 UnitFileChange
**changes
,
2005 size_t *n_changes
) {
2007 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2008 const char *config_path
;
2013 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2015 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2019 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2023 STRV_FOREACH(i
, files
) {
2024 _cleanup_free_
char *path
= NULL
;
2027 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2033 path
= path_make_absolute(*i
, config_path
);
2037 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2038 if (q
< 0 && r
>= 0)
2045 int unit_file_unmask(
2046 UnitFileScope scope
,
2047 UnitFileFlags flags
,
2048 const char *root_dir
,
2050 UnitFileChange
**changes
,
2051 size_t *n_changes
) {
2053 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2054 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2055 _cleanup_strv_free_
char **todo
= NULL
;
2056 size_t n_todo
= 0, n_allocated
= 0;
2057 const char *config_path
;
2059 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2063 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2065 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2069 STRV_FOREACH(i
, files
) {
2070 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2073 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2074 _cleanup_free_
char *path
= NULL
;
2076 path
= path_make_absolute(*i
, config_path
);
2080 r
= null_or_empty_path(path
);
2088 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2091 todo
[n_todo
] = strdup(*i
);
2102 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2103 STRV_FOREACH(i
, todo
) {
2104 _cleanup_free_
char *path
= NULL
;
2107 path
= path_make_absolute(*i
, config_path
);
2111 if (!dry_run
&& unlink(path
) < 0) {
2112 if (errno
!= ENOENT
) {
2115 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2121 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2123 rp
= skip_root(&paths
, path
);
2124 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2129 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2138 UnitFileScope scope
,
2139 UnitFileFlags flags
,
2140 const char *root_dir
,
2142 UnitFileChange
**changes
,
2143 size_t *n_changes
) {
2145 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2146 _cleanup_strv_free_
char **todo
= NULL
;
2147 size_t n_todo
= 0, n_allocated
= 0;
2148 const char *config_path
;
2153 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2155 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2159 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2163 STRV_FOREACH(i
, files
) {
2164 _cleanup_free_
char *full
= NULL
;
2168 if (!path_is_absolute(*i
))
2172 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2175 full
= prefix_root(paths
.root_dir
, *i
);
2179 if (lstat(full
, &st
) < 0)
2181 r
= stat_verify_regular(&st
);
2185 q
= in_search_path(&paths
, *i
);
2191 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2194 todo
[n_todo
] = strdup(*i
);
2204 STRV_FOREACH(i
, todo
) {
2205 _cleanup_free_
char *new_path
= NULL
;
2207 new_path
= path_make_absolute(basename(*i
), config_path
);
2211 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2212 if (q
< 0 && r
>= 0)
2219 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2225 /* Checks whether the path is one where the drop-in directories shall be removed. */
2227 r
= path_is_config(paths
, path
, true);
2231 r
= path_is_control(paths
, path
);
2235 return path_is_transient(paths
, path
);
2238 int unit_file_revert(
2239 UnitFileScope scope
,
2240 const char *root_dir
,
2242 UnitFileChange
**changes
,
2243 size_t *n_changes
) {
2245 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2246 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2247 _cleanup_strv_free_
char **todo
= NULL
;
2248 size_t n_todo
= 0, n_allocated
= 0;
2252 /* Puts a unit file back into vendor state. This means:
2254 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2255 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2257 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2258 * "config", but not in "transient" or "control" or even "generated").
2260 * We remove all that in both the runtime and the persistent directories, if that applies.
2263 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2267 STRV_FOREACH(i
, files
) {
2268 bool has_vendor
= false;
2271 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2274 STRV_FOREACH(p
, paths
.search_path
) {
2275 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2278 path
= path_make_absolute(*i
, *p
);
2282 r
= lstat(path
, &st
);
2284 if (errno
!= ENOENT
)
2286 } else if (S_ISREG(st
.st_mode
)) {
2287 /* Check if there's a vendor version */
2288 r
= path_is_vendor(&paths
, path
);
2295 dropin
= strappend(path
, ".d");
2299 r
= lstat(dropin
, &st
);
2301 if (errno
!= ENOENT
)
2303 } else if (S_ISDIR(st
.st_mode
)) {
2304 /* Remove the drop-ins */
2305 r
= path_shall_revert(&paths
, dropin
);
2309 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2312 todo
[n_todo
++] = TAKE_PTR(dropin
);
2320 /* OK, there's a vendor version, hence drop all configuration versions */
2321 STRV_FOREACH(p
, paths
.search_path
) {
2322 _cleanup_free_
char *path
= NULL
;
2325 path
= path_make_absolute(*i
, *p
);
2329 r
= lstat(path
, &st
);
2331 if (errno
!= ENOENT
)
2333 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2334 r
= path_is_config(&paths
, path
, true);
2338 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2341 todo
[n_todo
++] = TAKE_PTR(path
);
2350 STRV_FOREACH(i
, todo
) {
2351 _cleanup_strv_free_
char **fs
= NULL
;
2355 (void) get_files_in_directory(*i
, &fs
);
2357 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2358 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2363 STRV_FOREACH(j
, fs
) {
2364 _cleanup_free_
char *t
= NULL
;
2366 t
= strjoin(*i
, "/", *j
);
2370 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2373 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2375 rp
= skip_root(&paths
, *i
);
2376 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2381 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2385 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2392 int unit_file_add_dependency(
2393 UnitFileScope scope
,
2394 UnitFileFlags flags
,
2395 const char *root_dir
,
2399 UnitFileChange
**changes
,
2400 size_t *n_changes
) {
2402 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2403 _cleanup_(install_context_done
) InstallContext c
= {};
2404 UnitFileInstallInfo
*i
, *target_info
;
2405 const char *config_path
;
2410 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2413 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2416 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2419 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2423 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2427 r
= install_info_discover_and_check(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2428 &target_info
, changes
, n_changes
);
2432 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2434 STRV_FOREACH(f
, files
) {
2437 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2438 &i
, changes
, n_changes
);
2442 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2444 /* We didn't actually load anything from the unit
2445 * file, but instead just add in our new symlink to
2448 if (dep
== UNIT_WANTS
)
2451 l
= &i
->required_by
;
2454 *l
= strv_new(target_info
->name
);
2459 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2462 int unit_file_enable(
2463 UnitFileScope scope
,
2464 UnitFileFlags flags
,
2465 const char *root_dir
,
2467 UnitFileChange
**changes
,
2468 size_t *n_changes
) {
2470 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2471 _cleanup_(install_context_done
) InstallContext c
= {};
2472 const char *config_path
;
2473 UnitFileInstallInfo
*i
;
2478 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2480 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2484 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2488 STRV_FOREACH(f
, files
) {
2489 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2490 &i
, changes
, n_changes
);
2494 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2497 /* This will return the number of symlink rules that were
2498 supposed to be created, not the ones actually created. This
2499 is useful to determine whether the passed files had any
2500 installation data at all. */
2502 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2505 int unit_file_disable(
2506 UnitFileScope scope
,
2507 UnitFileFlags flags
,
2508 const char *root_dir
,
2510 UnitFileChange
**changes
,
2511 size_t *n_changes
) {
2513 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2514 _cleanup_(install_context_done
) InstallContext c
= {};
2515 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2516 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2517 const char *config_path
;
2522 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2524 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2528 STRV_FOREACH(i
, files
) {
2529 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2532 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2537 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2541 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2542 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2550 int unit_file_reenable(
2551 UnitFileScope scope
,
2552 UnitFileFlags flags
,
2553 const char *root_dir
,
2555 UnitFileChange
**changes
,
2556 size_t *n_changes
) {
2562 /* First, we invoke the disable command with only the basename... */
2563 l
= strv_length(files
);
2564 n
= newa(char*, l
+1);
2565 for (i
= 0; i
< l
; i
++)
2566 n
[i
] = basename(files
[i
]);
2569 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2573 /* But the enable command with the full name */
2574 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2577 int unit_file_set_default(
2578 UnitFileScope scope
,
2579 UnitFileFlags flags
,
2580 const char *root_dir
,
2582 UnitFileChange
**changes
,
2583 size_t *n_changes
) {
2585 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2586 _cleanup_(install_context_done
) InstallContext c
= {};
2587 UnitFileInstallInfo
*i
;
2588 const char *new_path
;
2592 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2595 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2597 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2600 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2604 r
= install_info_discover_and_check(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2608 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2609 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2612 int unit_file_get_default(
2613 UnitFileScope scope
,
2614 const char *root_dir
,
2617 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2618 _cleanup_(install_context_done
) InstallContext c
= {};
2619 UnitFileInstallInfo
*i
;
2624 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2627 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2631 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2635 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2639 n
= strdup(i
->name
);
2647 int unit_file_lookup_state(
2648 UnitFileScope scope
,
2649 const LookupPaths
*paths
,
2651 UnitFileState
*ret
) {
2653 _cleanup_(install_context_done
) InstallContext c
= {};
2654 UnitFileInstallInfo
*i
;
2655 UnitFileState state
;
2661 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2664 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2669 /* Shortcut things, if the caller just wants to know if this unit exists. */
2675 case UNIT_FILE_TYPE_MASKED
:
2676 r
= path_is_runtime(paths
, i
->path
, true);
2680 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2683 case UNIT_FILE_TYPE_REGULAR
:
2684 r
= path_is_generator(paths
, i
->path
);
2688 state
= UNIT_FILE_GENERATED
;
2692 r
= path_is_transient(paths
, i
->path
);
2696 state
= UNIT_FILE_TRANSIENT
;
2700 /* Check if any of the Alias= symlinks have been created.
2701 * We ignore other aliases, and only check those that would
2702 * be created by systemctl enable for this unit. */
2703 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2709 /* Check if the file is known under other names. If it is,
2710 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2711 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2715 state
= UNIT_FILE_INDIRECT
;
2717 if (unit_file_install_info_has_rules(i
))
2718 state
= UNIT_FILE_DISABLED
;
2719 else if (unit_file_install_info_has_also(i
))
2720 state
= UNIT_FILE_INDIRECT
;
2722 state
= UNIT_FILE_STATIC
;
2728 assert_not_reached("Unexpect unit file type.");
2735 int unit_file_get_state(
2736 UnitFileScope scope
,
2737 const char *root_dir
,
2739 UnitFileState
*ret
) {
2741 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2745 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2748 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2752 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2755 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2756 _cleanup_(install_context_done
) InstallContext c
= {};
2762 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2765 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2774 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2775 _cleanup_strv_free_
char **instances
= NULL
;
2776 _cleanup_free_
char *unit_name
= NULL
;
2780 assert(out_instances
);
2781 assert(out_unit_name
);
2783 r
= extract_first_word(&pattern
, &unit_name
, NULL
, 0);
2787 /* We handle the instances logic when unit name is extracted */
2789 /* We only create instances when a rule of templated unit
2790 * is seen. A rule like enable foo@.service a b c will
2791 * result in an array of (a, b, c) as instance names */
2792 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2795 instances
= strv_split(pattern
, WHITESPACE
);
2799 *out_instances
= TAKE_PTR(instances
);
2802 *out_unit_name
= TAKE_PTR(unit_name
);
2807 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2808 _cleanup_(presets_freep
) Presets ps
= {};
2809 size_t n_allocated
= 0;
2810 _cleanup_strv_free_
char **files
= NULL
;
2815 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2819 case UNIT_FILE_SYSTEM
:
2820 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2821 "/etc/systemd/system-preset",
2822 "/run/systemd/system-preset",
2823 "/usr/local/lib/systemd/system-preset",
2824 "/usr/lib/systemd/system-preset",
2826 "/lib/systemd/system-preset",
2831 case UNIT_FILE_GLOBAL
:
2832 case UNIT_FILE_USER
:
2833 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2834 "/etc/systemd/user-preset",
2835 "/run/systemd/user-preset",
2836 "/usr/local/lib/systemd/user-preset",
2837 "/usr/lib/systemd/user-preset",
2842 assert_not_reached("Invalid unit file scope");
2848 STRV_FOREACH(p
, files
) {
2849 _cleanup_fclose_
FILE *f
;
2852 f
= fopen(*p
, "re");
2854 if (errno
== ENOENT
)
2861 _cleanup_free_
char *line
= NULL
;
2862 PresetRule rule
= {};
2863 const char *parameter
;
2866 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2877 if (strchr(COMMENTS
, *l
))
2880 parameter
= first_word(l
, "enable");
2883 char **instances
= NULL
;
2885 /* Unit_name will remain the same as parameter when no instances are specified */
2886 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2888 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2892 rule
= (PresetRule
) {
2893 .pattern
= unit_name
,
2894 .action
= PRESET_ENABLE
,
2895 .instances
= instances
,
2899 parameter
= first_word(l
, "disable");
2903 pattern
= strdup(parameter
);
2907 rule
= (PresetRule
) {
2909 .action
= PRESET_DISABLE
,
2914 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2917 ps
.rules
[ps
.n_rules
++] = rule
;
2921 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2931 static int pattern_match_multiple_instances(
2932 const PresetRule rule
,
2933 const char *unit_name
,
2936 _cleanup_free_
char *templated_name
= NULL
;
2939 /* If no ret is needed or the rule itself does not have instances
2940 * initalized, we return not matching */
2941 if (!ret
|| !rule
.instances
)
2944 r
= unit_name_template(unit_name
, &templated_name
);
2947 if (!streq(rule
.pattern
, templated_name
))
2950 /* Compose a list of specified instances when unit name is a template */
2951 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
2952 _cleanup_free_
char *prefix
= NULL
;
2953 _cleanup_strv_free_
char **out_strv
= NULL
;
2956 r
= unit_name_to_prefix(unit_name
, &prefix
);
2960 STRV_FOREACH(iter
, rule
.instances
) {
2961 _cleanup_free_
char *name
= NULL
;
2962 r
= unit_name_build(prefix
, *iter
, ".service", &name
);
2965 r
= strv_extend(&out_strv
, name
);
2970 *ret
= TAKE_PTR(out_strv
);
2973 /* We now know the input unit name is an instance name */
2974 _cleanup_free_
char *instance_name
= NULL
;
2976 r
= unit_name_to_instance(unit_name
, &instance_name
);
2980 if (strv_find(rule
.instances
, instance_name
))
2986 static int query_presets(const char *name
, const Presets presets
, char ***instance_name_list
) {
2987 PresetAction action
= PRESET_UNKNOWN
;
2990 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2993 for (i
= 0; i
< presets
.n_rules
; i
++)
2994 if (pattern_match_multiple_instances(presets
.rules
[i
], name
, instance_name_list
) > 0 ||
2995 fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2996 action
= presets
.rules
[i
].action
;
3001 case PRESET_UNKNOWN
:
3002 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3005 if (instance_name_list
&& *instance_name_list
)
3006 STRV_FOREACH(s
, *instance_name_list
)
3007 log_debug("Preset files say enable %s.", *s
);
3009 log_debug("Preset files say enable %s.", name
);
3011 case PRESET_DISABLE
:
3012 log_debug("Preset files say disable %s.", name
);
3015 assert_not_reached("invalid preset action");
3019 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
3020 _cleanup_(presets_freep
) Presets presets
= {};
3023 r
= read_presets(scope
, root_dir
, &presets
);
3027 return query_presets(name
, presets
, NULL
);
3030 static int execute_preset(
3031 UnitFileScope scope
,
3032 UnitFileFlags flags
,
3033 InstallContext
*plus
,
3034 InstallContext
*minus
,
3035 const LookupPaths
*paths
,
3037 UnitFilePresetMode mode
,
3038 UnitFileChange
**changes
,
3039 size_t *n_changes
) {
3041 const char *config_path
;
3042 bool force
= !!(flags
& UNIT_FILE_FORCE
);
3043 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
3050 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3051 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3053 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
3057 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
3058 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
3064 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3065 /* Returns number of symlinks that where supposed to be installed. */
3066 q
= install_context_apply(scope
, plus
, paths
,
3067 runtime
? paths
->runtime_config
: paths
->persistent_config
,
3068 force
, SEARCH_LOAD
, changes
, n_changes
);
3076 static int preset_prepare_one(
3077 UnitFileScope scope
,
3078 InstallContext
*plus
,
3079 InstallContext
*minus
,
3083 UnitFileChange
**changes
,
3084 size_t *n_changes
) {
3086 _cleanup_(install_context_done
) InstallContext tmp
= {};
3087 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3088 UnitFileInstallInfo
*i
;
3091 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3094 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3095 &i
, changes
, n_changes
);
3098 if (!streq(name
, i
->name
)) {
3099 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3103 r
= query_presets(name
, presets
, &instance_name_list
);
3108 if (instance_name_list
) {
3110 STRV_FOREACH(s
, instance_name_list
) {
3111 r
= install_info_discover_and_check(scope
, plus
, paths
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3112 &i
, changes
, n_changes
);
3117 r
= install_info_discover_and_check(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3118 &i
, changes
, n_changes
);
3124 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3125 &i
, changes
, n_changes
);
3130 int unit_file_preset(
3131 UnitFileScope scope
,
3132 UnitFileFlags flags
,
3133 const char *root_dir
,
3135 UnitFilePresetMode mode
,
3136 UnitFileChange
**changes
,
3137 size_t *n_changes
) {
3139 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3140 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3141 _cleanup_(presets_freep
) Presets presets
= {};
3146 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3147 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3149 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3153 r
= read_presets(scope
, root_dir
, &presets
);
3157 STRV_FOREACH(i
, files
) {
3158 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3163 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3166 int unit_file_preset_all(
3167 UnitFileScope scope
,
3168 UnitFileFlags flags
,
3169 const char *root_dir
,
3170 UnitFilePresetMode mode
,
3171 UnitFileChange
**changes
,
3172 size_t *n_changes
) {
3174 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3175 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3176 _cleanup_(presets_freep
) Presets presets
= {};
3181 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3182 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3184 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3188 r
= read_presets(scope
, root_dir
, &presets
);
3192 STRV_FOREACH(i
, paths
.search_path
) {
3193 _cleanup_closedir_
DIR *d
= NULL
;
3198 if (errno
== ENOENT
)
3204 FOREACH_DIRENT(de
, d
, return -errno
) {
3205 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3208 dirent_ensure_type(d
, de
);
3210 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3213 /* we don't pass changes[] in, because we want to handle errors on our own */
3214 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3216 r
= unit_file_changes_add(changes
, n_changes
,
3217 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3218 else if (r
== -ENOLINK
)
3219 r
= unit_file_changes_add(changes
, n_changes
,
3220 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3221 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3228 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3231 static void unit_file_list_free_one(UnitFileList
*f
) {
3239 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3240 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3243 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3245 int unit_file_get_list(
3246 UnitFileScope scope
,
3247 const char *root_dir
,
3252 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3257 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3260 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3264 STRV_FOREACH(i
, paths
.search_path
) {
3265 _cleanup_closedir_
DIR *d
= NULL
;
3270 if (errno
== ENOENT
)
3272 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3273 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3280 FOREACH_DIRENT(de
, d
, return -errno
) {
3281 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3283 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3286 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3289 if (hashmap_get(h
, de
->d_name
))
3292 dirent_ensure_type(d
, de
);
3294 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3297 f
= new0(UnitFileList
, 1);
3301 f
->path
= path_make_absolute(de
->d_name
, *i
);
3305 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3307 f
->state
= UNIT_FILE_BAD
;
3309 if (!strv_isempty(states
) &&
3310 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3313 r
= hashmap_put(h
, basename(f
->path
), f
);
3317 f
= NULL
; /* prevent cleanup */
3324 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3325 [UNIT_FILE_ENABLED
] = "enabled",
3326 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3327 [UNIT_FILE_LINKED
] = "linked",
3328 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3329 [UNIT_FILE_MASKED
] = "masked",
3330 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3331 [UNIT_FILE_STATIC
] = "static",
3332 [UNIT_FILE_DISABLED
] = "disabled",
3333 [UNIT_FILE_INDIRECT
] = "indirect",
3334 [UNIT_FILE_GENERATED
] = "generated",
3335 [UNIT_FILE_TRANSIENT
] = "transient",
3336 [UNIT_FILE_BAD
] = "bad",
3339 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3341 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3342 [UNIT_FILE_SYMLINK
] = "symlink",
3343 [UNIT_FILE_UNLINK
] = "unlink",
3344 [UNIT_FILE_IS_MASKED
] = "masked",
3345 [UNIT_FILE_IS_DANGLING
] = "dangling",
3348 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3350 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3351 [UNIT_FILE_PRESET_FULL
] = "full",
3352 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3353 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3356 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);