1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include "alloc-util.h"
16 #include "conf-files.h"
17 #include "conf-parser.h"
19 #include "dirent-util.h"
20 #include "extract-word.h"
25 #include "install-printf.h"
27 #include "locale-util.h"
31 #include "path-lookup.h"
32 #include "path-util.h"
36 #include "stat-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
40 #include "unit-name.h"
42 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
44 typedef enum SearchFlags
{
46 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 1 << 1,
47 SEARCH_DROPIN
= 1 << 2,
51 OrderedHashmap
*will_process
;
52 OrderedHashmap
*have_processed
;
72 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
75 return !strv_isempty(i
->aliases
) ||
76 !strv_isempty(i
->wanted_by
) ||
77 !strv_isempty(i
->required_by
);
80 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
83 return !strv_isempty(i
->also
);
86 static inline void presets_freep(Presets
*p
) {
92 for (i
= 0; i
< p
->n_rules
; i
++) {
93 free(p
->rules
[i
].pattern
);
94 strv_free(p
->rules
[i
].instances
);
101 bool unit_type_may_alias(UnitType type
) {
111 bool unit_type_may_template(UnitType type
) {
120 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
121 [UNIT_FILE_TYPE_REGULAR
] = "regular",
122 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
123 [UNIT_FILE_TYPE_MASKED
] = "masked",
126 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
128 static int in_search_path(const LookupPaths
*p
, const char *path
) {
129 _cleanup_free_
char *parent
= NULL
;
134 parent
= dirname_malloc(path
);
138 STRV_FOREACH(i
, p
->search_path
)
139 if (path_equal(parent
, *i
))
145 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
154 e
= path_startswith(path
, p
->root_dir
);
158 /* Make sure the returned path starts with a slash */
160 if (e
== path
|| e
[-1] != '/')
169 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
170 _cleanup_free_
char *parent
= NULL
;
175 parent
= dirname_malloc(path
);
179 return path_equal_ptr(parent
, p
->generator
) ||
180 path_equal_ptr(parent
, p
->generator_early
) ||
181 path_equal_ptr(parent
, p
->generator_late
);
184 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
185 _cleanup_free_
char *parent
= NULL
;
190 parent
= dirname_malloc(path
);
194 return path_equal_ptr(parent
, p
->transient
);
197 static int path_is_control(const LookupPaths
*p
, const char *path
) {
198 _cleanup_free_
char *parent
= NULL
;
203 parent
= dirname_malloc(path
);
207 return path_equal_ptr(parent
, p
->persistent_control
) ||
208 path_equal_ptr(parent
, p
->runtime_control
);
211 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
212 _cleanup_free_
char *parent
= NULL
;
217 /* Note that we do *not* have generic checks for /etc or /run in place, since with
218 * them we couldn't discern configuration from transient or generated units */
221 parent
= dirname_malloc(path
);
228 return path_equal_ptr(path
, p
->persistent_config
) ||
229 path_equal_ptr(path
, p
->runtime_config
);
232 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
233 _cleanup_free_
char *parent
= NULL
;
239 /* Everything in /run is considered runtime. On top of that we also add
240 * explicit checks for the various runtime directories, as safety net. */
242 rpath
= skip_root(p
, path
);
243 if (rpath
&& path_startswith(rpath
, "/run"))
247 parent
= dirname_malloc(path
);
254 return path_equal_ptr(path
, p
->runtime_config
) ||
255 path_equal_ptr(path
, p
->generator
) ||
256 path_equal_ptr(path
, p
->generator_early
) ||
257 path_equal_ptr(path
, p
->generator_late
) ||
258 path_equal_ptr(path
, p
->transient
) ||
259 path_equal_ptr(path
, p
->runtime_control
);
262 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
268 rpath
= skip_root(p
, path
);
272 if (path_startswith(rpath
, "/usr"))
276 if (path_startswith(rpath
, "/lib"))
280 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
283 int unit_file_changes_add(
284 UnitFileChange
**changes
,
286 UnitFileChangeType type
,
288 const char *source
) {
290 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
294 assert(!changes
== !n_changes
);
299 c
= reallocarray(*changes
, *n_changes
+ 1, sizeof(UnitFileChange
));
308 if (!p
|| (source
&& !s
))
311 path_simplify(p
, false);
313 path_simplify(s
, false);
315 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
321 void unit_file_changes_free(UnitFileChange
*changes
, size_t n_changes
) {
324 assert(changes
|| n_changes
== 0);
326 for (i
= 0; i
< n_changes
; i
++) {
327 free(changes
[i
].path
);
328 free(changes
[i
].source
);
334 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, size_t n_changes
, bool quiet
) {
338 assert(changes
|| n_changes
== 0);
339 /* If verb is not specified, errors are not allowed! */
340 assert(verb
|| r
>= 0);
342 for (i
= 0; i
< n_changes
; i
++) {
343 assert(verb
|| changes
[i
].type
>= 0);
345 switch(changes
[i
].type
) {
346 case UNIT_FILE_SYMLINK
:
348 log_info("Created symlink %s %s %s.",
350 special_glyph(ARROW
),
353 case UNIT_FILE_UNLINK
:
355 log_info("Removed %s.", changes
[i
].path
);
357 case UNIT_FILE_IS_MASKED
:
359 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
361 case UNIT_FILE_IS_DANGLING
:
363 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
367 if (changes
[i
].source
)
368 log_error_errno(changes
[i
].type
,
369 "Failed to %s unit, file %s already exists and is a symlink to %s.",
370 verb
, changes
[i
].path
, changes
[i
].source
);
372 log_error_errno(changes
[i
].type
,
373 "Failed to %s unit, file %s already exists.",
374 verb
, changes
[i
].path
);
378 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
379 verb
, changes
[i
].path
);
383 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
384 verb
, changes
[i
].path
);
388 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
389 verb
, changes
[i
].path
);
394 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
399 assert(changes
[i
].type
< 0);
400 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
401 verb
, changes
[i
].path
);
406 if (r
< 0 && !logged
)
407 log_error_errno(r
, "Failed to %s: %m.", verb
);
411 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
412 * wc should be the full path in the host file system.
414 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
415 assert(path_is_absolute(wd
));
417 /* This will give incorrect results if the paths are relative and go outside
418 * of the chroot. False negatives are possible. */
423 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
424 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
425 return path_equal_or_files_same(a
, b
, 0);
428 static int create_symlink(
429 const LookupPaths
*paths
,
430 const char *old_path
,
431 const char *new_path
,
433 UnitFileChange
**changes
,
436 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
443 rp
= skip_root(paths
, old_path
);
447 /* Actually create a symlink, and remember that we did. Is
448 * smart enough to check if there's already a valid symlink in
451 * Returns 1 if a symlink was created or already exists and points to
452 * the right place, or negative on error.
455 mkdir_parents_label(new_path
, 0755);
457 if (symlink(old_path
, new_path
) >= 0) {
458 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
462 if (errno
!= EEXIST
) {
463 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
467 r
= readlink_malloc(new_path
, &dest
);
469 /* translate EINVAL (non-symlink exists) to EEXIST */
473 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
477 dirname
= dirname_malloc(new_path
);
481 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
485 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
489 r
= symlink_atomic(old_path
, new_path
);
491 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
495 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
496 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
501 static int mark_symlink_for_removal(
502 Set
**remove_symlinks_to
,
510 r
= set_ensure_allocated(remove_symlinks_to
, &path_hash_ops
);
518 path_simplify(n
, false);
520 r
= set_consume(*remove_symlinks_to
, n
);
529 static int remove_marked_symlinks_fd(
530 Set
*remove_symlinks_to
,
533 const char *config_path
,
534 const LookupPaths
*lp
,
537 UnitFileChange
**changes
,
540 _cleanup_closedir_
DIR *d
= NULL
;
544 assert(remove_symlinks_to
);
559 FOREACH_DIRENT(de
, d
, return -errno
) {
561 dirent_ensure_type(d
, de
);
563 if (de
->d_type
== DT_DIR
) {
564 _cleanup_free_
char *p
= NULL
;
567 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
577 p
= path_make_absolute(de
->d_name
, path
);
583 /* This will close nfd, regardless whether it succeeds or not */
584 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
588 } else if (de
->d_type
== DT_LNK
) {
589 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
594 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
597 p
= path_make_absolute(de
->d_name
, path
);
600 path_simplify(p
, false);
602 q
= readlink_malloc(p
, &dest
);
611 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
612 * the same name as a file that is marked. */
614 found
= set_contains(remove_symlinks_to
, dest
) ||
615 set_contains(remove_symlinks_to
, basename(dest
)) ||
616 set_contains(remove_symlinks_to
, de
->d_name
);
622 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
625 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
629 (void) rmdir_parents(p
, config_path
);
632 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
634 /* Now, remember the full path (but with the root prefix removed) of
635 * the symlink we just removed, and remove any symlinks to it, too. */
637 rp
= skip_root(lp
, p
);
638 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
641 if (q
> 0 && !dry_run
)
649 static int remove_marked_symlinks(
650 Set
*remove_symlinks_to
,
651 const char *config_path
,
652 const LookupPaths
*lp
,
654 UnitFileChange
**changes
,
657 _cleanup_close_
int fd
= -1;
664 if (set_size(remove_symlinks_to
) <= 0)
667 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
669 return errno
== ENOENT
? 0 : -errno
;
675 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
679 /* This takes possession of cfd and closes it */
680 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
688 static int is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
691 if (streq(name
, i
->name
))
694 if (strv_contains(i
->aliases
, name
))
697 /* Look for template symlink matching DefaultInstance */
698 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
699 _cleanup_free_
char *s
= NULL
;
701 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
706 } else if (streq(name
, s
))
713 static int find_symlinks_fd(
714 const char *root_dir
,
715 UnitFileInstallInfo
*i
,
719 const char *config_path
,
720 bool *same_name_link
) {
722 _cleanup_closedir_
DIR *d
= NULL
;
730 assert(same_name_link
);
738 FOREACH_DIRENT(de
, d
, return -errno
) {
740 dirent_ensure_type(d
, de
);
742 if (de
->d_type
== DT_DIR
) {
743 _cleanup_free_
char *p
= NULL
;
746 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
756 p
= path_make_absolute(de
->d_name
, path
);
762 /* This will close nfd, regardless whether it succeeds or not */
763 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
764 p
, config_path
, same_name_link
);
770 } else if (de
->d_type
== DT_LNK
) {
771 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
772 bool found_path
, found_dest
, b
= false;
775 /* Acquire symlink name */
776 p
= path_make_absolute(de
->d_name
, path
);
780 /* Acquire symlink destination */
781 q
= readlink_malloc(p
, &dest
);
791 if (!path_is_absolute(dest
)) {
794 x
= prefix_root(root_dir
, dest
);
802 /* Check if the symlink itself matches what we
804 if (path_is_absolute(i
->name
))
805 found_path
= path_equal(p
, i
->name
);
807 found_path
= streq(de
->d_name
, i
->name
);
809 /* Check if what the symlink points to
810 * matches what we are looking for */
811 if (path_is_absolute(i
->name
))
812 found_dest
= path_equal(dest
, i
->name
);
814 found_dest
= streq(basename(dest
), i
->name
);
816 if (found_path
&& found_dest
) {
817 _cleanup_free_
char *t
= NULL
;
819 /* Filter out same name links in the main
821 t
= path_make_absolute(i
->name
, config_path
);
825 b
= path_equal(t
, p
);
829 *same_name_link
= true;
830 else if (found_path
|| found_dest
) {
834 /* Check if symlink name is in the set of names used by [Install] */
835 q
= is_symlink_with_known_name(i
, de
->d_name
);
847 static int find_symlinks(
848 const char *root_dir
,
849 UnitFileInstallInfo
*i
,
851 const char *config_path
,
852 bool *same_name_link
) {
858 assert(same_name_link
);
860 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
862 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
867 /* This takes possession of fd and closes it */
868 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
869 config_path
, config_path
, same_name_link
);
872 static int find_symlinks_in_scope(
874 const LookupPaths
*paths
,
875 UnitFileInstallInfo
*i
,
877 UnitFileState
*state
) {
879 bool same_name_link_runtime
= false, same_name_link_config
= false;
880 bool enabled_in_runtime
= false, enabled_at_all
= false;
887 STRV_FOREACH(p
, paths
->search_path
) {
888 bool same_name_link
= false;
890 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
894 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
896 if (path_equal_ptr(*p
, paths
->persistent_config
)) {
897 /* This is the best outcome, let's return it immediately. */
898 *state
= UNIT_FILE_ENABLED
;
902 /* look for global enablement of user units */
903 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
904 *state
= UNIT_FILE_ENABLED
;
908 r
= path_is_runtime(paths
, *p
, false);
912 enabled_in_runtime
= true;
914 enabled_at_all
= true;
916 } else if (same_name_link
) {
917 if (path_equal_ptr(*p
, paths
->persistent_config
))
918 same_name_link_config
= true;
920 r
= path_is_runtime(paths
, *p
, false);
924 same_name_link_runtime
= true;
929 if (enabled_in_runtime
) {
930 *state
= UNIT_FILE_ENABLED_RUNTIME
;
934 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
935 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
936 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
937 * something, and hence are a much stronger concept. */
938 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
939 *state
= UNIT_FILE_STATIC
;
943 /* Hmm, we didn't find it, but maybe we found the same name
945 if (same_name_link_config
) {
946 *state
= UNIT_FILE_LINKED
;
949 if (same_name_link_runtime
) {
950 *state
= UNIT_FILE_LINKED_RUNTIME
;
957 static void install_info_free(UnitFileInstallInfo
*i
) {
964 strv_free(i
->aliases
);
965 strv_free(i
->wanted_by
);
966 strv_free(i
->required_by
);
968 free(i
->default_instance
);
969 free(i
->symlink_target
);
973 static void install_context_done(InstallContext
*c
) {
976 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
977 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
980 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
981 UnitFileInstallInfo
*i
;
983 i
= ordered_hashmap_get(c
->have_processed
, name
);
987 return ordered_hashmap_get(c
->will_process
, name
);
990 static int install_info_may_process(
991 UnitFileInstallInfo
*i
,
992 const LookupPaths
*paths
,
993 UnitFileChange
**changes
,
998 /* Checks whether the loaded unit file is one we should process, or is masked,
999 * transient or generated and thus not subject to enable/disable operations. */
1001 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1002 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1005 if (path_is_generator(paths
, i
->path
) ||
1006 path_is_transient(paths
, i
->path
)) {
1007 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1008 return -EADDRNOTAVAIL
;
1015 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1016 * hashmap, or retrieves the existing one if already present.
1018 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1020 static int install_info_add(
1025 UnitFileInstallInfo
**ret
) {
1027 UnitFileInstallInfo
*i
= NULL
;
1031 assert(name
|| path
);
1034 name
= basename(path
);
1036 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1039 i
= install_info_find(c
, name
);
1041 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1048 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1052 i
= new0(UnitFileInstallInfo
, 1);
1055 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1056 i
->auxiliary
= auxiliary
;
1058 i
->name
= strdup(name
);
1065 i
->path
= strdup(path
);
1072 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1082 install_info_free(i
);
1086 static int config_parse_alias(
1088 const char *filename
,
1090 const char *section
,
1091 unsigned section_line
,
1105 type
= unit_name_to_type(unit
);
1106 if (!unit_type_may_alias(type
))
1107 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1108 "Alias= is not allowed for %s units, ignoring.",
1109 unit_type_to_string(type
));
1111 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1112 lvalue
, ltype
, rvalue
, data
, userdata
);
1115 static int config_parse_also(
1117 const char *filename
,
1119 const char *section
,
1120 unsigned section_line
,
1127 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1128 InstallContext
*c
= data
;
1137 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1139 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1145 r
= install_full_printf(info
, word
, &printed
);
1149 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1152 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1156 r
= strv_push(&info
->also
, printed
);
1166 static int config_parse_default_instance(
1168 const char *filename
,
1170 const char *section
,
1171 unsigned section_line
,
1178 UnitFileInstallInfo
*i
= data
;
1179 _cleanup_free_
char *printed
= NULL
;
1187 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1188 /* When enabling an instance, we might be using a template unit file,
1189 * but we should ignore DefaultInstance silently. */
1191 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1192 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1193 "DefaultInstance= only makes sense for template units, ignoring.");
1195 r
= install_full_printf(i
, rvalue
, &printed
);
1199 if (!unit_instance_is_valid(printed
))
1202 return free_and_replace(i
->default_instance
, printed
);
1205 static int unit_file_load(
1207 UnitFileInstallInfo
*info
,
1209 const char *root_dir
,
1210 SearchFlags flags
) {
1212 const ConfigTableItem items
[] = {
1213 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1214 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1215 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1216 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1217 { "Install", "Also", config_parse_also
, 0, c
},
1222 _cleanup_fclose_
FILE *f
= NULL
;
1223 _cleanup_close_
int fd
= -1;
1230 if (!(flags
& SEARCH_DROPIN
)) {
1231 /* Loading or checking for the main unit file… */
1233 type
= unit_name_to_type(info
->name
);
1236 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) && !unit_type_may_template(type
)) {
1237 log_error("Unit type %s cannot be templated.", unit_type_to_string(type
));
1241 if (!(flags
& SEARCH_LOAD
)) {
1242 r
= lstat(path
, &st
);
1246 if (null_or_empty(&st
))
1247 info
->type
= UNIT_FILE_TYPE_MASKED
;
1248 else if (S_ISREG(st
.st_mode
))
1249 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1250 else if (S_ISLNK(st
.st_mode
))
1252 else if (S_ISDIR(st
.st_mode
))
1260 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1264 /* 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. */
1266 if (!(flags
& SEARCH_LOAD
))
1269 fd
= chase_symlinks_and_open(path
, root_dir
, 0, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
, NULL
);
1274 if (fstat(fd
, &st
) < 0)
1277 if (null_or_empty(&st
)) {
1278 if ((flags
& SEARCH_DROPIN
) == 0)
1279 info
->type
= UNIT_FILE_TYPE_MASKED
;
1284 r
= stat_verify_regular(&st
);
1288 f
= fdopen(fd
, "re");
1293 /* c is only needed if we actually load the file (it's referenced from items[] btw, in case you wonder.) */
1296 r
= config_parse(info
->name
, path
, f
,
1298 config_item_table_lookup
, items
,
1299 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1301 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1303 if ((flags
& SEARCH_DROPIN
) == 0)
1304 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1307 (int) strv_length(info
->aliases
) +
1308 (int) strv_length(info
->wanted_by
) +
1309 (int) strv_length(info
->required_by
);
1312 static int unit_file_load_or_readlink(
1314 UnitFileInstallInfo
*info
,
1316 const char *root_dir
,
1317 SearchFlags flags
) {
1319 _cleanup_free_
char *target
= NULL
;
1322 r
= unit_file_load(c
, info
, path
, root_dir
, flags
);
1323 if (r
!= -ELOOP
|| (flags
& SEARCH_DROPIN
))
1326 /* This is a symlink, let's read it. */
1328 r
= readlink_malloc(path
, &target
);
1332 if (path_equal(target
, "/dev/null"))
1333 info
->type
= UNIT_FILE_TYPE_MASKED
;
1338 bn
= basename(target
);
1340 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1342 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1345 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1347 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1350 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1352 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1357 /* Enforce that the symlink destination does not
1358 * change the unit file type. */
1360 a
= unit_name_to_type(info
->name
);
1361 b
= unit_name_to_type(bn
);
1362 if (a
< 0 || b
< 0 || a
!= b
)
1365 if (path_is_absolute(target
))
1366 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1367 info
->symlink_target
= prefix_root(root_dir
, target
);
1369 /* This is a relative path, take it relative to the dir the symlink is located in. */
1370 info
->symlink_target
= file_in_same_dir(path
, target
);
1371 if (!info
->symlink_target
)
1374 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1380 static int unit_file_search(
1382 UnitFileInstallInfo
*info
,
1383 const LookupPaths
*paths
,
1384 SearchFlags flags
) {
1386 const char *dropin_dir_name
= NULL
, *dropin_template_dir_name
= NULL
;
1387 _cleanup_strv_free_
char **dirs
= NULL
, **files
= NULL
;
1388 _cleanup_free_
char *template = NULL
;
1389 bool found_unit
= false;
1396 /* Was this unit already loaded? */
1397 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1401 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1405 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1406 r
= unit_name_template(info
->name
, &template);
1411 STRV_FOREACH(p
, paths
->search_path
) {
1412 _cleanup_free_
char *path
= NULL
;
1414 path
= strjoin(*p
, "/", info
->name
);
1418 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1420 info
->path
= TAKE_PTR(path
);
1424 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1428 if (!found_unit
&& template) {
1430 /* Unit file doesn't exist, however instance
1431 * enablement was requested. We will check if it is
1432 * possible to load template unit file. */
1434 STRV_FOREACH(p
, paths
->search_path
) {
1435 _cleanup_free_
char *path
= NULL
;
1437 path
= strjoin(*p
, "/", template);
1441 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1443 info
->path
= TAKE_PTR(path
);
1447 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1453 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1457 if (info
->type
== UNIT_FILE_TYPE_MASKED
)
1460 /* Search for drop-in directories */
1462 dropin_dir_name
= strjoina(info
->name
, ".d");
1463 STRV_FOREACH(p
, paths
->search_path
) {
1466 path
= path_join(NULL
, *p
, dropin_dir_name
);
1470 r
= strv_consume(&dirs
, path
);
1476 dropin_template_dir_name
= strjoina(template, ".d");
1477 STRV_FOREACH(p
, paths
->search_path
) {
1480 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1484 r
= strv_consume(&dirs
, path
);
1490 /* Load drop-in conf files */
1492 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1494 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1496 STRV_FOREACH(p
, files
) {
1497 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
| SEARCH_DROPIN
);
1499 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1505 static int install_info_follow(
1507 UnitFileInstallInfo
*i
,
1508 const char *root_dir
,
1510 bool ignore_different_name
) {
1515 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1517 if (!i
->symlink_target
)
1520 /* If the basename doesn't match, the caller should add a
1521 * complete new entry for this. */
1523 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1526 free_and_replace(i
->path
, i
->symlink_target
);
1527 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1529 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1533 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1534 * target, maybe more than once. Propagate the instance name if present.
1536 static int install_info_traverse(
1537 UnitFileScope scope
,
1539 const LookupPaths
*paths
,
1540 UnitFileInstallInfo
*start
,
1542 UnitFileInstallInfo
**ret
) {
1544 UnitFileInstallInfo
*i
;
1552 r
= unit_file_search(c
, start
, paths
, flags
);
1557 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1558 /* Follow the symlink */
1560 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1563 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1564 r
= path_is_config(paths
, i
->path
, true);
1571 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1573 _cleanup_free_
char *buffer
= NULL
;
1576 /* Target has a different name, create a new
1577 * install info object for that, and continue
1580 bn
= basename(i
->symlink_target
);
1582 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1583 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1585 _cleanup_free_
char *instance
= NULL
;
1587 r
= unit_name_to_instance(i
->name
, &instance
);
1591 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1595 if (streq(buffer
, i
->name
)) {
1597 /* We filled in the instance, and the target stayed the same? If so, then let's
1598 * honour the link as it is. */
1600 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1610 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1614 /* Try again, with the new target we found. */
1615 r
= unit_file_search(c
, i
, paths
, flags
);
1617 /* Translate error code to highlight this specific case */
1632 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1633 * or the name (otherwise). root_dir is prepended to the path.
1635 static int install_info_add_auto(
1637 const LookupPaths
*paths
,
1638 const char *name_or_path
,
1639 UnitFileInstallInfo
**ret
) {
1642 assert(name_or_path
);
1644 if (path_is_absolute(name_or_path
)) {
1647 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1649 return install_info_add(c
, NULL
, pp
, false, ret
);
1651 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1654 static int install_info_discover(
1655 UnitFileScope scope
,
1657 const LookupPaths
*paths
,
1660 UnitFileInstallInfo
**ret
,
1661 UnitFileChange
**changes
,
1662 size_t *n_changes
) {
1664 UnitFileInstallInfo
*i
;
1671 r
= install_info_add_auto(c
, paths
, name
, &i
);
1673 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1676 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1680 static int install_info_discover_and_check(
1681 UnitFileScope scope
,
1683 const LookupPaths
*paths
,
1686 UnitFileInstallInfo
**ret
,
1687 UnitFileChange
**changes
,
1688 size_t *n_changes
) {
1692 r
= install_info_discover(scope
, c
, paths
, name
, flags
, ret
, changes
, n_changes
);
1696 return install_info_may_process(ret
? *ret
: NULL
, paths
, changes
, n_changes
);
1699 static int install_info_symlink_alias(
1700 UnitFileInstallInfo
*i
,
1701 const LookupPaths
*paths
,
1702 const char *config_path
,
1704 UnitFileChange
**changes
,
1705 size_t *n_changes
) {
1712 assert(config_path
);
1714 STRV_FOREACH(s
, i
->aliases
) {
1715 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1717 q
= install_full_printf(i
, *s
, &dst
);
1721 alias_path
= path_make_absolute(dst
, config_path
);
1725 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1733 static int install_info_symlink_wants(
1734 UnitFileInstallInfo
*i
,
1735 const LookupPaths
*paths
,
1736 const char *config_path
,
1739 UnitFileChange
**changes
,
1740 size_t *n_changes
) {
1742 _cleanup_free_
char *buf
= NULL
;
1749 assert(config_path
);
1751 if (strv_isempty(list
))
1754 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1755 UnitFileInstallInfo instance
= {
1756 .type
= _UNIT_FILE_TYPE_INVALID
,
1758 _cleanup_free_
char *path
= NULL
;
1760 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1764 instance
.name
= buf
;
1765 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1769 path
= TAKE_PTR(instance
.path
);
1771 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1772 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1780 STRV_FOREACH(s
, list
) {
1781 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1783 q
= install_full_printf(i
, *s
, &dst
);
1787 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1792 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1796 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1804 static int install_info_symlink_link(
1805 UnitFileInstallInfo
*i
,
1806 const LookupPaths
*paths
,
1807 const char *config_path
,
1809 UnitFileChange
**changes
,
1810 size_t *n_changes
) {
1812 _cleanup_free_
char *path
= NULL
;
1817 assert(config_path
);
1820 r
= in_search_path(paths
, i
->path
);
1826 path
= strjoin(config_path
, "/", i
->name
);
1830 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1833 static int install_info_apply(
1834 UnitFileInstallInfo
*i
,
1835 const LookupPaths
*paths
,
1836 const char *config_path
,
1838 UnitFileChange
**changes
,
1839 size_t *n_changes
) {
1845 assert(config_path
);
1847 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1850 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1852 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1856 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1860 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1861 /* Do not count links to the unit file towards the "carries_install_info" count */
1862 if (r
== 0 && q
< 0)
1868 static int install_context_apply(
1869 UnitFileScope scope
,
1871 const LookupPaths
*paths
,
1872 const char *config_path
,
1875 UnitFileChange
**changes
,
1876 size_t *n_changes
) {
1878 UnitFileInstallInfo
*i
;
1883 assert(config_path
);
1885 if (ordered_hashmap_isempty(c
->will_process
))
1888 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1893 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1896 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1900 q
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1902 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1906 /* We can attempt to process a masked unit when a different unit
1907 * that we were processing specifies it in Also=. */
1908 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1909 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1911 /* Assume that something *could* have been enabled here,
1912 * avoid "empty [Install] section" warning. */
1917 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1920 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1932 static int install_context_mark_for_removal(
1933 UnitFileScope scope
,
1935 const LookupPaths
*paths
,
1936 Set
**remove_symlinks_to
,
1937 UnitFileChange
**changes
,
1938 size_t *n_changes
) {
1940 UnitFileInstallInfo
*i
;
1946 /* Marks all items for removal */
1948 if (ordered_hashmap_isempty(c
->will_process
))
1951 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1955 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1957 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1961 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1962 if (r
== -ENOLINK
) {
1963 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1964 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1965 } else if (r
== -ENOENT
) {
1967 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1968 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1970 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1971 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1975 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1976 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1977 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1978 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1979 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1981 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1982 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1986 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1995 UnitFileScope scope
,
1996 UnitFileFlags flags
,
1997 const char *root_dir
,
1999 UnitFileChange
**changes
,
2000 size_t *n_changes
) {
2002 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2003 const char *config_path
;
2008 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2010 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2014 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2018 STRV_FOREACH(i
, files
) {
2019 _cleanup_free_
char *path
= NULL
;
2022 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2028 path
= path_make_absolute(*i
, config_path
);
2032 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2033 if (q
< 0 && r
>= 0)
2040 int unit_file_unmask(
2041 UnitFileScope scope
,
2042 UnitFileFlags flags
,
2043 const char *root_dir
,
2045 UnitFileChange
**changes
,
2046 size_t *n_changes
) {
2048 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2049 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2050 _cleanup_strv_free_
char **todo
= NULL
;
2051 size_t n_todo
= 0, n_allocated
= 0;
2052 const char *config_path
;
2054 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2058 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2060 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2064 STRV_FOREACH(i
, files
) {
2065 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2068 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2069 _cleanup_free_
char *path
= NULL
;
2071 path
= path_make_absolute(*i
, config_path
);
2075 r
= null_or_empty_path(path
);
2083 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2086 todo
[n_todo
] = strdup(*i
);
2097 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2098 STRV_FOREACH(i
, todo
) {
2099 _cleanup_free_
char *path
= NULL
;
2102 path
= path_make_absolute(*i
, config_path
);
2106 if (!dry_run
&& unlink(path
) < 0) {
2107 if (errno
!= ENOENT
) {
2110 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2116 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2118 rp
= skip_root(&paths
, path
);
2119 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2124 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2133 UnitFileScope scope
,
2134 UnitFileFlags flags
,
2135 const char *root_dir
,
2137 UnitFileChange
**changes
,
2138 size_t *n_changes
) {
2140 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2141 _cleanup_strv_free_
char **todo
= NULL
;
2142 size_t n_todo
= 0, n_allocated
= 0;
2143 const char *config_path
;
2148 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2150 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2154 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2158 STRV_FOREACH(i
, files
) {
2159 _cleanup_free_
char *full
= NULL
;
2163 if (!path_is_absolute(*i
))
2167 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2170 full
= prefix_root(paths
.root_dir
, *i
);
2174 if (lstat(full
, &st
) < 0)
2176 r
= stat_verify_regular(&st
);
2180 q
= in_search_path(&paths
, *i
);
2186 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2189 todo
[n_todo
] = strdup(*i
);
2199 STRV_FOREACH(i
, todo
) {
2200 _cleanup_free_
char *new_path
= NULL
;
2202 new_path
= path_make_absolute(basename(*i
), config_path
);
2206 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2207 if (q
< 0 && r
>= 0)
2214 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2220 /* Checks whether the path is one where the drop-in directories shall be removed. */
2222 r
= path_is_config(paths
, path
, true);
2226 r
= path_is_control(paths
, path
);
2230 return path_is_transient(paths
, path
);
2233 int unit_file_revert(
2234 UnitFileScope scope
,
2235 const char *root_dir
,
2237 UnitFileChange
**changes
,
2238 size_t *n_changes
) {
2240 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2241 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2242 _cleanup_strv_free_
char **todo
= NULL
;
2243 size_t n_todo
= 0, n_allocated
= 0;
2247 /* Puts a unit file back into vendor state. This means:
2249 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2250 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2252 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2253 * "config", but not in "transient" or "control" or even "generated").
2255 * We remove all that in both the runtime and the persistent directories, if that applies.
2258 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2262 STRV_FOREACH(i
, files
) {
2263 bool has_vendor
= false;
2266 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2269 STRV_FOREACH(p
, paths
.search_path
) {
2270 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2273 path
= path_make_absolute(*i
, *p
);
2277 r
= lstat(path
, &st
);
2279 if (errno
!= ENOENT
)
2281 } else if (S_ISREG(st
.st_mode
)) {
2282 /* Check if there's a vendor version */
2283 r
= path_is_vendor(&paths
, path
);
2290 dropin
= strappend(path
, ".d");
2294 r
= lstat(dropin
, &st
);
2296 if (errno
!= ENOENT
)
2298 } else if (S_ISDIR(st
.st_mode
)) {
2299 /* Remove the drop-ins */
2300 r
= path_shall_revert(&paths
, dropin
);
2304 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2307 todo
[n_todo
++] = TAKE_PTR(dropin
);
2315 /* OK, there's a vendor version, hence drop all configuration versions */
2316 STRV_FOREACH(p
, paths
.search_path
) {
2317 _cleanup_free_
char *path
= NULL
;
2320 path
= path_make_absolute(*i
, *p
);
2324 r
= lstat(path
, &st
);
2326 if (errno
!= ENOENT
)
2328 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2329 r
= path_is_config(&paths
, path
, true);
2333 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2336 todo
[n_todo
++] = TAKE_PTR(path
);
2345 STRV_FOREACH(i
, todo
) {
2346 _cleanup_strv_free_
char **fs
= NULL
;
2350 (void) get_files_in_directory(*i
, &fs
);
2352 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2353 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2358 STRV_FOREACH(j
, fs
) {
2359 _cleanup_free_
char *t
= NULL
;
2361 t
= strjoin(*i
, "/", *j
);
2365 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2368 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2370 rp
= skip_root(&paths
, *i
);
2371 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2376 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2380 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2387 int unit_file_add_dependency(
2388 UnitFileScope scope
,
2389 UnitFileFlags flags
,
2390 const char *root_dir
,
2394 UnitFileChange
**changes
,
2395 size_t *n_changes
) {
2397 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2398 _cleanup_(install_context_done
) InstallContext c
= {};
2399 UnitFileInstallInfo
*i
, *target_info
;
2400 const char *config_path
;
2405 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2408 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2411 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2414 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2418 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2422 r
= install_info_discover_and_check(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2423 &target_info
, changes
, n_changes
);
2427 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2429 STRV_FOREACH(f
, files
) {
2432 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2433 &i
, changes
, n_changes
);
2437 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2439 /* We didn't actually load anything from the unit
2440 * file, but instead just add in our new symlink to
2443 if (dep
== UNIT_WANTS
)
2446 l
= &i
->required_by
;
2449 *l
= strv_new(target_info
->name
, NULL
);
2454 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2457 int unit_file_enable(
2458 UnitFileScope scope
,
2459 UnitFileFlags flags
,
2460 const char *root_dir
,
2462 UnitFileChange
**changes
,
2463 size_t *n_changes
) {
2465 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2466 _cleanup_(install_context_done
) InstallContext c
= {};
2467 const char *config_path
;
2468 UnitFileInstallInfo
*i
;
2473 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2475 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2479 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2483 STRV_FOREACH(f
, files
) {
2484 r
= install_info_discover_and_check(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2485 &i
, changes
, n_changes
);
2489 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2492 /* This will return the number of symlink rules that were
2493 supposed to be created, not the ones actually created. This
2494 is useful to determine whether the passed files had any
2495 installation data at all. */
2497 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2500 int unit_file_disable(
2501 UnitFileScope scope
,
2502 UnitFileFlags flags
,
2503 const char *root_dir
,
2505 UnitFileChange
**changes
,
2506 size_t *n_changes
) {
2508 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2509 _cleanup_(install_context_done
) InstallContext c
= {};
2510 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2511 bool dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2512 const char *config_path
;
2517 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2519 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2523 STRV_FOREACH(i
, files
) {
2524 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2527 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2532 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, changes
, n_changes
);
2536 FOREACH_STRING(config_path
, paths
.runtime_config
, paths
.persistent_config
) {
2537 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2545 int unit_file_reenable(
2546 UnitFileScope scope
,
2547 UnitFileFlags flags
,
2548 const char *root_dir
,
2550 UnitFileChange
**changes
,
2551 size_t *n_changes
) {
2557 /* First, we invoke the disable command with only the basename... */
2558 l
= strv_length(files
);
2559 n
= newa(char*, l
+1);
2560 for (i
= 0; i
< l
; i
++)
2561 n
[i
] = basename(files
[i
]);
2564 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2568 /* But the enable command with the full name */
2569 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2572 int unit_file_set_default(
2573 UnitFileScope scope
,
2574 UnitFileFlags flags
,
2575 const char *root_dir
,
2577 UnitFileChange
**changes
,
2578 size_t *n_changes
) {
2580 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2581 _cleanup_(install_context_done
) InstallContext c
= {};
2582 UnitFileInstallInfo
*i
;
2583 const char *new_path
;
2587 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2590 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2592 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2595 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2599 r
= install_info_discover_and_check(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2603 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2604 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2607 int unit_file_get_default(
2608 UnitFileScope scope
,
2609 const char *root_dir
,
2612 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2613 _cleanup_(install_context_done
) InstallContext c
= {};
2614 UnitFileInstallInfo
*i
;
2619 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2622 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2626 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2630 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2634 n
= strdup(i
->name
);
2642 int unit_file_lookup_state(
2643 UnitFileScope scope
,
2644 const LookupPaths
*paths
,
2646 UnitFileState
*ret
) {
2648 _cleanup_(install_context_done
) InstallContext c
= {};
2649 UnitFileInstallInfo
*i
;
2650 UnitFileState state
;
2656 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2659 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2664 /* Shortcut things, if the caller just wants to know if this unit exists. */
2670 case UNIT_FILE_TYPE_MASKED
:
2671 r
= path_is_runtime(paths
, i
->path
, true);
2675 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2678 case UNIT_FILE_TYPE_REGULAR
:
2679 r
= path_is_generator(paths
, i
->path
);
2683 state
= UNIT_FILE_GENERATED
;
2687 r
= path_is_transient(paths
, i
->path
);
2691 state
= UNIT_FILE_TRANSIENT
;
2695 /* Check if any of the Alias= symlinks have been created.
2696 * We ignore other aliases, and only check those that would
2697 * be created by systemctl enable for this unit. */
2698 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2704 /* Check if the file is known under other names. If it is,
2705 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2706 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2710 state
= UNIT_FILE_INDIRECT
;
2712 if (unit_file_install_info_has_rules(i
))
2713 state
= UNIT_FILE_DISABLED
;
2714 else if (unit_file_install_info_has_also(i
))
2715 state
= UNIT_FILE_INDIRECT
;
2717 state
= UNIT_FILE_STATIC
;
2723 assert_not_reached("Unexpect unit file type.");
2730 int unit_file_get_state(
2731 UnitFileScope scope
,
2732 const char *root_dir
,
2734 UnitFileState
*ret
) {
2736 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
2740 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2743 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2747 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2750 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2751 _cleanup_(install_context_done
) InstallContext c
= {};
2757 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2760 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2769 static int split_pattern_into_name_and_instances(const char *pattern
, char **out_unit_name
, char ***out_instances
) {
2770 _cleanup_strv_free_
char **instances
= NULL
;
2771 _cleanup_free_
char *unit_name
= NULL
;
2775 assert(out_instances
);
2776 assert(out_unit_name
);
2778 r
= extract_first_word(&pattern
, &unit_name
, NULL
, 0);
2782 /* We handle the instances logic when unit name is extracted */
2784 /* We only create instances when a rule of templated unit
2785 * is seen. A rule like enable foo@.service a b c will
2786 * result in an array of (a, b, c) as instance names */
2787 if (!unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
))
2790 instances
= strv_split(pattern
, WHITESPACE
);
2794 *out_instances
= TAKE_PTR(instances
);
2797 *out_unit_name
= TAKE_PTR(unit_name
);
2802 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2803 _cleanup_(presets_freep
) Presets ps
= {};
2804 size_t n_allocated
= 0;
2805 _cleanup_strv_free_
char **files
= NULL
;
2810 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2814 case UNIT_FILE_SYSTEM
:
2815 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2816 "/etc/systemd/system-preset",
2817 "/run/systemd/system-preset",
2818 "/usr/local/lib/systemd/system-preset",
2819 "/usr/lib/systemd/system-preset",
2821 "/lib/systemd/system-preset",
2826 case UNIT_FILE_GLOBAL
:
2827 case UNIT_FILE_USER
:
2828 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2829 "/etc/systemd/user-preset",
2830 "/run/systemd/user-preset",
2831 "/usr/local/lib/systemd/user-preset",
2832 "/usr/lib/systemd/user-preset",
2837 assert_not_reached("Invalid unit file scope");
2843 STRV_FOREACH(p
, files
) {
2844 _cleanup_fclose_
FILE *f
;
2847 f
= fopen(*p
, "re");
2849 if (errno
== ENOENT
)
2856 _cleanup_free_
char *line
= NULL
;
2857 PresetRule rule
= {};
2858 const char *parameter
;
2861 r
= read_line(f
, LONG_LINE_MAX
, &line
);
2872 if (strchr(COMMENTS
, *l
))
2875 parameter
= first_word(l
, "enable");
2878 char **instances
= NULL
;
2880 /* Unit_name will remain the same as parameter when no instances are specified */
2881 r
= split_pattern_into_name_and_instances(parameter
, &unit_name
, &instances
);
2883 log_syntax(NULL
, LOG_WARNING
, *p
, n
, r
, "Couldn't parse line '%s'. Ignoring.", line
);
2887 rule
= (PresetRule
) {
2888 .pattern
= unit_name
,
2889 .action
= PRESET_ENABLE
,
2890 .instances
= instances
,
2894 parameter
= first_word(l
, "disable");
2898 pattern
= strdup(parameter
);
2902 rule
= (PresetRule
) {
2904 .action
= PRESET_DISABLE
,
2909 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2912 ps
.rules
[ps
.n_rules
++] = rule
;
2916 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2926 static int pattern_match_multiple_instances(
2927 const PresetRule rule
,
2928 const char *unit_name
,
2931 _cleanup_free_
char *templated_name
= NULL
;
2934 /* If no ret is needed or the rule itself does not have instances
2935 * initalized, we return not matching */
2936 if (!ret
|| !rule
.instances
)
2939 r
= unit_name_template(unit_name
, &templated_name
);
2942 if (!streq(rule
.pattern
, templated_name
))
2945 /* Compose a list of specified instances when unit name is a template */
2946 if (unit_name_is_valid(unit_name
, UNIT_NAME_TEMPLATE
)) {
2947 _cleanup_free_
char *prefix
= NULL
;
2948 _cleanup_strv_free_
char **out_strv
= NULL
;
2951 r
= unit_name_to_prefix(unit_name
, &prefix
);
2955 STRV_FOREACH(iter
, rule
.instances
) {
2956 _cleanup_free_
char *name
= NULL
;
2957 r
= unit_name_build(prefix
, *iter
, ".service", &name
);
2960 r
= strv_extend(&out_strv
, name
);
2965 *ret
= TAKE_PTR(out_strv
);
2968 /* We now know the input unit name is an instance name */
2969 _cleanup_free_
char *instance_name
= NULL
;
2971 r
= unit_name_to_instance(unit_name
, &instance_name
);
2975 if (strv_find(rule
.instances
, instance_name
))
2981 static int query_presets(const char *name
, const Presets presets
, char ***instance_name_list
) {
2982 PresetAction action
= PRESET_UNKNOWN
;
2985 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2988 for (i
= 0; i
< presets
.n_rules
; i
++)
2989 if (pattern_match_multiple_instances(presets
.rules
[i
], name
, instance_name_list
) > 0 ||
2990 fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2991 action
= presets
.rules
[i
].action
;
2996 case PRESET_UNKNOWN
:
2997 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
3000 if (instance_name_list
&& *instance_name_list
)
3001 STRV_FOREACH(s
, *instance_name_list
)
3002 log_debug("Preset files say enable %s.", *s
);
3004 log_debug("Preset files say enable %s.", name
);
3006 case PRESET_DISABLE
:
3007 log_debug("Preset files say disable %s.", name
);
3010 assert_not_reached("invalid preset action");
3014 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
3015 _cleanup_(presets_freep
) Presets presets
= {};
3018 r
= read_presets(scope
, root_dir
, &presets
);
3022 return query_presets(name
, presets
, NULL
);
3025 static int execute_preset(
3026 UnitFileScope scope
,
3027 UnitFileFlags flags
,
3028 InstallContext
*plus
,
3029 InstallContext
*minus
,
3030 const LookupPaths
*paths
,
3032 UnitFilePresetMode mode
,
3033 UnitFileChange
**changes
,
3034 size_t *n_changes
) {
3036 const char *config_path
;
3037 bool force
= !!(flags
& UNIT_FILE_FORCE
);
3038 bool runtime
= !!(flags
& UNIT_FILE_RUNTIME
);
3045 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
3046 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
3048 q
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, changes
, n_changes
);
3052 FOREACH_STRING(config_path
, paths
->runtime_config
, paths
->persistent_config
) {
3053 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
3059 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
3060 /* Returns number of symlinks that where supposed to be installed. */
3061 q
= install_context_apply(scope
, plus
, paths
,
3062 runtime
? paths
->runtime_config
: paths
->persistent_config
,
3063 force
, SEARCH_LOAD
, changes
, n_changes
);
3071 static int preset_prepare_one(
3072 UnitFileScope scope
,
3073 InstallContext
*plus
,
3074 InstallContext
*minus
,
3078 UnitFileChange
**changes
,
3079 size_t *n_changes
) {
3081 _cleanup_(install_context_done
) InstallContext tmp
= {};
3082 _cleanup_strv_free_
char **instance_name_list
= NULL
;
3083 UnitFileInstallInfo
*i
;
3086 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
3089 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3090 &i
, changes
, n_changes
);
3093 if (!streq(name
, i
->name
)) {
3094 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3098 r
= query_presets(name
, presets
, &instance_name_list
);
3103 if (instance_name_list
) {
3105 STRV_FOREACH(s
, instance_name_list
) {
3106 r
= install_info_discover_and_check(scope
, plus
, paths
, *s
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3107 &i
, changes
, n_changes
);
3112 r
= install_info_discover_and_check(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3113 &i
, changes
, n_changes
);
3119 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3120 &i
, changes
, n_changes
);
3125 int unit_file_preset(
3126 UnitFileScope scope
,
3127 UnitFileFlags flags
,
3128 const char *root_dir
,
3130 UnitFilePresetMode mode
,
3131 UnitFileChange
**changes
,
3132 size_t *n_changes
) {
3134 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3135 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3136 _cleanup_(presets_freep
) Presets presets
= {};
3141 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3142 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3144 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3148 r
= read_presets(scope
, root_dir
, &presets
);
3152 STRV_FOREACH(i
, files
) {
3153 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3158 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, files
, mode
, changes
, n_changes
);
3161 int unit_file_preset_all(
3162 UnitFileScope scope
,
3163 UnitFileFlags flags
,
3164 const char *root_dir
,
3165 UnitFilePresetMode mode
,
3166 UnitFileChange
**changes
,
3167 size_t *n_changes
) {
3169 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3170 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3171 _cleanup_(presets_freep
) Presets presets
= {};
3176 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3177 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3179 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3183 r
= read_presets(scope
, root_dir
, &presets
);
3187 STRV_FOREACH(i
, paths
.search_path
) {
3188 _cleanup_closedir_
DIR *d
= NULL
;
3193 if (errno
== ENOENT
)
3199 FOREACH_DIRENT(de
, d
, return -errno
) {
3200 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3203 dirent_ensure_type(d
, de
);
3205 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3208 /* we don't pass changes[] in, because we want to handle errors on our own */
3209 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3211 r
= unit_file_changes_add(changes
, n_changes
,
3212 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3213 else if (r
== -ENOLINK
)
3214 r
= unit_file_changes_add(changes
, n_changes
,
3215 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3216 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3223 return execute_preset(scope
, flags
, &plus
, &minus
, &paths
, NULL
, mode
, changes
, n_changes
);
3226 static void unit_file_list_free_one(UnitFileList
*f
) {
3234 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3235 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3238 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3240 int unit_file_get_list(
3241 UnitFileScope scope
,
3242 const char *root_dir
,
3247 _cleanup_(lookup_paths_free
) LookupPaths paths
= {};
3252 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3255 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3259 STRV_FOREACH(i
, paths
.search_path
) {
3260 _cleanup_closedir_
DIR *d
= NULL
;
3265 if (errno
== ENOENT
)
3267 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3268 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3275 FOREACH_DIRENT(de
, d
, return -errno
) {
3276 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3278 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3281 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3284 if (hashmap_get(h
, de
->d_name
))
3287 dirent_ensure_type(d
, de
);
3289 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3292 f
= new0(UnitFileList
, 1);
3296 f
->path
= path_make_absolute(de
->d_name
, *i
);
3300 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3302 f
->state
= UNIT_FILE_BAD
;
3304 if (!strv_isempty(states
) &&
3305 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3308 r
= hashmap_put(h
, basename(f
->path
), f
);
3312 f
= NULL
; /* prevent cleanup */
3319 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3320 [UNIT_FILE_ENABLED
] = "enabled",
3321 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3322 [UNIT_FILE_LINKED
] = "linked",
3323 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3324 [UNIT_FILE_MASKED
] = "masked",
3325 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3326 [UNIT_FILE_STATIC
] = "static",
3327 [UNIT_FILE_DISABLED
] = "disabled",
3328 [UNIT_FILE_INDIRECT
] = "indirect",
3329 [UNIT_FILE_GENERATED
] = "generated",
3330 [UNIT_FILE_TRANSIENT
] = "transient",
3331 [UNIT_FILE_BAD
] = "bad",
3334 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3336 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3337 [UNIT_FILE_SYMLINK
] = "symlink",
3338 [UNIT_FILE_UNLINK
] = "unlink",
3339 [UNIT_FILE_IS_MASKED
] = "masked",
3340 [UNIT_FILE_IS_DANGLING
] = "dangling",
3343 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3345 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3346 [UNIT_FILE_PRESET_FULL
] = "full",
3347 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3348 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3351 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);