1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty <of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
33 #include "alloc-util.h"
34 #include "conf-files.h"
35 #include "conf-parser.h"
36 #include "dirent-util.h"
37 #include "extract-word.h"
42 #include "install-printf.h"
44 #include "locale-util.h"
48 #include "path-lookup.h"
49 #include "path-util.h"
53 #include "stat-util.h"
54 #include "string-table.h"
55 #include "string-util.h"
57 #include "unit-name.h"
59 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
61 typedef enum SearchFlags
{
63 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 2,
67 OrderedHashmap
*will_process
;
68 OrderedHashmap
*have_processed
;
87 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
90 return !strv_isempty(i
->aliases
) ||
91 !strv_isempty(i
->wanted_by
) ||
92 !strv_isempty(i
->required_by
);
95 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
98 return !strv_isempty(i
->also
);
101 static inline void presets_freep(Presets
*p
) {
107 for (i
= 0; i
< p
->n_rules
; i
++)
108 free(p
->rules
[i
].pattern
);
114 static int unit_file_lookup_state(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
, UnitFileState
*ret
);
116 bool unit_type_may_alias(UnitType type
) {
126 bool unit_type_may_template(UnitType type
) {
135 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
136 [UNIT_FILE_TYPE_REGULAR
] = "regular",
137 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
138 [UNIT_FILE_TYPE_MASKED
] = "masked",
141 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
143 static int in_search_path(const LookupPaths
*p
, const char *path
) {
144 _cleanup_free_
char *parent
= NULL
;
149 parent
= dirname_malloc(path
);
153 STRV_FOREACH(i
, p
->search_path
)
154 if (path_equal(parent
, *i
))
160 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
169 e
= path_startswith(path
, p
->root_dir
);
173 /* Make sure the returned path starts with a slash */
175 if (e
== path
|| e
[-1] != '/')
184 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
185 _cleanup_free_
char *parent
= NULL
;
190 parent
= dirname_malloc(path
);
194 return path_equal_ptr(parent
, p
->generator
) ||
195 path_equal_ptr(parent
, p
->generator_early
) ||
196 path_equal_ptr(parent
, p
->generator_late
);
199 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
200 _cleanup_free_
char *parent
= NULL
;
205 parent
= dirname_malloc(path
);
209 return path_equal_ptr(parent
, p
->transient
);
212 static int path_is_control(const LookupPaths
*p
, const char *path
) {
213 _cleanup_free_
char *parent
= NULL
;
218 parent
= dirname_malloc(path
);
222 return path_equal_ptr(parent
, p
->persistent_control
) ||
223 path_equal_ptr(parent
, p
->runtime_control
);
226 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
227 _cleanup_free_
char *parent
= NULL
;
232 /* Note that we do *not* have generic checks for /etc or /run in place, since with
233 * them we couldn't discern configuration from transient or generated units */
236 parent
= dirname_malloc(path
);
243 return path_equal_ptr(path
, p
->persistent_config
) ||
244 path_equal_ptr(path
, p
->runtime_config
);
247 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
248 _cleanup_free_
char *parent
= NULL
;
254 /* Everything in /run is considered runtime. On top of that we also add
255 * explicit checks for the various runtime directories, as safety net. */
257 rpath
= skip_root(p
, path
);
258 if (rpath
&& path_startswith(rpath
, "/run"))
262 parent
= dirname_malloc(path
);
269 return path_equal_ptr(path
, p
->runtime_config
) ||
270 path_equal_ptr(path
, p
->generator
) ||
271 path_equal_ptr(path
, p
->generator_early
) ||
272 path_equal_ptr(path
, p
->generator_late
) ||
273 path_equal_ptr(path
, p
->transient
) ||
274 path_equal_ptr(path
, p
->runtime_control
);
277 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
283 rpath
= skip_root(p
, path
);
287 if (path_startswith(rpath
, "/usr"))
291 if (path_startswith(rpath
, "/lib"))
295 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
298 int unit_file_changes_add(
299 UnitFileChange
**changes
,
301 UnitFileChangeType type
,
303 const char *source
) {
305 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
309 assert(!changes
== !n_changes
);
314 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
323 if (!p
|| (source
&& !s
))
326 path_kill_slashes(p
);
328 path_kill_slashes(s
);
330 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
336 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
339 assert(changes
|| n_changes
== 0);
341 for (i
= 0; i
< n_changes
; i
++) {
342 free(changes
[i
].path
);
343 free(changes
[i
].source
);
349 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, unsigned n_changes
, bool quiet
) {
353 assert(changes
|| n_changes
== 0);
354 /* If verb is not specified, errors are not allowed! */
355 assert(verb
|| r
>= 0);
357 for (i
= 0; i
< n_changes
; i
++) {
358 assert(verb
|| changes
[i
].type
>= 0);
360 switch(changes
[i
].type
) {
361 case UNIT_FILE_SYMLINK
:
363 log_info("Created symlink %s %s %s.",
365 special_glyph(ARROW
),
368 case UNIT_FILE_UNLINK
:
370 log_info("Removed %s.", changes
[i
].path
);
372 case UNIT_FILE_IS_MASKED
:
374 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
376 case UNIT_FILE_IS_DANGLING
:
378 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
382 if (changes
[i
].source
)
383 log_error_errno(changes
[i
].type
,
384 "Failed to %s unit, file %s already exists and is a symlink to %s.",
385 verb
, changes
[i
].path
, changes
[i
].source
);
387 log_error_errno(changes
[i
].type
,
388 "Failed to %s unit, file %s already exists.",
389 verb
, changes
[i
].path
);
393 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
394 verb
, changes
[i
].path
);
398 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
399 verb
, changes
[i
].path
);
403 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
404 verb
, changes
[i
].path
);
409 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
414 assert(changes
[i
].type
< 0);
415 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
416 verb
, changes
[i
].path
);
421 if (r
< 0 && !logged
)
422 log_error_errno(r
, "Failed to %s: %m.", verb
);
426 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
427 * wc should be the full path in the host file system.
429 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
430 assert(path_is_absolute(wd
));
432 /* This will give incorrect results if the paths are relative and go outside
433 * of the chroot. False negatives are possible. */
438 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
439 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
440 return path_equal_or_files_same(a
, b
, 0);
443 static int create_symlink(
444 const LookupPaths
*paths
,
445 const char *old_path
,
446 const char *new_path
,
448 UnitFileChange
**changes
,
449 unsigned *n_changes
) {
451 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
458 rp
= skip_root(paths
, old_path
);
462 /* Actually create a symlink, and remember that we did. Is
463 * smart enough to check if there's already a valid symlink in
466 * Returns 1 if a symlink was created or already exists and points to
467 * the right place, or negative on error.
470 mkdir_parents_label(new_path
, 0755);
472 if (symlink(old_path
, new_path
) >= 0) {
473 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
477 if (errno
!= EEXIST
) {
478 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
482 r
= readlink_malloc(new_path
, &dest
);
484 /* translate EINVAL (non-symlink exists) to EEXIST */
488 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
492 dirname
= dirname_malloc(new_path
);
496 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
500 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
504 r
= symlink_atomic(old_path
, new_path
);
506 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
510 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
511 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
516 static int mark_symlink_for_removal(
517 Set
**remove_symlinks_to
,
525 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
533 path_kill_slashes(n
);
535 r
= set_consume(*remove_symlinks_to
, n
);
544 static int remove_marked_symlinks_fd(
545 Set
*remove_symlinks_to
,
548 const char *config_path
,
549 const LookupPaths
*lp
,
552 UnitFileChange
**changes
,
553 unsigned *n_changes
) {
555 _cleanup_closedir_
DIR *d
= NULL
;
559 assert(remove_symlinks_to
);
574 FOREACH_DIRENT(de
, d
, return -errno
) {
576 dirent_ensure_type(d
, de
);
578 if (de
->d_type
== DT_DIR
) {
579 _cleanup_free_
char *p
= NULL
;
582 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
592 p
= path_make_absolute(de
->d_name
, path
);
598 /* This will close nfd, regardless whether it succeeds or not */
599 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
603 } else if (de
->d_type
== DT_LNK
) {
604 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
609 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
612 p
= path_make_absolute(de
->d_name
, path
);
615 path_kill_slashes(p
);
617 q
= readlink_malloc(p
, &dest
);
626 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
627 * the same name as a file that is marked. */
629 found
= set_contains(remove_symlinks_to
, dest
) ||
630 set_contains(remove_symlinks_to
, basename(dest
)) ||
631 set_contains(remove_symlinks_to
, de
->d_name
);
637 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
640 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
644 (void) rmdir_parents(p
, config_path
);
647 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
649 /* Now, remember the full path (but with the root prefix removed) of
650 * the symlink we just removed, and remove any symlinks to it, too. */
652 rp
= skip_root(lp
, p
);
653 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
656 if (q
> 0 && !dry_run
)
664 static int remove_marked_symlinks(
665 Set
*remove_symlinks_to
,
666 const char *config_path
,
667 const LookupPaths
*lp
,
669 UnitFileChange
**changes
,
670 unsigned *n_changes
) {
672 _cleanup_close_
int fd
= -1;
679 if (set_size(remove_symlinks_to
) <= 0)
682 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
684 return errno
== ENOENT
? 0 : -errno
;
690 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
694 /* This takes possession of cfd and closes it */
695 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
703 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
706 if (streq(name
, i
->name
))
709 if (strv_contains(i
->aliases
, name
))
712 /* Look for template symlink matching DefaultInstance */
713 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
714 _cleanup_free_
char *s
= NULL
;
716 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
721 } else if (streq(name
, s
))
728 static int find_symlinks_fd(
729 const char *root_dir
,
730 UnitFileInstallInfo
*i
,
734 const char *config_path
,
735 bool *same_name_link
) {
737 _cleanup_closedir_
DIR *d
= NULL
;
745 assert(same_name_link
);
753 FOREACH_DIRENT(de
, d
, return -errno
) {
755 dirent_ensure_type(d
, de
);
757 if (de
->d_type
== DT_DIR
) {
758 _cleanup_free_
char *p
= NULL
;
761 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
771 p
= path_make_absolute(de
->d_name
, path
);
777 /* This will close nfd, regardless whether it succeeds or not */
778 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
779 p
, config_path
, same_name_link
);
785 } else if (de
->d_type
== DT_LNK
) {
786 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
787 bool found_path
, found_dest
, b
= false;
790 /* Acquire symlink name */
791 p
= path_make_absolute(de
->d_name
, path
);
795 /* Acquire symlink destination */
796 q
= readlink_malloc(p
, &dest
);
806 if (!path_is_absolute(dest
)) {
809 x
= prefix_root(root_dir
, dest
);
817 /* Check if the symlink itself matches what we
819 if (path_is_absolute(i
->name
))
820 found_path
= path_equal(p
, i
->name
);
822 found_path
= streq(de
->d_name
, i
->name
);
824 /* Check if what the symlink points to
825 * matches what we are looking for */
826 if (path_is_absolute(i
->name
))
827 found_dest
= path_equal(dest
, i
->name
);
829 found_dest
= streq(basename(dest
), i
->name
);
831 if (found_path
&& found_dest
) {
832 _cleanup_free_
char *t
= NULL
;
834 /* Filter out same name links in the main
836 t
= path_make_absolute(i
->name
, config_path
);
840 b
= path_equal(t
, p
);
844 *same_name_link
= true;
845 else if (found_path
|| found_dest
) {
849 /* Check if symlink name is in the set of names used by [Install] */
850 q
= is_symlink_with_known_name(i
, de
->d_name
);
862 static int find_symlinks(
863 const char *root_dir
,
864 UnitFileInstallInfo
*i
,
866 const char *config_path
,
867 bool *same_name_link
) {
873 assert(same_name_link
);
875 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
877 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
882 /* This takes possession of fd and closes it */
883 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
884 config_path
, config_path
, same_name_link
);
887 static int find_symlinks_in_scope(
889 const LookupPaths
*paths
,
890 UnitFileInstallInfo
*i
,
892 UnitFileState
*state
) {
894 bool same_name_link_runtime
= false, same_name_link_config
= false;
895 bool enabled_in_runtime
= false, enabled_at_all
= false;
902 STRV_FOREACH(p
, paths
->search_path
) {
903 bool same_name_link
= false;
905 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
909 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
911 r
= path_is_config(paths
, *p
, false);
915 /* This is the best outcome, let's return it immediately. */
916 *state
= UNIT_FILE_ENABLED
;
920 /* look for globally enablement of user units */
921 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
922 *state
= UNIT_FILE_ENABLED
;
926 r
= path_is_runtime(paths
, *p
, false);
930 enabled_in_runtime
= true;
932 enabled_at_all
= true;
934 } else if (same_name_link
) {
936 r
= path_is_config(paths
, *p
, false);
940 same_name_link_config
= true;
942 r
= path_is_runtime(paths
, *p
, false);
946 same_name_link_runtime
= true;
951 if (enabled_in_runtime
) {
952 *state
= UNIT_FILE_ENABLED_RUNTIME
;
956 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
957 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
958 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
959 * something, and hence are a much stronger concept. */
960 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
961 *state
= UNIT_FILE_STATIC
;
965 /* Hmm, we didn't find it, but maybe we found the same name
967 if (same_name_link_config
) {
968 *state
= UNIT_FILE_LINKED
;
971 if (same_name_link_runtime
) {
972 *state
= UNIT_FILE_LINKED_RUNTIME
;
979 static void install_info_free(UnitFileInstallInfo
*i
) {
986 strv_free(i
->aliases
);
987 strv_free(i
->wanted_by
);
988 strv_free(i
->required_by
);
990 free(i
->default_instance
);
991 free(i
->symlink_target
);
995 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
996 UnitFileInstallInfo
*i
;
1001 while ((i
= ordered_hashmap_steal_first(m
)))
1002 install_info_free(i
);
1004 return ordered_hashmap_free(m
);
1007 static void install_context_done(InstallContext
*c
) {
1010 c
->will_process
= install_info_hashmap_free(c
->will_process
);
1011 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
1014 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
1015 UnitFileInstallInfo
*i
;
1017 i
= ordered_hashmap_get(c
->have_processed
, name
);
1021 return ordered_hashmap_get(c
->will_process
, name
);
1024 static int install_info_may_process(
1025 UnitFileInstallInfo
*i
,
1026 const LookupPaths
*paths
,
1027 UnitFileChange
**changes
,
1028 unsigned *n_changes
) {
1032 /* Checks whether the loaded unit file is one we should process, or is masked,
1033 * transient or generated and thus not subject to enable/disable operations. */
1035 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1036 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1039 if (path_is_generator(paths
, i
->path
) ||
1040 path_is_transient(paths
, i
->path
)) {
1041 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1042 return -EADDRNOTAVAIL
;
1049 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1050 * hashmap, or retrieves the existing one if already present.
1052 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1054 static int install_info_add(
1059 UnitFileInstallInfo
**ret
) {
1061 UnitFileInstallInfo
*i
= NULL
;
1065 assert(name
|| path
);
1068 name
= basename(path
);
1070 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1073 i
= install_info_find(c
, name
);
1075 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1082 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1086 i
= new0(UnitFileInstallInfo
, 1);
1089 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1090 i
->auxiliary
= auxiliary
;
1092 i
->name
= strdup(name
);
1099 i
->path
= strdup(path
);
1106 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1116 install_info_free(i
);
1120 static int config_parse_alias(
1122 const char *filename
,
1124 const char *section
,
1125 unsigned section_line
,
1139 type
= unit_name_to_type(unit
);
1140 if (!unit_type_may_alias(type
))
1141 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1142 "Alias= is not allowed for %s units, ignoring.",
1143 unit_type_to_string(type
));
1145 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1146 lvalue
, ltype
, rvalue
, data
, userdata
);
1149 static int config_parse_also(
1151 const char *filename
,
1153 const char *section
,
1154 unsigned section_line
,
1161 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1162 InstallContext
*c
= data
;
1171 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1173 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1179 r
= install_full_printf(info
, word
, &printed
);
1183 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1186 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1190 r
= strv_push(&info
->also
, printed
);
1200 static int config_parse_default_instance(
1202 const char *filename
,
1204 const char *section
,
1205 unsigned section_line
,
1212 UnitFileInstallInfo
*i
= data
;
1213 _cleanup_free_
char *printed
= NULL
;
1221 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1222 /* When enabling an instance, we might be using a template unit file,
1223 * but we should ignore DefaultInstance silently. */
1225 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1226 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1227 "DefaultInstance= only makes sense for template units, ignoring.");
1229 r
= install_full_printf(i
, rvalue
, &printed
);
1233 if (!unit_instance_is_valid(printed
))
1236 return free_and_replace(i
->default_instance
, printed
);
1239 static int unit_file_load(
1241 UnitFileInstallInfo
*info
,
1243 SearchFlags flags
) {
1245 const ConfigTableItem items
[] = {
1246 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1247 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1248 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1249 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1250 { "Install", "Also", config_parse_also
, 0, c
},
1255 _cleanup_fclose_
FILE *f
= NULL
;
1256 _cleanup_close_
int fd
= -1;
1263 type
= unit_name_to_type(info
->name
);
1264 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) &&
1265 !unit_type_may_template(type
))
1266 return log_error_errno(EINVAL
, "Unit type %s cannot be templated.", unit_type_to_string(type
));
1268 if (!(flags
& SEARCH_LOAD
)) {
1269 r
= lstat(path
, &st
);
1273 if (null_or_empty(&st
))
1274 info
->type
= UNIT_FILE_TYPE_MASKED
;
1275 else if (S_ISREG(st
.st_mode
))
1276 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1277 else if (S_ISLNK(st
.st_mode
))
1279 else if (S_ISDIR(st
.st_mode
))
1287 /* c is only needed if we actually load the file */
1290 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1293 if (fstat(fd
, &st
) < 0)
1295 if (null_or_empty(&st
)) {
1296 info
->type
= UNIT_FILE_TYPE_MASKED
;
1299 if (S_ISDIR(st
.st_mode
))
1301 if (!S_ISREG(st
.st_mode
))
1304 f
= fdopen(fd
, "re");
1309 r
= config_parse(info
->name
, path
, f
,
1311 config_item_table_lookup
, items
,
1312 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1314 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1316 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1319 (int) strv_length(info
->aliases
) +
1320 (int) strv_length(info
->wanted_by
) +
1321 (int) strv_length(info
->required_by
);
1324 static int unit_file_load_or_readlink(
1326 UnitFileInstallInfo
*info
,
1328 const char *root_dir
,
1329 SearchFlags flags
) {
1331 _cleanup_free_
char *target
= NULL
;
1334 r
= unit_file_load(c
, info
, path
, flags
);
1338 /* This is a symlink, let's read it. */
1340 r
= readlink_malloc(path
, &target
);
1344 if (path_equal(target
, "/dev/null"))
1345 info
->type
= UNIT_FILE_TYPE_MASKED
;
1350 bn
= basename(target
);
1352 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1354 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1357 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1359 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1362 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1364 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1369 /* Enforce that the symlink destination does not
1370 * change the unit file type. */
1372 a
= unit_name_to_type(info
->name
);
1373 b
= unit_name_to_type(bn
);
1374 if (a
< 0 || b
< 0 || a
!= b
)
1377 if (path_is_absolute(target
))
1378 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1379 info
->symlink_target
= prefix_root(root_dir
, target
);
1381 /* This is a relative path, take it relative to the dir the symlink is located in. */
1382 info
->symlink_target
= file_in_same_dir(path
, target
);
1383 if (!info
->symlink_target
)
1386 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1392 static int unit_file_search(
1394 UnitFileInstallInfo
*info
,
1395 const LookupPaths
*paths
,
1396 SearchFlags flags
) {
1398 _cleanup_free_
char *template = NULL
;
1399 _cleanup_strv_free_
char **dirs
= NULL
;
1400 _cleanup_strv_free_
char **files
= NULL
;
1401 const char *dropin_dir_name
= NULL
;
1402 const char *dropin_template_dir_name
= NULL
;
1407 bool found_unit
= false;
1412 /* Was this unit already loaded? */
1413 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1417 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1421 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1422 r
= unit_name_template(info
->name
, &template);
1427 STRV_FOREACH(p
, paths
->search_path
) {
1428 _cleanup_free_
char *path
= NULL
;
1430 path
= strjoin(*p
, "/", info
->name
);
1434 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1442 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1446 if (!found_unit
&& template) {
1448 /* Unit file doesn't exist, however instance
1449 * enablement was requested. We will check if it is
1450 * possible to load template unit file. */
1452 STRV_FOREACH(p
, paths
->search_path
) {
1453 _cleanup_free_
char *path
= NULL
;
1455 path
= strjoin(*p
, "/", template);
1459 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1466 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1472 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1476 /* Search for drop-in directories */
1478 dropin_dir_name
= strjoina(info
->name
, ".d");
1479 STRV_FOREACH(p
, paths
->search_path
) {
1482 path
= path_join(NULL
, *p
, dropin_dir_name
);
1486 r
= strv_consume(&dirs
, path
);
1492 dropin_template_dir_name
= strjoina(template, ".d");
1493 STRV_FOREACH(p
, paths
->search_path
) {
1496 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1500 r
= strv_consume(&dirs
, path
);
1506 /* Load drop-in conf files */
1508 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1510 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1512 STRV_FOREACH(p
, files
) {
1513 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
);
1515 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1521 static int install_info_follow(
1523 UnitFileInstallInfo
*i
,
1524 const char *root_dir
,
1526 bool ignore_different_name
) {
1531 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1533 if (!i
->symlink_target
)
1536 /* If the basename doesn't match, the caller should add a
1537 * complete new entry for this. */
1539 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1542 free_and_replace(i
->path
, i
->symlink_target
);
1543 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1545 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1549 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1550 * target, maybe more than once. Propagate the instance name if present.
1552 static int install_info_traverse(
1553 UnitFileScope scope
,
1555 const LookupPaths
*paths
,
1556 UnitFileInstallInfo
*start
,
1558 UnitFileInstallInfo
**ret
) {
1560 UnitFileInstallInfo
*i
;
1568 r
= unit_file_search(c
, start
, paths
, flags
);
1573 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1574 /* Follow the symlink */
1576 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1579 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1580 r
= path_is_config(paths
, i
->path
, true);
1587 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1589 _cleanup_free_
char *buffer
= NULL
;
1592 /* Target has a different name, create a new
1593 * install info object for that, and continue
1596 bn
= basename(i
->symlink_target
);
1598 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1599 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1601 _cleanup_free_
char *instance
= NULL
;
1603 r
= unit_name_to_instance(i
->name
, &instance
);
1607 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1611 if (streq(buffer
, i
->name
)) {
1613 /* We filled in the instance, and the target stayed the same? If so, then let's
1614 * honour the link as it is. */
1616 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1626 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1630 /* Try again, with the new target we found. */
1631 r
= unit_file_search(c
, i
, paths
, flags
);
1633 /* Translate error code to highlight this specific case */
1648 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1649 * or the name (otherwise). root_dir is prepended to the path.
1651 static int install_info_add_auto(
1653 const LookupPaths
*paths
,
1654 const char *name_or_path
,
1655 UnitFileInstallInfo
**ret
) {
1658 assert(name_or_path
);
1660 if (path_is_absolute(name_or_path
)) {
1663 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1665 return install_info_add(c
, NULL
, pp
, false, ret
);
1667 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1670 static int install_info_discover(
1671 UnitFileScope scope
,
1673 const LookupPaths
*paths
,
1676 UnitFileInstallInfo
**ret
,
1677 UnitFileChange
**changes
,
1678 unsigned *n_changes
) {
1680 UnitFileInstallInfo
*i
;
1687 r
= install_info_add_auto(c
, paths
, name
, &i
);
1689 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1692 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1696 static int install_info_symlink_alias(
1697 UnitFileInstallInfo
*i
,
1698 const LookupPaths
*paths
,
1699 const char *config_path
,
1701 UnitFileChange
**changes
,
1702 unsigned *n_changes
) {
1709 assert(config_path
);
1711 STRV_FOREACH(s
, i
->aliases
) {
1712 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1714 q
= install_full_printf(i
, *s
, &dst
);
1718 alias_path
= path_make_absolute(dst
, config_path
);
1722 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1730 static int install_info_symlink_wants(
1731 UnitFileInstallInfo
*i
,
1732 const LookupPaths
*paths
,
1733 const char *config_path
,
1736 UnitFileChange
**changes
,
1737 unsigned *n_changes
) {
1739 _cleanup_free_
char *buf
= NULL
;
1746 assert(config_path
);
1748 if (strv_isempty(list
))
1751 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1752 UnitFileInstallInfo instance
= {
1753 .type
= _UNIT_FILE_TYPE_INVALID
,
1755 _cleanup_free_
char *path
= NULL
;
1757 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1761 instance
.name
= buf
;
1762 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1766 path
= instance
.path
;
1767 instance
.path
= NULL
;
1769 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1770 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1778 STRV_FOREACH(s
, list
) {
1779 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1781 q
= install_full_printf(i
, *s
, &dst
);
1785 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1790 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1794 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1802 static int install_info_symlink_link(
1803 UnitFileInstallInfo
*i
,
1804 const LookupPaths
*paths
,
1805 const char *config_path
,
1807 UnitFileChange
**changes
,
1808 unsigned *n_changes
) {
1810 _cleanup_free_
char *path
= NULL
;
1815 assert(config_path
);
1818 r
= in_search_path(paths
, i
->path
);
1824 path
= strjoin(config_path
, "/", i
->name
);
1828 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1831 static int install_info_apply(
1832 UnitFileInstallInfo
*i
,
1833 const LookupPaths
*paths
,
1834 const char *config_path
,
1836 UnitFileChange
**changes
,
1837 unsigned *n_changes
) {
1843 assert(config_path
);
1845 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1848 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1850 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1854 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1858 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1859 /* Do not count links to the unit file towards the "carries_install_info" count */
1860 if (r
== 0 && q
< 0)
1866 static int install_context_apply(
1867 UnitFileScope scope
,
1869 const LookupPaths
*paths
,
1870 const char *config_path
,
1873 UnitFileChange
**changes
,
1874 unsigned *n_changes
) {
1876 UnitFileInstallInfo
*i
;
1881 assert(config_path
);
1883 if (ordered_hashmap_isempty(c
->will_process
))
1886 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1891 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1894 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1898 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1900 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1904 /* We can attempt to process a masked unit when a different unit
1905 * that we were processing specifies it in Also=. */
1906 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1907 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1909 /* Assume that something *could* have been enabled here,
1910 * avoid "empty [Install] section" warning. */
1915 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1918 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1930 static int install_context_mark_for_removal(
1931 UnitFileScope scope
,
1933 const LookupPaths
*paths
,
1934 Set
**remove_symlinks_to
,
1935 const char *config_path
,
1936 UnitFileChange
**changes
,
1937 unsigned *n_changes
) {
1939 UnitFileInstallInfo
*i
;
1944 assert(config_path
);
1946 /* Marks all items for removal */
1948 if (ordered_hashmap_isempty(c
->will_process
))
1951 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1955 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1957 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1961 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1962 if (r
== -ENOLINK
) {
1963 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1964 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1965 } else if (r
== -ENOENT
) {
1967 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1968 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1970 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1971 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1975 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1976 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1977 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1978 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1979 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1981 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1982 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1986 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1995 UnitFileScope scope
,
1996 UnitFileFlags flags
,
1997 const char *root_dir
,
1999 UnitFileChange
**changes
,
2000 unsigned *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 unsigned *n_changes
) {
2048 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2049 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2050 _cleanup_strv_free_
char **todo
= NULL
;
2051 size_t n_todo
= 0, n_allocated
= 0;
2052 const char *config_path
;
2058 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2060 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2064 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2068 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2070 STRV_FOREACH(i
, files
) {
2071 _cleanup_free_
char *path
= NULL
;
2073 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2076 path
= path_make_absolute(*i
, config_path
);
2080 r
= null_or_empty_path(path
);
2088 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2091 todo
[n_todo
] = strdup(*i
);
2101 STRV_FOREACH(i
, todo
) {
2102 _cleanup_free_
char *path
= NULL
;
2105 path
= path_make_absolute(*i
, config_path
);
2109 if (!dry_run
&& unlink(path
) < 0) {
2110 if (errno
!= ENOENT
) {
2113 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2119 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2121 rp
= skip_root(&paths
, path
);
2122 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2127 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2135 UnitFileScope scope
,
2136 UnitFileFlags flags
,
2137 const char *root_dir
,
2139 UnitFileChange
**changes
,
2140 unsigned *n_changes
) {
2142 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2143 _cleanup_strv_free_
char **todo
= NULL
;
2144 size_t n_todo
= 0, n_allocated
= 0;
2145 const char *config_path
;
2150 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2152 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2156 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2160 STRV_FOREACH(i
, files
) {
2161 _cleanup_free_
char *full
= NULL
;
2165 if (!path_is_absolute(*i
))
2169 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2172 full
= prefix_root(paths
.root_dir
, *i
);
2176 if (lstat(full
, &st
) < 0)
2178 if (S_ISLNK(st
.st_mode
))
2180 if (S_ISDIR(st
.st_mode
))
2182 if (!S_ISREG(st
.st_mode
))
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 unsigned *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
++] = dropin
;
2321 /* OK, there's a vendor version, hence drop all configuration versions */
2322 STRV_FOREACH(p
, paths
.search_path
) {
2323 _cleanup_free_
char *path
= NULL
;
2326 path
= path_make_absolute(*i
, *p
);
2330 r
= lstat(path
, &st
);
2332 if (errno
!= ENOENT
)
2334 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2335 r
= path_is_config(&paths
, path
, true);
2339 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2342 todo
[n_todo
++] = path
;
2352 STRV_FOREACH(i
, todo
) {
2353 _cleanup_strv_free_
char **fs
= NULL
;
2357 (void) get_files_in_directory(*i
, &fs
);
2359 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2360 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2365 STRV_FOREACH(j
, fs
) {
2366 _cleanup_free_
char *t
= NULL
;
2368 t
= strjoin(*i
, "/", *j
);
2372 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2375 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2377 rp
= skip_root(&paths
, *i
);
2378 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2383 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2387 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2394 int unit_file_add_dependency(
2395 UnitFileScope scope
,
2396 UnitFileFlags flags
,
2397 const char *root_dir
,
2401 UnitFileChange
**changes
,
2402 unsigned *n_changes
) {
2404 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2405 _cleanup_(install_context_done
) InstallContext c
= {};
2406 UnitFileInstallInfo
*i
, *target_info
;
2407 const char *config_path
;
2412 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2415 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2418 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2421 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2425 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2429 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2430 &target_info
, changes
, n_changes
);
2433 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2437 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2439 STRV_FOREACH(f
, files
) {
2442 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2443 &i
, changes
, n_changes
);
2446 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2450 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2452 /* We didn't actually load anything from the unit
2453 * file, but instead just add in our new symlink to
2456 if (dep
== UNIT_WANTS
)
2459 l
= &i
->required_by
;
2462 *l
= strv_new(target_info
->name
, NULL
);
2467 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2470 int unit_file_enable(
2471 UnitFileScope scope
,
2472 UnitFileFlags flags
,
2473 const char *root_dir
,
2475 UnitFileChange
**changes
,
2476 unsigned *n_changes
) {
2478 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2479 _cleanup_(install_context_done
) InstallContext c
= {};
2480 const char *config_path
;
2481 UnitFileInstallInfo
*i
;
2486 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2488 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2492 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2496 STRV_FOREACH(f
, files
) {
2497 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2498 &i
, changes
, n_changes
);
2501 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2505 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2508 /* This will return the number of symlink rules that were
2509 supposed to be created, not the ones actually created. This
2510 is useful to determine whether the passed files had any
2511 installation data at all. */
2513 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2516 int unit_file_disable(
2517 UnitFileScope scope
,
2518 UnitFileFlags flags
,
2519 const char *root_dir
,
2521 UnitFileChange
**changes
,
2522 unsigned *n_changes
) {
2524 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2525 _cleanup_(install_context_done
) InstallContext c
= {};
2526 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2527 const char *config_path
;
2532 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2534 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2538 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2542 STRV_FOREACH(i
, files
) {
2543 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2546 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2551 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2555 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2558 int unit_file_reenable(
2559 UnitFileScope scope
,
2560 UnitFileFlags flags
,
2561 const char *root_dir
,
2563 UnitFileChange
**changes
,
2564 unsigned *n_changes
) {
2570 /* First, we invoke the disable command with only the basename... */
2571 l
= strv_length(files
);
2572 n
= newa(char*, l
+1);
2573 for (i
= 0; i
< l
; i
++)
2574 n
[i
] = basename(files
[i
]);
2577 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2581 /* But the enable command with the full name */
2582 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2585 int unit_file_set_default(
2586 UnitFileScope scope
,
2587 UnitFileFlags flags
,
2588 const char *root_dir
,
2590 UnitFileChange
**changes
,
2591 unsigned *n_changes
) {
2593 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2594 _cleanup_(install_context_done
) InstallContext c
= {};
2595 UnitFileInstallInfo
*i
;
2596 const char *new_path
;
2600 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2603 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2605 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2608 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2612 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2615 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2619 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2620 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2623 int unit_file_get_default(
2624 UnitFileScope scope
,
2625 const char *root_dir
,
2628 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2629 _cleanup_(install_context_done
) InstallContext c
= {};
2630 UnitFileInstallInfo
*i
;
2635 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2638 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2642 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2646 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2650 n
= strdup(i
->name
);
2658 static int unit_file_lookup_state(
2659 UnitFileScope scope
,
2660 const LookupPaths
*paths
,
2662 UnitFileState
*ret
) {
2664 _cleanup_(install_context_done
) InstallContext c
= {};
2665 UnitFileInstallInfo
*i
;
2666 UnitFileState state
;
2672 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2675 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2680 /* Shortcut things, if the caller just wants to know if this unit exists. */
2686 case UNIT_FILE_TYPE_MASKED
:
2687 r
= path_is_runtime(paths
, i
->path
, true);
2691 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2694 case UNIT_FILE_TYPE_REGULAR
:
2695 r
= path_is_generator(paths
, i
->path
);
2699 state
= UNIT_FILE_GENERATED
;
2703 r
= path_is_transient(paths
, i
->path
);
2707 state
= UNIT_FILE_TRANSIENT
;
2711 /* Check if any of the Alias= symlinks have been created.
2712 * We ignore other aliases, and only check those that would
2713 * be created by systemctl enable for this unit. */
2714 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2720 /* Check if the file is known under other names. If it is,
2721 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2722 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2726 state
= UNIT_FILE_INDIRECT
;
2728 if (unit_file_install_info_has_rules(i
))
2729 state
= UNIT_FILE_DISABLED
;
2730 else if (unit_file_install_info_has_also(i
))
2731 state
= UNIT_FILE_INDIRECT
;
2733 state
= UNIT_FILE_STATIC
;
2739 assert_not_reached("Unexpect unit file type.");
2746 int unit_file_get_state(
2747 UnitFileScope scope
,
2748 const char *root_dir
,
2750 UnitFileState
*ret
) {
2752 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2756 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2759 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2763 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2766 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2767 _cleanup_(install_context_done
) InstallContext c
= {};
2773 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2776 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2785 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2786 _cleanup_(presets_freep
) Presets ps
= {};
2787 size_t n_allocated
= 0;
2788 _cleanup_strv_free_
char **files
= NULL
;
2793 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2796 if (scope
== UNIT_FILE_SYSTEM
)
2797 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2798 "/etc/systemd/system-preset",
2799 "/usr/local/lib/systemd/system-preset",
2800 "/usr/lib/systemd/system-preset",
2802 "/lib/systemd/system-preset",
2805 else if (scope
== UNIT_FILE_GLOBAL
)
2806 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2807 "/etc/systemd/user-preset",
2808 "/usr/local/lib/systemd/user-preset",
2809 "/usr/lib/systemd/user-preset",
2812 *presets
= (Presets
){};
2820 STRV_FOREACH(p
, files
) {
2821 _cleanup_fclose_
FILE *f
;
2822 char line
[LINE_MAX
];
2825 f
= fopen(*p
, "re");
2827 if (errno
== ENOENT
)
2833 FOREACH_LINE(line
, f
, return -errno
) {
2834 PresetRule rule
= {};
2835 const char *parameter
;
2843 if (strchr(COMMENTS
, *l
))
2846 parameter
= first_word(l
, "enable");
2850 pattern
= strdup(parameter
);
2854 rule
= (PresetRule
) {
2856 .action
= PRESET_ENABLE
,
2860 parameter
= first_word(l
, "disable");
2864 pattern
= strdup(parameter
);
2868 rule
= (PresetRule
) {
2870 .action
= PRESET_DISABLE
,
2875 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2878 ps
.rules
[ps
.n_rules
++] = rule
;
2882 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2892 static int query_presets(const char *name
, const Presets presets
) {
2893 PresetAction action
= PRESET_UNKNOWN
;
2896 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2899 for (i
= 0; i
< presets
.n_rules
; i
++)
2900 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2901 action
= presets
.rules
[i
].action
;
2906 case PRESET_UNKNOWN
:
2907 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2910 log_debug("Preset files say enable %s.", name
);
2912 case PRESET_DISABLE
:
2913 log_debug("Preset files say disable %s.", name
);
2916 assert_not_reached("invalid preset action");
2920 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2921 _cleanup_(presets_freep
) Presets presets
= {};
2924 r
= read_presets(scope
, root_dir
, &presets
);
2928 return query_presets(name
, presets
);
2931 static int execute_preset(
2932 UnitFileScope scope
,
2933 InstallContext
*plus
,
2934 InstallContext
*minus
,
2935 const LookupPaths
*paths
,
2936 const char *config_path
,
2938 UnitFilePresetMode mode
,
2940 UnitFileChange
**changes
,
2941 unsigned *n_changes
) {
2948 assert(config_path
);
2950 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2951 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2953 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2957 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2961 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2964 /* Returns number of symlinks that where supposed to be installed. */
2965 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2977 static int preset_prepare_one(
2978 UnitFileScope scope
,
2979 InstallContext
*plus
,
2980 InstallContext
*minus
,
2984 UnitFileChange
**changes
,
2985 unsigned *n_changes
) {
2987 _cleanup_(install_context_done
) InstallContext tmp
= {};
2988 UnitFileInstallInfo
*i
;
2991 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2994 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2995 &i
, changes
, n_changes
);
2998 if (!streq(name
, i
->name
)) {
2999 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
3003 r
= query_presets(name
, presets
);
3008 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3009 &i
, changes
, n_changes
);
3013 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
3017 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3018 &i
, changes
, n_changes
);
3023 int unit_file_preset(
3024 UnitFileScope scope
,
3025 UnitFileFlags flags
,
3026 const char *root_dir
,
3028 UnitFilePresetMode mode
,
3029 UnitFileChange
**changes
,
3030 unsigned *n_changes
) {
3032 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3033 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3034 _cleanup_(presets_freep
) Presets presets
= {};
3035 const char *config_path
;
3040 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3041 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3043 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3047 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3051 r
= read_presets(scope
, root_dir
, &presets
);
3055 STRV_FOREACH(i
, files
) {
3056 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3061 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3064 int unit_file_preset_all(
3065 UnitFileScope scope
,
3066 UnitFileFlags flags
,
3067 const char *root_dir
,
3068 UnitFilePresetMode mode
,
3069 UnitFileChange
**changes
,
3070 unsigned *n_changes
) {
3072 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3073 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3074 _cleanup_(presets_freep
) Presets presets
= {};
3075 const char *config_path
= NULL
;
3080 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3081 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3083 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3087 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3091 r
= read_presets(scope
, root_dir
, &presets
);
3095 STRV_FOREACH(i
, paths
.search_path
) {
3096 _cleanup_closedir_
DIR *d
= NULL
;
3101 if (errno
== ENOENT
)
3107 FOREACH_DIRENT(de
, d
, return -errno
) {
3109 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3112 dirent_ensure_type(d
, de
);
3114 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3117 /* we don't pass changes[] in, because we want to handle errors on our own */
3118 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3120 r
= unit_file_changes_add(changes
, n_changes
,
3121 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3122 else if (r
== -ENOLINK
)
3123 r
= unit_file_changes_add(changes
, n_changes
,
3124 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3125 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3132 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3135 static void unit_file_list_free_one(UnitFileList
*f
) {
3143 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3146 while ((i
= hashmap_steal_first(h
)))
3147 unit_file_list_free_one(i
);
3149 return hashmap_free(h
);
3152 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3154 int unit_file_get_list(
3155 UnitFileScope scope
,
3156 const char *root_dir
,
3161 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3166 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3169 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3173 STRV_FOREACH(i
, paths
.search_path
) {
3174 _cleanup_closedir_
DIR *d
= NULL
;
3179 if (errno
== ENOENT
)
3181 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3182 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3189 FOREACH_DIRENT(de
, d
, return -errno
) {
3190 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3192 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3195 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3198 if (hashmap_get(h
, de
->d_name
))
3201 dirent_ensure_type(d
, de
);
3203 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3206 f
= new0(UnitFileList
, 1);
3210 f
->path
= path_make_absolute(de
->d_name
, *i
);
3214 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3216 f
->state
= UNIT_FILE_BAD
;
3218 if (!strv_isempty(states
) &&
3219 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3222 r
= hashmap_put(h
, basename(f
->path
), f
);
3226 f
= NULL
; /* prevent cleanup */
3233 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3234 [UNIT_FILE_ENABLED
] = "enabled",
3235 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3236 [UNIT_FILE_LINKED
] = "linked",
3237 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3238 [UNIT_FILE_MASKED
] = "masked",
3239 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3240 [UNIT_FILE_STATIC
] = "static",
3241 [UNIT_FILE_DISABLED
] = "disabled",
3242 [UNIT_FILE_INDIRECT
] = "indirect",
3243 [UNIT_FILE_GENERATED
] = "generated",
3244 [UNIT_FILE_TRANSIENT
] = "transient",
3245 [UNIT_FILE_BAD
] = "bad",
3248 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3250 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3251 [UNIT_FILE_SYMLINK
] = "symlink",
3252 [UNIT_FILE_UNLINK
] = "unlink",
3253 [UNIT_FILE_IS_MASKED
] = "masked",
3254 [UNIT_FILE_IS_DANGLING
] = "dangling",
3257 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3259 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3260 [UNIT_FILE_PRESET_FULL
] = "full",
3261 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3262 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3265 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);