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 name
= basename(filename
);
1139 type
= unit_name_to_type(name
);
1140 if (!unit_type_may_alias(type
))
1141 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1142 "Alias= is not allowed for %s units, ignoring.",
1143 unit_type_to_string(type
));
1145 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1146 lvalue
, ltype
, rvalue
, data
, userdata
);
1149 static int config_parse_also(
1151 const char *filename
,
1153 const char *section
,
1154 unsigned section_line
,
1161 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1162 InstallContext
*c
= data
;
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
;
1213 _cleanup_free_
char *printed
= NULL
;
1220 name
= basename(filename
);
1221 if (unit_name_is_valid(name
, UNIT_NAME_INSTANCE
))
1222 /* When enabling an instance, we might be using a template unit file,
1223 * but we should ignore DefaultInstance silently. */
1225 if (!unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
))
1226 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1227 "DefaultInstance= only makes sense for template units, ignoring.");
1229 r
= install_full_printf(i
, rvalue
, &printed
);
1233 if (!unit_instance_is_valid(printed
))
1236 return free_and_replace(i
->default_instance
, printed
);
1239 static int unit_file_load(
1241 UnitFileInstallInfo
*info
,
1243 SearchFlags flags
) {
1245 const ConfigTableItem items
[] = {
1246 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1247 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1248 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1249 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1250 { "Install", "Also", config_parse_also
, 0, c
},
1256 _cleanup_fclose_
FILE *f
= NULL
;
1257 _cleanup_close_
int fd
= -1;
1264 name
= basename(path
);
1265 type
= unit_name_to_type(name
);
1266 if (unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) &&
1267 !unit_type_may_template(type
))
1268 return log_error_errno(EINVAL
, "Unit type %s cannot be templated.", unit_type_to_string(type
));
1270 if (!(flags
& SEARCH_LOAD
)) {
1271 r
= lstat(path
, &st
);
1275 if (null_or_empty(&st
))
1276 info
->type
= UNIT_FILE_TYPE_MASKED
;
1277 else if (S_ISREG(st
.st_mode
))
1278 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1279 else if (S_ISLNK(st
.st_mode
))
1281 else if (S_ISDIR(st
.st_mode
))
1289 /* c is only needed if we actually load the file */
1292 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1295 if (fstat(fd
, &st
) < 0)
1297 if (null_or_empty(&st
)) {
1298 info
->type
= UNIT_FILE_TYPE_MASKED
;
1301 if (S_ISDIR(st
.st_mode
))
1303 if (!S_ISREG(st
.st_mode
))
1306 f
= fdopen(fd
, "re");
1311 r
= config_parse(NULL
, path
, f
,
1313 config_item_table_lookup
, items
,
1314 true, true, false, info
);
1316 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1318 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1321 (int) strv_length(info
->aliases
) +
1322 (int) strv_length(info
->wanted_by
) +
1323 (int) strv_length(info
->required_by
);
1326 static int unit_file_load_or_readlink(
1328 UnitFileInstallInfo
*info
,
1330 const char *root_dir
,
1331 SearchFlags flags
) {
1333 _cleanup_free_
char *target
= NULL
;
1336 r
= unit_file_load(c
, info
, path
, flags
);
1340 /* This is a symlink, let's read it. */
1342 r
= readlink_malloc(path
, &target
);
1346 if (path_equal(target
, "/dev/null"))
1347 info
->type
= UNIT_FILE_TYPE_MASKED
;
1352 bn
= basename(target
);
1354 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1356 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1359 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1361 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1364 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1366 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1371 /* Enforce that the symlink destination does not
1372 * change the unit file type. */
1374 a
= unit_name_to_type(info
->name
);
1375 b
= unit_name_to_type(bn
);
1376 if (a
< 0 || b
< 0 || a
!= b
)
1379 if (path_is_absolute(target
))
1380 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1381 info
->symlink_target
= prefix_root(root_dir
, target
);
1383 /* This is a relative path, take it relative to the dir the symlink is located in. */
1384 info
->symlink_target
= file_in_same_dir(path
, target
);
1385 if (!info
->symlink_target
)
1388 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1394 static int unit_file_search(
1396 UnitFileInstallInfo
*info
,
1397 const LookupPaths
*paths
,
1398 SearchFlags flags
) {
1400 _cleanup_free_
char *template = NULL
;
1407 /* Was this unit already loaded? */
1408 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1412 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1416 STRV_FOREACH(p
, paths
->search_path
) {
1417 _cleanup_free_
char *path
= NULL
;
1419 path
= strjoin(*p
, "/", info
->name
);
1423 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1428 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1432 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1433 /* Unit file doesn't exist, however instance
1434 * enablement was requested. We will check if it is
1435 * possible to load template unit file. */
1437 r
= unit_name_template(info
->name
, &template);
1441 STRV_FOREACH(p
, paths
->search_path
) {
1442 _cleanup_free_
char *path
= NULL
;
1444 path
= strjoin(*p
, "/", template);
1448 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1453 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1458 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1462 static int install_info_follow(
1464 UnitFileInstallInfo
*i
,
1465 const char *root_dir
,
1467 bool ignore_different_name
) {
1472 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1474 if (!i
->symlink_target
)
1477 /* If the basename doesn't match, the caller should add a
1478 * complete new entry for this. */
1480 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1483 free_and_replace(i
->path
, i
->symlink_target
);
1484 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1486 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1490 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1491 * target, maybe more than once. Propagate the instance name if present.
1493 static int install_info_traverse(
1494 UnitFileScope scope
,
1496 const LookupPaths
*paths
,
1497 UnitFileInstallInfo
*start
,
1499 UnitFileInstallInfo
**ret
) {
1501 UnitFileInstallInfo
*i
;
1509 r
= unit_file_search(c
, start
, paths
, flags
);
1514 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1515 /* Follow the symlink */
1517 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1520 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1521 r
= path_is_config(paths
, i
->path
, true);
1528 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1530 _cleanup_free_
char *buffer
= NULL
;
1533 /* Target has a different name, create a new
1534 * install info object for that, and continue
1537 bn
= basename(i
->symlink_target
);
1539 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1540 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1542 _cleanup_free_
char *instance
= NULL
;
1544 r
= unit_name_to_instance(i
->name
, &instance
);
1548 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1552 if (streq(buffer
, i
->name
)) {
1554 /* We filled in the instance, and the target stayed the same? If so, then let's
1555 * honour the link as it is. */
1557 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1567 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1571 /* Try again, with the new target we found. */
1572 r
= unit_file_search(c
, i
, paths
, flags
);
1574 /* Translate error code to highlight this specific case */
1589 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1590 * or the name (otherwise). root_dir is prepended to the path.
1592 static int install_info_add_auto(
1594 const LookupPaths
*paths
,
1595 const char *name_or_path
,
1596 UnitFileInstallInfo
**ret
) {
1599 assert(name_or_path
);
1601 if (path_is_absolute(name_or_path
)) {
1604 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1606 return install_info_add(c
, NULL
, pp
, false, ret
);
1608 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1611 static int install_info_discover(
1612 UnitFileScope scope
,
1614 const LookupPaths
*paths
,
1617 UnitFileInstallInfo
**ret
,
1618 UnitFileChange
**changes
,
1619 unsigned *n_changes
) {
1621 UnitFileInstallInfo
*i
;
1628 r
= install_info_add_auto(c
, paths
, name
, &i
);
1630 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1633 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1637 static int install_info_symlink_alias(
1638 UnitFileInstallInfo
*i
,
1639 const LookupPaths
*paths
,
1640 const char *config_path
,
1642 UnitFileChange
**changes
,
1643 unsigned *n_changes
) {
1650 assert(config_path
);
1652 STRV_FOREACH(s
, i
->aliases
) {
1653 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1655 q
= install_full_printf(i
, *s
, &dst
);
1659 alias_path
= path_make_absolute(dst
, config_path
);
1663 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1671 static int install_info_symlink_wants(
1672 UnitFileInstallInfo
*i
,
1673 const LookupPaths
*paths
,
1674 const char *config_path
,
1677 UnitFileChange
**changes
,
1678 unsigned *n_changes
) {
1680 _cleanup_free_
char *buf
= NULL
;
1687 assert(config_path
);
1689 if (strv_isempty(list
))
1692 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1693 UnitFileInstallInfo instance
= {
1694 .type
= _UNIT_FILE_TYPE_INVALID
,
1696 _cleanup_free_
char *path
= NULL
;
1698 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1702 instance
.name
= buf
;
1703 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1707 path
= instance
.path
;
1708 instance
.path
= NULL
;
1710 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1711 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1719 STRV_FOREACH(s
, list
) {
1720 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1722 q
= install_full_printf(i
, *s
, &dst
);
1726 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1731 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1735 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1743 static int install_info_symlink_link(
1744 UnitFileInstallInfo
*i
,
1745 const LookupPaths
*paths
,
1746 const char *config_path
,
1748 UnitFileChange
**changes
,
1749 unsigned *n_changes
) {
1751 _cleanup_free_
char *path
= NULL
;
1756 assert(config_path
);
1759 r
= in_search_path(paths
, i
->path
);
1765 path
= strjoin(config_path
, "/", i
->name
);
1769 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1772 static int install_info_apply(
1773 UnitFileInstallInfo
*i
,
1774 const LookupPaths
*paths
,
1775 const char *config_path
,
1777 UnitFileChange
**changes
,
1778 unsigned *n_changes
) {
1784 assert(config_path
);
1786 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1789 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1791 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1795 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1799 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1800 /* Do not count links to the unit file towards the "carries_install_info" count */
1801 if (r
== 0 && q
< 0)
1807 static int install_context_apply(
1808 UnitFileScope scope
,
1810 const LookupPaths
*paths
,
1811 const char *config_path
,
1814 UnitFileChange
**changes
,
1815 unsigned *n_changes
) {
1817 UnitFileInstallInfo
*i
;
1822 assert(config_path
);
1824 if (ordered_hashmap_isempty(c
->will_process
))
1827 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1832 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1835 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1839 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1841 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1845 /* We can attempt to process a masked unit when a different unit
1846 * that we were processing specifies it in Also=. */
1847 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1848 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1850 /* Assume that something *could* have been enabled here,
1851 * avoid "empty [Install] section" warning. */
1856 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1859 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1871 static int install_context_mark_for_removal(
1872 UnitFileScope scope
,
1874 const LookupPaths
*paths
,
1875 Set
**remove_symlinks_to
,
1876 const char *config_path
,
1877 UnitFileChange
**changes
,
1878 unsigned *n_changes
) {
1880 UnitFileInstallInfo
*i
;
1885 assert(config_path
);
1887 /* Marks all items for removal */
1889 if (ordered_hashmap_isempty(c
->will_process
))
1892 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1896 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1898 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1902 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1903 if (r
== -ENOLINK
) {
1904 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1905 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1906 } else if (r
== -ENOENT
) {
1908 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1909 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1911 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1912 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1916 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1917 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1918 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1919 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1920 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1922 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1923 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1927 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1936 UnitFileScope scope
,
1937 UnitFileFlags flags
,
1938 const char *root_dir
,
1940 UnitFileChange
**changes
,
1941 unsigned *n_changes
) {
1943 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1944 const char *config_path
;
1949 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1951 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1955 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
1959 STRV_FOREACH(i
, files
) {
1960 _cleanup_free_
char *path
= NULL
;
1963 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1969 path
= path_make_absolute(*i
, config_path
);
1973 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
1974 if (q
< 0 && r
>= 0)
1981 int unit_file_unmask(
1982 UnitFileScope scope
,
1983 UnitFileFlags flags
,
1984 const char *root_dir
,
1986 UnitFileChange
**changes
,
1987 unsigned *n_changes
) {
1989 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1990 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1991 _cleanup_strv_free_
char **todo
= NULL
;
1992 size_t n_todo
= 0, n_allocated
= 0;
1993 const char *config_path
;
1999 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2001 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2005 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2009 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2011 STRV_FOREACH(i
, files
) {
2012 _cleanup_free_
char *path
= NULL
;
2014 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2017 path
= path_make_absolute(*i
, config_path
);
2021 r
= null_or_empty_path(path
);
2029 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2032 todo
[n_todo
] = strdup(*i
);
2042 STRV_FOREACH(i
, todo
) {
2043 _cleanup_free_
char *path
= NULL
;
2046 path
= path_make_absolute(*i
, config_path
);
2050 if (!dry_run
&& unlink(path
) < 0) {
2051 if (errno
!= ENOENT
) {
2054 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2060 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2062 rp
= skip_root(&paths
, path
);
2063 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2068 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2076 UnitFileScope scope
,
2077 UnitFileFlags flags
,
2078 const char *root_dir
,
2080 UnitFileChange
**changes
,
2081 unsigned *n_changes
) {
2083 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2084 _cleanup_strv_free_
char **todo
= NULL
;
2085 size_t n_todo
= 0, n_allocated
= 0;
2086 const char *config_path
;
2091 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2093 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2097 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2101 STRV_FOREACH(i
, files
) {
2102 _cleanup_free_
char *full
= NULL
;
2106 if (!path_is_absolute(*i
))
2110 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2113 full
= prefix_root(paths
.root_dir
, *i
);
2117 if (lstat(full
, &st
) < 0)
2119 if (S_ISLNK(st
.st_mode
))
2121 if (S_ISDIR(st
.st_mode
))
2123 if (!S_ISREG(st
.st_mode
))
2126 q
= in_search_path(&paths
, *i
);
2132 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2135 todo
[n_todo
] = strdup(*i
);
2145 STRV_FOREACH(i
, todo
) {
2146 _cleanup_free_
char *new_path
= NULL
;
2148 new_path
= path_make_absolute(basename(*i
), config_path
);
2152 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2153 if (q
< 0 && r
>= 0)
2160 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2166 /* Checks whether the path is one where the drop-in directories shall be removed. */
2168 r
= path_is_config(paths
, path
, true);
2172 r
= path_is_control(paths
, path
);
2176 return path_is_transient(paths
, path
);
2179 int unit_file_revert(
2180 UnitFileScope scope
,
2181 const char *root_dir
,
2183 UnitFileChange
**changes
,
2184 unsigned *n_changes
) {
2186 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2187 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2188 _cleanup_strv_free_
char **todo
= NULL
;
2189 size_t n_todo
= 0, n_allocated
= 0;
2193 /* Puts a unit file back into vendor state. This means:
2195 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2196 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2198 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2199 * "config", but not in "transient" or "control" or even "generated").
2201 * We remove all that in both the runtime and the persistent directories, if that applies.
2204 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2208 STRV_FOREACH(i
, files
) {
2209 bool has_vendor
= false;
2212 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2215 STRV_FOREACH(p
, paths
.search_path
) {
2216 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2219 path
= path_make_absolute(*i
, *p
);
2223 r
= lstat(path
, &st
);
2225 if (errno
!= ENOENT
)
2227 } else if (S_ISREG(st
.st_mode
)) {
2228 /* Check if there's a vendor version */
2229 r
= path_is_vendor(&paths
, path
);
2236 dropin
= strappend(path
, ".d");
2240 r
= lstat(dropin
, &st
);
2242 if (errno
!= ENOENT
)
2244 } else if (S_ISDIR(st
.st_mode
)) {
2245 /* Remove the drop-ins */
2246 r
= path_shall_revert(&paths
, dropin
);
2250 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2253 todo
[n_todo
++] = dropin
;
2262 /* OK, there's a vendor version, hence drop all configuration versions */
2263 STRV_FOREACH(p
, paths
.search_path
) {
2264 _cleanup_free_
char *path
= NULL
;
2267 path
= path_make_absolute(*i
, *p
);
2271 r
= lstat(path
, &st
);
2273 if (errno
!= ENOENT
)
2275 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2276 r
= path_is_config(&paths
, path
, true);
2280 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2283 todo
[n_todo
++] = path
;
2293 STRV_FOREACH(i
, todo
) {
2294 _cleanup_strv_free_
char **fs
= NULL
;
2298 (void) get_files_in_directory(*i
, &fs
);
2300 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2301 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2306 STRV_FOREACH(j
, fs
) {
2307 _cleanup_free_
char *t
= NULL
;
2309 t
= strjoin(*i
, "/", *j
);
2313 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2316 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2318 rp
= skip_root(&paths
, *i
);
2319 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2324 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2328 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2335 int unit_file_add_dependency(
2336 UnitFileScope scope
,
2337 UnitFileFlags flags
,
2338 const char *root_dir
,
2342 UnitFileChange
**changes
,
2343 unsigned *n_changes
) {
2345 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2346 _cleanup_(install_context_done
) InstallContext c
= {};
2347 UnitFileInstallInfo
*i
, *target_info
;
2348 const char *config_path
;
2353 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2356 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2359 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2362 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2366 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2370 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2371 &target_info
, changes
, n_changes
);
2374 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2378 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2380 STRV_FOREACH(f
, files
) {
2383 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2384 &i
, changes
, n_changes
);
2387 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2391 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2393 /* We didn't actually load anything from the unit
2394 * file, but instead just add in our new symlink to
2397 if (dep
== UNIT_WANTS
)
2400 l
= &i
->required_by
;
2403 *l
= strv_new(target_info
->name
, NULL
);
2408 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2411 int unit_file_enable(
2412 UnitFileScope scope
,
2413 UnitFileFlags flags
,
2414 const char *root_dir
,
2416 UnitFileChange
**changes
,
2417 unsigned *n_changes
) {
2419 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2420 _cleanup_(install_context_done
) InstallContext c
= {};
2421 const char *config_path
;
2422 UnitFileInstallInfo
*i
;
2427 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2429 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2433 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2437 STRV_FOREACH(f
, files
) {
2438 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2439 &i
, changes
, n_changes
);
2442 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2446 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2449 /* This will return the number of symlink rules that were
2450 supposed to be created, not the ones actually created. This
2451 is useful to determine whether the passed files had any
2452 installation data at all. */
2454 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2457 int unit_file_disable(
2458 UnitFileScope scope
,
2459 UnitFileFlags flags
,
2460 const char *root_dir
,
2462 UnitFileChange
**changes
,
2463 unsigned *n_changes
) {
2465 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2466 _cleanup_(install_context_done
) InstallContext c
= {};
2467 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2468 const char *config_path
;
2473 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2475 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2479 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2483 STRV_FOREACH(i
, files
) {
2484 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2487 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2492 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2496 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2499 int unit_file_reenable(
2500 UnitFileScope scope
,
2501 UnitFileFlags flags
,
2502 const char *root_dir
,
2504 UnitFileChange
**changes
,
2505 unsigned *n_changes
) {
2511 /* First, we invoke the disable command with only the basename... */
2512 l
= strv_length(files
);
2513 n
= newa(char*, l
+1);
2514 for (i
= 0; i
< l
; i
++)
2515 n
[i
] = basename(files
[i
]);
2518 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2522 /* But the enable command with the full name */
2523 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2526 int unit_file_set_default(
2527 UnitFileScope scope
,
2528 UnitFileFlags flags
,
2529 const char *root_dir
,
2531 UnitFileChange
**changes
,
2532 unsigned *n_changes
) {
2534 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2535 _cleanup_(install_context_done
) InstallContext c
= {};
2536 UnitFileInstallInfo
*i
;
2537 const char *new_path
;
2541 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2544 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2546 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2549 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2553 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2556 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2560 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2561 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2564 int unit_file_get_default(
2565 UnitFileScope scope
,
2566 const char *root_dir
,
2569 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2570 _cleanup_(install_context_done
) InstallContext c
= {};
2571 UnitFileInstallInfo
*i
;
2576 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2579 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2583 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2587 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2591 n
= strdup(i
->name
);
2599 static int unit_file_lookup_state(
2600 UnitFileScope scope
,
2601 const LookupPaths
*paths
,
2603 UnitFileState
*ret
) {
2605 _cleanup_(install_context_done
) InstallContext c
= {};
2606 UnitFileInstallInfo
*i
;
2607 UnitFileState state
;
2613 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2616 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2621 /* Shortcut things, if the caller just wants to know if this unit exists. */
2627 case UNIT_FILE_TYPE_MASKED
:
2628 r
= path_is_runtime(paths
, i
->path
, true);
2632 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2635 case UNIT_FILE_TYPE_REGULAR
:
2636 r
= path_is_generator(paths
, i
->path
);
2640 state
= UNIT_FILE_GENERATED
;
2644 r
= path_is_transient(paths
, i
->path
);
2648 state
= UNIT_FILE_TRANSIENT
;
2652 /* Check if any of the Alias= symlinks have been created.
2653 * We ignore other aliases, and only check those that would
2654 * be created by systemctl enable for this unit. */
2655 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2661 /* Check if the file is known under other names. If it is,
2662 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2663 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2667 state
= UNIT_FILE_INDIRECT
;
2669 if (unit_file_install_info_has_rules(i
))
2670 state
= UNIT_FILE_DISABLED
;
2671 else if (unit_file_install_info_has_also(i
))
2672 state
= UNIT_FILE_INDIRECT
;
2674 state
= UNIT_FILE_STATIC
;
2680 assert_not_reached("Unexpect unit file type.");
2687 int unit_file_get_state(
2688 UnitFileScope scope
,
2689 const char *root_dir
,
2691 UnitFileState
*ret
) {
2693 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2697 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2700 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2704 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2707 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2708 _cleanup_(install_context_done
) InstallContext c
= {};
2714 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2717 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2726 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2727 _cleanup_(presets_freep
) Presets ps
= {};
2728 size_t n_allocated
= 0;
2729 _cleanup_strv_free_
char **files
= NULL
;
2734 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2737 if (scope
== UNIT_FILE_SYSTEM
)
2738 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2739 "/etc/systemd/system-preset",
2740 "/usr/local/lib/systemd/system-preset",
2741 "/usr/lib/systemd/system-preset",
2743 "/lib/systemd/system-preset",
2746 else if (scope
== UNIT_FILE_GLOBAL
)
2747 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2748 "/etc/systemd/user-preset",
2749 "/usr/local/lib/systemd/user-preset",
2750 "/usr/lib/systemd/user-preset",
2753 *presets
= (Presets
){};
2761 STRV_FOREACH(p
, files
) {
2762 _cleanup_fclose_
FILE *f
;
2763 char line
[LINE_MAX
];
2766 f
= fopen(*p
, "re");
2768 if (errno
== ENOENT
)
2774 FOREACH_LINE(line
, f
, return -errno
) {
2775 PresetRule rule
= {};
2776 const char *parameter
;
2784 if (strchr(COMMENTS
, *l
))
2787 parameter
= first_word(l
, "enable");
2791 pattern
= strdup(parameter
);
2795 rule
= (PresetRule
) {
2797 .action
= PRESET_ENABLE
,
2801 parameter
= first_word(l
, "disable");
2805 pattern
= strdup(parameter
);
2809 rule
= (PresetRule
) {
2811 .action
= PRESET_DISABLE
,
2816 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2819 ps
.rules
[ps
.n_rules
++] = rule
;
2823 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2833 static int query_presets(const char *name
, const Presets presets
) {
2834 PresetAction action
= PRESET_UNKNOWN
;
2837 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2840 for (i
= 0; i
< presets
.n_rules
; i
++)
2841 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2842 action
= presets
.rules
[i
].action
;
2847 case PRESET_UNKNOWN
:
2848 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2851 log_debug("Preset files say enable %s.", name
);
2853 case PRESET_DISABLE
:
2854 log_debug("Preset files say disable %s.", name
);
2857 assert_not_reached("invalid preset action");
2861 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2862 _cleanup_(presets_freep
) Presets presets
= {};
2865 r
= read_presets(scope
, root_dir
, &presets
);
2869 return query_presets(name
, presets
);
2872 static int execute_preset(
2873 UnitFileScope scope
,
2874 InstallContext
*plus
,
2875 InstallContext
*minus
,
2876 const LookupPaths
*paths
,
2877 const char *config_path
,
2879 UnitFilePresetMode mode
,
2881 UnitFileChange
**changes
,
2882 unsigned *n_changes
) {
2889 assert(config_path
);
2891 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2892 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2894 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2898 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2902 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2905 /* Returns number of symlinks that where supposed to be installed. */
2906 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2918 static int preset_prepare_one(
2919 UnitFileScope scope
,
2920 InstallContext
*plus
,
2921 InstallContext
*minus
,
2925 UnitFileChange
**changes
,
2926 unsigned *n_changes
) {
2928 _cleanup_(install_context_done
) InstallContext tmp
= {};
2929 UnitFileInstallInfo
*i
;
2932 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2935 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2936 &i
, changes
, n_changes
);
2939 if (!streq(name
, i
->name
)) {
2940 log_debug("Skipping %s because is an alias for %s", name
, i
->name
);
2944 r
= query_presets(name
, presets
);
2949 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2950 &i
, changes
, n_changes
);
2954 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
2958 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2959 &i
, changes
, n_changes
);
2964 int unit_file_preset(
2965 UnitFileScope scope
,
2966 UnitFileFlags flags
,
2967 const char *root_dir
,
2969 UnitFilePresetMode mode
,
2970 UnitFileChange
**changes
,
2971 unsigned *n_changes
) {
2973 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2974 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2975 _cleanup_(presets_freep
) Presets presets
= {};
2976 const char *config_path
;
2981 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2982 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2984 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2988 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2992 r
= read_presets(scope
, root_dir
, &presets
);
2996 STRV_FOREACH(i
, files
) {
2997 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3002 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3005 int unit_file_preset_all(
3006 UnitFileScope scope
,
3007 UnitFileFlags flags
,
3008 const char *root_dir
,
3009 UnitFilePresetMode mode
,
3010 UnitFileChange
**changes
,
3011 unsigned *n_changes
) {
3013 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3014 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3015 _cleanup_(presets_freep
) Presets presets
= {};
3016 const char *config_path
= NULL
;
3021 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3022 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3024 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3028 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3032 r
= read_presets(scope
, root_dir
, &presets
);
3036 STRV_FOREACH(i
, paths
.search_path
) {
3037 _cleanup_closedir_
DIR *d
= NULL
;
3042 if (errno
== ENOENT
)
3048 FOREACH_DIRENT(de
, d
, return -errno
) {
3050 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3053 dirent_ensure_type(d
, de
);
3055 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3058 /* we don't pass changes[] in, because we want to handle errors on our own */
3059 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3061 r
= unit_file_changes_add(changes
, n_changes
,
3062 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3063 else if (r
== -ENOLINK
)
3064 r
= unit_file_changes_add(changes
, n_changes
,
3065 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3071 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3074 static void unit_file_list_free_one(UnitFileList
*f
) {
3082 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3085 while ((i
= hashmap_steal_first(h
)))
3086 unit_file_list_free_one(i
);
3088 return hashmap_free(h
);
3091 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3093 int unit_file_get_list(
3094 UnitFileScope scope
,
3095 const char *root_dir
,
3100 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3105 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3108 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3112 STRV_FOREACH(i
, paths
.search_path
) {
3113 _cleanup_closedir_
DIR *d
= NULL
;
3118 if (errno
== ENOENT
)
3120 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3121 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3128 FOREACH_DIRENT(de
, d
, return -errno
) {
3129 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3131 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3134 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3137 if (hashmap_get(h
, de
->d_name
))
3140 dirent_ensure_type(d
, de
);
3142 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3145 f
= new0(UnitFileList
, 1);
3149 f
->path
= path_make_absolute(de
->d_name
, *i
);
3153 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3155 f
->state
= UNIT_FILE_BAD
;
3157 if (!strv_isempty(states
) &&
3158 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3161 r
= hashmap_put(h
, basename(f
->path
), f
);
3165 f
= NULL
; /* prevent cleanup */
3172 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3173 [UNIT_FILE_ENABLED
] = "enabled",
3174 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3175 [UNIT_FILE_LINKED
] = "linked",
3176 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3177 [UNIT_FILE_MASKED
] = "masked",
3178 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3179 [UNIT_FILE_STATIC
] = "static",
3180 [UNIT_FILE_DISABLED
] = "disabled",
3181 [UNIT_FILE_INDIRECT
] = "indirect",
3182 [UNIT_FILE_GENERATED
] = "generated",
3183 [UNIT_FILE_TRANSIENT
] = "transient",
3184 [UNIT_FILE_BAD
] = "bad",
3187 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3189 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3190 [UNIT_FILE_SYMLINK
] = "symlink",
3191 [UNIT_FILE_UNLINK
] = "unlink",
3192 [UNIT_FILE_IS_MASKED
] = "masked",
3193 [UNIT_FILE_IS_DANGLING
] = "dangling",
3196 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3198 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3199 [UNIT_FILE_PRESET_FULL
] = "full",
3200 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3201 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3204 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);