1 /* SPDX-License-Identifier: LGPL-2.1+ */
11 /* When we include libgen.h because we need dirname() we immediately
12 * undefine basename() since libgen.h defines it as a macro to the POSIX
13 * version which is really broken. We prefer GNU basename(). */
19 #include "alloc-util.h"
20 #include "bus-error.h"
21 #include "bus-locator.h"
23 #include "bus-wait-for-jobs.h"
24 #include "cgroup-setup.h"
25 #include "cgroup-util.h"
30 #include "namespace-util.h"
31 #include "path-util.h"
32 #include "process-util.h"
33 #include "random-util.h"
37 char* setup_fake_runtime_dir(void) {
38 char t
[] = "/tmp/fake-xdg-runtime-XXXXXX", *p
;
40 assert_se(mkdtemp(t
));
41 assert_se(setenv("XDG_RUNTIME_DIR", t
, 1) >= 0);
42 assert_se(p
= strdup(t
));
47 static void load_testdata_env(void) {
48 static bool called
= false;
49 _cleanup_free_
char *s
= NULL
;
50 _cleanup_free_
char *envpath
= NULL
;
51 _cleanup_strv_free_
char **pairs
= NULL
;
58 assert_se(readlink_and_make_absolute("/proc/self/exe", &s
) >= 0);
61 envpath
= path_join(s
, "systemd-runtest.env");
62 if (load_env_file_pairs(NULL
, envpath
, &pairs
) < 0)
65 STRV_FOREACH_PAIR(k
, v
, pairs
)
69 int get_testdata_dir(const char *suffix
, char **ret
) {
75 /* if the env var is set, use that */
76 dir
= getenv("SYSTEMD_TEST_DATA");
78 dir
= SYSTEMD_TEST_DATA
;
79 if (access(dir
, F_OK
) < 0)
80 return log_error_errno(errno
, "ERROR: $SYSTEMD_TEST_DATA directory [%s] not accessible: %m", dir
);
82 p
= path_join(dir
, suffix
);
90 const char* get_catalog_dir(void) {
95 /* if the env var is set, use that */
96 env
= getenv("SYSTEMD_CATALOG_DIR");
98 env
= SYSTEMD_CATALOG_DIR
;
99 if (access(env
, F_OK
) < 0) {
100 fprintf(stderr
, "ERROR: $SYSTEMD_CATALOG_DIR directory [%s] does not exist\n", env
);
106 bool slow_tests_enabled(void) {
109 r
= getenv_bool("SYSTEMD_SLOW_TESTS");
114 log_warning_errno(r
, "Cannot parse $SYSTEMD_SLOW_TESTS, ignoring.");
115 return SYSTEMD_SLOW_TESTS_DEFAULT
;
118 void test_setup_logging(int level
) {
119 log_set_max_level(level
);
120 log_parse_environment();
124 int log_tests_skipped(const char *message
) {
125 log_notice("%s: %s, skipping tests.",
126 program_invocation_short_name
, message
);
127 return EXIT_TEST_SKIP
;
130 int log_tests_skipped_errno(int r
, const char *message
) {
131 log_notice_errno(r
, "%s: %s, skipping tests: %m",
132 program_invocation_short_name
, message
);
133 return EXIT_TEST_SKIP
;
136 bool have_namespaces(void) {
140 /* Checks whether namespaces are available. In some cases they aren't. We do this by calling unshare(), and we
141 * do so in a child process in order not to affect our own process. */
148 if (detach_mount_namespace() < 0)
154 assert_se(waitid(P_PID
, pid
, &si
, WEXITED
) >= 0);
155 assert_se(si
.si_code
== CLD_EXITED
);
157 if (si
.si_status
== EXIT_SUCCESS
)
160 if (si
.si_status
== EXIT_FAILURE
)
163 assert_not_reached("unexpected exit code");
166 bool can_memlock(void) {
167 /* Let's see if we can mlock() a larger blob of memory. BPF programs are charged against
168 * RLIMIT_MEMLOCK, hence let's first make sure we can lock memory at all, and skip the test if we
169 * cannot. Why not check RLIMIT_MEMLOCK explicitly? Because in container environments the
170 * RLIMIT_MEMLOCK value we see might not match the RLIMIT_MEMLOCK value actually in effect. */
172 void *p
= mmap(NULL
, CAN_MEMLOCK_SIZE
, PROT_READ
|PROT_WRITE
, MAP_ANONYMOUS
|MAP_SHARED
, -1, 0);
176 bool b
= mlock(p
, CAN_MEMLOCK_SIZE
) >= 0;
178 assert_se(munlock(p
, CAN_MEMLOCK_SIZE
) >= 0);
180 assert_se(munmap(p
, CAN_MEMLOCK_SIZE
) >= 0);
184 static int allocate_scope(void) {
185 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
186 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
187 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
188 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
189 _cleanup_free_
char *scope
= NULL
;
193 /* Let's try to run this test in a scope of its own, with delegation turned on, so that PID 1 doesn't
194 * interfere with our cgroup management. */
196 r
= sd_bus_default_system(&bus
);
198 return log_error_errno(r
, "Failed to connect to system bus: %m");
200 r
= bus_wait_for_jobs_new(bus
, &w
);
204 if (asprintf(&scope
, "%s-%" PRIx64
".scope", program_invocation_short_name
, random_u64()) < 0)
207 r
= bus_message_new_method_call(bus
, &m
, bus_systemd_mgr
, "StartTransientUnit");
209 return bus_log_create_error(r
);
212 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
214 return bus_log_create_error(r
);
217 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
219 return bus_log_create_error(r
);
221 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid_cached());
223 return bus_log_create_error(r
);
225 r
= sd_bus_message_append(m
, "(sv)", "Delegate", "b", 1);
227 return bus_log_create_error(r
);
229 r
= sd_bus_message_append(m
, "(sv)", "CollectMode", "s", "inactive-or-failed");
231 return bus_log_create_error(r
);
233 r
= sd_bus_message_close_container(m
);
235 return bus_log_create_error(r
);
237 /* Auxiliary units */
238 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
240 return bus_log_create_error(r
);
242 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
244 return log_error_errno(r
, "Failed to start transient scope unit: %s", bus_error_message(&error
, r
));
246 r
= sd_bus_message_read(reply
, "o", &object
);
248 return bus_log_parse_error(r
);
250 r
= bus_wait_for_jobs_one(w
, object
, false);
257 int enter_cgroup_subroot(char **ret_cgroup
) {
258 _cleanup_free_
char *cgroup_root
= NULL
, *cgroup_subroot
= NULL
;
259 CGroupMask supported
;
262 r
= allocate_scope();
264 log_warning_errno(r
, "Couldn't allocate a scope unit for this test, proceeding without.");
266 r
= cg_pid_get_path(NULL
, 0, &cgroup_root
);
268 return log_warning_errno(r
, "cg_pid_get_path(NULL, 0, ...) failed: %m");
271 assert_se(asprintf(&cgroup_subroot
, "%s/%" PRIx64
, cgroup_root
, random_u64()) >= 0);
272 assert_se(cg_mask_supported(&supported
) >= 0);
274 /* If this fails, then we don't mind as the later cgroup operations will fail too, and it's fine if
275 * we handle any errors at that point. */
277 r
= cg_create_everywhere(supported
, _CGROUP_MASK_ALL
, cgroup_subroot
);
281 r
= cg_attach_everywhere(supported
, cgroup_subroot
, 0, NULL
, NULL
);
286 *ret_cgroup
= TAKE_PTR(cgroup_subroot
);