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"))
289 #ifdef HAVE_SPLIT_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
);
850 log_info("is_symlink_with_known_name(%s, %s) → %d", i
->name
, de
->d_name
, q
);
862 static int find_symlinks(
863 const char *root_dir
,
864 UnitFileInstallInfo
*i
,
866 const char *config_path
,
867 bool *same_name_link
) {
873 assert(same_name_link
);
875 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
877 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
882 /* This takes possession of fd and closes it */
883 return find_symlinks_fd(root_dir
, i
, match_name
, fd
,
884 config_path
, config_path
, same_name_link
);
887 static int find_symlinks_in_scope(
889 const LookupPaths
*paths
,
890 UnitFileInstallInfo
*i
,
892 UnitFileState
*state
) {
894 bool same_name_link_runtime
= false, same_name_link_config
= false;
895 bool enabled_in_runtime
= false, enabled_at_all
= false;
902 STRV_FOREACH(p
, paths
->search_path
) {
903 bool same_name_link
= false;
905 r
= find_symlinks(paths
->root_dir
, i
, match_name
, *p
, &same_name_link
);
909 /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */
911 r
= path_is_config(paths
, *p
, false);
915 /* This is the best outcome, let's return it immediately. */
916 *state
= UNIT_FILE_ENABLED
;
920 /* look for globally enablement of user units */
921 if (scope
== UNIT_FILE_USER
&& path_is_user_config_dir(*p
)) {
922 *state
= UNIT_FILE_ENABLED
;
926 r
= path_is_runtime(paths
, *p
, false);
930 enabled_in_runtime
= true;
932 enabled_at_all
= true;
934 } else if (same_name_link
) {
936 r
= path_is_config(paths
, *p
, false);
940 same_name_link_config
= true;
942 r
= path_is_runtime(paths
, *p
, false);
946 same_name_link_runtime
= true;
951 if (enabled_in_runtime
) {
952 *state
= UNIT_FILE_ENABLED_RUNTIME
;
956 /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path
957 * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only
958 * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate
959 * something, and hence are a much stronger concept. */
960 if (enabled_at_all
&& unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
)) {
961 *state
= UNIT_FILE_STATIC
;
965 /* Hmm, we didn't find it, but maybe we found the same name
967 if (same_name_link_config
) {
968 *state
= UNIT_FILE_LINKED
;
971 if (same_name_link_runtime
) {
972 *state
= UNIT_FILE_LINKED_RUNTIME
;
979 static void install_info_free(UnitFileInstallInfo
*i
) {
986 strv_free(i
->aliases
);
987 strv_free(i
->wanted_by
);
988 strv_free(i
->required_by
);
990 free(i
->default_instance
);
991 free(i
->symlink_target
);
995 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
996 UnitFileInstallInfo
*i
;
1001 while ((i
= ordered_hashmap_steal_first(m
)))
1002 install_info_free(i
);
1004 return ordered_hashmap_free(m
);
1007 static void install_context_done(InstallContext
*c
) {
1010 c
->will_process
= install_info_hashmap_free(c
->will_process
);
1011 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
1014 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
1015 UnitFileInstallInfo
*i
;
1017 i
= ordered_hashmap_get(c
->have_processed
, name
);
1021 return ordered_hashmap_get(c
->will_process
, name
);
1024 static int install_info_may_process(
1025 UnitFileInstallInfo
*i
,
1026 const LookupPaths
*paths
,
1027 UnitFileChange
**changes
,
1028 unsigned *n_changes
) {
1032 /* Checks whether the loaded unit file is one we should process, or is masked,
1033 * transient or generated and thus not subject to enable/disable operations. */
1035 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1036 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
1039 if (path_is_generator(paths
, i
->path
) ||
1040 path_is_transient(paths
, i
->path
)) {
1041 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
1042 return -EADDRNOTAVAIL
;
1049 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
1050 * hashmap, or retrieves the existing one if already present.
1052 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
1054 static int install_info_add(
1059 UnitFileInstallInfo
**ret
) {
1061 UnitFileInstallInfo
*i
= NULL
;
1065 assert(name
|| path
);
1068 name
= basename(path
);
1070 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
1073 i
= install_info_find(c
, name
);
1075 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
1082 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
1086 i
= new0(UnitFileInstallInfo
, 1);
1089 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1090 i
->auxiliary
= auxiliary
;
1092 i
->name
= strdup(name
);
1099 i
->path
= strdup(path
);
1106 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1116 install_info_free(i
);
1120 static int config_parse_alias(
1122 const char *filename
,
1124 const char *section
,
1125 unsigned section_line
,
1139 name
= basename(filename
);
1140 type
= unit_name_to_type(name
);
1141 if (!unit_type_may_alias(type
))
1142 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1143 "Alias= is not allowed for %s units, ignoring.",
1144 unit_type_to_string(type
));
1146 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1147 lvalue
, ltype
, rvalue
, data
, userdata
);
1150 static int config_parse_also(
1152 const char *filename
,
1154 const char *section
,
1155 unsigned section_line
,
1162 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1163 InstallContext
*c
= data
;
1171 _cleanup_free_
char *word
= NULL
, *printed
= NULL
;
1173 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1179 r
= install_full_printf(info
, word
, &printed
);
1183 if (!unit_name_is_valid(printed
, UNIT_NAME_ANY
))
1186 r
= install_info_add(c
, printed
, NULL
, true, &alsoinfo
);
1190 r
= strv_push(&info
->also
, printed
);
1200 static int config_parse_default_instance(
1202 const char *filename
,
1204 const char *section
,
1205 unsigned section_line
,
1212 UnitFileInstallInfo
*i
= data
;
1214 _cleanup_free_
char *printed
= NULL
;
1221 name
= basename(filename
);
1222 if (unit_name_is_valid(name
, UNIT_NAME_INSTANCE
))
1223 /* When enabling an instance, we might be using a template unit file,
1224 * but we should ignore DefaultInstance silently. */
1226 if (!unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
))
1227 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1228 "DefaultInstance= only makes sense for template units, ignoring.");
1230 r
= install_full_printf(i
, rvalue
, &printed
);
1234 if (!unit_instance_is_valid(printed
))
1237 return free_and_replace(i
->default_instance
, printed
);
1240 static int unit_file_load(
1242 UnitFileInstallInfo
*info
,
1244 SearchFlags flags
) {
1246 const ConfigTableItem items
[] = {
1247 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1248 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1249 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1250 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1251 { "Install", "Also", config_parse_also
, 0, c
},
1257 _cleanup_fclose_
FILE *f
= NULL
;
1258 _cleanup_close_
int fd
= -1;
1265 name
= basename(path
);
1266 type
= unit_name_to_type(name
);
1267 if (unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) &&
1268 !unit_type_may_template(type
))
1269 return log_error_errno(EINVAL
, "Unit type %s cannot be templated.", unit_type_to_string(type
));
1271 if (!(flags
& SEARCH_LOAD
)) {
1272 r
= lstat(path
, &st
);
1276 if (null_or_empty(&st
))
1277 info
->type
= UNIT_FILE_TYPE_MASKED
;
1278 else if (S_ISREG(st
.st_mode
))
1279 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1280 else if (S_ISLNK(st
.st_mode
))
1282 else if (S_ISDIR(st
.st_mode
))
1290 /* c is only needed if we actually load the file */
1293 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1296 if (fstat(fd
, &st
) < 0)
1298 if (null_or_empty(&st
)) {
1299 info
->type
= UNIT_FILE_TYPE_MASKED
;
1302 if (S_ISDIR(st
.st_mode
))
1304 if (!S_ISREG(st
.st_mode
))
1307 f
= fdopen(fd
, "re");
1312 r
= config_parse(NULL
, path
, f
,
1314 config_item_table_lookup
, items
,
1315 true, true, false, info
);
1317 return log_debug_errno(r
, "Failed to parse %s: %m", info
->name
);
1319 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1322 (int) strv_length(info
->aliases
) +
1323 (int) strv_length(info
->wanted_by
) +
1324 (int) strv_length(info
->required_by
);
1327 static int unit_file_load_or_readlink(
1329 UnitFileInstallInfo
*info
,
1331 const char *root_dir
,
1332 SearchFlags flags
) {
1334 _cleanup_free_
char *target
= NULL
;
1337 r
= unit_file_load(c
, info
, path
, flags
);
1341 /* This is a symlink, let's read it. */
1343 r
= readlink_malloc(path
, &target
);
1347 if (path_equal(target
, "/dev/null"))
1348 info
->type
= UNIT_FILE_TYPE_MASKED
;
1353 bn
= basename(target
);
1355 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1357 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1360 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1362 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1365 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1367 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1372 /* Enforce that the symlink destination does not
1373 * change the unit file type. */
1375 a
= unit_name_to_type(info
->name
);
1376 b
= unit_name_to_type(bn
);
1377 if (a
< 0 || b
< 0 || a
!= b
)
1380 if (path_is_absolute(target
))
1381 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1382 info
->symlink_target
= prefix_root(root_dir
, target
);
1384 /* This is a relative path, take it relative to the dir the symlink is located in. */
1385 info
->symlink_target
= file_in_same_dir(path
, target
);
1386 if (!info
->symlink_target
)
1389 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1395 static int unit_file_search(
1397 UnitFileInstallInfo
*info
,
1398 const LookupPaths
*paths
,
1399 SearchFlags flags
) {
1401 _cleanup_free_
char *template = NULL
;
1408 /* Was this unit already loaded? */
1409 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1413 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1417 STRV_FOREACH(p
, paths
->search_path
) {
1418 _cleanup_free_
char *path
= NULL
;
1420 path
= strjoin(*p
, "/", info
->name
);
1424 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1429 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1433 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1434 /* Unit file doesn't exist, however instance
1435 * enablement was requested. We will check if it is
1436 * possible to load template unit file. */
1438 r
= unit_name_template(info
->name
, &template);
1442 STRV_FOREACH(p
, paths
->search_path
) {
1443 _cleanup_free_
char *path
= NULL
;
1445 path
= strjoin(*p
, "/", template);
1449 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1454 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1459 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1463 static int install_info_follow(
1465 UnitFileInstallInfo
*i
,
1466 const char *root_dir
,
1468 bool ignore_different_name
) {
1473 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1475 if (!i
->symlink_target
)
1478 /* If the basename doesn't match, the caller should add a
1479 * complete new entry for this. */
1481 if (!ignore_different_name
&& !streq(basename(i
->symlink_target
), i
->name
))
1484 free_and_replace(i
->path
, i
->symlink_target
);
1485 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1487 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1491 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1492 * target, maybe more than once. Propagate the instance name if present.
1494 static int install_info_traverse(
1495 UnitFileScope scope
,
1497 const LookupPaths
*paths
,
1498 UnitFileInstallInfo
*start
,
1500 UnitFileInstallInfo
**ret
) {
1502 UnitFileInstallInfo
*i
;
1510 r
= unit_file_search(c
, start
, paths
, flags
);
1515 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1516 /* Follow the symlink */
1518 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1521 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1522 r
= path_is_config(paths
, i
->path
, true);
1529 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, false);
1531 _cleanup_free_
char *buffer
= NULL
;
1534 /* Target has a different name, create a new
1535 * install info object for that, and continue
1538 bn
= basename(i
->symlink_target
);
1540 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1541 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1543 _cleanup_free_
char *instance
= NULL
;
1545 r
= unit_name_to_instance(i
->name
, &instance
);
1549 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1553 if (streq(buffer
, i
->name
)) {
1555 /* We filled in the instance, and the target stayed the same? If so, then let's
1556 * honour the link as it is. */
1558 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
, true);
1568 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1572 /* Try again, with the new target we found. */
1573 r
= unit_file_search(c
, i
, paths
, flags
);
1575 /* Translate error code to highlight this specific case */
1590 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1591 * or the name (otherwise). root_dir is prepended to the path.
1593 static int install_info_add_auto(
1595 const LookupPaths
*paths
,
1596 const char *name_or_path
,
1597 UnitFileInstallInfo
**ret
) {
1600 assert(name_or_path
);
1602 if (path_is_absolute(name_or_path
)) {
1605 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1607 return install_info_add(c
, NULL
, pp
, false, ret
);
1609 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1612 static int install_info_discover(
1613 UnitFileScope scope
,
1615 const LookupPaths
*paths
,
1618 UnitFileInstallInfo
**ret
,
1619 UnitFileChange
**changes
,
1620 unsigned *n_changes
) {
1622 UnitFileInstallInfo
*i
;
1629 r
= install_info_add_auto(c
, paths
, name
, &i
);
1631 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1634 unit_file_changes_add(changes
, n_changes
, r
, name
, NULL
);
1638 static int install_info_symlink_alias(
1639 UnitFileInstallInfo
*i
,
1640 const LookupPaths
*paths
,
1641 const char *config_path
,
1643 UnitFileChange
**changes
,
1644 unsigned *n_changes
) {
1651 assert(config_path
);
1653 STRV_FOREACH(s
, i
->aliases
) {
1654 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1656 q
= install_full_printf(i
, *s
, &dst
);
1660 alias_path
= path_make_absolute(dst
, config_path
);
1664 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1672 static int install_info_symlink_wants(
1673 UnitFileInstallInfo
*i
,
1674 const LookupPaths
*paths
,
1675 const char *config_path
,
1678 UnitFileChange
**changes
,
1679 unsigned *n_changes
) {
1681 _cleanup_free_
char *buf
= NULL
;
1688 assert(config_path
);
1690 if (strv_isempty(list
))
1693 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
) && i
->default_instance
) {
1694 UnitFileInstallInfo instance
= {
1695 .type
= _UNIT_FILE_TYPE_INVALID
,
1697 _cleanup_free_
char *path
= NULL
;
1699 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1703 instance
.name
= buf
;
1704 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1708 path
= instance
.path
;
1709 instance
.path
= NULL
;
1711 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1712 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1720 STRV_FOREACH(s
, list
) {
1721 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1723 q
= install_full_printf(i
, *s
, &dst
);
1727 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1732 path
= strjoin(config_path
, "/", dst
, suffix
, n
);
1736 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1744 static int install_info_symlink_link(
1745 UnitFileInstallInfo
*i
,
1746 const LookupPaths
*paths
,
1747 const char *config_path
,
1749 UnitFileChange
**changes
,
1750 unsigned *n_changes
) {
1752 _cleanup_free_
char *path
= NULL
;
1757 assert(config_path
);
1760 r
= in_search_path(paths
, i
->path
);
1766 path
= strjoin(config_path
, "/", i
->name
);
1770 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1773 static int install_info_apply(
1774 UnitFileInstallInfo
*i
,
1775 const LookupPaths
*paths
,
1776 const char *config_path
,
1778 UnitFileChange
**changes
,
1779 unsigned *n_changes
) {
1785 assert(config_path
);
1787 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1790 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1792 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1796 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1800 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1801 /* Do not count links to the unit file towards the "carries_install_info" count */
1802 if (r
== 0 && q
< 0)
1808 static int install_context_apply(
1809 UnitFileScope scope
,
1811 const LookupPaths
*paths
,
1812 const char *config_path
,
1815 UnitFileChange
**changes
,
1816 unsigned *n_changes
) {
1818 UnitFileInstallInfo
*i
;
1823 assert(config_path
);
1825 if (ordered_hashmap_isempty(c
->will_process
))
1828 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1833 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1836 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1840 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1842 unit_file_changes_add(changes
, n_changes
, r
, i
->name
, NULL
);
1846 /* We can attempt to process a masked unit when a different unit
1847 * that we were processing specifies it in Also=. */
1848 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1849 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1851 /* Assume that something *could* have been enabled here,
1852 * avoid "empty [Install] section" warning. */
1857 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1860 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1872 static int install_context_mark_for_removal(
1873 UnitFileScope scope
,
1875 const LookupPaths
*paths
,
1876 Set
**remove_symlinks_to
,
1877 const char *config_path
,
1878 UnitFileChange
**changes
,
1879 unsigned *n_changes
) {
1881 UnitFileInstallInfo
*i
;
1886 assert(config_path
);
1888 /* Marks all items for removal */
1890 if (ordered_hashmap_isempty(c
->will_process
))
1893 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1897 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1899 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1903 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1904 if (r
== -ENOLINK
) {
1905 log_debug_errno(r
, "Name %s leads to a dangling symlink, removing name.", i
->name
);
1906 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_DANGLING
, i
->path
?: i
->name
, NULL
);
1907 } else if (r
== -ENOENT
) {
1909 if (i
->auxiliary
) /* some unit specified in Also= or similar is missing */
1910 log_debug_errno(r
, "Auxiliary unit of %s not found, removing name.", i
->name
);
1912 log_debug_errno(r
, "Unit %s not found, removing name.", i
->name
);
1913 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1917 log_debug_errno(r
, "Failed to find unit %s, removing name: %m", i
->name
);
1918 unit_file_changes_add(changes
, n_changes
, r
, i
->path
?: i
->name
, NULL
);
1919 } else if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1920 log_debug("Unit file %s is masked, ignoring.", i
->name
);
1921 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
?: i
->name
, NULL
);
1923 } else if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1924 log_debug("Unit %s has type %s, ignoring.", i
->name
, unit_file_type_to_string(i
->type
) ?: "invalid");
1928 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1937 UnitFileScope scope
,
1938 UnitFileFlags flags
,
1939 const char *root_dir
,
1941 UnitFileChange
**changes
,
1942 unsigned *n_changes
) {
1944 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1945 const char *config_path
;
1950 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1952 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1956 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
1960 STRV_FOREACH(i
, files
) {
1961 _cleanup_free_
char *path
= NULL
;
1964 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1970 path
= path_make_absolute(*i
, config_path
);
1974 q
= create_symlink(&paths
, "/dev/null", path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
1975 if (q
< 0 && r
>= 0)
1982 int unit_file_unmask(
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 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1992 _cleanup_strv_free_
char **todo
= NULL
;
1993 size_t n_todo
= 0, n_allocated
= 0;
1994 const char *config_path
;
2000 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2002 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2006 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2010 dry_run
= !!(flags
& UNIT_FILE_DRY_RUN
);
2012 STRV_FOREACH(i
, files
) {
2013 _cleanup_free_
char *path
= NULL
;
2015 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2018 path
= path_make_absolute(*i
, config_path
);
2022 r
= null_or_empty_path(path
);
2030 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2033 todo
[n_todo
] = strdup(*i
);
2043 STRV_FOREACH(i
, todo
) {
2044 _cleanup_free_
char *path
= NULL
;
2047 path
= path_make_absolute(*i
, config_path
);
2051 if (!dry_run
&& unlink(path
) < 0) {
2052 if (errno
!= ENOENT
) {
2055 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
2061 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
2063 rp
= skip_root(&paths
, path
);
2064 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
2069 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, dry_run
, changes
, n_changes
);
2077 UnitFileScope scope
,
2078 UnitFileFlags flags
,
2079 const char *root_dir
,
2081 UnitFileChange
**changes
,
2082 unsigned *n_changes
) {
2084 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2085 _cleanup_strv_free_
char **todo
= NULL
;
2086 size_t n_todo
= 0, n_allocated
= 0;
2087 const char *config_path
;
2092 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2094 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2098 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2102 STRV_FOREACH(i
, files
) {
2103 _cleanup_free_
char *full
= NULL
;
2107 if (!path_is_absolute(*i
))
2111 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
2114 full
= prefix_root(paths
.root_dir
, *i
);
2118 if (lstat(full
, &st
) < 0)
2120 if (S_ISLNK(st
.st_mode
))
2122 if (S_ISDIR(st
.st_mode
))
2124 if (!S_ISREG(st
.st_mode
))
2127 q
= in_search_path(&paths
, *i
);
2133 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2136 todo
[n_todo
] = strdup(*i
);
2146 STRV_FOREACH(i
, todo
) {
2147 _cleanup_free_
char *new_path
= NULL
;
2149 new_path
= path_make_absolute(basename(*i
), config_path
);
2153 q
= create_symlink(&paths
, *i
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2154 if (q
< 0 && r
>= 0)
2161 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2167 /* Checks whether the path is one where the drop-in directories shall be removed. */
2169 r
= path_is_config(paths
, path
, true);
2173 r
= path_is_control(paths
, path
);
2177 return path_is_transient(paths
, path
);
2180 int unit_file_revert(
2181 UnitFileScope scope
,
2182 const char *root_dir
,
2184 UnitFileChange
**changes
,
2185 unsigned *n_changes
) {
2187 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2188 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2189 _cleanup_strv_free_
char **todo
= NULL
;
2190 size_t n_todo
= 0, n_allocated
= 0;
2194 /* Puts a unit file back into vendor state. This means:
2196 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2197 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2199 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2200 * "config", but not in "transient" or "control" or even "generated").
2202 * We remove all that in both the runtime and the persistent directories, if that applies.
2205 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2209 STRV_FOREACH(i
, files
) {
2210 bool has_vendor
= false;
2213 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2216 STRV_FOREACH(p
, paths
.search_path
) {
2217 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2220 path
= path_make_absolute(*i
, *p
);
2224 r
= lstat(path
, &st
);
2226 if (errno
!= ENOENT
)
2228 } else if (S_ISREG(st
.st_mode
)) {
2229 /* Check if there's a vendor version */
2230 r
= path_is_vendor(&paths
, path
);
2237 dropin
= strappend(path
, ".d");
2241 r
= lstat(dropin
, &st
);
2243 if (errno
!= ENOENT
)
2245 } else if (S_ISDIR(st
.st_mode
)) {
2246 /* Remove the drop-ins */
2247 r
= path_shall_revert(&paths
, dropin
);
2251 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2254 todo
[n_todo
++] = dropin
;
2263 /* OK, there's a vendor version, hence drop all configuration versions */
2264 STRV_FOREACH(p
, paths
.search_path
) {
2265 _cleanup_free_
char *path
= NULL
;
2268 path
= path_make_absolute(*i
, *p
);
2272 r
= lstat(path
, &st
);
2274 if (errno
!= ENOENT
)
2276 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2277 r
= path_is_config(&paths
, path
, true);
2281 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2284 todo
[n_todo
++] = path
;
2294 STRV_FOREACH(i
, todo
) {
2295 _cleanup_strv_free_
char **fs
= NULL
;
2299 (void) get_files_in_directory(*i
, &fs
);
2301 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2302 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2307 STRV_FOREACH(j
, fs
) {
2308 _cleanup_free_
char *t
= NULL
;
2310 t
= strjoin(*i
, "/", *j
);
2314 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2317 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2319 rp
= skip_root(&paths
, *i
);
2320 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2325 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, false, changes
, n_changes
);
2329 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, false, changes
, n_changes
);
2336 int unit_file_add_dependency(
2337 UnitFileScope scope
,
2338 UnitFileFlags flags
,
2339 const char *root_dir
,
2343 UnitFileChange
**changes
,
2344 unsigned *n_changes
) {
2346 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2347 _cleanup_(install_context_done
) InstallContext c
= {};
2348 UnitFileInstallInfo
*i
, *target_info
;
2349 const char *config_path
;
2354 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2357 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2360 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2363 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2367 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2371 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2372 &target_info
, changes
, n_changes
);
2375 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2379 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2381 STRV_FOREACH(f
, files
) {
2384 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2385 &i
, changes
, n_changes
);
2388 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2392 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2394 /* We didn't actually load anything from the unit
2395 * file, but instead just add in our new symlink to
2398 if (dep
== UNIT_WANTS
)
2401 l
= &i
->required_by
;
2404 *l
= strv_new(target_info
->name
, NULL
);
2409 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2412 int unit_file_enable(
2413 UnitFileScope scope
,
2414 UnitFileFlags flags
,
2415 const char *root_dir
,
2417 UnitFileChange
**changes
,
2418 unsigned *n_changes
) {
2420 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2421 _cleanup_(install_context_done
) InstallContext c
= {};
2422 const char *config_path
;
2423 UnitFileInstallInfo
*i
;
2428 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2430 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2434 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2438 STRV_FOREACH(f
, files
) {
2439 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2440 &i
, changes
, n_changes
);
2443 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2447 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2450 /* This will return the number of symlink rules that were
2451 supposed to be created, not the ones actually created. This
2452 is useful to determine whether the passed files had any
2453 installation data at all. */
2455 return install_context_apply(scope
, &c
, &paths
, config_path
, !!(flags
& UNIT_FILE_FORCE
), SEARCH_LOAD
, changes
, n_changes
);
2458 int unit_file_disable(
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 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2469 const char *config_path
;
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(i
, files
) {
2485 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2488 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2493 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2497 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, !!(flags
& UNIT_FILE_DRY_RUN
), changes
, n_changes
);
2500 int unit_file_reenable(
2501 UnitFileScope scope
,
2502 UnitFileFlags flags
,
2503 const char *root_dir
,
2505 UnitFileChange
**changes
,
2506 unsigned *n_changes
) {
2512 /* First, we invoke the disable command with only the basename... */
2513 l
= strv_length(files
);
2514 n
= newa(char*, l
+1);
2515 for (i
= 0; i
< l
; i
++)
2516 n
[i
] = basename(files
[i
]);
2519 r
= unit_file_disable(scope
, flags
, root_dir
, n
, changes
, n_changes
);
2523 /* But the enable command with the full name */
2524 return unit_file_enable(scope
, flags
, root_dir
, files
, changes
, n_changes
);
2527 int unit_file_set_default(
2528 UnitFileScope scope
,
2529 UnitFileFlags flags
,
2530 const char *root_dir
,
2532 UnitFileChange
**changes
,
2533 unsigned *n_changes
) {
2535 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2536 _cleanup_(install_context_done
) InstallContext c
= {};
2537 UnitFileInstallInfo
*i
;
2538 const char *new_path
;
2542 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2545 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2547 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2550 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2554 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
, changes
, n_changes
);
2557 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2561 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2562 return create_symlink(&paths
, i
->path
, new_path
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
2565 int unit_file_get_default(
2566 UnitFileScope scope
,
2567 const char *root_dir
,
2570 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2571 _cleanup_(install_context_done
) InstallContext c
= {};
2572 UnitFileInstallInfo
*i
;
2577 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2580 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2584 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2588 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2592 n
= strdup(i
->name
);
2600 static int unit_file_lookup_state(
2601 UnitFileScope scope
,
2602 const LookupPaths
*paths
,
2604 UnitFileState
*ret
) {
2606 _cleanup_(install_context_done
) InstallContext c
= {};
2607 UnitFileInstallInfo
*i
;
2608 UnitFileState state
;
2614 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2617 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2622 /* Shortcut things, if the caller just wants to know if this unit exists. */
2628 case UNIT_FILE_TYPE_MASKED
:
2629 r
= path_is_runtime(paths
, i
->path
, true);
2633 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2636 case UNIT_FILE_TYPE_REGULAR
:
2637 r
= path_is_generator(paths
, i
->path
);
2641 state
= UNIT_FILE_GENERATED
;
2645 r
= path_is_transient(paths
, i
->path
);
2649 state
= UNIT_FILE_TRANSIENT
;
2653 /* Check if any of the Alias= symlinks have been created.
2654 * We ignore other aliases, and only check those that would
2655 * be created by systemctl enable for this unit. */
2656 r
= find_symlinks_in_scope(scope
, paths
, i
, true, &state
);
2662 /* Check if the file is known under other names. If it is,
2663 * it might be in use. Report that as UNIT_FILE_INDIRECT. */
2664 r
= find_symlinks_in_scope(scope
, paths
, i
, false, &state
);
2668 state
= UNIT_FILE_INDIRECT
;
2670 if (unit_file_install_info_has_rules(i
))
2671 state
= UNIT_FILE_DISABLED
;
2672 else if (unit_file_install_info_has_also(i
))
2673 state
= UNIT_FILE_INDIRECT
;
2675 state
= UNIT_FILE_STATIC
;
2681 assert_not_reached("Unexpect unit file type.");
2688 int unit_file_get_state(
2689 UnitFileScope scope
,
2690 const char *root_dir
,
2692 UnitFileState
*ret
) {
2694 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2698 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2701 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2705 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2708 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2709 _cleanup_(install_context_done
) InstallContext c
= {};
2715 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2718 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
, NULL
, NULL
);
2727 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2728 _cleanup_(presets_freep
) Presets ps
= {};
2729 size_t n_allocated
= 0;
2730 _cleanup_strv_free_
char **files
= NULL
;
2735 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2738 if (scope
== UNIT_FILE_SYSTEM
)
2739 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2740 "/etc/systemd/system-preset",
2741 "/usr/local/lib/systemd/system-preset",
2742 "/usr/lib/systemd/system-preset",
2743 #ifdef HAVE_SPLIT_USR
2744 "/lib/systemd/system-preset",
2747 else if (scope
== UNIT_FILE_GLOBAL
)
2748 r
= conf_files_list(&files
, ".preset", root_dir
, 0,
2749 "/etc/systemd/user-preset",
2750 "/usr/local/lib/systemd/user-preset",
2751 "/usr/lib/systemd/user-preset",
2754 *presets
= (Presets
){};
2762 STRV_FOREACH(p
, files
) {
2763 _cleanup_fclose_
FILE *f
;
2764 char line
[LINE_MAX
];
2767 f
= fopen(*p
, "re");
2769 if (errno
== ENOENT
)
2775 FOREACH_LINE(line
, f
, return -errno
) {
2776 PresetRule rule
= {};
2777 const char *parameter
;
2785 if (strchr(COMMENTS
, *l
))
2788 parameter
= first_word(l
, "enable");
2792 pattern
= strdup(parameter
);
2796 rule
= (PresetRule
) {
2798 .action
= PRESET_ENABLE
,
2802 parameter
= first_word(l
, "disable");
2806 pattern
= strdup(parameter
);
2810 rule
= (PresetRule
) {
2812 .action
= PRESET_DISABLE
,
2817 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2820 ps
.rules
[ps
.n_rules
++] = rule
;
2824 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2834 static int query_presets(const char *name
, const Presets presets
) {
2835 PresetAction action
= PRESET_UNKNOWN
;
2838 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2841 for (i
= 0; i
< presets
.n_rules
; i
++)
2842 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2843 action
= presets
.rules
[i
].action
;
2848 case PRESET_UNKNOWN
:
2849 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2852 log_debug("Preset files say enable %s.", name
);
2854 case PRESET_DISABLE
:
2855 log_debug("Preset files say disable %s.", name
);
2858 assert_not_reached("invalid preset action");
2862 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2863 _cleanup_(presets_freep
) Presets presets
= {};
2866 r
= read_presets(scope
, root_dir
, &presets
);
2870 return query_presets(name
, presets
);
2873 static int execute_preset(
2874 UnitFileScope scope
,
2875 InstallContext
*plus
,
2876 InstallContext
*minus
,
2877 const LookupPaths
*paths
,
2878 const char *config_path
,
2880 UnitFilePresetMode mode
,
2882 UnitFileChange
**changes
,
2883 unsigned *n_changes
) {
2890 assert(config_path
);
2892 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2893 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2895 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
, changes
, n_changes
);
2899 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, false, changes
, n_changes
);
2903 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2906 /* Returns number of symlinks that where supposed to be installed. */
2907 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2919 static int preset_prepare_one(
2920 UnitFileScope scope
,
2921 InstallContext
*plus
,
2922 InstallContext
*minus
,
2926 UnitFileChange
**changes
,
2927 unsigned *n_changes
) {
2929 _cleanup_(install_context_done
) InstallContext tmp
= {};
2930 UnitFileInstallInfo
*i
;
2933 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2936 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2937 &i
, changes
, n_changes
);
2940 if (!streq(name
, i
->name
)) {
2941 log_debug("Skipping %s because is an alias for %s", name
, i
->name
);
2945 r
= query_presets(name
, presets
);
2950 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2951 &i
, changes
, n_changes
);
2955 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
2959 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
,
2960 &i
, changes
, n_changes
);
2965 int unit_file_preset(
2966 UnitFileScope scope
,
2967 UnitFileFlags flags
,
2968 const char *root_dir
,
2970 UnitFilePresetMode mode
,
2971 UnitFileChange
**changes
,
2972 unsigned *n_changes
) {
2974 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2975 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2976 _cleanup_(presets_freep
) Presets presets
= {};
2977 const char *config_path
;
2982 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2983 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2985 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2989 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
2993 r
= read_presets(scope
, root_dir
, &presets
);
2997 STRV_FOREACH(i
, files
) {
2998 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
3003 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3006 int unit_file_preset_all(
3007 UnitFileScope scope
,
3008 UnitFileFlags flags
,
3009 const char *root_dir
,
3010 UnitFilePresetMode mode
,
3011 UnitFileChange
**changes
,
3012 unsigned *n_changes
) {
3014 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
3015 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3016 _cleanup_(presets_freep
) Presets presets
= {};
3017 const char *config_path
= NULL
;
3022 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3023 assert(mode
< _UNIT_FILE_PRESET_MAX
);
3025 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3029 config_path
= (flags
& UNIT_FILE_RUNTIME
) ? paths
.runtime_config
: paths
.persistent_config
;
3033 r
= read_presets(scope
, root_dir
, &presets
);
3037 STRV_FOREACH(i
, paths
.search_path
) {
3038 _cleanup_closedir_
DIR *d
= NULL
;
3043 if (errno
== ENOENT
)
3049 FOREACH_DIRENT(de
, d
, return -errno
) {
3051 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3054 dirent_ensure_type(d
, de
);
3056 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3059 /* we don't pass changes[] in, because we want to handle errors on our own */
3060 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
3062 r
= unit_file_changes_add(changes
, n_changes
,
3063 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
3064 else if (r
== -ENOLINK
)
3065 r
= unit_file_changes_add(changes
, n_changes
,
3066 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
3072 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, !!(flags
& UNIT_FILE_FORCE
), changes
, n_changes
);
3075 static void unit_file_list_free_one(UnitFileList
*f
) {
3083 Hashmap
* unit_file_list_free(Hashmap
*h
) {
3086 while ((i
= hashmap_steal_first(h
)))
3087 unit_file_list_free_one(i
);
3089 return hashmap_free(h
);
3092 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
3094 int unit_file_get_list(
3095 UnitFileScope scope
,
3096 const char *root_dir
,
3101 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
3106 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
3109 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
3113 STRV_FOREACH(i
, paths
.search_path
) {
3114 _cleanup_closedir_
DIR *d
= NULL
;
3119 if (errno
== ENOENT
)
3121 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
3122 log_debug_errno(errno
, "Failed to open \"%s\": %m", *i
);
3129 FOREACH_DIRENT(de
, d
, return -errno
) {
3130 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
3132 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
3135 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
3138 if (hashmap_get(h
, de
->d_name
))
3141 dirent_ensure_type(d
, de
);
3143 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
3146 f
= new0(UnitFileList
, 1);
3150 f
->path
= path_make_absolute(de
->d_name
, *i
);
3154 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
3156 f
->state
= UNIT_FILE_BAD
;
3158 if (!strv_isempty(states
) &&
3159 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
3162 r
= hashmap_put(h
, basename(f
->path
), f
);
3166 f
= NULL
; /* prevent cleanup */
3173 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
3174 [UNIT_FILE_ENABLED
] = "enabled",
3175 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
3176 [UNIT_FILE_LINKED
] = "linked",
3177 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3178 [UNIT_FILE_MASKED
] = "masked",
3179 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3180 [UNIT_FILE_STATIC
] = "static",
3181 [UNIT_FILE_DISABLED
] = "disabled",
3182 [UNIT_FILE_INDIRECT
] = "indirect",
3183 [UNIT_FILE_GENERATED
] = "generated",
3184 [UNIT_FILE_TRANSIENT
] = "transient",
3185 [UNIT_FILE_BAD
] = "bad",
3188 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3190 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3191 [UNIT_FILE_SYMLINK
] = "symlink",
3192 [UNIT_FILE_UNLINK
] = "unlink",
3193 [UNIT_FILE_IS_MASKED
] = "masked",
3194 [UNIT_FILE_IS_DANGLING
] = "dangling",
3197 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3199 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3200 [UNIT_FILE_PRESET_FULL
] = "full",
3201 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3202 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3205 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);