xref: /xnu-11417.121.6/tests/posix_spawn_alt_rosetta.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1 #include <darwintest.h>
2 #include <mach-o/dyld.h>
3 #include <spawn.h>
4 #include <spawn_private.h>
5 #include <unistd.h>
6 #include <sys/wait.h>
7 #include <fcntl.h>
8 #include <stdlib.h>
9 
10 #include <TargetConditionals.h>
11 
12 T_DECL(posix_spawn_alt_rosetta,
13     "verify posix_spawn_set_alt_rosetta_np switches to alternative rosetta runtime",
14     T_META_ASROOT(true),
15     T_META_REQUIRES_SYSCTL_EQ("kern.development", 1),
16     T_META_ENABLED(false /* rdar://133955592 */))
17 {
18 #if TARGET_OS_OSX && defined(__arm64__)
19 	int ret, pid;
20 	posix_spawnattr_t spawnattr;
21 	char path[1024];
22 	uint32_t size = sizeof(path);
23 	cpu_type_t cpuprefs[] = { CPU_TYPE_X86_64 };
24 	cpu_type_t subcpuprefs[] = { CPU_SUBTYPE_ANY };
25 	int wait_ret = 0;
26 
27 	if (access("/Library/Apple/usr/libexec/oah/libRosettaRuntime", O_RDONLY) != 0) {
28 		T_SKIP("Rosetta not installed");
29 		return;
30 	}
31 
32 	if (access("/usr/local/libexec/rosetta/runtime_internal", O_RDONLY) != 0) {
33 		system("mkdir -p /usr/local/libexec/oah");
34 		system("cp /Library/Apple/usr/libexec/rosetta/runtime /usr/local/libexec/rosetta/runtime_internal");
35 	}
36 
37 	T_QUIET; T_ASSERT_EQ(_NSGetExecutablePath(path, &size), 0, NULL);
38 	T_QUIET; T_ASSERT_LT(strlcat(path, "_helper", size), (unsigned long)size, NULL);
39 
40 	ret = posix_spawnattr_init(&spawnattr);
41 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_init");
42 
43 	// 1) Run natively
44 
45 	ret = posix_spawn(&pid, path, NULL, &spawnattr, NULL, NULL);
46 	T_ASSERT_EQ(ret, 0, "posix_spawn should succeed");
47 	ret = waitpid(pid, &wait_ret, 0);
48 	T_QUIET; T_ASSERT_EQ(ret, pid, "child pid");
49 	T_QUIET; T_ASSERT_EQ(WIFEXITED(wait_ret), 1, "child process should have called exit()");
50 	T_ASSERT_EQ(WEXITSTATUS(wait_ret), 0, "running natively should return 0");
51 
52 	// 2) Set archpref to run under Rosetta
53 
54 	ret = posix_spawnattr_setarchpref_np(&spawnattr, sizeof(cpuprefs) / sizeof(cpuprefs[0]), cpuprefs, subcpuprefs, NULL);
55 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_setarchpref_np");
56 
57 	ret = posix_spawn(&pid, path, NULL, &spawnattr, NULL, NULL);
58 	T_ASSERT_EQ(ret, 0, "posix_spawn should succeed");
59 	ret = waitpid(pid, &wait_ret, 0);
60 	T_QUIET; T_ASSERT_EQ(ret, pid, "child pid");
61 	T_QUIET; T_ASSERT_EQ(WIFEXITED(wait_ret), 1, "child process should have called exit()");
62 	T_ASSERT_EQ(WEXITSTATUS(wait_ret), 1, "running in rosetta should return 1");
63 
64 	// 3) Request alternative Rosetta runtime
65 
66 	ret = posix_spawnattr_set_alt_rosetta_np(&spawnattr, 0);
67 	T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "posix_spawnattr_setarchpref_np");
68 
69 	ret = posix_spawn(&pid, path, NULL, &spawnattr, NULL, NULL);
70 	T_ASSERT_EQ(ret, 0, "posix_spawn should succeed");
71 	ret = waitpid(pid, &wait_ret, 0);
72 	T_QUIET; T_ASSERT_EQ(ret, pid, "child pid");
73 	T_QUIET; T_ASSERT_EQ(WIFEXITED(wait_ret), 1, "child process should have called exit()");
74 	T_ASSERT_EQ(WEXITSTATUS(wait_ret), 2, "running with alternative rosetta runtime should return 2");
75 
76 	ret = posix_spawnattr_destroy(&spawnattr);
77 	T_QUIET; T_ASSERT_EQ(ret, 0, "posix_spawnattr_destroy");
78 #else
79 	T_SKIP("Not arm64 macOS");
80 #endif
81 }
82