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 void install_context_done(InstallContext
*c
) {
998 c
->will_process
= ordered_hashmap_free_with_destructor(c
->will_process
, install_info_free
);
999 c
->have_processed
= ordered_hashmap_free_with_destructor(c
->have_processed
, install_info_free
);
1002 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
1003 UnitFileInstallInfo
*i
;
1005 i
= ordered_hashmap_get(c
->have_processed
, name
);
1009 return ordered_hashmap_get(c
->will_process
, name
);
1012 static int install_info_may_process(
1013 UnitFileInstallInfo
*i
,
1014 const LookupPaths
*paths
,
1015 UnitFileChange
**changes
,
1016 unsigned *n_changes
) {
1020 /* Checks whether the loaded unit file is one we should process, or is masked,
1021 * transient or generated and thus not subject to enable/disable operations. */
1023 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1024 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1027 if (path_is_generator(paths
, i
->path
) ||
1028 path_is_transient(paths
, i
->path
)) {
1029 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1030 return -EADDRNOTAVAIL
;
1037 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1038 * hashmap, or retrieves the existing one if already present.
1040 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1042 static int install_info_add(
1047 UnitFileInstallInfo
**ret
) {
1049 UnitFileInstallInfo
*i
= NULL
;
1053 assert(name
|| path
);
1056 name
= basename(path
);
1058 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1061 i
= install_info_find(c
, name
);
1063 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1070 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1074 i
= new0(UnitFileInstallInfo
, 1);
1077 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1078 i
->auxiliary
= auxiliary
;
1080 i
->name
= strdup(name
);
1087 i
->path
= strdup(path
);
1094 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1104 install_info_free(i
);
1108 static int config_parse_alias(
1110 const char *filename
,
1112 const char *section
,
1113 unsigned section_line
,
1127 type
= unit_name_to_type(unit
);
1128 if (!unit_type_may_alias(type
))
1129 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1130 "Alias= is not allowed for %s units, ignoring.",
1131 unit_type_to_string(type
));
1133 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1134 lvalue
, ltype
, rvalue
, data
, userdata
);
1137 static int config_parse_also(
1139 const char *filename
,
1141 const char *section
,
1142 unsigned section_line
,
1149 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1150 InstallContext
*c
= data
;
1159 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1161 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1167 r
= install_full_printf(info
, word
, &printed
);
1171 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1174 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1178 r
= strv_push(&info
->also
, printed
);
1188 static int config_parse_default_instance(
1190 const char *filename
,
1192 const char *section
,
1193 unsigned section_line
,
1200 UnitFileInstallInfo
*i
= data
;
1201 _cleanup_free_
char *printed
= NULL
;
1209 if (unit_name_is_valid(unit
, UNIT_NAME_INSTANCE
))
1210 /* When enabling an instance, we might be using a template unit file,
1211 * but we should ignore DefaultInstance silently. */
1213 if (!unit_name_is_valid(unit
, UNIT_NAME_TEMPLATE
))
1214 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1215 "DefaultInstance= only makes sense for template units, ignoring.");
1217 r
= install_full_printf(i
, rvalue
, &printed
);
1221 if (!unit_instance_is_valid(printed
))
1224 return free_and_replace(i
->default_instance
, printed
);
1227 static int unit_file_load(
1229 UnitFileInstallInfo
*info
,
1231 SearchFlags flags
) {
1233 const ConfigTableItem items
[] = {
1234 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1235 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1236 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1237 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1238 { "Install", "Also", config_parse_also
, 0, c
},
1243 _cleanup_fclose_
FILE *f
= NULL
;
1244 _cleanup_close_
int fd
= -1;
1251 type
= unit_name_to_type(info
->name
);
1252 if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) &&
1253 !unit_type_may_template(type
))
1254 return log_error_errno(EINVAL
, "Unit type %s cannot be templated.", unit_type_to_string(type
));
1256 if (!(flags
& SEARCH_LOAD
)) {
1257 r
= lstat(path
, &st
);
1261 if (null_or_empty(&st
))
1262 info
->type
= UNIT_FILE_TYPE_MASKED
;
1263 else if (S_ISREG(st
.st_mode
))
1264 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1265 else if (S_ISLNK(st
.st_mode
))
1267 else if (S_ISDIR(st
.st_mode
))
1275 /* c is only needed if we actually load the file */
1278 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1281 if (fstat(fd
, &st
) < 0)
1283 if (null_or_empty(&st
)) {
1284 info
->type
= UNIT_FILE_TYPE_MASKED
;
1287 if (S_ISDIR(st
.st_mode
))
1289 if (!S_ISREG(st
.st_mode
))
1292 f
= fdopen(fd
, "re");
1297 r
= config_parse(info
->name
, path
, f
,
1299 config_item_table_lookup
, items
,
1300 CONFIG_PARSE_RELAXED
|CONFIG_PARSE_ALLOW_INCLUDE
, info
);
1302 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1304 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1307 (int) strv_length(info
->aliases
) +
1308 (int) strv_length(info
->wanted_by
) +
1309 (int) strv_length(info
->required_by
);
1312 static int unit_file_load_or_readlink(
1314 UnitFileInstallInfo
*info
,
1316 const char *root_dir
,
1317 SearchFlags flags
) {
1319 _cleanup_free_
char *target
= NULL
;
1322 r
= unit_file_load(c
, info
, path
, flags
);
1326 /* This is a symlink, let's read it. */
1328 r
= readlink_malloc(path
, &target
);
1332 if (path_equal(target
, "/dev/null"))
1333 info
->type
= UNIT_FILE_TYPE_MASKED
;
1338 bn
= basename(target
);
1340 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1342 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1345 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1347 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1350 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1352 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1357 /* Enforce that the symlink destination does not
1358 * change the unit file type. */
1360 a
= unit_name_to_type(info
->name
);
1361 b
= unit_name_to_type(bn
);
1362 if (a
< 0 || b
< 0 || a
!= b
)
1365 if (path_is_absolute(target
))
1366 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1367 info
->symlink_target
= prefix_root(root_dir
, target
);
1369 /* This is a relative path, take it relative to the dir the symlink is located in. */
1370 info
->symlink_target
= file_in_same_dir(path
, target
);
1371 if (!info
->symlink_target
)
1374 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1380 static int unit_file_search(
1382 UnitFileInstallInfo
*info
,
1383 const LookupPaths
*paths
,
1384 SearchFlags flags
) {
1386 _cleanup_free_
char *template = NULL
;
1387 _cleanup_strv_free_
char **dirs
= NULL
;
1388 _cleanup_strv_free_
char **files
= NULL
;
1389 const char *dropin_dir_name
= NULL
;
1390 const char *dropin_template_dir_name
= NULL
;
1395 bool found_unit
= false;
1400 /* Was this unit already loaded? */
1401 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1405 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1409 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1410 r
= unit_name_template(info
->name
, &template);
1415 STRV_FOREACH(p
, paths
->search_path
) {
1416 _cleanup_free_
char *path
= NULL
;
1418 path
= strjoin(*p
, "/", info
->name
);
1422 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1430 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1434 if (!found_unit
&& template) {
1436 /* Unit file doesn't exist, however instance
1437 * enablement was requested. We will check if it is
1438 * possible to load template unit file. */
1440 STRV_FOREACH(p
, paths
->search_path
) {
1441 _cleanup_free_
char *path
= NULL
;
1443 path
= strjoin(*p
, "/", template);
1447 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1454 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1460 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1464 /* Search for drop-in directories */
1466 dropin_dir_name
= strjoina(info
->name
, ".d");
1467 STRV_FOREACH(p
, paths
->search_path
) {
1470 path
= path_join(NULL
, *p
, dropin_dir_name
);
1474 r
= strv_consume(&dirs
, path
);
1480 dropin_template_dir_name
= strjoina(template, ".d");
1481 STRV_FOREACH(p
, paths
->search_path
) {
1484 path
= path_join(NULL
, *p
, dropin_template_dir_name
);
1488 r
= strv_consume(&dirs
, path
);
1494 /* Load drop-in conf files */
1496 r
= conf_files_list_strv(&files
, ".conf", NULL
, 0, (const char**) dirs
);
1498 return log_debug_errno(r
, "Failed to get list of conf files: %m");
1500 STRV_FOREACH(p
, files
) {
1501 r
= unit_file_load_or_readlink(c
, info
, *p
, paths
->root_dir
, flags
);
1503 return log_debug_errno(r
, "Failed to load conf file %s: %m", *p
);
1509 static int install_info_follow(
1511 UnitFileInstallInfo
*i
,
1512 const char *root_dir
,
1514 bool ignore_different_name
) {
1519 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1521 if (!i
->symlink_target
)
1524 /* If the basename doesn't match, the caller should add a
1525 * complete new entry for this. */
1527 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1530 free_and_replace(i
->path
, i
->symlink_target
);
1531 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1533 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1537 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1538 * target, maybe more than once. Propagate the instance name if present.
1540 static int install_info_traverse(
1541 UnitFileScope scope
,
1543 const LookupPaths
*paths
,
1544 UnitFileInstallInfo
*start
,
1546 UnitFileInstallInfo
**ret
) {
1548 UnitFileInstallInfo
*i
;
1556 r
= unit_file_search(c
, start
, paths
, flags
);
1561 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1562 /* Follow the symlink */
1564 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1567 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1568 r
= path_is_config(paths
, i
->path
, true);
1575 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1577 _cleanup_free_
char *buffer
= NULL
;
1580 /* Target has a different name, create a new
1581 * install info object for that, and continue
1584 bn
= basename(i
->symlink_target
);
1586 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1587 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1589 _cleanup_free_
char *instance
= NULL
;
1591 r
= unit_name_to_instance(i
->name
, &instance
);
1595 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1599 if (streq(buffer
, i
->name
)) {
1601 /* We filled in the instance, and the target stayed the same? If so, then let's
1602 * honour the link as it is. */
1604 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1614 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1618 /* Try again, with the new target we found. */
1619 r
= unit_file_search(c
, i
, paths
, flags
);
1621 /* Translate error code to highlight this specific case */
1636 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1637 * or the name (otherwise). root_dir is prepended to the path.
1639 static int install_info_add_auto(
1641 const LookupPaths
*paths
,
1642 const char *name_or_path
,
1643 UnitFileInstallInfo
**ret
) {
1646 assert(name_or_path
);
1648 if (path_is_absolute(name_or_path
)) {
1651 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1653 return install_info_add(c
, NULL
, pp
, false, ret
);
1655 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1658 static int install_info_discover(
1659 UnitFileScope scope
,
1661 const LookupPaths
*paths
,
1664 UnitFileInstallInfo
**ret
,
1665 UnitFileChange
**changes
,
1666 unsigned *n_changes
) {
1668 UnitFileInstallInfo
*i
;
1675 r
= install_info_add_auto(c
, paths
, name
, &i
);
1677 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1680 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1684 static int install_info_symlink_alias(
1685 UnitFileInstallInfo
*i
,
1686 const LookupPaths
*paths
,
1687 const char *config_path
,
1689 UnitFileChange
**changes
,
1690 unsigned *n_changes
) {
1697 assert(config_path
);
1699 STRV_FOREACH(s
, i
->aliases
) {
1700 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1702 q
= install_full_printf(i
, *s
, &dst
);
1706 alias_path
= path_make_absolute(dst
, config_path
);
1710 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1718 static int install_info_symlink_wants(
1719 UnitFileInstallInfo
*i
,
1720 const LookupPaths
*paths
,
1721 const char *config_path
,
1724 UnitFileChange
**changes
,
1725 unsigned *n_changes
) {
1727 _cleanup_free_
char *buf
= NULL
;
1734 assert(config_path
);
1736 if (strv_isempty(list
))
1739 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1740 UnitFileInstallInfo instance
= {
1741 .type
= _UNIT_FILE_TYPE_INVALID
,
1743 _cleanup_free_
char *path
= NULL
;
1745 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1749 instance
.name
= buf
;
1750 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1754 path
= instance
.path
;
1755 instance
.path
= NULL
;
1757 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1758 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1766 STRV_FOREACH(s
, list
) {
1767 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1769 q
= install_full_printf(i
, *s
, &dst
);
1773 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1778 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1782 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1790 static int install_info_symlink_link(
1791 UnitFileInstallInfo
*i
,
1792 const LookupPaths
*paths
,
1793 const char *config_path
,
1795 UnitFileChange
**changes
,
1796 unsigned *n_changes
) {
1798 _cleanup_free_
char *path
= NULL
;
1803 assert(config_path
);
1806 r
= in_search_path(paths
, i
->path
);
1812 path
= strjoin(config_path
, "/", i
->name
);
1816 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1819 static int install_info_apply(
1820 UnitFileInstallInfo
*i
,
1821 const LookupPaths
*paths
,
1822 const char *config_path
,
1824 UnitFileChange
**changes
,
1825 unsigned *n_changes
) {
1831 assert(config_path
);
1833 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1836 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1838 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1842 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1846 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1847 /* Do not count links to the unit file towards the "carries_install_info" count */
1848 if (r
== 0 && q
< 0)
1854 static int install_context_apply(
1855 UnitFileScope scope
,
1857 const LookupPaths
*paths
,
1858 const char *config_path
,
1861 UnitFileChange
**changes
,
1862 unsigned *n_changes
) {
1864 UnitFileInstallInfo
*i
;
1869 assert(config_path
);
1871 if (ordered_hashmap_isempty(c
->will_process
))
1874 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1879 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1882 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1886 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1888 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1892 /* We can attempt to process a masked unit when a different unit
1893 * that we were processing specifies it in Also=. */
1894 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1895 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1897 /* Assume that something *could* have been enabled here,
1898 * avoid "empty [Install] section" warning. */
1903 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1906 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1918 static int install_context_mark_for_removal(
1919 UnitFileScope scope
,
1921 const LookupPaths
*paths
,
1922 Set
**remove_symlinks_to
,
1923 const char *config_path
,
1924 UnitFileChange
**changes
,
1925 unsigned *n_changes
) {
1927 UnitFileInstallInfo
*i
;
1932 assert(config_path
);
1934 /* Marks all items for removal */
1936 if (ordered_hashmap_isempty(c
->will_process
))
1939 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1943 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1945 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1949 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1950 if (r
== -ENOLINK
) {
1951 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1952 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1953 } else if (r
== -ENOENT
) {
1955 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1956 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1958 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1959 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1963 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1964 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1965 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1966 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1967 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1969 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1970 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1974 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1983 UnitFileScope scope
,
1984 UnitFileFlags flags
,
1985 const char *root_dir
,
1987 UnitFileChange
**changes
,
1988 unsigned *n_changes
) {
1990 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1991 const char *config_path
;
1996 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1998 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2002 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2006 STRV_FOREACH(i
, files
) {
2007 _cleanup_free_
char *path
= NULL
;
2010 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
2016 path
= path_make_absolute(*i
, config_path
);
2020 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2021 if (q
< 0 && r
>= 0)
2028 int unit_file_unmask(
2029 UnitFileScope scope
,
2030 UnitFileFlags flags
,
2031 const char *root_dir
,
2033 UnitFileChange
**changes
,
2034 unsigned *n_changes
) {
2036 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2037 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2038 _cleanup_strv_free_
char **todo
= NULL
;
2039 size_t n_todo
= 0, n_allocated
= 0;
2040 const char *config_path
;
2046 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2048 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2052 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2056 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2058 STRV_FOREACH(i
, files
) {
2059 _cleanup_free_
char *path
= NULL
;
2061 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2064 path
= path_make_absolute(*i
, config_path
);
2068 r
= null_or_empty_path(path
);
2076 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2079 todo
[n_todo
] = strdup(*i
);
2089 STRV_FOREACH(i
, todo
) {
2090 _cleanup_free_
char *path
= NULL
;
2093 path
= path_make_absolute(*i
, config_path
);
2097 if (!dry_run
&& unlink(path
) < 0) {
2098 if (errno
!= ENOENT
) {
2101 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2107 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2109 rp
= skip_root(&paths
, path
);
2110 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2115 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2123 UnitFileScope scope
,
2124 UnitFileFlags flags
,
2125 const char *root_dir
,
2127 UnitFileChange
**changes
,
2128 unsigned *n_changes
) {
2130 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2131 _cleanup_strv_free_
char **todo
= NULL
;
2132 size_t n_todo
= 0, n_allocated
= 0;
2133 const char *config_path
;
2138 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2140 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2144 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2148 STRV_FOREACH(i
, files
) {
2149 _cleanup_free_
char *full
= NULL
;
2153 if (!path_is_absolute(*i
))
2157 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2160 full
= prefix_root(paths
.root_dir
, *i
);
2164 if (lstat(full
, &st
) < 0)
2166 if (S_ISLNK(st
.st_mode
))
2168 if (S_ISDIR(st
.st_mode
))
2170 if (!S_ISREG(st
.st_mode
))
2173 q
= in_search_path(&paths
, *i
);
2179 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2182 todo
[n_todo
] = strdup(*i
);
2192 STRV_FOREACH(i
, todo
) {
2193 _cleanup_free_
char *new_path
= NULL
;
2195 new_path
= path_make_absolute(basename(*i
), config_path
);
2199 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2200 if (q
< 0 && r
>= 0)
2207 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2213 /* Checks whether the path is one where the drop-in directories shall be removed. */
2215 r
= path_is_config(paths
, path
, true);
2219 r
= path_is_control(paths
, path
);
2223 return path_is_transient(paths
, path
);
2226 int unit_file_revert(
2227 UnitFileScope scope
,
2228 const char *root_dir
,
2230 UnitFileChange
**changes
,
2231 unsigned *n_changes
) {
2233 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2234 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2235 _cleanup_strv_free_
char **todo
= NULL
;
2236 size_t n_todo
= 0, n_allocated
= 0;
2240 /* Puts a unit file back into vendor state. This means:
2242 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2243 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2245 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2246 * "config", but not in "transient" or "control" or even "generated").
2248 * We remove all that in both the runtime and the persistent directories, if that applies.
2251 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2255 STRV_FOREACH(i
, files
) {
2256 bool has_vendor
= false;
2259 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2262 STRV_FOREACH(p
, paths
.search_path
) {
2263 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2266 path
= path_make_absolute(*i
, *p
);
2270 r
= lstat(path
, &st
);
2272 if (errno
!= ENOENT
)
2274 } else if (S_ISREG(st
.st_mode
)) {
2275 /* Check if there's a vendor version */
2276 r
= path_is_vendor(&paths
, path
);
2283 dropin
= strappend(path
, ".d");
2287 r
= lstat(dropin
, &st
);
2289 if (errno
!= ENOENT
)
2291 } else if (S_ISDIR(st
.st_mode
)) {
2292 /* Remove the drop-ins */
2293 r
= path_shall_revert(&paths
, dropin
);
2297 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2300 todo
[n_todo
++] = dropin
;
2309 /* OK, there's a vendor version, hence drop all configuration versions */
2310 STRV_FOREACH(p
, paths
.search_path
) {
2311 _cleanup_free_
char *path
= NULL
;
2314 path
= path_make_absolute(*i
, *p
);
2318 r
= lstat(path
, &st
);
2320 if (errno
!= ENOENT
)
2322 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2323 r
= path_is_config(&paths
, path
, true);
2327 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2330 todo
[n_todo
++] = path
;
2340 STRV_FOREACH(i
, todo
) {
2341 _cleanup_strv_free_
char **fs
= NULL
;
2345 (void) get_files_in_directory(*i
, &fs
);
2347 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2348 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2353 STRV_FOREACH(j
, fs
) {
2354 _cleanup_free_
char *t
= NULL
;
2356 t
= strjoin(*i
, "/", *j
);
2360 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2363 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2365 rp
= skip_root(&paths
, *i
);
2366 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2371 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2375 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2382 int unit_file_add_dependency(
2383 UnitFileScope scope
,
2384 UnitFileFlags flags
,
2385 const char *root_dir
,
2389 UnitFileChange
**changes
,
2390 unsigned *n_changes
) {
2392 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2393 _cleanup_(install_context_done
) InstallContext c
= {};
2394 UnitFileInstallInfo
*i
, *target_info
;
2395 const char *config_path
;
2400 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2403 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2406 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2409 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2413 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2417 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2418 &target_info
, changes
, n_changes
);
2421 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2425 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2427 STRV_FOREACH(f
, files
) {
2430 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2431 &i
, changes
, n_changes
);
2434 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2438 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2440 /* We didn't actually load anything from the unit
2441 * file, but instead just add in our new symlink to
2444 if (dep
== UNIT_WANTS
)
2447 l
= &i
->required_by
;
2450 *l
= strv_new(target_info
->name
, NULL
);
2455 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2458 int unit_file_enable(
2459 UnitFileScope scope
,
2460 UnitFileFlags flags
,
2461 const char *root_dir
,
2463 UnitFileChange
**changes
,
2464 unsigned *n_changes
) {
2466 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2467 _cleanup_(install_context_done
) InstallContext c
= {};
2468 const char *config_path
;
2469 UnitFileInstallInfo
*i
;
2474 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2476 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2480 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2484 STRV_FOREACH(f
, files
) {
2485 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2486 &i
, changes
, n_changes
);
2489 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2493 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2496 /* This will return the number of symlink rules that were
2497 supposed to be created, not the ones actually created. This
2498 is useful to determine whether the passed files had any
2499 installation data at all. */
2501 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2504 int unit_file_disable(
2505 UnitFileScope scope
,
2506 UnitFileFlags flags
,
2507 const char *root_dir
,
2509 UnitFileChange
**changes
,
2510 unsigned *n_changes
) {
2512 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2513 _cleanup_(install_context_done
) InstallContext c
= {};
2514 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2515 const char *config_path
;
2520 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2522 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2526 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2530 STRV_FOREACH(i
, files
) {
2531 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2534 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2539 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2543 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2546 int unit_file_reenable(
2547 UnitFileScope scope
,
2548 UnitFileFlags flags
,
2549 const char *root_dir
,
2551 UnitFileChange
**changes
,
2552 unsigned *n_changes
) {
2558 /* First, we invoke the disable command with only the basename... */
2559 l
= strv_length(files
);
2560 n
= newa(char*, l
+1);
2561 for (i
= 0; i
< l
; i
++)
2562 n
[i
] = basename(files
[i
]);
2565 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2569 /* But the enable command with the full name */
2570 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2573 int unit_file_set_default(
2574 UnitFileScope scope
,
2575 UnitFileFlags flags
,
2576 const char *root_dir
,
2578 UnitFileChange
**changes
,
2579 unsigned *n_changes
) {
2581 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2582 _cleanup_(install_context_done
) InstallContext c
= {};
2583 UnitFileInstallInfo
*i
;
2584 const char *new_path
;
2588 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2591 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2593 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2596 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2600 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2603 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2607 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2608 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2611 int unit_file_get_default(
2612 UnitFileScope scope
,
2613 const char *root_dir
,
2616 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2617 _cleanup_(install_context_done
) InstallContext c
= {};
2618 UnitFileInstallInfo
*i
;
2623 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2626 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2630 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2634 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2638 n
= strdup(i
->name
);
2646 static int unit_file_lookup_state(
2647 UnitFileScope scope
,
2648 const LookupPaths
*paths
,
2650 UnitFileState
*ret
) {
2652 _cleanup_(install_context_done
) InstallContext c
= {};
2653 UnitFileInstallInfo
*i
;
2654 UnitFileState state
;
2660 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2663 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2668 /* Shortcut things, if the caller just wants to know if this unit exists. */
2674 case UNIT_FILE_TYPE_MASKED
:
2675 r
= path_is_runtime(paths
, i
->path
, true);
2679 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2682 case UNIT_FILE_TYPE_REGULAR
:
2683 r
= path_is_generator(paths
, i
->path
);
2687 state
= UNIT_FILE_GENERATED
;
2691 r
= path_is_transient(paths
, i
->path
);
2695 state
= UNIT_FILE_TRANSIENT
;
2699 /* Check if any of the Alias= symlinks have been created.
2700 * We ignore other aliases, and only check those that would
2701 * be created by systemctl enable for this unit. */
2702 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2708 /* Check if the file is known under other names. If it is,
2709 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2710 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2714 state
= UNIT_FILE_INDIRECT
;
2716 if (unit_file_install_info_has_rules(i
))
2717 state
= UNIT_FILE_DISABLED
;
2718 else if (unit_file_install_info_has_also(i
))
2719 state
= UNIT_FILE_INDIRECT
;
2721 state
= UNIT_FILE_STATIC
;
2727 assert_not_reached("Unexpect unit file type.");
2734 int unit_file_get_state(
2735 UnitFileScope scope
,
2736 const char *root_dir
,
2738 UnitFileState
*ret
) {
2740 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2744 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2747 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2751 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2754 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2755 _cleanup_(install_context_done
) InstallContext c
= {};
2761 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2764 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2773 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2774 _cleanup_(presets_freep
) Presets ps
= {};
2775 size_t n_allocated
= 0;
2776 _cleanup_strv_free_
char **files
= NULL
;
2781 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2784 if (scope
== UNIT_FILE_SYSTEM
)
2785 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2786 "/etc/systemd/system-preset",
2787 "/run/systemd/system-preset",
2788 "/usr/local/lib/systemd/system-preset",
2789 "/usr/lib/systemd/system-preset",
2791 "/lib/systemd/system-preset",
2794 else if (scope
== UNIT_FILE_GLOBAL
)
2795 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2796 "/etc/systemd/user-preset",
2797 "/run/systemd/user-preset",
2798 "/usr/local/lib/systemd/user-preset",
2799 "/usr/lib/systemd/user-preset",
2802 *presets
= (Presets
){};
2810 STRV_FOREACH(p
, files
) {
2811 _cleanup_fclose_
FILE *f
;
2812 char line
[LINE_MAX
];
2815 f
= fopen(*p
, "re");
2817 if (errno
== ENOENT
)
2823 FOREACH_LINE(line
, f
, return -errno
) {
2824 PresetRule rule
= {};
2825 const char *parameter
;
2833 if (strchr(COMMENTS
, *l
))
2836 parameter
= first_word(l
, "enable");
2840 pattern
= strdup(parameter
);
2844 rule
= (PresetRule
) {
2846 .action
= PRESET_ENABLE
,
2850 parameter
= first_word(l
, "disable");
2854 pattern
= strdup(parameter
);
2858 rule
= (PresetRule
) {
2860 .action
= PRESET_DISABLE
,
2865 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2868 ps
.rules
[ps
.n_rules
++] = rule
;
2872 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2882 static int query_presets(const char *name
, const Presets presets
) {
2883 PresetAction action
= PRESET_UNKNOWN
;
2886 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2889 for (i
= 0; i
< presets
.n_rules
; i
++)
2890 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2891 action
= presets
.rules
[i
].action
;
2896 case PRESET_UNKNOWN
:
2897 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2900 log_debug("Preset files say enable %s.", name
);
2902 case PRESET_DISABLE
:
2903 log_debug("Preset files say disable %s.", name
);
2906 assert_not_reached("invalid preset action");
2910 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2911 _cleanup_(presets_freep
) Presets presets
= {};
2914 r
= read_presets(scope
, root_dir
, &presets
);
2918 return query_presets(name
, presets
);
2921 static int execute_preset(
2922 UnitFileScope scope
,
2923 InstallContext
*plus
,
2924 InstallContext
*minus
,
2925 const LookupPaths
*paths
,
2926 const char *config_path
,
2928 UnitFilePresetMode mode
,
2930 UnitFileChange
**changes
,
2931 unsigned *n_changes
) {
2938 assert(config_path
);
2940 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2941 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2943 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2947 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2951 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2954 /* Returns number of symlinks that where supposed to be installed. */
2955 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2967 static int preset_prepare_one(
2968 UnitFileScope scope
,
2969 InstallContext
*plus
,
2970 InstallContext
*minus
,
2974 UnitFileChange
**changes
,
2975 unsigned *n_changes
) {
2977 _cleanup_(install_context_done
) InstallContext tmp
= {};
2978 UnitFileInstallInfo
*i
;
2981 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2984 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2985 &i
, changes
, n_changes
);
2988 if (!streq(name
, i
->name
)) {
2989 log_debug("Skipping %s because it is an alias for %s.", name
, i
->name
);
2993 r
= query_presets(name
, presets
);
2998 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2999 &i
, changes
, n_changes
);
3003 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
3007 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
3008 &i
, changes
, n_changes
);
3013 int unit_file_preset(
3014 UnitFileScope scope
,
3015 UnitFileFlags flags
,
3016 const char *root_dir
,
3018 UnitFilePresetMode mode
,
3019 UnitFileChange
**changes
,
3020 unsigned *n_changes
) {
3022 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3023 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3024 _cleanup_(presets_freep
) Presets presets
= {};
3025 const char *config_path
;
3030 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3031 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3033 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3037 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3041 r
= read_presets(scope
, root_dir
, &presets
);
3045 STRV_FOREACH(i
, files
) {
3046 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3051 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3054 int unit_file_preset_all(
3055 UnitFileScope scope
,
3056 UnitFileFlags flags
,
3057 const char *root_dir
,
3058 UnitFilePresetMode mode
,
3059 UnitFileChange
**changes
,
3060 unsigned *n_changes
) {
3062 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3063 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3064 _cleanup_(presets_freep
) Presets presets
= {};
3065 const char *config_path
= NULL
;
3070 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3071 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3073 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3077 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3081 r
= read_presets(scope
, root_dir
, &presets
);
3085 STRV_FOREACH(i
, paths
.search_path
) {
3086 _cleanup_closedir_
DIR *d
= NULL
;
3091 if (errno
== ENOENT
)
3097 FOREACH_DIRENT(de
, d
, return -errno
) {
3099 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3102 dirent_ensure_type(d
, de
);
3104 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3107 /* we don't pass changes[] in, because we want to handle errors on our own */
3108 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3110 r
= unit_file_changes_add(changes
, n_changes
,
3111 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3112 else if (r
== -ENOLINK
)
3113 r
= unit_file_changes_add(changes
, n_changes
,
3114 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3115 else if (r
== -EADDRNOTAVAIL
) /* Ignore generated/transient units when applying preset */
3122 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3125 static void unit_file_list_free_one(UnitFileList
*f
) {
3133 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3134 return hashmap_free_with_destructor(h
, unit_file_list_free_one
);
3137 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3139 int unit_file_get_list(
3140 UnitFileScope scope
,
3141 const char *root_dir
,
3146 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3151 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3154 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3158 STRV_FOREACH(i
, paths
.search_path
) {
3159 _cleanup_closedir_
DIR *d
= NULL
;
3164 if (errno
== ENOENT
)
3166 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3167 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3174 FOREACH_DIRENT(de
, d
, return -errno
) {
3175 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3177 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3180 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3183 if (hashmap_get(h
, de
->d_name
))
3186 dirent_ensure_type(d
, de
);
3188 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3191 f
= new0(UnitFileList
, 1);
3195 f
->path
= path_make_absolute(de
->d_name
, *i
);
3199 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3201 f
->state
= UNIT_FILE_BAD
;
3203 if (!strv_isempty(states
) &&
3204 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3207 r
= hashmap_put(h
, basename(f
->path
), f
);
3211 f
= NULL
; /* prevent cleanup */
3218 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3219 [UNIT_FILE_ENABLED
] = "enabled",
3220 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3221 [UNIT_FILE_LINKED
] = "linked",
3222 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3223 [UNIT_FILE_MASKED
] = "masked",
3224 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3225 [UNIT_FILE_STATIC
] = "static",
3226 [UNIT_FILE_DISABLED
] = "disabled",
3227 [UNIT_FILE_INDIRECT
] = "indirect",
3228 [UNIT_FILE_GENERATED
] = "generated",
3229 [UNIT_FILE_TRANSIENT
] = "transient",
3230 [UNIT_FILE_BAD
] = "bad",
3233 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3235 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3236 [UNIT_FILE_SYMLINK
] = "symlink",
3237 [UNIT_FILE_UNLINK
] = "unlink",
3238 [UNIT_FILE_IS_MASKED
] = "masked",
3239 [UNIT_FILE_IS_DANGLING
] = "dangling",
3242 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3244 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3245 [UNIT_FILE_PRESET_FULL
] = "full",
3246 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3247 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3250 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);