1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "initrd-util.h"
8 #include "path-lookup.h"
10 #include "random-util.h"
16 #include "time-util.h"
17 #include "unit-file.h"
19 TEST(unit_validate_alias_symlink_and_warn
) {
20 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a.service", "/other/b.service") == 0);
21 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a.service", "/other/b.socket") == -EXDEV
);
22 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a.service", "/other/b.foobar") == -EXDEV
);
23 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@.service", "/other/b@.service") == 0);
24 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@.service", "/other/b@.socket") == -EXDEV
);
25 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@XXX.service", "/other/b@YYY.service") == -EXDEV
);
26 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@XXX.service", "/other/b@YYY.socket") == -EXDEV
);
27 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@.service", "/other/b@YYY.service") == -EXDEV
);
28 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@XXX.service", "/other/b@XXX.service") == 0);
29 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@XXX.service", "/other/b@.service") == 0);
30 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@.service", "/other/b.service") == -EXDEV
);
31 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a.service", "/other/b@.service") == -EXDEV
);
32 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a@.slice", "/other/b.slice") == -EINVAL
);
33 assert_se(unit_validate_alias_symlink_or_warn(LOG_INFO
, "/path/a.slice", "/other/b.slice") == -EINVAL
);
36 TEST(unit_file_build_name_map
) {
37 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
38 _cleanup_hashmap_free_ Hashmap
*unit_ids
= NULL
;
39 _cleanup_hashmap_free_ Hashmap
*unit_names
= NULL
;
45 ids
= strv_skip(saved_argv
, 1);
47 assert_se(lookup_paths_init(&lp
, RUNTIME_SCOPE_SYSTEM
, 0, NULL
) >= 0);
49 assert_se(unit_file_build_name_map(&lp
, &mtime
, &unit_ids
, &unit_names
, NULL
) == 1);
51 HASHMAP_FOREACH_KEY(dst
, k
, unit_ids
)
52 log_info("ids: %s → %s", k
, dst
);
54 HASHMAP_FOREACH_KEY(v
, k
, unit_names
) {
55 _cleanup_free_
char *j
= strv_join(v
, ", ");
56 log_info("aliases: %s ← %s", k
, j
);
59 char buf
[FORMAT_TIMESTAMP_MAX
];
60 log_debug("Last modification time: %s", format_timestamp(buf
, sizeof buf
, mtime
));
62 r
= unit_file_build_name_map(&lp
, &mtime
, &unit_ids
, &unit_names
, NULL
);
63 assert_se(IN_SET(r
, 0, 1));
65 log_debug("Cache rebuild skipped based on mtime.");
67 STRV_FOREACH(id
, ids
) {
68 const char *fragment
, *name
;
69 _cleanup_set_free_ Set
*names
= NULL
;
70 log_info("*** %s ***", *id
);
71 r
= unit_file_find_fragment(unit_ids
,
77 log_info("fragment: %s", fragment
);
79 SET_FOREACH(name
, names
)
80 log_info(" %s", name
);
83 /* Make sure everything still works if we don't collect names. */
84 STRV_FOREACH(id
, ids
) {
86 log_info("*** %s ***", *id
);
87 r
= unit_file_find_fragment(unit_ids
,
93 log_info("fragment: %s", fragment
);
97 static bool test_unit_file_remove_from_name_map_trail(const LookupPaths
*lp
, size_t trial
) {
100 log_debug("/* %s(trial=%zu) */", __func__
, trial
);
102 _cleanup_hashmap_free_ Hashmap
*unit_ids
= NULL
, *unit_names
= NULL
;
103 _cleanup_set_free_ Set
*path_cache
= NULL
;
104 ASSERT_OK_POSITIVE(unit_file_build_name_map(lp
, NULL
, &unit_ids
, &unit_names
, &path_cache
));
106 _cleanup_free_
char *name
= NULL
;
107 for (size_t i
= 0; i
< 100; i
++) {
108 ASSERT_OK(asprintf(&name
, "test-unit-file-%"PRIx64
".service", random_u64()));
109 if (!hashmap_contains(unit_ids
, name
))
113 ASSERT_NOT_NULL(name
);
115 _cleanup_free_
char *path
= path_join(lp
->transient
, name
);
116 ASSERT_NOT_NULL(path
);
117 ASSERT_OK(write_string_file(path
, "[Unit]\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
));
119 uint64_t cache_timestamp_hash
= 0;
120 ASSERT_OK_POSITIVE(unit_file_build_name_map(lp
, &cache_timestamp_hash
, &unit_ids
, &unit_names
, &path_cache
));
122 ASSERT_STREQ(hashmap_get(unit_ids
, name
), path
);
123 ASSERT_TRUE(strv_equal(hashmap_get(unit_names
, name
), STRV_MAKE(name
)));
124 ASSERT_TRUE(set_contains(path_cache
, path
));
126 ASSERT_OK_ERRNO(unlink(path
));
128 ASSERT_OK(r
= unit_file_remove_from_name_map(lp
, &cache_timestamp_hash
, &unit_ids
, &unit_names
, &path_cache
, path
));
130 return false; /* someone touches unit files. Retrying. */
132 ASSERT_FALSE(hashmap_contains(unit_ids
, name
));
133 ASSERT_FALSE(hashmap_contains(unit_names
, path
));
134 ASSERT_FALSE(set_contains(path_cache
, path
));
136 _cleanup_hashmap_free_ Hashmap
*unit_ids_2
= NULL
, *unit_names_2
= NULL
;
137 _cleanup_set_free_ Set
*path_cache_2
= NULL
;
138 ASSERT_OK_POSITIVE(unit_file_build_name_map(lp
, NULL
, &unit_ids_2
, &unit_names_2
, &path_cache_2
));
140 if (hashmap_size(unit_ids
) != hashmap_size(unit_ids_2
) ||
141 hashmap_size(unit_names
) != hashmap_size(unit_names_2
) ||
142 !set_equal(path_cache
, path_cache_2
))
146 HASHMAP_FOREACH_KEY(v
, k
, unit_ids
)
147 if (!streq_ptr(hashmap_get(unit_ids_2
, k
), v
))
151 HASHMAP_FOREACH_KEY(l
, k
, unit_names
)
152 if (!strv_equal_ignore_order(hashmap_get(unit_names_2
, k
), l
))
159 TEST(unit_file_remove_from_name_map
) {
160 _cleanup_(rm_rf_physical_and_freep
) char *d
= NULL
;
162 _cleanup_(lookup_paths_done
) LookupPaths lp
= {};
163 ASSERT_OK(lookup_paths_init(&lp
, RUNTIME_SCOPE_SYSTEM
, LOOKUP_PATHS_TEMPORARY_GENERATED
, NULL
));
164 ASSERT_NOT_NULL((d
= strdup(lp
.temporary_dir
)));
166 for (size_t i
= 0; i
< 10; i
++)
167 if (test_unit_file_remove_from_name_map_trail(&lp
, i
))
170 assert_not_reached();
173 TEST(runlevel_to_target
) {
174 in_initrd_force(false);
175 ASSERT_STREQ(runlevel_to_target(NULL
), NULL
);
176 ASSERT_STREQ(runlevel_to_target("unknown-runlevel"), NULL
);
177 ASSERT_STREQ(runlevel_to_target("rd.unknown-runlevel"), NULL
);
178 ASSERT_STREQ(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET
);
179 ASSERT_STREQ(runlevel_to_target("rd.rescue"), NULL
);
181 in_initrd_force(true);
182 ASSERT_STREQ(runlevel_to_target(NULL
), NULL
);
183 ASSERT_STREQ(runlevel_to_target("unknown-runlevel"), NULL
);
184 ASSERT_STREQ(runlevel_to_target("rd.unknown-runlevel"), NULL
);
185 ASSERT_STREQ(runlevel_to_target("3"), NULL
);
186 ASSERT_STREQ(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET
);
189 static int intro(void) {
190 log_show_color(true);
194 DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG
, intro
);