2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty <of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
32 #include "alloc-util.h"
33 #include "conf-files.h"
34 #include "conf-parser.h"
35 #include "dirent-util.h"
36 #include "extract-word.h"
41 #include "install-printf.h"
43 #include "locale-util.h"
47 #include "path-lookup.h"
48 #include "path-util.h"
52 #include "stat-util.h"
53 #include "string-table.h"
54 #include "string-util.h"
56 #include "unit-name.h"
58 #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64
60 typedef enum SearchFlags
{
62 SEARCH_FOLLOW_CONFIG_SYMLINKS
= 2,
66 OrderedHashmap
*will_process
;
67 OrderedHashmap
*have_processed
;
86 static inline bool unit_file_install_info_has_rules(UnitFileInstallInfo
*i
) {
89 return !strv_isempty(i
->aliases
) ||
90 !strv_isempty(i
->wanted_by
) ||
91 !strv_isempty(i
->required_by
);
94 static inline bool unit_file_install_info_has_also(UnitFileInstallInfo
*i
) {
97 return !strv_isempty(i
->also
);
100 static inline void presets_freep(Presets
*p
) {
106 for (i
= 0; i
< p
->n_rules
; i
++)
107 free(p
->rules
[i
].pattern
);
113 static int unit_file_lookup_state(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
, UnitFileState
*ret
);
115 bool unit_type_may_alias(UnitType type
) {
125 bool unit_type_may_template(UnitType type
) {
134 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
135 [UNIT_FILE_TYPE_REGULAR
] = "regular",
136 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
137 [UNIT_FILE_TYPE_MASKED
] = "masked",
140 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
142 static int in_search_path(const LookupPaths
*p
, const char *path
) {
143 _cleanup_free_
char *parent
= NULL
;
148 parent
= dirname_malloc(path
);
152 STRV_FOREACH(i
, p
->search_path
)
153 if (path_equal(parent
, *i
))
159 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
168 e
= path_startswith(path
, p
->root_dir
);
172 /* Make sure the returned path starts with a slash */
174 if (e
== path
|| e
[-1] != '/')
183 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
184 _cleanup_free_
char *parent
= NULL
;
189 parent
= dirname_malloc(path
);
193 return path_equal_ptr(parent
, p
->generator
) ||
194 path_equal_ptr(parent
, p
->generator_early
) ||
195 path_equal_ptr(parent
, p
->generator_late
);
198 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
199 _cleanup_free_
char *parent
= NULL
;
204 parent
= dirname_malloc(path
);
208 return path_equal_ptr(parent
, p
->transient
);
211 static int path_is_control(const LookupPaths
*p
, const char *path
) {
212 _cleanup_free_
char *parent
= NULL
;
217 parent
= dirname_malloc(path
);
221 return path_equal_ptr(parent
, p
->persistent_control
) ||
222 path_equal_ptr(parent
, p
->runtime_control
);
225 static int path_is_config(const LookupPaths
*p
, const char *path
, bool check_parent
) {
226 _cleanup_free_
char *parent
= NULL
;
231 /* Note that we do *not* have generic checks for /etc or /run in place, since with
232 * them we couldn't discern configuration from transient or generated units */
235 parent
= dirname_malloc(path
);
242 return path_equal_ptr(path
, p
->persistent_config
) ||
243 path_equal_ptr(path
, p
->runtime_config
);
246 static int path_is_runtime(const LookupPaths
*p
, const char *path
, bool check_parent
) {
247 _cleanup_free_
char *parent
= NULL
;
253 /* Everything in /run is considered runtime. On top of that we also add
254 * explicit checks for the various runtime directories, as safety net. */
256 rpath
= skip_root(p
, path
);
257 if (rpath
&& path_startswith(rpath
, "/run"))
261 parent
= dirname_malloc(path
);
268 return path_equal_ptr(path
, p
->runtime_config
) ||
269 path_equal_ptr(path
, p
->generator
) ||
270 path_equal_ptr(path
, p
->generator_early
) ||
271 path_equal_ptr(path
, p
->generator_late
) ||
272 path_equal_ptr(path
, p
->transient
) ||
273 path_equal_ptr(path
, p
->runtime_control
);
276 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
282 rpath
= skip_root(p
, path
);
286 if (path_startswith(rpath
, "/usr"))
290 if (path_startswith(rpath
, "/lib"))
294 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
297 int unit_file_changes_add(
298 UnitFileChange
**changes
,
300 UnitFileChangeType type
,
302 const char *source
) {
304 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
308 assert(!changes
== !n_changes
);
313 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
322 if (!p
|| (source
&& !s
))
325 path_kill_slashes(p
);
327 path_kill_slashes(s
);
329 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
335 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
338 assert(changes
|| n_changes
== 0);
340 for (i
= 0; i
< n_changes
; i
++) {
341 free(changes
[i
].path
);
342 free(changes
[i
].source
);
348 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, unsigned n_changes
, bool quiet
) {
352 assert(changes
|| n_changes
== 0);
353 /* If verb is not specified, errors are not allowed! */
354 assert(verb
|| r
>= 0);
356 for (i
= 0; i
< n_changes
; i
++) {
357 assert(verb
|| changes
[i
].type
>= 0);
359 switch(changes
[i
].type
) {
360 case UNIT_FILE_SYMLINK
:
362 log_info("Created symlink %s %s %s.",
364 special_glyph(ARROW
),
367 case UNIT_FILE_UNLINK
:
369 log_info("Removed %s.", changes
[i
].path
);
371 case UNIT_FILE_IS_MASKED
:
373 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
375 case UNIT_FILE_IS_DANGLING
:
377 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
381 if (changes
[i
].source
)
382 log_error_errno(changes
[i
].type
,
383 "Failed to %s unit, file %s already exists and is a symlink to %s.",
384 verb
, changes
[i
].path
, changes
[i
].source
);
386 log_error_errno(changes
[i
].type
,
387 "Failed to %s unit, file %s already exists.",
388 verb
, changes
[i
].path
);
392 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
393 verb
, changes
[i
].path
);
397 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
398 verb
, changes
[i
].path
);
402 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
403 verb
, changes
[i
].path
);
408 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s does not exist.", verb
, changes
[i
].path
);
413 assert(changes
[i
].type
< 0);
414 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
415 verb
, changes
[i
].path
);
420 if (r
< 0 && !logged
)
421 log_error_errno(r
, "Failed to %s: %m.", verb
);
425 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
426 * wc should be the full path in the host file system.
428 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
429 assert(path_is_absolute(wd
));
431 /* This will give incorrect results if the paths are relative and go outside
432 * of the chroot. False negatives are possible. */
437 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
438 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
439 return path_equal_or_files_same(a
, b
, 0);
442 static int create_symlink(
443 const LookupPaths
*paths
,
444 const char *old_path
,
445 const char *new_path
,
447 UnitFileChange
**changes
,
448 unsigned *n_changes
) {
450 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
457 rp
= skip_root(paths
, old_path
);
461 /* Actually create a symlink, and remember that we did. Is
462 * smart enough to check if there's already a valid symlink in
465 * Returns 1 if a symlink was created or already exists and points to
466 * the right place, or negative on error.
469 mkdir_parents_label(new_path
, 0755);
471 if (symlink(old_path
, new_path
) >= 0) {
472 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
476 if (errno
!= EEXIST
) {
477 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
481 r
= readlink_malloc(new_path
, &dest
);
483 /* translate EINVAL (non-symlink exists) to EEXIST */
487 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
491 dirname
= dirname_malloc(new_path
);
495 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
499 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
503 r
= symlink_atomic(old_path
, new_path
);
505 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
509 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
510 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
515 static int mark_symlink_for_removal(
516 Set
**remove_symlinks_to
,
524 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
532 path_kill_slashes(n
);
534 r
= set_consume(*remove_symlinks_to
, n
);
543 static int remove_marked_symlinks_fd(
544 Set
*remove_symlinks_to
,
547 const char *config_path
,
548 const LookupPaths
*lp
,
551 UnitFileChange
**changes
,
552 unsigned *n_changes
) {
554 _cleanup_closedir_
DIR *d
= NULL
;
558 assert(remove_symlinks_to
);
573 FOREACH_DIRENT(de
, d
, return -errno
) {
575 dirent_ensure_type(d
, de
);
577 if (de
->d_type
== DT_DIR
) {
578 _cleanup_free_
char *p
= NULL
;
581 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
591 p
= path_make_absolute(de
->d_name
, path
);
597 /* This will close nfd, regardless whether it succeeds or not */
598 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, dry_run
, restart
, changes
, n_changes
);
602 } else if (de
->d_type
== DT_LNK
) {
603 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
608 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
611 p
= path_make_absolute(de
->d_name
, path
);
614 path_kill_slashes(p
);
616 q
= readlink_malloc(p
, &dest
);
625 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
626 * the same name as a file that is marked. */
628 found
= set_contains(remove_symlinks_to
, dest
) ||
629 set_contains(remove_symlinks_to
, basename(dest
)) ||
630 set_contains(remove_symlinks_to
, de
->d_name
);
636 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
639 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
643 (void) rmdir_parents(p
, config_path
);
646 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
648 /* Now, remember the full path (but with the root prefix removed) of
649 * the symlink we just removed, and remove any symlinks to it, too. */
651 rp
= skip_root(lp
, p
);
652 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
655 if (q
> 0 && !dry_run
)
663 static int remove_marked_symlinks(
664 Set
*remove_symlinks_to
,
665 const char *config_path
,
666 const LookupPaths
*lp
,
668 UnitFileChange
**changes
,
669 unsigned *n_changes
) {
671 _cleanup_close_
int fd
= -1;
678 if (set_size(remove_symlinks_to
) <= 0)
681 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
683 return errno
== ENOENT
? 0 : -errno
;
689 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
693 /* This takes possession of cfd and closes it */
694 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, dry_run
, &restart
, changes
, n_changes
);
702 static bool is_symlink_with_known_name(const UnitFileInstallInfo
*i
, const char *name
) {
705 if (streq(name
, i
->name
))
708 if (strv_contains(i
->aliases
, name
))
711 /* Look for template symlink matching DefaultInstance */
712 if (i
->default_instance
&& unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
713 _cleanup_free_
char *s
= NULL
;
715 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &s
);
720 } else if (streq(name
, s
))
727 static int find_symlinks_fd(
728 const char *root_dir
,
729 UnitFileInstallInfo
*i
,
733 const char *config_path
,
734 bool *same_name_link
) {
736 _cleanup_closedir_
DIR *d
= NULL
;
744 assert(same_name_link
);
752 FOREACH_DIRENT(de
, d
, return -errno
) {
754 dirent_ensure_type(d
, de
);
756 if (de
->d_type
== DT_DIR
) {
757 _cleanup_free_
char *p
= NULL
;
760 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
770 p
= path_make_absolute(de
->d_name
, path
);
776 /* This will close nfd, regardless whether it succeeds or not */
777 q
= find_symlinks_fd(root_dir
, i
, match_aliases
, nfd
,
778 p
, config_path
, same_name_link
);
784 } else if (de
->d_type
== DT_LNK
) {
785 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
786 bool found_path
, found_dest
, b
= false;
789 /* Acquire symlink name */
790 p
= path_make_absolute(de
->d_name
, path
);
794 /* Acquire symlink destination */
795 q
= readlink_malloc(p
, &dest
);
805 if (!path_is_absolute(dest
)) {
808 x
= prefix_root(root_dir
, dest
);
816 /* Check if the symlink itself matches what we
818 if (path_is_absolute(i
->name
))
819 found_path
= path_equal(p
, i
->name
);
821 found_path
= streq(de
->d_name
, i
->name
);
823 /* Check if what the symlink points to
824 * matches what we are looking for */
825 if (path_is_absolute(i
->name
))
826 found_dest
= path_equal(dest
, i
->name
);
828 found_dest
= streq(basename(dest
), i
->name
);
830 if (found_path
&& found_dest
) {
831 _cleanup_free_
char *t
= NULL
;
833 /* Filter out same name links in the main
835 t
= path_make_absolute(i
->name
, config_path
);
839 b
= path_equal(t
, p
);
843 *same_name_link
= true;
844 else if (found_path
|| found_dest
) {
848 /* Check if symlink name is in the set of names used by [Install] */
849 q
= is_symlink_with_known_name(i
, de
->d_name
);
861 static int find_symlinks(
862 const char *root_dir
,
863 UnitFileInstallInfo
*i
,
865 const char *config_path
,
866 bool *same_name_link
) {
872 assert(same_name_link
);
874 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
876 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
881 /* This takes possession of fd and closes it */
882 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
883 config_path
, config_path
, same_name_link
);
886 static int find_symlinks_in_scope(
888 const LookupPaths
*paths
,
889 UnitFileInstallInfo
*i
,
891 UnitFileState
*state
) {
893 bool same_name_link_runtime
= false, same_name_link_config
= false;
894 bool enabled_in_runtime
= false, enabled_at_all
= false;
901 STRV_FOREACH(p
, paths
->search_path
) {
902 bool same_name_link
= false;
904 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
908 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
910 r
= path_is_config(paths
, *p
, false);
914 /* This is the best outcome, let's return it immediately. */
915 *state
= UNIT_FILE_ENABLED
;
919 /* look for globally enablement of user units */
920 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
921 *state
= UNIT_FILE_ENABLED
;
925 r
= path_is_runtime(paths
, *p
, false);
929 enabled_in_runtime
= true;
931 enabled_at_all
= true;
933 } else if (same_name_link
) {
935 r
= path_is_config(paths
, *p
, false);
939 same_name_link_config
= true;
941 r
= path_is_runtime(paths
, *p
, false);
945 same_name_link_runtime
= true;
950 if (enabled_in_runtime
) {
951 *state
= UNIT_FILE_ENABLED_RUNTIME
;
955 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
956 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
957 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
958 * something, and hence are a much stronger concept. */
959 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
960 *state
= UNIT_FILE_STATIC
;
964 /* Hmm, we didn't find it, but maybe we found the same name
966 if (same_name_link_config
) {
967 *state
= UNIT_FILE_LINKED
;
970 if (same_name_link_runtime
) {
971 *state
= UNIT_FILE_LINKED_RUNTIME
;
978 static void install_info_free(UnitFileInstallInfo
*i
) {
985 strv_free(i
->aliases
);
986 strv_free(i
->wanted_by
);
987 strv_free(i
->required_by
);
989 free(i
->default_instance
);
990 free(i
->symlink_target
);
994 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
995 UnitFileInstallInfo
*i
;
1000 while ((i
= ordered_hashmap_steal_first(m
)))
1001 install_info_free(i
);
1003 return ordered_hashmap_free(m
);
1006 static void install_context_done(InstallContext
*c
) {
1009 c
->will_process
= install_info_hashmap_free(c
->will_process
);
1010 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
1013 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
1014 UnitFileInstallInfo
*i
;
1016 i
= ordered_hashmap_get(c
->have_processed
, name
);
1020 return ordered_hashmap_get(c
->will_process
, name
);
1023 static int install_info_may_process(
1024 UnitFileInstallInfo
*i
,
1025 const LookupPaths
*paths
,
1026 UnitFileChange
**changes
,
1027 unsigned *n_changes
) {
1031 /* Checks whether the loaded unit file is one we should process, or is masked,
1032 * transient or generated and thus not subject to enable/disable operations. */
1034 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1035 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1038 if (path_is_generator(paths
, i
->path
) ||
1039 path_is_transient(paths
, i
->path
)) {
1040 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1041 return -EADDRNOTAVAIL
;
1048 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1049 * hashmap, or retrieves the existing one if already present.
1051 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1053 static int install_info_add(
1058 UnitFileInstallInfo
**ret
) {
1060 UnitFileInstallInfo
*i
= NULL
;
1064 assert(name
|| path
);
1067 name
= basename(path
);
1069 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1072 i
= install_info_find(c
, name
);
1074 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1081 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1085 i
= new0(UnitFileInstallInfo
, 1);
1088 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1089 i
->auxiliary
= auxiliary
;
1091 i
->name
= strdup(name
);
1098 i
->path
= strdup(path
);
1105 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1115 install_info_free(i
);
1119 static int config_parse_alias(
1121 const char *filename
,
1123 const char *section
,
1124 unsigned section_line
,
1138 type
= unit_name_to_type(unit
);
1139 if (!unit_type_may_alias(type
))
1140 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1141 "Alias= is not allowed for %s units, ignoring.",
1142 unit_type_to_string(type
));
1144 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1145 lvalue
, ltype
, rvalue
, data
, userdata
);
1148 static int config_parse_also(
1150 const char *filename
,
1152 const char *section
,
1153 unsigned section_line
,
1160 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1161 InstallContext
*c
= data
;
1170 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1172 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1178 r
= install_full_printf(info
, word
, &printed
);
1182 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1185 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1189 r
= strv_push(&info
->also
, printed
);
1199 static int config_parse_default_instance(
1201 const char *filename
,
1203 const char *section
,
1204 unsigned section_line
,
1211 UnitFileInstallInfo
*i
= data
;
1212 _cleanup_free_
char *printed
= NULL
;
1220 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1221 /* When enabling an instance, we might be using a template unit file,
1222 * but we should ignore DefaultInstance silently. */
1224 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1225 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1226 "DefaultInstance= only makes sense for template units, ignoring. %s", unit
);
1228 r
= install_full_printf(i
, rvalue
, &printed
);
1232 if (!unit_instance_is_valid(printed
))
1235 return free_and_replace(i
->default_instance
, printed
);
1238 static int unit_file_load(
1240 UnitFileInstallInfo
*info
,
1242 SearchFlags flags
) {
1244 const ConfigTableItem items
[] = {
1245 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1246 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1247 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1248 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1249 { "Install", "Also", config_parse_also
, 0, c
},
1254 _cleanup_fclose_
FILE *f
= NULL
;
1255 _cleanup_close_
int fd
= -1;
1262 type
= unit_name_to_type(info
->name
);
1263 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) &&
1264 !unit_type_may_template(type
))
1265 return log_error_errno(EINVAL
, "Unit type %s cannot be templated.", unit_type_to_string(type
));
1267 if (!(flags
& SEARCH_LOAD
)) {
1268 r
= lstat(path
, &st
);
1272 if (null_or_empty(&st
))
1273 info
->type
= UNIT_FILE_TYPE_MASKED
;
1274 else if (S_ISREG(st
.st_mode
))
1275 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1276 else if (S_ISLNK(st
.st_mode
))
1278 else if (S_ISDIR(st
.st_mode
))
1286 /* c is only needed if we actually load the file */
1289 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1292 if (fstat(fd
, &st
) < 0)
1294 if (null_or_empty(&st
)) {
1295 info
->type
= UNIT_FILE_TYPE_MASKED
;
1298 if (S_ISDIR(st
.st_mode
))
1300 if (!S_ISREG(st
.st_mode
))
1303 f
= fdopen(fd
, "re");
1308 r
= config_parse(info
->name
, path
, f
,
1310 config_item_table_lookup
, items
,
1311 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1313 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1315 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1318 (int) strv_length(info
->aliases
) +
1319 (int) strv_length(info
->wanted_by
) +
1320 (int) strv_length(info
->required_by
);
1323 static int unit_file_load_or_readlink(
1325 UnitFileInstallInfo
*info
,
1327 const char *root_dir
,
1328 SearchFlags flags
) {
1330 _cleanup_free_
char *target
= NULL
;
1333 r
= unit_file_load(c
, info
, path
, flags
);
1337 /* This is a symlink, let's read it. */
1339 r
= readlink_malloc(path
, &target
);
1343 if (path_equal(target
, "/dev/null"))
1344 info
->type
= UNIT_FILE_TYPE_MASKED
;
1349 bn
= basename(target
);
1351 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1353 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1356 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1358 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1361 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1363 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1368 /* Enforce that the symlink destination does not
1369 * change the unit file type. */
1371 a
= unit_name_to_type(info
->name
);
1372 b
= unit_name_to_type(bn
);
1373 if (a
< 0 || b
< 0 || a
!= b
)
1376 if (path_is_absolute(target
))
1377 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1378 info
->symlink_target
= prefix_root(root_dir
, target
);
1380 /* This is a relative path, take it relative to the dir the symlink is located in. */
1381 info
->symlink_target
= file_in_same_dir(path
, target
);
1382 if (!info
->symlink_target
)
1385 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1391 static int unit_file_search(
1393 UnitFileInstallInfo
*info
,
1394 const LookupPaths
*paths
,
1395 SearchFlags flags
) {
1397 _cleanup_free_
char *template = NULL
;
1398 _cleanup_strv_free_
char **dirs
= NULL
;
1399 _cleanup_strv_free_
char **files
= NULL
;
1400 const char *dropin_dir_name
= NULL
;
1401 const char *dropin_template_dir_name
= NULL
;
1406 bool found_unit
= false;
1411 /* Was this unit already loaded? */
1412 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1416 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1420 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1421 r
= unit_name_template(info
->name
, &template);
1426 STRV_FOREACH(p
, paths
->search_path
) {
1427 _cleanup_free_
char *path
= NULL
;
1429 path
= strjoin(*p
, "/", info
->name
);
1433 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1441 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1445 if (!found_unit
&& template) {
1447 /* Unit file doesn't exist, however instance
1448 * enablement was requested. We will check if it is
1449 * possible to load template unit file. */
1451 STRV_FOREACH(p
, paths
->search_path
) {
1452 _cleanup_free_
char *path
= NULL
;
1454 path
= strjoin(*p
, "/", template);
1458 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1465 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1471 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1475 /* Search for drop-in directories */
1477 dropin_dir_name
= strjoina(info
->name
, ".d");
1478 STRV_FOREACH(p
, paths
->search_path
) {
1481 path
= path_join(NULL
, *p
, dropin_dir_name
);
1485 r
= strv_consume(&dirs
, path
);
1491 dropin_template_dir_name
= strjoina(template, ".d");
1492 STRV_FOREACH(p
, paths
->search_path
) {
1495 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1499 r
= strv_consume(&dirs
, path
);
1505 /* Load drop-in conf files */
1507 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1509 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1511 STRV_FOREACH(p
, files
) {
1512 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
);
1514 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1520 static int install_info_follow(
1522 UnitFileInstallInfo
*i
,
1523 const char *root_dir
,
1525 bool ignore_different_name
) {
1530 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1532 if (!i
->symlink_target
)
1535 /* If the basename doesn't match, the caller should add a
1536 * complete new entry for this. */
1538 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1541 free_and_replace(i
->path
, i
->symlink_target
);
1542 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1544 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1548 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1549 * target, maybe more than once. Propagate the instance name if present.
1551 static int install_info_traverse(
1552 UnitFileScope scope
,
1554 const LookupPaths
*paths
,
1555 UnitFileInstallInfo
*start
,
1557 UnitFileInstallInfo
**ret
) {
1559 UnitFileInstallInfo
*i
;
1567 r
= unit_file_search(c
, start
, paths
, flags
);
1572 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1573 /* Follow the symlink */
1575 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1578 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1579 r
= path_is_config(paths
, i
->path
, true);
1586 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1588 _cleanup_free_
char *buffer
= NULL
;
1591 /* Target has a different name, create a new
1592 * install info object for that, and continue
1595 bn
= basename(i
->symlink_target
);
1597 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1598 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1600 _cleanup_free_
char *instance
= NULL
;
1602 r
= unit_name_to_instance(i
->name
, &instance
);
1606 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1610 if (streq(buffer
, i
->name
)) {
1612 /* We filled in the instance, and the target stayed the same? If so, then let's
1613 * honour the link as it is. */
1615 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1625 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1629 /* Try again, with the new target we found. */
1630 r
= unit_file_search(c
, i
, paths
, flags
);
1632 /* Translate error code to highlight this specific case */
1647 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1648 * or the name (otherwise). root_dir is prepended to the path.
1650 static int install_info_add_auto(
1652 const LookupPaths
*paths
,
1653 const char *name_or_path
,
1654 UnitFileInstallInfo
**ret
) {
1657 assert(name_or_path
);
1659 if (path_is_absolute(name_or_path
)) {
1662 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1664 return install_info_add(c
, NULL
, pp
, false, ret
);
1666 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1669 static int install_info_discover(
1670 UnitFileScope scope
,
1672 const LookupPaths
*paths
,
1675 UnitFileInstallInfo
**ret
,
1676 UnitFileChange
**changes
,
1677 unsigned *n_changes
) {
1679 UnitFileInstallInfo
*i
;
1686 r
= install_info_add_auto(c
, paths
, name
, &i
);
1688 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1691 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1695 static int install_info_symlink_alias(
1696 UnitFileInstallInfo
*i
,
1697 const LookupPaths
*paths
,
1698 const char *config_path
,
1700 UnitFileChange
**changes
,
1701 unsigned *n_changes
) {
1708 assert(config_path
);
1710 STRV_FOREACH(s
, i
->aliases
) {
1711 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1713 q
= install_full_printf(i
, *s
, &dst
);
1717 alias_path
= path_make_absolute(dst
, config_path
);
1721 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1729 static int install_info_symlink_wants(
1730 UnitFileInstallInfo
*i
,
1731 const LookupPaths
*paths
,
1732 const char *config_path
,
1735 UnitFileChange
**changes
,
1736 unsigned *n_changes
) {
1738 _cleanup_free_
char *buf
= NULL
;
1745 assert(config_path
);
1747 if (strv_isempty(list
))
1750 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1751 UnitFileInstallInfo instance
= {
1752 .type
= _UNIT_FILE_TYPE_INVALID
,
1754 _cleanup_free_
char *path
= NULL
;
1756 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1760 instance
.name
= buf
;
1761 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1765 path
= instance
.path
;
1766 instance
.path
= NULL
;
1768 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1769 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1777 STRV_FOREACH(s
, list
) {
1778 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1780 q
= install_full_printf(i
, *s
, &dst
);
1784 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1789 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1793 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1801 static int install_info_symlink_link(
1802 UnitFileInstallInfo
*i
,
1803 const LookupPaths
*paths
,
1804 const char *config_path
,
1806 UnitFileChange
**changes
,
1807 unsigned *n_changes
) {
1809 _cleanup_free_
char *path
= NULL
;
1814 assert(config_path
);
1817 r
= in_search_path(paths
, i
->path
);
1823 path
= strjoin(config_path
, "/", i
->name
);
1827 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1830 static int install_info_apply(
1831 UnitFileInstallInfo
*i
,
1832 const LookupPaths
*paths
,
1833 const char *config_path
,
1835 UnitFileChange
**changes
,
1836 unsigned *n_changes
) {
1842 assert(config_path
);
1844 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1847 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1849 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1853 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1857 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1858 /* Do not count links to the unit file towards the "carries_install_info" count */
1859 if (r
== 0 && q
< 0)
1865 static int install_context_apply(
1866 UnitFileScope scope
,
1868 const LookupPaths
*paths
,
1869 const char *config_path
,
1872 UnitFileChange
**changes
,
1873 unsigned *n_changes
) {
1875 UnitFileInstallInfo
*i
;
1880 assert(config_path
);
1882 if (ordered_hashmap_isempty(c
->will_process
))
1885 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1890 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1893 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1897 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1899 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1903 /* We can attempt to process a masked unit when a different unit
1904 * that we were processing specifies it in Also=. */
1905 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1906 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1908 /* Assume that something *could* have been enabled here,
1909 * avoid "empty [Install] section" warning. */
1914 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1917 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1929 static int install_context_mark_for_removal(
1930 UnitFileScope scope
,
1932 const LookupPaths
*paths
,
1933 Set
**remove_symlinks_to
,
1934 const char *config_path
,
1935 UnitFileChange
**changes
,
1936 unsigned *n_changes
) {
1938 UnitFileInstallInfo
*i
;
1943 assert(config_path
);
1945 /* Marks all items for removal */
1947 if (ordered_hashmap_isempty(c
->will_process
))
1950 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1954 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1956 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1960 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1961 if (r
== -ENOLINK
) {
1962 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1963 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1964 } else if (r
== -ENOENT
) {
1966 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1967 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1969 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1970 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1974 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1975 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1976 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1977 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1978 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1980 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1981 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1985 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1994 UnitFileScope scope
,
1995 UnitFileFlags flags
,
1996 const char *root_dir
,
1998 UnitFileChange
**changes
,
1999 unsigned *n_changes
) {
2001 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2002 const char *config_path
;
2007 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2009 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2013 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2017 STRV_FOREACH(i
, files
) {
2018 _cleanup_free_
char *path
= NULL
;
2021 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2027 path
= path_make_absolute(*i
, config_path
);
2031 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2032 if (q
< 0 && r
>= 0)
2039 int unit_file_unmask(
2040 UnitFileScope scope
,
2041 UnitFileFlags flags
,
2042 const char *root_dir
,
2044 UnitFileChange
**changes
,
2045 unsigned *n_changes
) {
2047 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2048 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2049 _cleanup_strv_free_
char **todo
= NULL
;
2050 size_t n_todo
= 0, n_allocated
= 0;
2051 const char *config_path
;
2057 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2059 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2063 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2067 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2069 STRV_FOREACH(i
, files
) {
2070 _cleanup_free_
char *path
= NULL
;
2072 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2075 path
= path_make_absolute(*i
, config_path
);
2079 r
= null_or_empty_path(path
);
2087 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2090 todo
[n_todo
] = strdup(*i
);
2100 STRV_FOREACH(i
, todo
) {
2101 _cleanup_free_
char *path
= NULL
;
2104 path
= path_make_absolute(*i
, config_path
);
2108 if (!dry_run
&& unlink(path
) < 0) {
2109 if (errno
!= ENOENT
) {
2112 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2118 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2120 rp
= skip_root(&paths
, path
);
2121 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2126 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2134 UnitFileScope scope
,
2135 UnitFileFlags flags
,
2136 const char *root_dir
,
2138 UnitFileChange
**changes
,
2139 unsigned *n_changes
) {
2141 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2142 _cleanup_strv_free_
char **todo
= NULL
;
2143 size_t n_todo
= 0, n_allocated
= 0;
2144 const char *config_path
;
2149 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2151 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2155 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2159 STRV_FOREACH(i
, files
) {
2160 _cleanup_free_
char *full
= NULL
;
2164 if (!path_is_absolute(*i
))
2168 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2171 full
= prefix_root(paths
.root_dir
, *i
);
2175 if (lstat(full
, &st
) < 0)
2177 if (S_ISLNK(st
.st_mode
))
2179 if (S_ISDIR(st
.st_mode
))
2181 if (!S_ISREG(st
.st_mode
))
2184 q
= in_search_path(&paths
, *i
);
2190 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2193 todo
[n_todo
] = strdup(*i
);
2203 STRV_FOREACH(i
, todo
) {
2204 _cleanup_free_
char *new_path
= NULL
;
2206 new_path
= path_make_absolute(basename(*i
), config_path
);
2210 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2211 if (q
< 0 && r
>= 0)
2218 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2224 /* Checks whether the path is one where the drop-in directories shall be removed. */
2226 r
= path_is_config(paths
, path
, true);
2230 r
= path_is_control(paths
, path
);
2234 return path_is_transient(paths
, path
);
2237 int unit_file_revert(
2238 UnitFileScope scope
,
2239 const char *root_dir
,
2241 UnitFileChange
**changes
,
2242 unsigned *n_changes
) {
2244 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2245 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2246 _cleanup_strv_free_
char **todo
= NULL
;
2247 size_t n_todo
= 0, n_allocated
= 0;
2251 /* Puts a unit file back into vendor state. This means:
2253 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2254 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2256 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2257 * "config", but not in "transient" or "control" or even "generated").
2259 * We remove all that in both the runtime and the persistent directories, if that applies.
2262 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2266 STRV_FOREACH(i
, files
) {
2267 bool has_vendor
= false;
2270 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2273 STRV_FOREACH(p
, paths
.search_path
) {
2274 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2277 path
= path_make_absolute(*i
, *p
);
2281 r
= lstat(path
, &st
);
2283 if (errno
!= ENOENT
)
2285 } else if (S_ISREG(st
.st_mode
)) {
2286 /* Check if there's a vendor version */
2287 r
= path_is_vendor(&paths
, path
);
2294 dropin
= strappend(path
, ".d");
2298 r
= lstat(dropin
, &st
);
2300 if (errno
!= ENOENT
)
2302 } else if (S_ISDIR(st
.st_mode
)) {
2303 /* Remove the drop-ins */
2304 r
= path_shall_revert(&paths
, dropin
);
2308 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2311 todo
[n_todo
++] = dropin
;
2320 /* OK, there's a vendor version, hence drop all configuration versions */
2321 STRV_FOREACH(p
, paths
.search_path
) {
2322 _cleanup_free_
char *path
= NULL
;
2325 path
= path_make_absolute(*i
, *p
);
2329 r
= lstat(path
, &st
);
2331 if (errno
!= ENOENT
)
2333 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2334 r
= path_is_config(&paths
, path
, true);
2338 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2341 todo
[n_todo
++] = path
;
2351 STRV_FOREACH(i
, todo
) {
2352 _cleanup_strv_free_
char **fs
= NULL
;
2356 (void) get_files_in_directory(*i
, &fs
);
2358 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2359 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2364 STRV_FOREACH(j
, fs
) {
2365 _cleanup_free_
char *t
= NULL
;
2367 t
= strjoin(*i
, "/", *j
);
2371 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2374 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2376 rp
= skip_root(&paths
, *i
);
2377 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2382 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2386 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2393 int unit_file_add_dependency(
2394 UnitFileScope scope
,
2395 UnitFileFlags flags
,
2396 const char *root_dir
,
2400 UnitFileChange
**changes
,
2401 unsigned *n_changes
) {
2403 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2404 _cleanup_(install_context_done
) InstallContext c
= {};
2405 UnitFileInstallInfo
*i
, *target_info
;
2406 const char *config_path
;
2411 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2414 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2417 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2420 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2424 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2428 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2429 &target_info
, changes
, n_changes
);
2432 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2436 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2438 STRV_FOREACH(f
, files
) {
2441 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2442 &i
, changes
, n_changes
);
2445 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2449 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2451 /* We didn't actually load anything from the unit
2452 * file, but instead just add in our new symlink to
2455 if (dep
== UNIT_WANTS
)
2458 l
= &i
->required_by
;
2461 *l
= strv_new(target_info
->name
, NULL
);
2466 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2469 int unit_file_enable(
2470 UnitFileScope scope
,
2471 UnitFileFlags flags
,
2472 const char *root_dir
,
2474 UnitFileChange
**changes
,
2475 unsigned *n_changes
) {
2477 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2478 _cleanup_(install_context_done
) InstallContext c
= {};
2479 const char *config_path
;
2480 UnitFileInstallInfo
*i
;
2485 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2487 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2491 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2495 STRV_FOREACH(f
, files
) {
2496 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2497 &i
, changes
, n_changes
);
2500 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2504 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2507 /* This will return the number of symlink rules that were
2508 supposed to be created, not the ones actually created. This
2509 is useful to determine whether the passed files had any
2510 installation data at all. */
2512 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2515 int unit_file_disable(
2516 UnitFileScope scope
,
2517 UnitFileFlags flags
,
2518 const char *root_dir
,
2520 UnitFileChange
**changes
,
2521 unsigned *n_changes
) {
2523 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2524 _cleanup_(install_context_done
) InstallContext c
= {};
2525 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2526 const char *config_path
;
2531 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2533 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2537 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2541 STRV_FOREACH(i
, files
) {
2542 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2545 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2550 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2554 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2557 int unit_file_reenable(
2558 UnitFileScope scope
,
2559 UnitFileFlags flags
,
2560 const char *root_dir
,
2562 UnitFileChange
**changes
,
2563 unsigned *n_changes
) {
2569 /* First, we invoke the disable command with only the basename... */
2570 l
= strv_length(files
);
2571 n
= newa(char*, l
+1);
2572 for (i
= 0; i
< l
; i
++)
2573 n
[i
] = basename(files
[i
]);
2576 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2580 /* But the enable command with the full name */
2581 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2584 int unit_file_set_default(
2585 UnitFileScope scope
,
2586 UnitFileFlags flags
,
2587 const char *root_dir
,
2589 UnitFileChange
**changes
,
2590 unsigned *n_changes
) {
2592 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2593 _cleanup_(install_context_done
) InstallContext c
= {};
2594 UnitFileInstallInfo
*i
;
2595 const char *new_path
;
2599 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2602 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2604 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2607 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2611 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2614 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2618 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2619 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2622 int unit_file_get_default(
2623 UnitFileScope scope
,
2624 const char *root_dir
,
2627 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2628 _cleanup_(install_context_done
) InstallContext c
= {};
2629 UnitFileInstallInfo
*i
;
2634 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2637 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2641 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2645 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2649 n
= strdup(i
->name
);
2657 static int unit_file_lookup_state(
2658 UnitFileScope scope
,
2659 const LookupPaths
*paths
,
2661 UnitFileState
*ret
) {
2663 _cleanup_(install_context_done
) InstallContext c
= {};
2664 UnitFileInstallInfo
*i
;
2665 UnitFileState state
;
2671 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2674 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2679 /* Shortcut things, if the caller just wants to know if this unit exists. */
2685 case UNIT_FILE_TYPE_MASKED
:
2686 r
= path_is_runtime(paths
, i
->path
, true);
2690 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2693 case UNIT_FILE_TYPE_REGULAR
:
2694 r
= path_is_generator(paths
, i
->path
);
2698 state
= UNIT_FILE_GENERATED
;
2702 r
= path_is_transient(paths
, i
->path
);
2706 state
= UNIT_FILE_TRANSIENT
;
2710 /* Check if any of the Alias= symlinks have been created.
2711 * We ignore other aliases, and only check those that would
2712 * be created by systemctl enable for this unit. */
2713 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2719 /* Check if the file is known under other names. If it is,
2720 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2721 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2725 state
= UNIT_FILE_INDIRECT
;
2727 if (unit_file_install_info_has_rules(i
))
2728 state
= UNIT_FILE_DISABLED
;
2729 else if (unit_file_install_info_has_also(i
))
2730 state
= UNIT_FILE_INDIRECT
;
2732 state
= UNIT_FILE_STATIC
;
2738 assert_not_reached("Unexpect unit file type.");
2745 int unit_file_get_state(
2746 UnitFileScope scope
,
2747 const char *root_dir
,
2749 UnitFileState
*ret
) {
2751 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2755 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2758 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2762 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2765 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2766 _cleanup_(install_context_done
) InstallContext c
= {};
2772 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2775 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2784 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2785 _cleanup_(presets_freep
) Presets ps
= {};
2786 size_t n_allocated
= 0;
2787 _cleanup_strv_free_
char **files
= NULL
;
2792 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2795 if (scope
== UNIT_FILE_SYSTEM
)
2796 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2797 "/etc/systemd/system-preset",
2798 "/usr/local/lib/systemd/system-preset",
2799 "/usr/lib/systemd/system-preset",
2801 "/lib/systemd/system-preset",
2804 else if (scope
== UNIT_FILE_GLOBAL
)
2805 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2806 "/etc/systemd/user-preset",
2807 "/usr/local/lib/systemd/user-preset",
2808 "/usr/lib/systemd/user-preset",
2811 *presets
= (Presets
){};
2819 STRV_FOREACH(p
, files
) {
2820 _cleanup_fclose_
FILE *f
;
2821 char line
[LINE_MAX
];
2824 f
= fopen(*p
, "re");
2826 if (errno
== ENOENT
)
2832 FOREACH_LINE(line
, f
, return -errno
) {
2833 PresetRule rule
= {};
2834 const char *parameter
;
2842 if (strchr(COMMENTS
, *l
))
2845 parameter
= first_word(l
, "enable");
2849 pattern
= strdup(parameter
);
2853 rule
= (PresetRule
) {
2855 .action
= PRESET_ENABLE
,
2859 parameter
= first_word(l
, "disable");
2863 pattern
= strdup(parameter
);
2867 rule
= (PresetRule
) {
2869 .action
= PRESET_DISABLE
,
2874 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2877 ps
.rules
[ps
.n_rules
++] = rule
;
2881 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2891 static int query_presets(const char *name
, const Presets presets
) {
2892 PresetAction action
= PRESET_UNKNOWN
;
2895 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2898 for (i
= 0; i
< presets
.n_rules
; i
++)
2899 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2900 action
= presets
.rules
[i
].action
;
2905 case PRESET_UNKNOWN
:
2906 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2909 log_debug("Preset files say enable %s.", name
);
2911 case PRESET_DISABLE
:
2912 log_debug("Preset files say disable %s.", name
);
2915 assert_not_reached("invalid preset action");
2919 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2920 _cleanup_(presets_freep
) Presets presets
= {};
2923 r
= read_presets(scope
, root_dir
, &presets
);
2927 return query_presets(name
, presets
);
2930 static int execute_preset(
2931 UnitFileScope scope
,
2932 InstallContext
*plus
,
2933 InstallContext
*minus
,
2934 const LookupPaths
*paths
,
2935 const char *config_path
,
2937 UnitFilePresetMode mode
,
2939 UnitFileChange
**changes
,
2940 unsigned *n_changes
) {
2947 assert(config_path
);
2949 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2950 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2952 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2956 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2960 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2963 /* Returns number of symlinks that where supposed to be installed. */
2964 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2976 static int preset_prepare_one(
2977 UnitFileScope scope
,
2978 InstallContext
*plus
,
2979 InstallContext
*minus
,
2983 UnitFileChange
**changes
,
2984 unsigned *n_changes
) {
2986 _cleanup_(install_context_done
) InstallContext tmp
= {};
2987 UnitFileInstallInfo
*i
;
2990 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2993 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2994 &i
, changes
, n_changes
);
2997 if (!streq(name
, i
->name
)) {
2998 log_debug("Skipping %s because is an alias for %s", name
, i
->name
);
3002 r
= query_presets(name
, presets
);
3007 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3008 &i
, changes
, n_changes
);
3012 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
3016 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3017 &i
, changes
, n_changes
);
3022 int unit_file_preset(
3023 UnitFileScope scope
,
3024 UnitFileFlags flags
,
3025 const char *root_dir
,
3027 UnitFilePresetMode mode
,
3028 UnitFileChange
**changes
,
3029 unsigned *n_changes
) {
3031 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3032 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3033 _cleanup_(presets_freep
) Presets presets
= {};
3034 const char *config_path
;
3039 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3040 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3042 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3046 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3050 r
= read_presets(scope
, root_dir
, &presets
);
3054 STRV_FOREACH(i
, files
) {
3055 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3060 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3063 int unit_file_preset_all(
3064 UnitFileScope scope
,
3065 UnitFileFlags flags
,
3066 const char *root_dir
,
3067 UnitFilePresetMode mode
,
3068 UnitFileChange
**changes
,
3069 unsigned *n_changes
) {
3071 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3072 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3073 _cleanup_(presets_freep
) Presets presets
= {};
3074 const char *config_path
= NULL
;
3079 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3080 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3082 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3086 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3090 r
= read_presets(scope
, root_dir
, &presets
);
3094 STRV_FOREACH(i
, paths
.search_path
) {
3095 _cleanup_closedir_
DIR *d
= NULL
;
3100 if (errno
== ENOENT
)
3106 FOREACH_DIRENT(de
, d
, return -errno
) {
3108 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3111 dirent_ensure_type(d
, de
);
3113 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3116 /* we don't pass changes[] in, because we want to handle errors on our own */
3117 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3119 r
= unit_file_changes_add(changes
, n_changes
,
3120 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3121 else if (r
== -ENOLINK
)
3122 r
= unit_file_changes_add(changes
, n_changes
,
3123 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3129 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3132 static void unit_file_list_free_one(UnitFileList
*f
) {
3140 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3143 while ((i
= hashmap_steal_first(h
)))
3144 unit_file_list_free_one(i
);
3146 return hashmap_free(h
);
3149 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3151 int unit_file_get_list(
3152 UnitFileScope scope
,
3153 const char *root_dir
,
3158 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3163 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3166 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3170 STRV_FOREACH(i
, paths
.search_path
) {
3171 _cleanup_closedir_
DIR *d
= NULL
;
3176 if (errno
== ENOENT
)
3178 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3179 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3186 FOREACH_DIRENT(de
, d
, return -errno
) {
3187 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3189 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3192 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3195 if (hashmap_get(h
, de
->d_name
))
3198 dirent_ensure_type(d
, de
);
3200 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3203 f
= new0(UnitFileList
, 1);
3207 f
->path
= path_make_absolute(de
->d_name
, *i
);
3211 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3213 f
->state
= UNIT_FILE_BAD
;
3215 if (!strv_isempty(states
) &&
3216 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3219 r
= hashmap_put(h
, basename(f
->path
), f
);
3223 f
= NULL
; /* prevent cleanup */
3230 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3231 [UNIT_FILE_ENABLED
] = "enabled",
3232 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3233 [UNIT_FILE_LINKED
] = "linked",
3234 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3235 [UNIT_FILE_MASKED
] = "masked",
3236 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3237 [UNIT_FILE_STATIC
] = "static",
3238 [UNIT_FILE_DISABLED
] = "disabled",
3239 [UNIT_FILE_INDIRECT
] = "indirect",
3240 [UNIT_FILE_GENERATED
] = "generated",
3241 [UNIT_FILE_TRANSIENT
] = "transient",
3242 [UNIT_FILE_BAD
] = "bad",
3245 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3247 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3248 [UNIT_FILE_SYMLINK
] = "symlink",
3249 [UNIT_FILE_UNLINK
] = "unlink",
3250 [UNIT_FILE_IS_MASKED
] = "masked",
3251 [UNIT_FILE_IS_DANGLING
] = "dangling",
3254 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3256 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3257 [UNIT_FILE_PRESET_FULL
] = "full",
3258 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3259 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3262 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);