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 void presets_freep(Presets
*p
) {
92 for (i
= 0; i
< p
->n_rules
; i
++)
93 free(p
->rules
[i
].pattern
);
99 static int unit_file_lookup_state(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
, UnitFileState
*ret
);
101 bool unit_type_may_alias(UnitType type
) {
111 bool unit_type_may_template(UnitType type
) {
120 static const char *unit_file_type_table
[_UNIT_FILE_TYPE_MAX
] = {
121 [UNIT_FILE_TYPE_REGULAR
] = "regular",
122 [UNIT_FILE_TYPE_SYMLINK
] = "symlink",
123 [UNIT_FILE_TYPE_MASKED
] = "masked",
126 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type
, UnitFileType
);
128 static int in_search_path(const LookupPaths
*p
, const char *path
) {
129 _cleanup_free_
char *parent
= NULL
;
134 parent
= dirname_malloc(path
);
138 STRV_FOREACH(i
, p
->search_path
)
139 if (path_equal(parent
, *i
))
145 static const char* skip_root(const LookupPaths
*p
, const char *path
) {
154 e
= path_startswith(path
, p
->root_dir
);
158 /* Make sure the returned path starts with a slash */
160 if (e
== path
|| e
[-1] != '/')
169 static int path_is_generator(const LookupPaths
*p
, const char *path
) {
170 _cleanup_free_
char *parent
= NULL
;
175 parent
= dirname_malloc(path
);
179 return path_equal_ptr(parent
, p
->generator
) ||
180 path_equal_ptr(parent
, p
->generator_early
) ||
181 path_equal_ptr(parent
, p
->generator_late
);
184 static int path_is_transient(const LookupPaths
*p
, const char *path
) {
185 _cleanup_free_
char *parent
= NULL
;
190 parent
= dirname_malloc(path
);
194 return path_equal_ptr(parent
, p
->transient
);
197 static int path_is_control(const LookupPaths
*p
, const char *path
) {
198 _cleanup_free_
char *parent
= NULL
;
203 parent
= dirname_malloc(path
);
207 return path_equal_ptr(parent
, p
->persistent_control
) ||
208 path_equal_ptr(parent
, p
->runtime_control
);
211 static int path_is_config(const LookupPaths
*p
, const char *path
) {
212 _cleanup_free_
char *parent
= NULL
;
217 /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern
218 * configuration from transient or generated units */
220 parent
= dirname_malloc(path
);
224 return path_equal_ptr(parent
, p
->persistent_config
) ||
225 path_equal_ptr(parent
, p
->runtime_config
);
228 static int path_is_runtime(const LookupPaths
*p
, const char *path
) {
229 _cleanup_free_
char *parent
= NULL
;
235 /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime
236 * directories, as safety net. */
238 rpath
= skip_root(p
, path
);
239 if (rpath
&& path_startswith(rpath
, "/run"))
242 parent
= dirname_malloc(path
);
246 return path_equal_ptr(parent
, p
->runtime_config
) ||
247 path_equal_ptr(parent
, p
->generator
) ||
248 path_equal_ptr(parent
, p
->generator_early
) ||
249 path_equal_ptr(parent
, p
->generator_late
) ||
250 path_equal_ptr(parent
, p
->transient
) ||
251 path_equal_ptr(parent
, p
->runtime_control
);
254 static int path_is_vendor(const LookupPaths
*p
, const char *path
) {
260 rpath
= skip_root(p
, path
);
264 if (path_startswith(rpath
, "/usr"))
267 #ifdef HAVE_SPLIT_USR
268 if (path_startswith(rpath
, "/lib"))
272 return path_equal(rpath
, SYSTEM_DATA_UNIT_PATH
);
275 int unit_file_changes_add(
276 UnitFileChange
**changes
,
278 UnitFileChangeType type
,
280 const char *source
) {
282 _cleanup_free_
char *p
= NULL
, *s
= NULL
;
286 assert(!changes
== !n_changes
);
291 c
= realloc(*changes
, (*n_changes
+ 1) * sizeof(UnitFileChange
));
300 if (!p
|| (source
&& !s
))
303 path_kill_slashes(p
);
305 path_kill_slashes(s
);
307 c
[*n_changes
] = (UnitFileChange
) { type
, p
, s
};
313 void unit_file_changes_free(UnitFileChange
*changes
, unsigned n_changes
) {
316 assert(changes
|| n_changes
== 0);
318 for (i
= 0; i
< n_changes
; i
++) {
319 free(changes
[i
].path
);
320 free(changes
[i
].source
);
326 void unit_file_dump_changes(int r
, const char *verb
, const UnitFileChange
*changes
, unsigned n_changes
, bool quiet
) {
330 assert(changes
|| n_changes
== 0);
331 /* If verb is not specified, errors are not allowed! */
332 assert(verb
|| r
>= 0);
334 for (i
= 0; i
< n_changes
; i
++) {
335 assert(verb
|| changes
[i
].type
>= 0);
337 switch(changes
[i
].type
) {
338 case UNIT_FILE_SYMLINK
:
340 log_info("Created symlink %s %s %s.",
342 special_glyph(ARROW
),
345 case UNIT_FILE_UNLINK
:
347 log_info("Removed %s.", changes
[i
].path
);
349 case UNIT_FILE_IS_MASKED
:
351 log_info("Unit %s is masked, ignoring.", changes
[i
].path
);
353 case UNIT_FILE_IS_DANGLING
:
355 log_info("Unit %s is an alias to a unit that is not present, ignoring.",
359 if (changes
[i
].source
)
360 log_error_errno(changes
[i
].type
,
361 "Failed to %s unit, file %s already exists and is a symlink to %s.",
362 verb
, changes
[i
].path
, changes
[i
].source
);
364 log_error_errno(changes
[i
].type
,
365 "Failed to %s unit, file %s already exists.",
366 verb
, changes
[i
].path
);
370 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is masked.",
371 verb
, changes
[i
].path
);
375 log_error_errno(changes
[i
].type
, "Failed to %s unit, unit %s is transient or generated.",
376 verb
, changes
[i
].path
);
380 log_error_errno(changes
[i
].type
, "Failed to %s unit, refusing to operate on linked unit file %s",
381 verb
, changes
[i
].path
);
385 assert(changes
[i
].type
< 0);
386 log_error_errno(changes
[i
].type
, "Failed to %s unit, file %s: %m.",
387 verb
, changes
[i
].path
);
392 if (r
< 0 && !logged
)
393 log_error_errno(r
, "Failed to %s: %m.", verb
);
397 * Checks if two paths or symlinks from wd are the same, when root is the root of the filesystem.
398 * wc should be the full path in the host file system.
400 static bool chroot_symlinks_same(const char *root
, const char *wd
, const char *a
, const char *b
) {
401 assert(path_is_absolute(wd
));
403 /* This will give incorrect results if the paths are relative and go outside
404 * of the chroot. False negatives are possible. */
409 a
= strjoina(path_is_absolute(a
) ? root
: wd
, "/", a
);
410 b
= strjoina(path_is_absolute(b
) ? root
: wd
, "/", b
);
411 return path_equal_or_files_same(a
, b
);
414 static int create_symlink(
415 const LookupPaths
*paths
,
416 const char *old_path
,
417 const char *new_path
,
419 UnitFileChange
**changes
,
420 unsigned *n_changes
) {
422 _cleanup_free_
char *dest
= NULL
, *dirname
= NULL
;
429 rp
= skip_root(paths
, old_path
);
433 /* Actually create a symlink, and remember that we did. Is
434 * smart enough to check if there's already a valid symlink in
437 * Returns 1 if a symlink was created or already exists and points to
438 * the right place, or negative on error.
441 mkdir_parents_label(new_path
, 0755);
443 if (symlink(old_path
, new_path
) >= 0) {
444 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
448 if (errno
!= EEXIST
) {
449 unit_file_changes_add(changes
, n_changes
, -errno
, new_path
, NULL
);
453 r
= readlink_malloc(new_path
, &dest
);
455 /* translate EINVAL (non-symlink exists) to EEXIST */
459 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
463 dirname
= dirname_malloc(new_path
);
467 if (chroot_symlinks_same(paths
->root_dir
, dirname
, dest
, old_path
))
471 unit_file_changes_add(changes
, n_changes
, -EEXIST
, new_path
, dest
);
475 r
= symlink_atomic(old_path
, new_path
);
477 unit_file_changes_add(changes
, n_changes
, r
, new_path
, NULL
);
481 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, new_path
, NULL
);
482 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_SYMLINK
, new_path
, old_path
);
487 static int mark_symlink_for_removal(
488 Set
**remove_symlinks_to
,
496 r
= set_ensure_allocated(remove_symlinks_to
, &string_hash_ops
);
504 path_kill_slashes(n
);
506 r
= set_consume(*remove_symlinks_to
, n
);
515 static int remove_marked_symlinks_fd(
516 Set
*remove_symlinks_to
,
519 const char *config_path
,
520 const LookupPaths
*lp
,
522 UnitFileChange
**changes
,
523 unsigned *n_changes
) {
525 _cleanup_closedir_
DIR *d
= NULL
;
529 assert(remove_symlinks_to
);
544 FOREACH_DIRENT(de
, d
, return -errno
) {
546 dirent_ensure_type(d
, de
);
548 if (de
->d_type
== DT_DIR
) {
549 _cleanup_free_
char *p
= NULL
;
552 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
562 p
= path_make_absolute(de
->d_name
, path
);
568 /* This will close nfd, regardless whether it succeeds or not */
569 q
= remove_marked_symlinks_fd(remove_symlinks_to
, nfd
, p
, config_path
, lp
, restart
, changes
, n_changes
);
573 } else if (de
->d_type
== DT_LNK
) {
574 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
579 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
582 p
= path_make_absolute(de
->d_name
, path
);
585 path_kill_slashes(p
);
587 q
= readlink_malloc(p
, &dest
);
596 /* We remove all links pointing to a file or path that is marked, as well as all files sharing
597 * the same name as a file that is marked. */
599 found
= set_contains(remove_symlinks_to
, dest
) ||
600 set_contains(remove_symlinks_to
, basename(dest
)) ||
601 set_contains(remove_symlinks_to
, de
->d_name
);
606 if (unlinkat(fd
, de
->d_name
, 0) < 0 && errno
!= ENOENT
) {
609 unit_file_changes_add(changes
, n_changes
, -errno
, p
, NULL
);
613 (void) rmdir_parents(p
, config_path
);
615 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, p
, NULL
);
617 /* Now, remember the full path (but with the root prefix removed) of
618 * the symlink we just removed, and remove any symlinks to it, too. */
620 rp
= skip_root(lp
, p
);
621 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: p
);
632 static int remove_marked_symlinks(
633 Set
*remove_symlinks_to
,
634 const char *config_path
,
635 const LookupPaths
*lp
,
636 UnitFileChange
**changes
,
637 unsigned *n_changes
) {
639 _cleanup_close_
int fd
= -1;
646 if (set_size(remove_symlinks_to
) <= 0)
649 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
651 return errno
== ENOENT
? 0 : -errno
;
657 cfd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
661 /* This takes possession of cfd and closes it */
662 q
= remove_marked_symlinks_fd(remove_symlinks_to
, cfd
, config_path
, config_path
, lp
, &restart
, changes
, n_changes
);
670 static int find_symlinks_fd(
671 const char *root_dir
,
675 const char *config_path
,
676 const LookupPaths
*lp
,
677 bool *same_name_link
) {
679 _cleanup_closedir_
DIR *d
= NULL
;
688 assert(same_name_link
);
696 FOREACH_DIRENT(de
, d
, return -errno
) {
698 dirent_ensure_type(d
, de
);
700 if (de
->d_type
== DT_DIR
) {
701 _cleanup_free_
char *p
= NULL
;
704 nfd
= openat(fd
, de
->d_name
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
|O_NOFOLLOW
);
714 p
= path_make_absolute(de
->d_name
, path
);
720 /* This will close nfd, regardless whether it succeeds or not */
721 q
= find_symlinks_fd(root_dir
, name
, nfd
, p
, config_path
, lp
, same_name_link
);
727 } else if (de
->d_type
== DT_LNK
) {
728 _cleanup_free_
char *p
= NULL
, *dest
= NULL
;
729 bool found_path
, found_dest
, b
= false;
732 /* Acquire symlink name */
733 p
= path_make_absolute(de
->d_name
, path
);
737 /* Acquire symlink destination */
738 q
= readlink_malloc(p
, &dest
);
748 if (!path_is_absolute(dest
)) {
751 x
= prefix_root(root_dir
, dest
);
759 /* Check if the symlink itself matches what we
761 if (path_is_absolute(name
))
762 found_path
= path_equal(p
, name
);
764 found_path
= streq(de
->d_name
, name
);
766 /* Check if what the symlink points to
767 * matches what we are looking for */
768 if (path_is_absolute(name
))
769 found_dest
= path_equal(dest
, name
);
771 found_dest
= streq(basename(dest
), name
);
773 if (found_path
&& found_dest
) {
774 _cleanup_free_
char *t
= NULL
;
776 /* Filter out same name links in the main
778 t
= path_make_absolute(name
, config_path
);
782 b
= path_equal(t
, p
);
786 *same_name_link
= true;
787 else if (found_path
|| found_dest
)
795 static int find_symlinks(
796 const char *root_dir
,
798 const char *config_path
,
799 const LookupPaths
*lp
,
800 bool *same_name_link
) {
806 assert(same_name_link
);
808 fd
= open(config_path
, O_RDONLY
|O_NONBLOCK
|O_DIRECTORY
|O_CLOEXEC
);
810 if (IN_SET(errno
, ENOENT
, ENOTDIR
, EACCES
))
815 /* This takes possession of fd and closes it */
816 return find_symlinks_fd(root_dir
, name
, fd
, config_path
, config_path
, lp
, same_name_link
);
819 static int find_symlinks_in_scope(
821 const LookupPaths
*paths
,
823 UnitFileState
*state
) {
825 bool same_name_link_runtime
= false, same_name_link
= false;
829 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
833 /* First look in the persistent config path */
834 r
= find_symlinks(paths
->root_dir
, name
, paths
->persistent_config
, paths
, &same_name_link
);
838 *state
= UNIT_FILE_ENABLED
;
842 /* Then look in runtime config path */
843 r
= find_symlinks(paths
->root_dir
, name
, paths
->runtime_config
, paths
, &same_name_link_runtime
);
847 *state
= UNIT_FILE_ENABLED_RUNTIME
;
851 /* Hmm, we didn't find it, but maybe we found the same name
853 if (same_name_link
) {
854 *state
= UNIT_FILE_LINKED
;
857 if (same_name_link_runtime
) {
858 *state
= UNIT_FILE_LINKED_RUNTIME
;
865 static void install_info_free(UnitFileInstallInfo
*i
) {
872 strv_free(i
->aliases
);
873 strv_free(i
->wanted_by
);
874 strv_free(i
->required_by
);
876 free(i
->default_instance
);
877 free(i
->symlink_target
);
881 static OrderedHashmap
* install_info_hashmap_free(OrderedHashmap
*m
) {
882 UnitFileInstallInfo
*i
;
887 while ((i
= ordered_hashmap_steal_first(m
)))
888 install_info_free(i
);
890 return ordered_hashmap_free(m
);
893 static void install_context_done(InstallContext
*c
) {
896 c
->will_process
= install_info_hashmap_free(c
->will_process
);
897 c
->have_processed
= install_info_hashmap_free(c
->have_processed
);
900 static UnitFileInstallInfo
*install_info_find(InstallContext
*c
, const char *name
) {
901 UnitFileInstallInfo
*i
;
903 i
= ordered_hashmap_get(c
->have_processed
, name
);
907 return ordered_hashmap_get(c
->will_process
, name
);
910 static int install_info_may_process(
911 UnitFileInstallInfo
*i
,
912 const LookupPaths
*paths
,
913 UnitFileChange
**changes
,
914 unsigned *n_changes
) {
918 /* Checks whether the loaded unit file is one we should process, or is masked,
919 * transient or generated and thus not subject to enable/disable operations. */
921 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
922 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, i
->path
, NULL
);
925 if (path_is_generator(paths
, i
->path
) ||
926 path_is_transient(paths
, i
->path
)) {
927 unit_file_changes_add(changes
, n_changes
, -EADDRNOTAVAIL
, i
->path
, NULL
);
928 return -EADDRNOTAVAIL
;
935 * Adds a new UnitFileInstallInfo entry under name in the InstallContext.will_process
936 * hashmap, or retrieves the existing one if already present.
938 * Returns negative on error, 0 if the unit was already known, 1 otherwise.
940 static int install_info_add(
945 UnitFileInstallInfo
**ret
) {
947 UnitFileInstallInfo
*i
= NULL
;
951 assert(name
|| path
);
954 name
= basename(path
);
956 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
959 i
= install_info_find(c
, name
);
961 i
->auxiliary
= i
->auxiliary
&& auxiliary
;
968 r
= ordered_hashmap_ensure_allocated(&c
->will_process
, &string_hash_ops
);
972 i
= new0(UnitFileInstallInfo
, 1);
975 i
->type
= _UNIT_FILE_TYPE_INVALID
;
976 i
->auxiliary
= auxiliary
;
978 i
->name
= strdup(name
);
985 i
->path
= strdup(path
);
992 r
= ordered_hashmap_put(c
->will_process
, i
->name
, i
);
1002 install_info_free(i
);
1006 static int config_parse_alias(
1008 const char *filename
,
1010 const char *section
,
1011 unsigned section_line
,
1025 name
= basename(filename
);
1026 type
= unit_name_to_type(name
);
1027 if (!unit_type_may_alias(type
))
1028 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1029 "Alias= is not allowed for %s units, ignoring.",
1030 unit_type_to_string(type
));
1032 return config_parse_strv(unit
, filename
, line
, section
, section_line
,
1033 lvalue
, ltype
, rvalue
, data
, userdata
);
1036 static int config_parse_also(
1038 const char *filename
,
1040 const char *section
,
1041 unsigned section_line
,
1048 UnitFileInstallInfo
*info
= userdata
, *alsoinfo
= NULL
;
1049 InstallContext
*c
= data
;
1057 _cleanup_free_
char *word
= NULL
;
1059 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
1065 r
= install_info_add(c
, word
, NULL
, true, &alsoinfo
);
1069 r
= strv_push(&info
->also
, word
);
1079 static int config_parse_default_instance(
1081 const char *filename
,
1083 const char *section
,
1084 unsigned section_line
,
1091 UnitFileInstallInfo
*i
= data
;
1100 name
= basename(filename
);
1101 if (unit_name_is_valid(name
, UNIT_NAME_INSTANCE
))
1102 /* When enabling an instance, we might be using a template unit file,
1103 * but we should ignore DefaultInstance silently. */
1105 if (!unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
))
1106 return log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1107 "DefaultInstance= only makes sense for template units, ignoring.");
1109 r
= install_full_printf(i
, rvalue
, &printed
);
1113 if (!unit_instance_is_valid(printed
)) {
1118 free(i
->default_instance
);
1119 i
->default_instance
= printed
;
1124 static int unit_file_load(
1126 UnitFileInstallInfo
*info
,
1128 SearchFlags flags
) {
1130 const ConfigTableItem items
[] = {
1131 { "Install", "Alias", config_parse_alias
, 0, &info
->aliases
},
1132 { "Install", "WantedBy", config_parse_strv
, 0, &info
->wanted_by
},
1133 { "Install", "RequiredBy", config_parse_strv
, 0, &info
->required_by
},
1134 { "Install", "DefaultInstance", config_parse_default_instance
, 0, info
},
1135 { "Install", "Also", config_parse_also
, 0, c
},
1141 _cleanup_fclose_
FILE *f
= NULL
;
1142 _cleanup_close_
int fd
= -1;
1149 name
= basename(path
);
1150 type
= unit_name_to_type(name
);
1151 if (unit_name_is_valid(name
, UNIT_NAME_TEMPLATE
|UNIT_NAME_INSTANCE
) &&
1152 !unit_type_may_template(type
))
1153 return log_error_errno(EINVAL
, "Unit type %s cannot be templated.", unit_type_to_string(type
));
1155 if (!(flags
& SEARCH_LOAD
)) {
1156 r
= lstat(path
, &st
);
1160 if (null_or_empty(&st
))
1161 info
->type
= UNIT_FILE_TYPE_MASKED
;
1162 else if (S_ISREG(st
.st_mode
))
1163 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1164 else if (S_ISLNK(st
.st_mode
))
1166 else if (S_ISDIR(st
.st_mode
))
1174 /* c is only needed if we actually load the file */
1177 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NOFOLLOW
);
1180 if (fstat(fd
, &st
) < 0)
1182 if (null_or_empty(&st
)) {
1183 info
->type
= UNIT_FILE_TYPE_MASKED
;
1186 if (S_ISDIR(st
.st_mode
))
1188 if (!S_ISREG(st
.st_mode
))
1191 f
= fdopen(fd
, "re");
1196 r
= config_parse(NULL
, path
, f
,
1198 config_item_table_lookup
, items
,
1199 true, true, false, info
);
1203 info
->type
= UNIT_FILE_TYPE_REGULAR
;
1206 (int) strv_length(info
->aliases
) +
1207 (int) strv_length(info
->wanted_by
) +
1208 (int) strv_length(info
->required_by
);
1211 static int unit_file_load_or_readlink(
1213 UnitFileInstallInfo
*info
,
1215 const char *root_dir
,
1216 SearchFlags flags
) {
1218 _cleanup_free_
char *target
= NULL
;
1221 r
= unit_file_load(c
, info
, path
, flags
);
1225 /* This is a symlink, let's read it. */
1227 r
= readlink_malloc(path
, &target
);
1231 if (path_equal(target
, "/dev/null"))
1232 info
->type
= UNIT_FILE_TYPE_MASKED
;
1237 bn
= basename(target
);
1239 if (unit_name_is_valid(info
->name
, UNIT_NAME_PLAIN
)) {
1241 if (!unit_name_is_valid(bn
, UNIT_NAME_PLAIN
))
1244 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1246 if (!unit_name_is_valid(bn
, UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
))
1249 } else if (unit_name_is_valid(info
->name
, UNIT_NAME_TEMPLATE
)) {
1251 if (!unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
))
1256 /* Enforce that the symlink destination does not
1257 * change the unit file type. */
1259 a
= unit_name_to_type(info
->name
);
1260 b
= unit_name_to_type(bn
);
1261 if (a
< 0 || b
< 0 || a
!= b
)
1264 if (path_is_absolute(target
))
1265 /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
1266 info
->symlink_target
= prefix_root(root_dir
, target
);
1268 /* This is a relative path, take it relative to the dir the symlink is located in. */
1269 info
->symlink_target
= file_in_same_dir(path
, target
);
1270 if (!info
->symlink_target
)
1273 info
->type
= UNIT_FILE_TYPE_SYMLINK
;
1279 static int unit_file_search(
1281 UnitFileInstallInfo
*info
,
1282 const LookupPaths
*paths
,
1283 SearchFlags flags
) {
1285 _cleanup_free_
char *template = NULL
;
1292 /* Was this unit already loaded? */
1293 if (info
->type
!= _UNIT_FILE_TYPE_INVALID
)
1297 return unit_file_load_or_readlink(c
, info
, info
->path
, paths
->root_dir
, flags
);
1301 STRV_FOREACH(p
, paths
->search_path
) {
1302 _cleanup_free_
char *path
= NULL
;
1304 path
= strjoin(*p
, "/", info
->name
, NULL
);
1308 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1313 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1317 if (unit_name_is_valid(info
->name
, UNIT_NAME_INSTANCE
)) {
1318 /* Unit file doesn't exist, however instance
1319 * enablement was requested. We will check if it is
1320 * possible to load template unit file. */
1322 r
= unit_name_template(info
->name
, &template);
1326 STRV_FOREACH(p
, paths
->search_path
) {
1327 _cleanup_free_
char *path
= NULL
;
1329 path
= strjoin(*p
, "/", template, NULL
);
1333 r
= unit_file_load_or_readlink(c
, info
, path
, paths
->root_dir
, flags
);
1338 } else if (!IN_SET(r
, -ENOENT
, -ENOTDIR
, -EACCES
))
1343 log_debug("Cannot find unit %s%s%s.", info
->name
, template ? " or " : "", strempty(template));
1347 static int install_info_follow(
1349 UnitFileInstallInfo
*i
,
1350 const char *root_dir
,
1351 SearchFlags flags
) {
1356 if (i
->type
!= UNIT_FILE_TYPE_SYMLINK
)
1358 if (!i
->symlink_target
)
1361 /* If the basename doesn't match, the caller should add a
1362 * complete new entry for this. */
1364 if (!streq(basename(i
->symlink_target
), i
->name
))
1368 i
->path
= i
->symlink_target
;
1369 i
->symlink_target
= NULL
;
1370 i
->type
= _UNIT_FILE_TYPE_INVALID
;
1372 return unit_file_load_or_readlink(c
, i
, i
->path
, root_dir
, flags
);
1376 * Search for the unit file. If the unit name is a symlink, follow the symlink to the
1377 * target, maybe more than once. Propagate the instance name if present.
1379 static int install_info_traverse(
1380 UnitFileScope scope
,
1382 const LookupPaths
*paths
,
1383 UnitFileInstallInfo
*start
,
1385 UnitFileInstallInfo
**ret
) {
1387 UnitFileInstallInfo
*i
;
1395 r
= unit_file_search(c
, start
, paths
, flags
);
1400 while (i
->type
== UNIT_FILE_TYPE_SYMLINK
) {
1401 /* Follow the symlink */
1403 if (++k
> UNIT_FILE_FOLLOW_SYMLINK_MAX
)
1406 if (!(flags
& SEARCH_FOLLOW_CONFIG_SYMLINKS
)) {
1407 r
= path_is_config(paths
, i
->path
);
1414 r
= install_info_follow(c
, i
, paths
->root_dir
, flags
);
1416 _cleanup_free_
char *buffer
= NULL
;
1419 /* Target has a different name, create a new
1420 * install info object for that, and continue
1423 bn
= basename(i
->symlink_target
);
1425 if (unit_name_is_valid(i
->name
, UNIT_NAME_INSTANCE
) &&
1426 unit_name_is_valid(bn
, UNIT_NAME_TEMPLATE
)) {
1428 _cleanup_free_
char *instance
= NULL
;
1430 r
= unit_name_to_instance(i
->name
, &instance
);
1434 r
= unit_name_replace_instance(bn
, instance
, &buffer
);
1441 r
= install_info_add(c
, bn
, NULL
, false, &i
);
1445 /* Try again, with the new target we found. */
1446 r
= unit_file_search(c
, i
, paths
, flags
);
1448 /* Translate error code to highlight this specific case */
1463 * Call install_info_add() with name_or_path as the path (if name_or_path starts with "/")
1464 * or the name (otherwise). root_dir is prepended to the path.
1466 static int install_info_add_auto(
1468 const LookupPaths
*paths
,
1469 const char *name_or_path
,
1470 UnitFileInstallInfo
**ret
) {
1473 assert(name_or_path
);
1475 if (path_is_absolute(name_or_path
)) {
1478 pp
= prefix_roota(paths
->root_dir
, name_or_path
);
1480 return install_info_add(c
, NULL
, pp
, false, ret
);
1482 return install_info_add(c
, name_or_path
, NULL
, false, ret
);
1485 static int install_info_discover(
1486 UnitFileScope scope
,
1488 const LookupPaths
*paths
,
1491 UnitFileInstallInfo
**ret
) {
1493 UnitFileInstallInfo
*i
;
1500 r
= install_info_add_auto(c
, paths
, name
, &i
);
1504 return install_info_traverse(scope
, c
, paths
, i
, flags
, ret
);
1507 static int install_info_symlink_alias(
1508 UnitFileInstallInfo
*i
,
1509 const LookupPaths
*paths
,
1510 const char *config_path
,
1512 UnitFileChange
**changes
,
1513 unsigned *n_changes
) {
1520 assert(config_path
);
1522 STRV_FOREACH(s
, i
->aliases
) {
1523 _cleanup_free_
char *alias_path
= NULL
, *dst
= NULL
;
1525 q
= install_full_printf(i
, *s
, &dst
);
1529 alias_path
= path_make_absolute(dst
, config_path
);
1533 q
= create_symlink(paths
, i
->path
, alias_path
, force
, changes
, n_changes
);
1541 static int install_info_symlink_wants(
1542 UnitFileInstallInfo
*i
,
1543 const LookupPaths
*paths
,
1544 const char *config_path
,
1547 UnitFileChange
**changes
,
1548 unsigned *n_changes
) {
1550 _cleanup_free_
char *buf
= NULL
;
1557 assert(config_path
);
1559 if (strv_isempty(list
))
1562 if (unit_name_is_valid(i
->name
, UNIT_NAME_TEMPLATE
)) {
1563 UnitFileInstallInfo instance
= {
1564 .type
= _UNIT_FILE_TYPE_INVALID
,
1566 _cleanup_free_
char *path
= NULL
;
1568 /* Don't install any symlink if there's no default
1569 * instance configured */
1571 if (!i
->default_instance
)
1574 r
= unit_name_replace_instance(i
->name
, i
->default_instance
, &buf
);
1578 instance
.name
= buf
;
1579 r
= unit_file_search(NULL
, &instance
, paths
, SEARCH_FOLLOW_CONFIG_SYMLINKS
);
1583 path
= instance
.path
;
1584 instance
.path
= NULL
;
1586 if (instance
.type
== UNIT_FILE_TYPE_MASKED
) {
1587 unit_file_changes_add(changes
, n_changes
, -ERFKILL
, path
, NULL
);
1595 STRV_FOREACH(s
, list
) {
1596 _cleanup_free_
char *path
= NULL
, *dst
= NULL
;
1598 q
= install_full_printf(i
, *s
, &dst
);
1602 if (!unit_name_is_valid(dst
, UNIT_NAME_ANY
)) {
1607 path
= strjoin(config_path
, "/", dst
, suffix
, n
, NULL
);
1611 q
= create_symlink(paths
, i
->path
, path
, true, changes
, n_changes
);
1619 static int install_info_symlink_link(
1620 UnitFileInstallInfo
*i
,
1621 const LookupPaths
*paths
,
1622 const char *config_path
,
1624 UnitFileChange
**changes
,
1625 unsigned *n_changes
) {
1627 _cleanup_free_
char *path
= NULL
;
1632 assert(config_path
);
1635 r
= in_search_path(paths
, i
->path
);
1641 path
= strjoin(config_path
, "/", i
->name
, NULL
);
1645 return create_symlink(paths
, i
->path
, path
, force
, changes
, n_changes
);
1648 static int install_info_apply(
1649 UnitFileInstallInfo
*i
,
1650 const LookupPaths
*paths
,
1651 const char *config_path
,
1653 UnitFileChange
**changes
,
1654 unsigned *n_changes
) {
1660 assert(config_path
);
1662 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1665 r
= install_info_symlink_alias(i
, paths
, config_path
, force
, changes
, n_changes
);
1667 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->wanted_by
, ".wants/", changes
, n_changes
);
1671 q
= install_info_symlink_wants(i
, paths
, config_path
, i
->required_by
, ".requires/", changes
, n_changes
);
1675 q
= install_info_symlink_link(i
, paths
, config_path
, force
, changes
, n_changes
);
1676 /* Do not count links to the unit file towards the "carries_install_info" count */
1677 if (r
== 0 && q
< 0)
1683 static int install_context_apply(
1684 UnitFileScope scope
,
1686 const LookupPaths
*paths
,
1687 const char *config_path
,
1690 UnitFileChange
**changes
,
1691 unsigned *n_changes
) {
1693 UnitFileInstallInfo
*i
;
1698 assert(config_path
);
1700 if (ordered_hashmap_isempty(c
->will_process
))
1703 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1708 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1711 q
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1715 r
= install_info_traverse(scope
, c
, paths
, i
, flags
, NULL
);
1719 /* We can attempt to process a masked unit when a different unit
1720 * that we were processing specifies it in Also=. */
1721 if (i
->type
== UNIT_FILE_TYPE_MASKED
) {
1722 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_IS_MASKED
, i
->path
, NULL
);
1724 /* Assume that something *could* have been enabled here,
1725 * avoid "empty [Install] section" warning. */
1730 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
)
1733 q
= install_info_apply(i
, paths
, config_path
, force
, changes
, n_changes
);
1745 static int install_context_mark_for_removal(
1746 UnitFileScope scope
,
1748 const LookupPaths
*paths
,
1749 Set
**remove_symlinks_to
,
1750 const char *config_path
) {
1752 UnitFileInstallInfo
*i
;
1757 assert(config_path
);
1759 /* Marks all items for removal */
1761 if (ordered_hashmap_isempty(c
->will_process
))
1764 r
= ordered_hashmap_ensure_allocated(&c
->have_processed
, &string_hash_ops
);
1768 while ((i
= ordered_hashmap_first(c
->will_process
))) {
1770 r
= ordered_hashmap_move_one(c
->have_processed
, c
->will_process
, i
->name
);
1774 r
= install_info_traverse(scope
, c
, paths
, i
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, NULL
);
1775 if (r
== -ENOLINK
) {
1776 log_debug_errno(r
, "Name %s leads to a dangling symlink, ignoring.", i
->name
);
1778 } else if (r
== -ENOENT
&& i
->auxiliary
) {
1779 /* some unit specified in Also= or similar is missing */
1780 log_debug_errno(r
, "Auxiliary unit %s not found, ignoring.", i
->name
);
1783 return log_debug_errno(r
, "Failed to find unit %s: %m", i
->name
);
1785 if (i
->type
!= UNIT_FILE_TYPE_REGULAR
) {
1786 log_debug("Unit %s has type %s, ignoring.",
1788 unit_file_type_to_string(i
->type
) ?: "invalid");
1792 r
= mark_symlink_for_removal(remove_symlinks_to
, i
->name
);
1801 UnitFileScope scope
,
1803 const char *root_dir
,
1806 UnitFileChange
**changes
,
1807 unsigned *n_changes
) {
1809 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1810 const char *config_path
;
1815 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1817 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1821 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1823 STRV_FOREACH(i
, files
) {
1824 _cleanup_free_
char *path
= NULL
;
1827 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
)) {
1833 path
= path_make_absolute(*i
, config_path
);
1837 q
= create_symlink(&paths
, "/dev/null", path
, force
, changes
, n_changes
);
1838 if (q
< 0 && r
>= 0)
1845 int unit_file_unmask(
1846 UnitFileScope scope
,
1848 const char *root_dir
,
1850 UnitFileChange
**changes
,
1851 unsigned *n_changes
) {
1853 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1854 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
1855 _cleanup_free_
char **todo
= NULL
;
1856 size_t n_todo
= 0, n_allocated
= 0;
1857 const char *config_path
;
1862 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1864 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1868 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1870 STRV_FOREACH(i
, files
) {
1871 _cleanup_free_
char *path
= NULL
;
1873 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
1876 path
= path_make_absolute(*i
, config_path
);
1880 r
= null_or_empty_path(path
);
1888 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1891 todo
[n_todo
++] = *i
;
1897 STRV_FOREACH(i
, todo
) {
1898 _cleanup_free_
char *path
= NULL
;
1901 path
= path_make_absolute(*i
, config_path
);
1905 if (unlink(path
) < 0) {
1906 if (errno
!= ENOENT
) {
1909 unit_file_changes_add(changes
, n_changes
, -errno
, path
, NULL
);
1915 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, path
, NULL
);
1917 rp
= skip_root(&paths
, path
);
1918 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: path
);
1923 q
= remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, changes
, n_changes
);
1931 UnitFileScope scope
,
1933 const char *root_dir
,
1936 UnitFileChange
**changes
,
1937 unsigned *n_changes
) {
1939 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
1940 _cleanup_free_
char **todo
= NULL
;
1941 size_t n_todo
= 0, n_allocated
= 0;
1942 const char *config_path
;
1947 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
1949 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
1953 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
1955 STRV_FOREACH(i
, files
) {
1956 _cleanup_free_
char *full
= NULL
;
1960 if (!path_is_absolute(*i
))
1964 if (!unit_name_is_valid(fn
, UNIT_NAME_ANY
))
1967 full
= prefix_root(paths
.root_dir
, *i
);
1971 if (lstat(full
, &st
) < 0)
1973 if (S_ISLNK(st
.st_mode
))
1975 if (S_ISDIR(st
.st_mode
))
1977 if (!S_ISREG(st
.st_mode
))
1980 q
= in_search_path(&paths
, *i
);
1986 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
1989 todo
[n_todo
++] = *i
;
1995 STRV_FOREACH(i
, todo
) {
1996 _cleanup_free_
char *new_path
= NULL
;
1998 new_path
= path_make_absolute(basename(*i
), config_path
);
2002 q
= create_symlink(&paths
, *i
, new_path
, force
, changes
, n_changes
);
2003 if (q
< 0 && r
>= 0)
2010 static int path_shall_revert(const LookupPaths
*paths
, const char *path
) {
2016 /* Checks whether the path is one where the drop-in directories shall be removed. */
2018 r
= path_is_config(paths
, path
);
2022 r
= path_is_control(paths
, path
);
2026 return path_is_transient(paths
, path
);
2029 int unit_file_revert(
2030 UnitFileScope scope
,
2031 const char *root_dir
,
2033 UnitFileChange
**changes
,
2034 unsigned *n_changes
) {
2036 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2037 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2038 _cleanup_strv_free_
char **todo
= NULL
;
2039 size_t n_todo
= 0, n_allocated
= 0;
2043 /* Puts a unit file back into vendor state. This means:
2045 * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
2046 * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
2048 * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
2049 * "config", but not in "transient" or "control" or even "generated").
2051 * We remove all that in both the runtime and the persistent directories, if that applies.
2054 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2058 STRV_FOREACH(i
, files
) {
2059 bool has_vendor
= false;
2062 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2065 STRV_FOREACH(p
, paths
.search_path
) {
2066 _cleanup_free_
char *path
= NULL
, *dropin
= NULL
;
2069 path
= path_make_absolute(*i
, *p
);
2073 r
= lstat(path
, &st
);
2075 if (errno
!= ENOENT
)
2077 } else if (S_ISREG(st
.st_mode
)) {
2078 /* Check if there's a vendor version */
2079 r
= path_is_vendor(&paths
, path
);
2086 dropin
= strappend(path
, ".d");
2090 r
= lstat(dropin
, &st
);
2092 if (errno
!= ENOENT
)
2094 } else if (S_ISDIR(st
.st_mode
)) {
2095 /* Remove the drop-ins */
2096 r
= path_shall_revert(&paths
, dropin
);
2100 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2103 todo
[n_todo
++] = dropin
;
2112 /* OK, there's a vendor version, hence drop all configuration versions */
2113 STRV_FOREACH(p
, paths
.search_path
) {
2114 _cleanup_free_
char *path
= NULL
;
2117 path
= path_make_absolute(*i
, *p
);
2121 r
= lstat(path
, &st
);
2123 if (errno
!= ENOENT
)
2125 } else if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
2126 r
= path_is_config(&paths
, path
);
2130 if (!GREEDY_REALLOC0(todo
, n_allocated
, n_todo
+ 2))
2133 todo
[n_todo
++] = path
;
2143 STRV_FOREACH(i
, todo
) {
2144 _cleanup_strv_free_
char **fs
= NULL
;
2148 (void) get_files_in_directory(*i
, &fs
);
2150 q
= rm_rf(*i
, REMOVE_ROOT
|REMOVE_PHYSICAL
);
2151 if (q
< 0 && q
!= -ENOENT
&& r
>= 0) {
2156 STRV_FOREACH(j
, fs
) {
2157 _cleanup_free_
char *t
= NULL
;
2159 t
= strjoin(*i
, "/", *j
, NULL
);
2163 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, t
, NULL
);
2166 unit_file_changes_add(changes
, n_changes
, UNIT_FILE_UNLINK
, *i
, NULL
);
2168 rp
= skip_root(&paths
, *i
);
2169 q
= mark_symlink_for_removal(&remove_symlinks_to
, rp
?: *i
);
2174 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.runtime_config
, &paths
, changes
, n_changes
);
2178 q
= remove_marked_symlinks(remove_symlinks_to
, paths
.persistent_config
, &paths
, changes
, n_changes
);
2185 int unit_file_add_dependency(
2186 UnitFileScope scope
,
2188 const char *root_dir
,
2193 UnitFileChange
**changes
,
2194 unsigned *n_changes
) {
2196 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2197 _cleanup_(install_context_done
) InstallContext c
= {};
2198 UnitFileInstallInfo
*i
, *target_info
;
2199 const char *config_path
;
2204 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2207 if (!IN_SET(dep
, UNIT_WANTS
, UNIT_REQUIRES
))
2210 if (!unit_name_is_valid(target
, UNIT_NAME_ANY
))
2213 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2217 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2219 r
= install_info_discover(scope
, &c
, &paths
, target
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &target_info
);
2222 r
= install_info_may_process(target_info
, &paths
, changes
, n_changes
);
2226 assert(target_info
->type
== UNIT_FILE_TYPE_REGULAR
);
2228 STRV_FOREACH(f
, files
) {
2231 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2234 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2238 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2240 /* We didn't actually load anything from the unit
2241 * file, but instead just add in our new symlink to
2244 if (dep
== UNIT_WANTS
)
2247 l
= &i
->required_by
;
2250 *l
= strv_new(target_info
->name
, NULL
);
2255 return install_context_apply(scope
, &c
, &paths
, config_path
, force
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, changes
, n_changes
);
2258 int unit_file_enable(
2259 UnitFileScope scope
,
2261 const char *root_dir
,
2264 UnitFileChange
**changes
,
2265 unsigned *n_changes
) {
2267 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2268 _cleanup_(install_context_done
) InstallContext c
= {};
2269 const char *config_path
;
2270 UnitFileInstallInfo
*i
;
2275 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2277 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2281 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2283 STRV_FOREACH(f
, files
) {
2284 r
= install_info_discover(scope
, &c
, &paths
, *f
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2287 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2291 assert(i
->type
== UNIT_FILE_TYPE_REGULAR
);
2294 /* This will return the number of symlink rules that were
2295 supposed to be created, not the ones actually created. This
2296 is useful to determine whether the passed files had any
2297 installation data at all. */
2299 return install_context_apply(scope
, &c
, &paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2302 int unit_file_disable(
2303 UnitFileScope scope
,
2305 const char *root_dir
,
2307 UnitFileChange
**changes
,
2308 unsigned *n_changes
) {
2310 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2311 _cleanup_(install_context_done
) InstallContext c
= {};
2312 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2313 const char *config_path
;
2318 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2320 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2324 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2326 STRV_FOREACH(i
, files
) {
2327 if (!unit_name_is_valid(*i
, UNIT_NAME_ANY
))
2330 r
= install_info_add(&c
, *i
, NULL
, false, NULL
);
2335 r
= install_context_mark_for_removal(scope
, &c
, &paths
, &remove_symlinks_to
, config_path
);
2339 return remove_marked_symlinks(remove_symlinks_to
, config_path
, &paths
, changes
, n_changes
);
2342 int unit_file_reenable(
2343 UnitFileScope scope
,
2345 const char *root_dir
,
2348 UnitFileChange
**changes
,
2349 unsigned *n_changes
) {
2355 /* First, we invoke the disable command with only the basename... */
2356 l
= strv_length(files
);
2357 n
= newa(char*, l
+1);
2358 for (i
= 0; i
< l
; i
++)
2359 n
[i
] = basename(files
[i
]);
2362 r
= unit_file_disable(scope
, runtime
, root_dir
, n
, changes
, n_changes
);
2366 /* But the enable command with the full name */
2367 return unit_file_enable(scope
, runtime
, root_dir
, files
, force
, changes
, n_changes
);
2370 int unit_file_set_default(
2371 UnitFileScope scope
,
2372 const char *root_dir
,
2375 UnitFileChange
**changes
,
2376 unsigned *n_changes
) {
2378 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2379 _cleanup_(install_context_done
) InstallContext c
= {};
2380 UnitFileInstallInfo
*i
;
2381 const char *new_path
;
2385 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2388 if (unit_name_to_type(name
) != UNIT_TARGET
) /* this also validates the name */
2390 if (streq(name
, SPECIAL_DEFAULT_TARGET
))
2393 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2397 r
= install_info_discover(scope
, &c
, &paths
, name
, 0, &i
);
2400 r
= install_info_may_process(i
, &paths
, changes
, n_changes
);
2404 new_path
= strjoina(paths
.persistent_config
, "/" SPECIAL_DEFAULT_TARGET
);
2405 return create_symlink(&paths
, i
->path
, new_path
, force
, changes
, n_changes
);
2408 int unit_file_get_default(
2409 UnitFileScope scope
,
2410 const char *root_dir
,
2413 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2414 _cleanup_(install_context_done
) InstallContext c
= {};
2415 UnitFileInstallInfo
*i
;
2420 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2423 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2427 r
= install_info_discover(scope
, &c
, &paths
, SPECIAL_DEFAULT_TARGET
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2430 r
= install_info_may_process(i
, &paths
, NULL
, 0);
2434 n
= strdup(i
->name
);
2442 static int unit_file_lookup_state(
2443 UnitFileScope scope
,
2444 const LookupPaths
*paths
,
2446 UnitFileState
*ret
) {
2448 _cleanup_(install_context_done
) InstallContext c
= {};
2449 UnitFileInstallInfo
*i
;
2450 UnitFileState state
;
2456 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2459 r
= install_info_discover(scope
, &c
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2463 /* Shortcut things, if the caller just wants to know if this unit exists. */
2469 case UNIT_FILE_TYPE_MASKED
:
2470 r
= path_is_runtime(paths
, i
->path
);
2474 state
= r
> 0 ? UNIT_FILE_MASKED_RUNTIME
: UNIT_FILE_MASKED
;
2477 case UNIT_FILE_TYPE_REGULAR
:
2478 r
= path_is_generator(paths
, i
->path
);
2482 state
= UNIT_FILE_GENERATED
;
2486 r
= path_is_transient(paths
, i
->path
);
2490 state
= UNIT_FILE_TRANSIENT
;
2494 r
= find_symlinks_in_scope(scope
, paths
, i
->name
, &state
);
2498 if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i
))
2499 state
= UNIT_FILE_DISABLED
;
2500 else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i
))
2501 state
= UNIT_FILE_INDIRECT
;
2503 state
= UNIT_FILE_STATIC
;
2509 assert_not_reached("Unexpect unit file type.");
2516 int unit_file_get_state(
2517 UnitFileScope scope
,
2518 const char *root_dir
,
2520 UnitFileState
*ret
) {
2522 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2526 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2529 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2533 return unit_file_lookup_state(scope
, &paths
, name
, ret
);
2536 int unit_file_exists(UnitFileScope scope
, const LookupPaths
*paths
, const char *name
) {
2537 _cleanup_(install_context_done
) InstallContext c
= {};
2543 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2546 r
= install_info_discover(scope
, &c
, paths
, name
, 0, NULL
);
2555 static int read_presets(UnitFileScope scope
, const char *root_dir
, Presets
*presets
) {
2556 _cleanup_(presets_freep
) Presets ps
= {};
2557 size_t n_allocated
= 0;
2558 _cleanup_strv_free_
char **files
= NULL
;
2563 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2566 if (scope
== UNIT_FILE_SYSTEM
)
2567 r
= conf_files_list(&files
, ".preset", root_dir
,
2568 "/etc/systemd/system-preset",
2569 "/usr/local/lib/systemd/system-preset",
2570 "/usr/lib/systemd/system-preset",
2571 #ifdef HAVE_SPLIT_USR
2572 "/lib/systemd/system-preset",
2575 else if (scope
== UNIT_FILE_GLOBAL
)
2576 r
= conf_files_list(&files
, ".preset", root_dir
,
2577 "/etc/systemd/user-preset",
2578 "/usr/local/lib/systemd/user-preset",
2579 "/usr/lib/systemd/user-preset",
2582 *presets
= (Presets
){};
2590 STRV_FOREACH(p
, files
) {
2591 _cleanup_fclose_
FILE *f
;
2592 char line
[LINE_MAX
];
2595 f
= fopen(*p
, "re");
2597 if (errno
== ENOENT
)
2603 FOREACH_LINE(line
, f
, return -errno
) {
2604 PresetRule rule
= {};
2605 const char *parameter
;
2613 if (strchr(COMMENTS
, *l
))
2616 parameter
= first_word(l
, "enable");
2620 pattern
= strdup(parameter
);
2624 rule
= (PresetRule
) {
2626 .action
= PRESET_ENABLE
,
2630 parameter
= first_word(l
, "disable");
2634 pattern
= strdup(parameter
);
2638 rule
= (PresetRule
) {
2640 .action
= PRESET_DISABLE
,
2645 if (!GREEDY_REALLOC(ps
.rules
, n_allocated
, ps
.n_rules
+ 1))
2648 ps
.rules
[ps
.n_rules
++] = rule
;
2652 log_syntax(NULL
, LOG_WARNING
, *p
, n
, 0, "Couldn't parse line '%s'. Ignoring.", line
);
2662 static int query_presets(const char *name
, const Presets presets
) {
2663 PresetAction action
= PRESET_UNKNOWN
;
2666 if (!unit_name_is_valid(name
, UNIT_NAME_ANY
))
2669 for (i
= 0; i
< presets
.n_rules
; i
++)
2670 if (fnmatch(presets
.rules
[i
].pattern
, name
, FNM_NOESCAPE
) == 0) {
2671 action
= presets
.rules
[i
].action
;
2676 case PRESET_UNKNOWN
:
2677 log_debug("Preset files don't specify rule for %s. Enabling.", name
);
2680 log_debug("Preset files say enable %s.", name
);
2682 case PRESET_DISABLE
:
2683 log_debug("Preset files say disable %s.", name
);
2686 assert_not_reached("invalid preset action");
2690 int unit_file_query_preset(UnitFileScope scope
, const char *root_dir
, const char *name
) {
2691 _cleanup_(presets_freep
) Presets presets
= {};
2694 r
= read_presets(scope
, root_dir
, &presets
);
2698 return query_presets(name
, presets
);
2701 static int execute_preset(
2702 UnitFileScope scope
,
2703 InstallContext
*plus
,
2704 InstallContext
*minus
,
2705 const LookupPaths
*paths
,
2706 const char *config_path
,
2708 UnitFilePresetMode mode
,
2710 UnitFileChange
**changes
,
2711 unsigned *n_changes
) {
2718 assert(config_path
);
2720 if (mode
!= UNIT_FILE_PRESET_ENABLE_ONLY
) {
2721 _cleanup_set_free_free_ Set
*remove_symlinks_to
= NULL
;
2723 r
= install_context_mark_for_removal(scope
, minus
, paths
, &remove_symlinks_to
, config_path
);
2727 r
= remove_marked_symlinks(remove_symlinks_to
, config_path
, paths
, changes
, n_changes
);
2731 if (mode
!= UNIT_FILE_PRESET_DISABLE_ONLY
) {
2734 /* Returns number of symlinks that where supposed to be installed. */
2735 q
= install_context_apply(scope
, plus
, paths
, config_path
, force
, SEARCH_LOAD
, changes
, n_changes
);
2747 static int preset_prepare_one(
2748 UnitFileScope scope
,
2749 InstallContext
*plus
,
2750 InstallContext
*minus
,
2754 UnitFileChange
**changes
,
2755 unsigned *n_changes
) {
2757 _cleanup_(install_context_done
) InstallContext tmp
= {};
2758 UnitFileInstallInfo
*i
;
2761 if (install_info_find(plus
, name
) || install_info_find(minus
, name
))
2764 r
= install_info_discover(scope
, &tmp
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2767 if (!streq(name
, i
->name
)) {
2768 log_debug("Skipping %s because is an alias for %s", name
, i
->name
);
2772 r
= query_presets(name
, presets
);
2777 r
= install_info_discover(scope
, plus
, paths
, name
, SEARCH_LOAD
|SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2781 r
= install_info_may_process(i
, paths
, changes
, n_changes
);
2785 r
= install_info_discover(scope
, minus
, paths
, name
, SEARCH_FOLLOW_CONFIG_SYMLINKS
, &i
);
2790 int unit_file_preset(
2791 UnitFileScope scope
,
2793 const char *root_dir
,
2795 UnitFilePresetMode mode
,
2797 UnitFileChange
**changes
,
2798 unsigned *n_changes
) {
2800 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2801 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2802 _cleanup_(presets_freep
) Presets presets
= {};
2803 const char *config_path
;
2808 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2809 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2811 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2815 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2817 r
= read_presets(scope
, root_dir
, &presets
);
2821 STRV_FOREACH(i
, files
) {
2822 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, *i
, presets
, changes
, n_changes
);
2827 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, files
, mode
, force
, changes
, n_changes
);
2830 int unit_file_preset_all(
2831 UnitFileScope scope
,
2833 const char *root_dir
,
2834 UnitFilePresetMode mode
,
2836 UnitFileChange
**changes
,
2837 unsigned *n_changes
) {
2839 _cleanup_(install_context_done
) InstallContext plus
= {}, minus
= {};
2840 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2841 _cleanup_(presets_freep
) Presets presets
= {};
2842 const char *config_path
= NULL
;
2847 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2848 assert(mode
< _UNIT_FILE_PRESET_MAX
);
2850 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2854 config_path
= runtime
? paths
.runtime_config
: paths
.persistent_config
;
2856 r
= read_presets(scope
, root_dir
, &presets
);
2860 STRV_FOREACH(i
, paths
.search_path
) {
2861 _cleanup_closedir_
DIR *d
= NULL
;
2866 if (errno
== ENOENT
)
2872 FOREACH_DIRENT(de
, d
, return -errno
) {
2874 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2877 dirent_ensure_type(d
, de
);
2879 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2882 /* we don't pass changes[] in, because we want to handle errors on our own */
2883 r
= preset_prepare_one(scope
, &plus
, &minus
, &paths
, de
->d_name
, presets
, NULL
, 0);
2885 r
= unit_file_changes_add(changes
, n_changes
,
2886 UNIT_FILE_IS_MASKED
, de
->d_name
, NULL
);
2887 else if (r
== -ENOLINK
)
2888 r
= unit_file_changes_add(changes
, n_changes
,
2889 UNIT_FILE_IS_DANGLING
, de
->d_name
, NULL
);
2895 return execute_preset(scope
, &plus
, &minus
, &paths
, config_path
, NULL
, mode
, force
, changes
, n_changes
);
2898 static void unit_file_list_free_one(UnitFileList
*f
) {
2906 Hashmap
* unit_file_list_free(Hashmap
*h
) {
2909 while ((i
= hashmap_steal_first(h
)))
2910 unit_file_list_free_one(i
);
2912 return hashmap_free(h
);
2915 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList
*, unit_file_list_free_one
);
2917 int unit_file_get_list(
2918 UnitFileScope scope
,
2919 const char *root_dir
,
2924 _cleanup_lookup_paths_free_ LookupPaths paths
= {};
2929 assert(scope
< _UNIT_FILE_SCOPE_MAX
);
2932 r
= lookup_paths_init(&paths
, scope
, 0, root_dir
);
2936 STRV_FOREACH(i
, paths
.search_path
) {
2937 _cleanup_closedir_
DIR *d
= NULL
;
2942 if (errno
== ENOENT
)
2944 if (IN_SET(errno
, ENOTDIR
, EACCES
)) {
2945 log_debug("Failed to open \"%s\": %m", *i
);
2952 FOREACH_DIRENT(de
, d
, return -errno
) {
2953 _cleanup_(unit_file_list_free_onep
) UnitFileList
*f
= NULL
;
2955 if (!unit_name_is_valid(de
->d_name
, UNIT_NAME_ANY
))
2958 if (!strv_fnmatch_or_empty(patterns
, de
->d_name
, FNM_NOESCAPE
))
2961 if (hashmap_get(h
, de
->d_name
))
2964 dirent_ensure_type(d
, de
);
2966 if (!IN_SET(de
->d_type
, DT_LNK
, DT_REG
))
2969 f
= new0(UnitFileList
, 1);
2973 f
->path
= path_make_absolute(de
->d_name
, *i
);
2977 r
= unit_file_lookup_state(scope
, &paths
, de
->d_name
, &f
->state
);
2979 f
->state
= UNIT_FILE_BAD
;
2981 if (!strv_isempty(states
) &&
2982 !strv_contains(states
, unit_file_state_to_string(f
->state
)))
2985 r
= hashmap_put(h
, basename(f
->path
), f
);
2989 f
= NULL
; /* prevent cleanup */
2996 static const char* const unit_file_state_table
[_UNIT_FILE_STATE_MAX
] = {
2997 [UNIT_FILE_ENABLED
] = "enabled",
2998 [UNIT_FILE_ENABLED_RUNTIME
] = "enabled-runtime",
2999 [UNIT_FILE_LINKED
] = "linked",
3000 [UNIT_FILE_LINKED_RUNTIME
] = "linked-runtime",
3001 [UNIT_FILE_MASKED
] = "masked",
3002 [UNIT_FILE_MASKED_RUNTIME
] = "masked-runtime",
3003 [UNIT_FILE_STATIC
] = "static",
3004 [UNIT_FILE_DISABLED
] = "disabled",
3005 [UNIT_FILE_INDIRECT
] = "indirect",
3006 [UNIT_FILE_GENERATED
] = "generated",
3007 [UNIT_FILE_TRANSIENT
] = "transient",
3008 [UNIT_FILE_BAD
] = "bad",
3011 DEFINE_STRING_TABLE_LOOKUP(unit_file_state
, UnitFileState
);
3013 static const char* const unit_file_change_type_table
[_UNIT_FILE_CHANGE_TYPE_MAX
] = {
3014 [UNIT_FILE_SYMLINK
] = "symlink",
3015 [UNIT_FILE_UNLINK
] = "unlink",
3016 [UNIT_FILE_IS_MASKED
] = "masked",
3017 [UNIT_FILE_IS_DANGLING
] = "dangling",
3020 DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type
, UnitFileChangeType
);
3022 static const char* const unit_file_preset_mode_table
[_UNIT_FILE_PRESET_MAX
] = {
3023 [UNIT_FILE_PRESET_FULL
] = "full",
3024 [UNIT_FILE_PRESET_ENABLE_ONLY
] = "enable-only",
3025 [UNIT_FILE_PRESET_DISABLE_ONLY
] = "disable-only",
3028 DEFINE_STRING_TABLE_LOOKUP(unit_file_preset_mode
, UnitFilePresetMode
);