mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
Fix shell stream ownership and CPU frequency units
This commit is contained in:
1 parent
633c129a4f
commit
3ed48bd2ac
7 files changed
+425
-28
No files matched your search
+167
-4
@@ -7597,19 +7597,22 @@ index 6fa2d088c..655554284 100644
|
||||
int sandbox_issue_fs_extension(const char *path, uint64_t flags, char **ext_token);
|
||||
int sandbox_issue_fs_rw_extension(const char *path, char **ext_token);
|
||||
diff --git a/src/shellspawn/shellspawn.c b/src/shellspawn/shellspawn.c
|
||||
index f5ba615bb..fea23d638 100644
|
||||
index f5ba615..53d04ad 100644
|
||||
--- a/src/shellspawn/shellspawn.c
|
||||
+++ b/src/shellspawn/shellspawn.c
|
||||
@@ -36,7 +36,7 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -34,9 +34,10 @@ along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include "shellspawn.h"
|
||||
+#include "shellspawn-fds.h"
|
||||
#include "duct_signals.h"
|
||||
|
||||
-#define DBG 0
|
||||
+#define DBG 1
|
||||
+#define DBG (getenv("DARLING_SHELLSPAWN_DEBUG") && strcmp(getenv("DARLING_SHELLSPAWN_DEBUG"), "1") == 0)
|
||||
|
||||
int g_serverSocket = -1;
|
||||
struct sigaction sigchld_oldaction;
|
||||
@@ -50,6 +50,17 @@ void reapAll(void);
|
||||
@@ -50,6 +51,17 @@ void reapAll(void);
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
@@ -7627,6 +7630,123 @@ index f5ba615bb..fea23d638 100644
|
||||
// shellspawn (daemon) --fork()--> shellspawn (child) --fork()--> exec /bin/bash
|
||||
// in order to read the exit status of the shell process,
|
||||
// we have to allow it to become a zombie, therefore we need to
|
||||
@@ -125,7 +137,7 @@ void spawnShell(int fd)
|
||||
{
|
||||
pid_t shell_pid = -1;
|
||||
int shellfd[3] = { -1, -1, -1 };
|
||||
- int pipefd[2];
|
||||
+ int pipefd[2] = { -1, -1 };
|
||||
int rv;
|
||||
struct pollfd pfd[2];
|
||||
char** argv = NULL;
|
||||
@@ -143,6 +155,14 @@ void spawnShell(int fd)
|
||||
|
||||
char* alloc_exec = NULL;
|
||||
|
||||
+ // Keep the control socket out of the stdio slots before receiving streams.
|
||||
+ if (fd <= STDERR_FILENO) {
|
||||
+ int moved = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
+ if (moved < 0) goto err;
|
||||
+ close(fd);
|
||||
+ fd = moved;
|
||||
+ }
|
||||
+
|
||||
// Read commands from client
|
||||
while (read_cmds)
|
||||
{
|
||||
@@ -262,25 +282,20 @@ void spawnShell(int fd)
|
||||
argv = (char**) realloc(argv, sizeof(char*) * (argc + 1));
|
||||
argv[argc] = NULL;
|
||||
|
||||
- if (pipe(pipefd) == -1)
|
||||
- goto err;
|
||||
+ if (shellspawn_remap_stdio(shellfd) < 0) goto err;
|
||||
+ if (pipe(pipefd) == -1) goto err;
|
||||
|
||||
setsid();
|
||||
setpgrp();
|
||||
|
||||
- close(STDIN_FILENO);
|
||||
- close(STDOUT_FILENO);
|
||||
- close(STDERR_FILENO);
|
||||
-
|
||||
- dup2(shellfd[0], STDIN_FILENO);
|
||||
- dup2(shellfd[1], STDOUT_FILENO);
|
||||
- dup2(shellfd[2], STDERR_FILENO);
|
||||
-
|
||||
ioctl(STDIN_FILENO, TIOCSCTTY, STDIN_FILENO);
|
||||
|
||||
shell_pid = fork();
|
||||
+ if (shell_pid < 0) goto err;
|
||||
if (shell_pid == 0)
|
||||
{
|
||||
+ shellspawn_close_streams(shellfd);
|
||||
+ close(pipefd[0]);
|
||||
close(fd);
|
||||
|
||||
fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
|
||||
@@ -296,6 +311,7 @@ void spawnShell(int fd)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ shellspawn_close_streams(shellfd);
|
||||
if (alloc_exec)
|
||||
{
|
||||
free(alloc_exec);
|
||||
@@ -304,12 +320,14 @@ void spawnShell(int fd)
|
||||
|
||||
// Check that exec succeeded
|
||||
close(pipefd[1]); // close the write end
|
||||
+ pipefd[1] = -1;
|
||||
if (read(pipefd[0], &rv, sizeof(rv)) == sizeof(rv))
|
||||
{
|
||||
errno = rv;
|
||||
goto err;
|
||||
}
|
||||
close(pipefd[0]);
|
||||
+ pipefd[0] = -1;
|
||||
|
||||
// Now we start passing signals
|
||||
// and check for child process exit
|
||||
@@ -372,7 +390,7 @@ void spawnShell(int fd)
|
||||
|
||||
if (darwin_signal != 0)
|
||||
{
|
||||
- int fg_pid = tcgetpgrp(shellfd[0]);
|
||||
+ int fg_pid = tcgetpgrp(STDIN_FILENO);
|
||||
if (fg_pid != -1)
|
||||
{
|
||||
if (DBG) printf("fg_pid = %d\n", fg_pid);
|
||||
@@ -394,11 +412,7 @@ void spawnShell(int fd)
|
||||
kill(shell_pid, SIGKILL);
|
||||
|
||||
// Close shell fds
|
||||
- for (int i = 0; i < 3; i++)
|
||||
- {
|
||||
- if (shellfd[i] != -1)
|
||||
- close(shellfd[0]);
|
||||
- }
|
||||
+ shellspawn_close_streams(shellfd);
|
||||
|
||||
// Reap the child
|
||||
int wstatus;
|
||||
@@ -415,13 +429,11 @@ void spawnShell(int fd)
|
||||
reapAll();
|
||||
return;
|
||||
err:
|
||||
+ if (pipefd[0] >= 0) close(pipefd[0]);
|
||||
+ if (pipefd[1] >= 0) close(pipefd[1]);
|
||||
if (DBG) fprintf(stderr, "Error spawning shell: %s\n", strerror(errno));
|
||||
|
||||
- for (int i = 0; i < 3; i++)
|
||||
- {
|
||||
- if (shellfd[i] != -1)
|
||||
- close(shellfd[0]);
|
||||
- }
|
||||
+ shellspawn_close_streams(shellfd);
|
||||
|
||||
if (shell_pid != -1)
|
||||
kill(shell_pid, SIGKILL);
|
||||
diff --git a/src/startup/mldr/commpage.c b/src/startup/mldr/commpage.c
|
||||
index d9a7aea96..cc76f7a85 100644
|
||||
--- a/src/startup/mldr/commpage.c
|
||||
@@ -10537,3 +10657,46 @@ index 8077b7e..0556080 100644
|
||||
endif(NOT DEBIAN_PACKAGING)
|
||||
|
||||
add_custom_target(uninstall
|
||||
diff --git a/src/shellspawn/shellspawn-fds.h b/src/shellspawn/shellspawn-fds.h
|
||||
new file mode 100644
|
||||
index 0000000..1f3c473
|
||||
--- /dev/null
|
||||
+++ b/src/shellspawn/shellspawn-fds.h
|
||||
@@ -0,0 +1,37 @@
|
||||
+#ifndef SHELLSPAWN_FDS_H
|
||||
+#define SHELLSPAWN_FDS_H
|
||||
+#include <errno.h>
|
||||
+#include <fcntl.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+// Preserve every source before replacing any standard descriptor: sources can
|
||||
+// themselves be 0, 1 or 2 when the daemon was launched with closed stdio.
|
||||
+static int shellspawn_remap_stdio(const int streams[3])
|
||||
+{
|
||||
+ int saved[3] = { -1, -1, -1 };
|
||||
+ for (int i = 0; i < 3; ++i) {
|
||||
+ saved[i] = fcntl(streams[i], F_DUPFD_CLOEXEC, 3);
|
||||
+ if (saved[i] < 0) goto failure;
|
||||
+ }
|
||||
+ for (int i = 0; i < 3; ++i)
|
||||
+ if (dup2(saved[i], i) < 0) goto failure;
|
||||
+ for (int i = 0; i < 3; ++i) close(saved[i]);
|
||||
+ return 0;
|
||||
+failure: {
|
||||
+ int error = errno;
|
||||
+ for (int i = 0; i < 3; ++i) if (saved[i] >= 0) close(saved[i]);
|
||||
+ errno = error;
|
||||
+ return -1;
|
||||
+}}
|
||||
+
|
||||
+static void shellspawn_close_streams(int streams[3])
|
||||
+{
|
||||
+ for (int i = 0; i < 3; ++i) {
|
||||
+ int fd = streams[i];
|
||||
+ streams[i] = -1;
|
||||
+ for (int j = i + 1; j < 3; ++j)
|
||||
+ if (streams[j] == fd) streams[j] = -1;
|
||||
+ if (fd > STDERR_FILENO) close(fd);
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
+100
-18
@@ -1851,18 +1851,19 @@ index 7d5ef80..46debb8 100644
|
||||
[521] = sys_abort_with_payload,
|
||||
[524] = sys_setattrlistat,
|
||||
diff --git a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c
|
||||
index f273989..1093a3a 100644
|
||||
index f273989..058b985 100644
|
||||
--- a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c
|
||||
+++ b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/helper/misc/sysctl_hw.c
|
||||
@@ -9,6 +9,7 @@
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <darling/emulation/xnu_syscall/bsd/helper/misc/sysctl_proc.h>
|
||||
#include <darling/emulation/linux_premigration/ext/sys/utsname.h>
|
||||
#include <darling/emulation/common/simple.h>
|
||||
+#include <darling/emulation/common/cpu_topology.h>
|
||||
+#include <darling/emulation/common/cpu_frequency.h>
|
||||
#include <darling/emulation/common/string.h>
|
||||
|
||||
extern kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name);
|
||||
@@ -16,6 +17,7 @@ extern kern_return_t host_info(mach_port_name_t host, int itype, void* hinfo, ma
|
||||
@@ -16,6 +18,7 @@ extern kern_return_t host_info(mach_port_name_t host, int itype, void* hinfo, ma
|
||||
|
||||
/* Darling specific */
|
||||
enum {
|
||||
@@ -1870,10 +1871,13 @@ index f273989..1093a3a 100644
|
||||
_HW_PHYSICAL_CPU = 1000,
|
||||
_HW_PHYSICAL_CPU_MAX,
|
||||
_HW_LOGICAL_CPU,
|
||||
@@ -25,9 +27,12 @@ enum {
|
||||
@@ -24,10 +27,14 @@ enum {
|
||||
_HW_CPUSUBTYPE,
|
||||
_HW_CPUTHREADTYPE,
|
||||
_HW_64BITCAPABLE,
|
||||
_HW_CPUFREQUENCY = 15,
|
||||
- _HW_CPUFREQUENCY = 15,
|
||||
+ _HW_CPUFREQUENCY_COMPAT = 15,
|
||||
+ _HW_CPUFREQUENCY = 1500,
|
||||
+ _HW_CACHECONFIG = 1200,
|
||||
+ _HW_CACHESIZE,
|
||||
};
|
||||
@@ -1883,12 +1887,13 @@ index f273989..1093a3a 100644
|
||||
static sysctl_handler(handle_physicalcpu);
|
||||
static sysctl_handler(handle_physicalcpu_max);
|
||||
static sysctl_handler(handle_logicalcpu);
|
||||
@@ -39,11 +44,77 @@ static sysctl_handler(handle_cpusubtype);
|
||||
@@ -39,11 +46,78 @@ static sysctl_handler(handle_cpusubtype);
|
||||
static sysctl_handler(handle_cputhreadtype);
|
||||
static sysctl_handler(handle_cpu64bitcapable);
|
||||
static sysctl_handler(handle_machine);
|
||||
+static sysctl_handler(handle_model);
|
||||
static sysctl_handler(handle_cpufrequency);
|
||||
+static sysctl_handler(handle_cpufrequency_compat);
|
||||
+static sysctl_handler(handle_cacheconfig);
|
||||
+static sysctl_handler(handle_cachesize);
|
||||
+
|
||||
@@ -1962,19 +1967,21 @@ index f273989..1093a3a 100644
|
||||
{ .oid = _HW_PHYSICAL_CPU, .type = CTLTYPE_INT, .exttype = "", .name = "physicalcpu", .handler = handle_physicalcpu },
|
||||
{ .oid = _HW_PHYSICAL_CPU_MAX, .type = CTLTYPE_INT, .exttype = "", .name = "physicalcpu_max", .handler = handle_physicalcpu_max },
|
||||
{ .oid = _HW_LOGICAL_CPU, .type = CTLTYPE_INT, .exttype = "", .name = "logicalcpu", .handler = handle_logicalcpu },
|
||||
@@ -55,7 +126,11 @@ const struct known_sysctl sysctls_hw[] = {
|
||||
@@ -55,7 +129,12 @@ const struct known_sysctl sysctls_hw[] = {
|
||||
{ .oid = _HW_CPUTHREADTYPE, .type = CTLTYPE_INT, .exttype = "", .name = "cputhreadtype", .handler = handle_cputhreadtype },
|
||||
{ .oid = _HW_64BITCAPABLE, .type = CTLTYPE_INT, .exttype = "", .name = "cpu64bit_capable", .handler = handle_cpu64bitcapable },
|
||||
{ .oid = HW_MACHINE, .type = CTLTYPE_STRING, .exttype = "S", .name = "machine", .handler = handle_machine },
|
||||
- { .oid = _HW_CPUFREQUENCY, .type = CTLTYPE_INT, .exttype = "", .name = "cpufrequency", .handler = handle_cpufrequency },
|
||||
+ { .oid = _HW_OPTIONAL, .type = CTLTYPE_NODE, .exttype = "", .name = "optional", .subctls = sysctls_hw_optional },
|
||||
+ { .oid = HW_MODEL, .type = CTLTYPE_STRING, .exttype = "S", .name = "model", .handler = handle_model },
|
||||
{ .oid = _HW_CPUFREQUENCY, .type = CTLTYPE_INT, .exttype = "", .name = "cpufrequency", .handler = handle_cpufrequency },
|
||||
+ { .oid = _HW_CPUFREQUENCY, .type = CTLTYPE_QUAD, .exttype = "Q", .name = "cpufrequency", .handler = handle_cpufrequency },
|
||||
+ { .oid = _HW_CPUFREQUENCY_COMPAT, .type = CTLTYPE_INT, .exttype = "I", .name = "cpufrequency_compat", .handler = handle_cpufrequency_compat },
|
||||
+ { .oid = _HW_CACHECONFIG, .type = CTLTYPE_OPAQUE, .exttype = "Q", .name = "cacheconfig", .handler = handle_cacheconfig },
|
||||
+ { .oid = _HW_CACHESIZE, .type = CTLTYPE_OPAQUE, .exttype = "Q", .name = "cachesize", .handler = handle_cachesize },
|
||||
{ .oid = -1 }
|
||||
};
|
||||
|
||||
@@ -71,6 +146,32 @@ static const struct host_basic_info* gethostinfo(void)
|
||||
@@ -71,6 +150,32 @@ static const struct host_basic_info* gethostinfo(void)
|
||||
hself = mach_host_self();
|
||||
host_info(hself, HOST_BASIC_INFO, &hinfo, &hcount);
|
||||
mach_port_deallocate(mach_task_self(), hself);
|
||||
@@ -2007,7 +2014,7 @@ index f273989..1093a3a 100644
|
||||
}
|
||||
|
||||
return &hinfo;
|
||||
@@ -83,6 +184,13 @@ sysctl_handler(handle_availcpu)
|
||||
@@ -83,6 +188,13 @@ sysctl_handler(handle_availcpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2021,16 +2028,64 @@ index f273989..1093a3a 100644
|
||||
sysctl_handler(handle_physicalcpu)
|
||||
{
|
||||
sysctl_handle_size(sizeof(int));
|
||||
@@ -174,6 +282,8 @@ sysctl_handler(handle_cpufrequency)
|
||||
int freq = 2400000;
|
||||
char buf[16];
|
||||
@@ -169,16 +281,49 @@ sysctl_handler(handle_cputhreadtype)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ sysctl_handle_size(sizeof(int));
|
||||
+static long cpu_frequency(uint64_t* frequency)
|
||||
+{
|
||||
+ char buffer[32];
|
||||
+ const char* paths[] = {
|
||||
+ "/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
|
||||
+ "/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
|
||||
+ "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
|
||||
+ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
|
||||
+ };
|
||||
+ for (unsigned i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i)
|
||||
+ if (read_string(paths[i], buffer, sizeof(buffer)) && darling_frequency_hz(buffer, frequency)) return 0;
|
||||
+#if defined(__i386__) || defined(__x86_64__)
|
||||
+ unsigned int a, b, c, d;
|
||||
+ __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(0), "2"(0));
|
||||
+ if (a >= 0x16) {
|
||||
+ __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(0x16), "2"(0));
|
||||
+ if (a & 0xffff) {
|
||||
+ *frequency = (uint64_t)(a & 0xffff) * 1000000;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+ return -ENOENT;
|
||||
+}
|
||||
+
|
||||
if (read_string("/sys/bus/cpu/devices/cpu0/cpufreq/cpuinfo_max_freq", buf, sizeof(buf)))
|
||||
freq = __simple_atoi(buf, NULL);
|
||||
*((int*) old) = freq;
|
||||
@@ -193,3 +303,104 @@ sysctl_handler(handle_machine)
|
||||
sysctl_handler(handle_cpufrequency)
|
||||
{
|
||||
- int freq = 2400000;
|
||||
- char buf[16];
|
||||
+ uint64_t frequency;
|
||||
+ sysctl_handle_size(sizeof(frequency));
|
||||
+ long result = cpu_frequency(&frequency);
|
||||
+ if (!result) *((uint64_t*)old) = frequency;
|
||||
+ return result;
|
||||
+}
|
||||
|
||||
- if (read_string("/sys/bus/cpu/devices/cpu0/cpufreq/cpuinfo_max_freq", buf, sizeof(buf)))
|
||||
- freq = __simple_atoi(buf, NULL);
|
||||
- *((int*) old) = freq;
|
||||
-
|
||||
- return 0;
|
||||
+sysctl_handler(handle_cpufrequency_compat)
|
||||
+{
|
||||
+ // Numeric HW_CPU_FREQ retains XNU's legacy 32-bit ABI. Modern by-name
|
||||
+ // queries use the separate 64-bit OID above, as in kern_mib.c.
|
||||
+ uint64_t frequency;
|
||||
+ sysctl_handle_size(sizeof(uint32_t));
|
||||
+ long result = cpu_frequency(&frequency);
|
||||
+ if (!result) *((uint32_t*)old) = (uint32_t)frequency;
|
||||
+ return result;
|
||||
}
|
||||
|
||||
sysctl_handler(handle_cpu64bitcapable)
|
||||
@@ -193,3 +338,104 @@ sysctl_handler(handle_machine)
|
||||
copyout_string(need_uname()->machine, (char*) old, oldlen);
|
||||
return 0;
|
||||
}
|
||||
@@ -6083,3 +6138,30 @@ index 0000000..f185f6c
|
||||
+__sysctlbyname:
|
||||
+ /* Just jump to the syscall stub */
|
||||
+ jmp ___sysctlbyname
|
||||
diff --git a/darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h b/darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h
|
||||
new file mode 100644
|
||||
index 0000000..eb90f43
|
||||
--- /dev/null
|
||||
+++ b/darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+#ifndef DARLING_CPU_FREQUENCY_H
|
||||
+#define DARLING_CPU_FREQUENCY_H
|
||||
+#include <stdint.h>
|
||||
+#include <stdbool.h>
|
||||
+
|
||||
+// Linux cpufreq exposes kHz; Darwin's hw.cpufrequency is an unsigned 64-bit Hz value.
|
||||
+static inline bool darling_frequency_hz(const char* text, uint64_t* result)
|
||||
+{
|
||||
+ uint64_t value = 0;
|
||||
+ if (!text || !result || *text < '0' || *text > '9') return false;
|
||||
+ do {
|
||||
+ unsigned digit = (unsigned)(*text++ - '0');
|
||||
+ if (value > (UINT64_MAX - digit) / 10) return false;
|
||||
+ value = value * 10 + digit;
|
||||
+ } while (*text >= '0' && *text <= '9');
|
||||
+ while (*text == ' ' || *text == '\t' || *text == '\r' || *text == '\n') ++text;
|
||||
+ if (*text || !value || value > UINT64_MAX / 1000) return false;
|
||||
+ *result = value * 1000;
|
||||
+ return true;
|
||||
+}
|
||||
+#endif
|
||||
@@ -29,14 +29,19 @@ class CompatibilityChecks(unittest.TestCase):
|
||||
repo = ROOT / 'build/darling-src' / component['path']
|
||||
if not (repo / '.git').exists():
|
||||
self.skipTest('prepared Darling sources required')
|
||||
original = subprocess.check_output(['git', '-C', str(repo), 'show', component['revision'] + ':' + path])
|
||||
original = (None if path in component['new_files'] else
|
||||
subprocess.check_output(['git', '-C', str(repo), 'show', component['revision'] + ':' + path]))
|
||||
marker = 'diff --git a/' + path + ' b/' + path + '\n'
|
||||
patch = (ROOT / component['patch']).read_text().split(marker, 1)[1].split('\ndiff --git ', 1)[0]
|
||||
patch_text = (ROOT / component['patch']).read_text()
|
||||
if marker not in patch_text:
|
||||
return original.decode()
|
||||
patch = patch_text.split(marker, 1)[1].split('\ndiff --git ', 1)[0]
|
||||
with tempfile.TemporaryDirectory() as folder:
|
||||
target = Path(folder) / path
|
||||
target.parent.mkdir(parents=True)
|
||||
target.write_bytes(original)
|
||||
subprocess.run(['patch', '--silent', '-p1', '-d', folder], input=marker + patch,
|
||||
if original is not None:
|
||||
target.write_bytes(original)
|
||||
subprocess.run(['patch', '--silent', '-p1', '-d', folder], input=marker + patch + ("" if patch.endswith("\n") else "\n"),
|
||||
text=True, check=True, capture_output=True)
|
||||
return target.read_text()
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
"""Exercise the real patched descriptor helper and frequency conversion on the host."""
|
||||
import unittest
|
||||
import test_runtime_compatibility as sources
|
||||
|
||||
|
||||
class ShellCPUChecks(unittest.TestCase):
|
||||
patched = sources.CompatibilityChecks.patched
|
||||
run_c = sources.CompatibilityChecks.run_c
|
||||
|
||||
def test_frequency_units_width_and_invalid_inputs(self):
|
||||
root = 'darling/src/libsystem_kernel/emulation/'
|
||||
header = self.patched('xnu', root + 'include/common/cpu_frequency.h')
|
||||
original = self.patched('xnu', root + 'include/xnu_syscall/bsd/impl/misc/sysctl.h')
|
||||
size_macro = original[original.index('#define sysctl_handle_size'):original.index('typedef long')]
|
||||
source = self.patched('xnu', root + 'src/xnu_syscall/bsd/helper/misc/sysctl_hw.c')
|
||||
start = source.index('static long cpu_frequency(')
|
||||
handler = source[start:source.index('\nsysctl_handler(handle_cpu64bitcapable)', start)]
|
||||
self.run_c(header + '''
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
static unsigned reads;
|
||||
static bool read_string(const char* path, char* dst, int size) {
|
||||
++reads; strcpy(dst, "5600000\\n"); return true;
|
||||
}
|
||||
#define sysctl_handler(name) long name(void* old, unsigned long* oldlen)
|
||||
''' + size_macro + handler + '''
|
||||
int main(void) {
|
||||
uint64_t hz = 17;
|
||||
assert(darling_frequency_hz("2400000\\n", &hz) && hz == 2400000000ULL);
|
||||
assert(darling_frequency_hz("5600000", &hz) && hz == 5600000000ULL);
|
||||
const char *bad[] = {"", "0", "-1", " 123", "12MHz", "18446744073709551616", "18446744073709552"};
|
||||
for (unsigned i=0; i<sizeof(bad)/sizeof(bad[0]); ++i) {
|
||||
hz = 17; assert(!darling_frequency_hz(bad[i], &hz) && hz == 17);
|
||||
}
|
||||
unsigned long length = 0;
|
||||
assert(handle_cpufrequency(NULL, &length) == 0 && length == 8 && reads == 0);
|
||||
length = 4; hz = 17;
|
||||
assert(handle_cpufrequency(&hz, &length) == -EINVAL && hz == 17 && reads == 0);
|
||||
length = sizeof(hz);
|
||||
assert(handle_cpufrequency(&hz, &length) == 0 && hz == 5600000000ULL && length == 8);
|
||||
uint32_t legacy = 0; length = sizeof(legacy);
|
||||
assert(handle_cpufrequency_compat(&legacy, &length) == 0 && length == 4 && legacy == (uint32_t)5600000000ULL);
|
||||
}
|
||||
''')
|
||||
|
||||
def test_stdio_aliases_cleanup_and_failure_do_not_close_other_descriptors(self):
|
||||
header = self.patched('darling', 'src/shellspawn/shellspawn-fds.h')
|
||||
self.run_c('#define _GNU_SOURCE\n' + header + '''
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
static unsigned open_count(void) {
|
||||
unsigned n = 0; for (int fd=3; fd<256; ++fd) if (fcntl(fd, F_GETFD) >= 0) ++n; return n;
|
||||
}
|
||||
int main(void) {
|
||||
pid_t child = fork(); assert(child >= 0);
|
||||
if (!child) {
|
||||
int p[3][2], sentinel[2];
|
||||
for (int i=0; i<3; ++i) assert(pipe(p[i]) == 0);
|
||||
assert(pipe(sentinel) == 0);
|
||||
for (int i=0; i<3; ++i) assert(dup2(p[i][0], i) == i);
|
||||
struct stat expected[3], actual;
|
||||
int alias[3] = {2,0,1};
|
||||
for (int i=0; i<3; ++i) assert(fstat(alias[i], &expected[i]) == 0);
|
||||
assert(shellspawn_remap_stdio(alias) == 0);
|
||||
for (int i=0; i<3; ++i) {
|
||||
assert(fstat(i, &actual) == 0 && actual.st_ino == expected[i].st_ino);
|
||||
assert(!(fcntl(i, F_GETFD) & FD_CLOEXEC));
|
||||
}
|
||||
int streams[3] = {p[0][0],p[1][0],p[2][0]};
|
||||
shellspawn_close_streams(streams);
|
||||
for (int i=0; i<3; ++i) assert(fcntl(p[i][0], F_GETFD) == -1 && streams[i] == -1);
|
||||
assert(fcntl(sentinel[0], F_GETFD) >= 0);
|
||||
streams[0] = streams[1] = streams[2] = p[0][1];
|
||||
shellspawn_close_streams(streams); shellspawn_close_streams(streams);
|
||||
unsigned before = open_count();
|
||||
int invalid[3] = {sentinel[0],-1,sentinel[1]};
|
||||
for (int i=0; i<1000; ++i) assert(shellspawn_remap_stdio(invalid) == -1 && errno == EBADF);
|
||||
assert(open_count() == before && fcntl(sentinel[0], F_GETFD) >= 0);
|
||||
_exit(0);
|
||||
}
|
||||
int status; assert(waitpid(child, &status, 0) == child && WIFEXITED(status) && WEXITSTATUS(status) == 0);
|
||||
}
|
||||
''')
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the frequency units and legacy ABI check against the prepared SDK."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
sdk = json.loads((root / 'build/config.json').read_text())['sdk']
|
||||
flags = {}
|
||||
resource = subprocess.check_output(['clang', '-print-resource-dir'], text=True).strip()
|
||||
for line in (root / 'build/darling-src/build/src/frameworks/CoreVideo/CMakeFiles/CoreVideo.dir/flags.make').read_text().splitlines():
|
||||
if line.startswith('C_') and ' = ' in line:
|
||||
key, value = line.split(' = ', 1)
|
||||
flags[key] = [re.sub(r'/usr/lib/clang/\d+/include', resource + '/include', v) for v in shlex.split(value)]
|
||||
obj = root / 'build/riot-cpu-frequency-check.o'
|
||||
subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FLAGS'],
|
||||
'-O2', '-c', str(root / 'tools/riot-cpu-frequency-check.c'), '-o', str(obj)], check=True)
|
||||
subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld', '-nostdlib',
|
||||
'-isysroot', sdk, str(obj), '-lSystem', '-o', str(root / 'build/riot-cpu-frequency-check')], check=True)
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
int main(void) {
|
||||
size_t length = 0;
|
||||
if (sysctlbyname("hw.cpufrequency", NULL, &length, NULL, 0) || length != sizeof(uint64_t)) return 1;
|
||||
const char *paths[] = {
|
||||
"/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
|
||||
"/Volumes/SystemRoot/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
|
||||
"/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq",
|
||||
"/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
|
||||
};
|
||||
uint64_t expected = 0;
|
||||
for (unsigned i=0; i<4; ++i) {
|
||||
FILE* source = fopen(paths[i], "r");
|
||||
unsigned long long khz = 0;
|
||||
if (!source) continue;
|
||||
int found = fscanf(source, "%llu", &khz); fclose(source);
|
||||
if (found == 1 && khz > 0 && khz <= UINT64_MAX/1000) { expected = khz * 1000; break; }
|
||||
}
|
||||
uint64_t hz = 0;
|
||||
length = sizeof(hz);
|
||||
if (sysctlbyname("hw.cpufrequency", &hz, &length, NULL, 0)) {
|
||||
if (errno != ENOENT || expected) return 2;
|
||||
puts("CPU_FREQUENCY unavailable=1 invented_frequency=0 pass=1");
|
||||
return 0;
|
||||
}
|
||||
if (length != 8 || hz < 1000000) return 3;
|
||||
if (expected && hz != expected) return 4;
|
||||
struct { uint32_t before, value, after; } legacy = {0x12345678,0,0x87654321};
|
||||
int mib[] = {CTL_HW, HW_CPU_FREQ}; length = sizeof(legacy.value);
|
||||
if (sysctl(mib, 2, &legacy.value, &length, NULL, 0) || length != 4 || legacy.value != (uint32_t)hz ||
|
||||
legacy.before != 0x12345678 || legacy.after != 0x87654321) return 5;
|
||||
printf("CPU_FREQUENCY hz=%llu width64=1 legacy_width32=1 pass=1\n", (unsigned long long)hz);
|
||||
return 0;
|
||||
}
|
||||
@@ -24,7 +24,8 @@
|
||||
"src/frameworks/OpenDirectory/src/ODLocalDirectory.m",
|
||||
"src/frameworks/OpenGL/CGLAsyncPresent.inc",
|
||||
"src/frameworks/OpenGL/include/OpenGL/DarlingNativePresent.h",
|
||||
"src/startup/mldr/commpage-cpu-caps.h"
|
||||
"src/startup/mldr/commpage-cpu-caps.h",
|
||||
"src/shellspawn/shellspawn-fds.h"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -282,7 +283,8 @@
|
||||
"darling/src/libsystem_kernel/emulation/include/xnu_syscall/bsd/impl/misc/mac_syscall.h",
|
||||
"darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/guarded/change_fdguard_np.c",
|
||||
"darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/mac_syscall.c",
|
||||
"libsyscall/wrappers/__sysctlbyname.S"
|
||||
"libsyscall/wrappers/__sysctlbyname.S",
|
||||
"darling/src/libsystem_kernel/emulation/include/common/cpu_frequency.h"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user