Copy Over libsystem_kernel Files From "src/kernel"

Instead of copying over the "libsystem", we will use one that already exist in this repo (hence the symlink).
This commit is contained in:
Thomas A 2023-05-17 09:45:57 -07:00
parent 89fa103bd5
commit 4d0d5857b9
574 changed files with 26675 additions and 0 deletions

View File

@ -0,0 +1,80 @@
project(darling-libsystem_kernel)
cmake_minimum_required(VERSION 3.10)
if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
cmake_policy(SET CMP0018 NEW)
endif(COMMAND cmake_policy)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(emulation/linux)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3 -w -fblocks -ffreestanding")
# Why -bind_at_load is necessary:
# I couldn't find something like -Bsymbolic in Apple's ld
# -> internal functions are being resolved by dyld
# -> dyld places stubs -> stubs go into dyld_stub_binder at first use
# -> there is a temporary loss of 16-byte stack alignment in __darling_bsd_syscall
# -> dyld_stub_binder checks for this and bails out with a SIGSEGV
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__DARWIN_UNIX03 -fPIC -w -nostdinc -Wl,-bind_at_load")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib")
#set(DYLIB_INSTALL_NAME "/usr/lib/system/libsystem_c.dylib")
#add_darling_library(fakelibc SHARED fakelibc.c)
#make_fat(fakelibc)
#set(DYLIB_INSTALL_NAME "/usr/lib/system/libdyld.dylib")
#add_darling_library(fakedyld SHARED fakedyld.c)
#make_fat(fakedyld)
add_definitions(-DHAVE_STDINT_H=1)
add_definitions(-DPRIVATE=1)
add_subdirectory(libsyscall)
set(DYLIB_INSTALL_NAME "/usr/lib/system/libsystem_kernel.dylib")
add_circular(system_kernel FAT
OBJECTS
$<IF:$<BOOL:${BUILD_TARGET_32BIT}>,$<TARGET_OBJECTS:libsyscall_32>,>
$<IF:$<BOOL:${BUILD_TARGET_64BIT}>,$<TARGET_OBJECTS:libsyscall_64>,>
$<TARGET_OBJECTS:libsyscall>
$<TARGET_OBJECTS:libsyscall_dynamic>
#$<TARGET_OBJECTS:kqueue>
$<TARGET_OBJECTS:emulation>
$<TARGET_OBJECTS:mach_server_client>
SIBLINGS
system_c
compiler_rt
system_dyld
DEPENDENCIES
libsimple_darling
)
#target_link_libraries(system_kernel system_duct platform_static32 platform_static64)
make_fat(system_kernel)
add_library(system_kernel_static32 STATIC
$<TARGET_OBJECTS:libsyscall_32>
$<TARGET_OBJECTS:libsyscall>
$<TARGET_OBJECTS:emulation_dyld>
$<TARGET_OBJECTS:mach_server_client_dyld>
)
add_library(system_kernel_static64 STATIC
$<TARGET_OBJECTS:libsyscall_64>
$<TARGET_OBJECTS:libsyscall>
$<TARGET_OBJECTS:emulation_dyld>
$<TARGET_OBJECTS:mach_server_client_dyld>
)
target_link_libraries(system_kernel_static32 PRIVATE
libsimple_darling
)
target_link_libraries(system_kernel_static64 PRIVATE
libsimple_darling
)
install(TARGETS system_kernel DESTINATION libexec/darling/usr/lib/system)
add_dependencies(system_kernel migcom)

View File

@ -0,0 +1,333 @@
project(emulation)
add_subdirectory(mach)
cmake_policy(SET CMP0005 NEW)
enable_language(ASM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fvisibility=hidden -fPIC -fno-builtin -ggdb -Wno-int-conversion -Wno-compare-distinct-pointer-types")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib")
add_definitions(-DBSDTHREAD_WRAP_LINUX_PTHREAD
-DEMULATED_SYSNAME="Darwin"
-DEMULATED_RELEASE="20.6.0"
-DEMULATED_VERSION="Darwin Kernel Version 20.6.0"
-DEMULATED_OSVERSION="20G1120"
-DEMULATED_OSPRODUCTVERSION="11.7.4"
)
# include src/startup for rtsig.h
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/src/startup
${CMAKE_BINARY_DIR}/src/kernel/libsyscall
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_BINARY_DIR}/src/external/darlingserver/include
${CMAKE_SOURCE_DIR}/src/external/darlingserver/include
)
mig(signal/mach_exc.defs)
mig(signal/exc.defs)
set(emulation_sources
${CMAKE_CURRENT_BINARY_DIR}/signal/mach_excUser.c
elfcalls_wrapper.c
base.c
syscalls.c
simple.c
errno.c
readline.c
common_at.c
fdpath.c
wrapped/shm_open.c
wrapped/shm_unlink.c
wrapped/sem_open.c
wrapped/sem_unlink.c
wrapped/sem_wait.c
wrapped/sem_trywait.c
wrapped/sem_close.c
wrapped/sem_post.c
guarded/guarded_open_np.c
guarded/guarded_close_np.c
guarded/guarded_kqueue_np.c
guarded/table.c
machdep/machdeps.c
machdep/machdep-table.S
machdep/tls.c
unistd/write.c
unistd/read.c
unistd/pread.c
unistd/pwrite.c
unistd/readv.c
unistd/writev.c
unistd/flock.c
unistd/initgroups.c
mount/unmount.c
mman/mman.c
mman/madvise.c
mman/msync.c
kqueue/kqueue.c
kqueue/kevent.c
kqueue/kevent64.c
kqueue/kevent_qos.c
unistd/getsid.c
unistd/fsync.c
unistd/sync.c
unistd/fdatasync.c
unistd/dup.c
unistd/dup2.c
unistd/exit.c
unistd/close.c
unistd/fchdir.c
unistd/fchown.c
unistd/fchownat.c
unistd/fchmod.c
unistd/fchmodat.c
unistd/getegid.c
unistd/setgid.c
unistd/setuid.c
unistd/settid.c
unistd/setegid.c
unistd/seteuid.c
unistd/setsid.c
unistd/getuid.c
unistd/gettid.c
unistd/geteuid.c
unistd/getpid.c
unistd/lseek.c
unistd/ftruncate.c
unistd/truncate.c
unistd/access.c
unistd/faccessat.c
unistd/readlink.c
unistd/readlinkat.c
unistd/symlink.c
unistd/symlinkat.c
unistd/link.c
unistd/linkat.c
unistd/unlink.c
unistd/unlinkat.c
unistd/chdir.c
unistd/mknod.c
unistd/chmod.c
unistd/chown.c
unistd/lchown.c
unistd/umask.c
unistd/chroot.c
unistd/getgid.c
unistd/getppid.c
unistd/rename.c
unistd/renameat.c
unistd/getpgrp.c
unistd/getdtablesize.c
unistd/setpgid.c
unistd/setgroups.c
unistd/getgroups.c
unistd/getpgid.c
unistd/pipe.c
unistd/chmod_extended.c
unistd/fchmod_extended.c
unistd/fchflags.c
unistd/chflags.c
unistd/issetugid.c
select/select.c
select/pselect.c
select/poll.c
process/vfork.c
process/fork.c
process/wait4.c
process/waitid.c
process/execve.c
process/posix_spawn.c
process/getpriority.c
process/setpriority.c
signal/duct_signals.c
signal/kill.c
signal/sigaltstack.c
signal/sigaction.c
signal/sigreturn.c
signal/sigprocmask.c
signal/sig_restorer.S
signal/sigsuspend.c
signal/sigpending.c
signal/sigexc.c
signal/sigwait.c
misc/ptrace.c
misc/getentropy.c
misc/syscall.c
misc/shared_region_check_np.c
misc/ioctl.c
misc/thread_selfid.c
misc/proc_info.c
misc/sysctl.c
misc/sysctl_proc.c
misc/sysctl_hw.c
misc/sysctl_kern.c
misc/sysctl_unspec.c
misc/sysctl_machdep.c
misc/sysctl_sysctl.c
misc/sysctl_net.c
misc/sysctl_vm.c
misc/getrlimit.c
misc/setrlimit.c
misc/gethostuuid.c
misc/getrusage.c
misc/getlogin.c
misc/setlogin.c
misc/reboot.c
misc/iopolicysys.c
misc/csops.c
misc/fileport_makeport.c
misc/fileport_makefd.c
misc/csrctl.c
misc/fsgetpath.c
misc/abort_with_payload.c
misc/clonefile.c
fcntl/open.c
fcntl/openat.c
fcntl/fcntl.c
network/socket.c
network/socketpair.c
network/connect.c
network/recvmsg.c
network/sendmsg.c
network/duct.c
network/recvfrom.c
network/accept.c
network/getpeername.c
network/getsockname.c
network/shutdown.c
network/getsockopt.c
network/setsockopt.c
network/sendto.c
network/bind.c
network/listen.c
stat/fstat.c
stat/fstatat.c
stat/lstat.c
stat/stat.c
stat/stat64_extended.c
stat/lstat64_extended.c
stat/fstat64_extended.c
stat/getfsstat.c
stat/statfs.c
stat/fstatfs.c
stat/mkdir.c
stat/mkdirat.c
stat/mkfifo.c
stat/rmdir.c
stat/common.c
xattr/getattrlistbulk.c
xattr/getattrlistat.c
xattr/getattrlist.c
xattr/fgetattrlist.c
xattr/setattrlistat.c
xattr/setattrlist.c
xattr/fsetattrlist.c
xattr/listxattr.c
xattr/flistxattr.c
xattr/removexattr.c
xattr/fremovexattr.c
xattr/getxattr.c
xattr/fgetxattr.c
xattr/setxattr.c
xattr/fsetxattr.c
synch/semwait_signal.c
hfs/stub.c
dirent/getdirentries.c
time/gettimeofday.c
time/utimes.c
time/futimes.c
time/setitimer.c
time/getitimer.c
ioctl/ioctl.c
ioctl/termios.c
ioctl/filio.c
ioctl/socket.c
ext/sysinfo.c
ext/uname.c
ext/nanosleep.c
ext/epoll_create.c
ext/epoll_create1.c
ext/epoll_ctl.c
ext/epoll_wait.c
ext/inotify_init.c
ext/inotify_init1.c
ext/inotify_add_watch.c
ext/inotify_rm_watch.c
ext/eventfd.c
ext/eventfd_read.c
ext/eventfd_write.c
ext/signalfd.c
ext/timerfd_create.c
ext/timerfd_settime.c
ext/timerfd_gettime.c
ext/clock_nanosleep.c
ext/clock_gettime.c
ext/sched_yield.c
ext/syslog.c
ext/futex.c
ext/mremap.c
ext/file_handle.c
ext/fanotify.c
ext/for-xtrace.c
ext/for-libelfloader.c
ext/for-libkqueue.c
bsdthread/bsdthread_register.c
bsdthread/bsdthread_create.c
bsdthread/bsdthread_ctl.c
bsdthread/bsdthread_terminate.c
bsdthread/disable_threadsignal.c
bsdthread/workq_kernreturn.c
bsdthread/workq_open.c
bsdthread/pthread_kill.c
bsdthread/pthread_chdir.c
bsdthread/pthread_fchdir.c
bsdthread/pthread_markcancel.c
bsdthread/pthread_canceled.c
psynch/psynch_rw_rdlock.c
psynch/psynch_rw_wrlock.c
psynch/psynch_rw_unlock.c
psynch/psynch_cvclrprepost.c
psynch/psynch_mutexwait.c
psynch/psynch_mutexdrop.c
psynch/psynch_cvwait.c
psynch/psynch_cvbroad.c
psynch/psynch_cvsignal.c
psynch/ulock_wait.c
psynch/ulock_wake.c
sysv_sem/semget.c
sysv_sem/semctl.c
sysv_sem/semop.c
conf/pathconf.c
conf/fpathconf.c
mach/audit_session_self.c
audit/audit_addr.c
vchroot_userspace.c
syscalls-table.S
linux-syscall.S
xtrace-hooks.S
${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c
resources/dserver-rpc-defs.c
)
set_source_files_properties(signal/duct_signals.c PROPERTIES COMPILE_FLAGS "-nostdinc")
set_source_files_properties(signal/sigexc.c PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/signal/exc.h)
set_source_files_properties(${CMAKE_BINARY_DIR}/src/external/darlingserver/src/rpc.c PROPERTIES
GENERATED TRUE
COMPILE_FLAGS "-include ${CMAKE_CURRENT_SOURCE_DIR}/resources/dserver-rpc-defs.h"
)
include_directories(
../../../libsimple/include
)
add_darling_object_library(emulation ${emulation_sources})
add_darling_object_library(emulation_dyld ${emulation_sources})
set_target_properties(emulation_dyld PROPERTIES COMPILE_FLAGS "-ffunction-sections -DVARIANT_DYLD")
add_dependencies(emulation rtsig_h generate_dserver_rpc_wrappers)
add_dependencies(emulation_dyld rtsig_h generate_dserver_rpc_wrappers)
make_fat(emulation)
make_fat(emulation_dyld)

View File

@ -0,0 +1,42 @@
#include "audit_addr.h"
#include "../unistd/geteuid.h"
#include "../misc/getentropy.h"
#include <os/lock.h>
#define min(a, b) ((a < b) ? a : b)
extern void* memcpy(void* dest, const void* src, __SIZE_TYPE__ n);
// global variable because we need to inherit this across child processes
static auditinfo_addr_t info = {
.ai_auid = AU_DEFAUDITID,
.ai_mask = {0},
.ai_termid = { .at_type = AU_IPv4 },
.ai_asid = AU_DEFAUDITSID,
.ai_mask = 0,
};
// should be a rw lock but *shrug*
static os_unfair_lock info_lock = OS_UNFAIR_LOCK_INIT;
long sys_getaudit_addr(struct auditinfo_addr* auditinfo_addr, int length) {
os_unfair_lock_lock(&info_lock);
memcpy(auditinfo_addr, &info, min(length, sizeof(auditinfo_addr_t)));
os_unfair_lock_unlock(&info_lock);
return 0;
};
long sys_setaudit_addr(struct auditinfo_addr* auditinfo_addr, int length) {
os_unfair_lock_lock(&info_lock);
memcpy(&info, auditinfo_addr, min(length, sizeof(auditinfo_addr_t)));
if (info.ai_asid == AU_ASSIGN_ASID) {
// generate a new session ID
sys_getentropy(&info.ai_asid, sizeof(info.ai_asid));
}
os_unfair_lock_unlock(&info_lock);
return 0;
};

View File

@ -0,0 +1,10 @@
#ifndef _DARLING_EMULATION_AUDIT_AUDIT_ADDR_H
#define _DARLING_EMULATION_AUDIT_AUDIT_ADDR_H
#include <stdint.h>
#include <bsm/audit.h>
long sys_getaudit_addr(struct auditinfo_addr* auditinfo_addr, int length);
long sys_setaudit_addr(struct auditinfo_addr* auditinfo_addr, int length);
#endif // _DARLING_EMULATION_AUDIT_GETAUDIT_ADDR_H

View File

@ -0,0 +1,38 @@
#define BUILDING_BASE_C
#include "base.h"
#include <linux-syscalls/linux.h>
#include "simple.h"
#include "duct_errno.h"
#include "syscalls.h"
long __unknown_syscall(int nr, ...)
{
__simple_printf("Unimplemented syscall (%d)\n", nr);
return -ENOSYS;
}
long __unknown_syscall_machdep(int nr, ...)
{
__simple_printf("Unimplemented machdep trap (%d)\n", nr);
return -ENOSYS;
}
VISIBLE
int __linux_syscall(int nr, long a1, long a2, long a3, long a4, long a5, long a6)
{
return linux_syscall(a1, a2, a3, a4, a5, a6, nr);
}
#ifdef __TESTING
void _start()
{
#ifdef __x86_64__
__asm__ ("andq $-16, %rsp");
#elif defined(__i386__
__asm__ ("andl $-16, %esp");
#endif
__simple_printf("Hello world\n");
LINUX_SYSCALL1(__NR_exit, 0);
}
#endif

View File

@ -0,0 +1,40 @@
#ifndef LINUX_BASE_H
#define LINUX_BASE_H
#define VISIBLE __attribute__ ((visibility ("default")))
#define LINUX_SYSCALL0(nr) linux_syscall(0, 0, 0, 0, 0, 0, nr)
#define LINUX_SYSCALL1(nr, a1) linux_syscall((long)a1, 0, 0, 0, 0, 0, nr)
#define LINUX_SYSCALL2(nr, a1, a2) linux_syscall((long)a1, (long)a2, 0, 0, 0, 0, nr)
#define LINUX_SYSCALL3(nr, a1, a2, a3) linux_syscall((long)a1, (long)a2, (long)a3, 0, 0, 0, nr)
#define LINUX_SYSCALL4(nr, a1, a2, a3, a4) linux_syscall((long)a1, (long)a2, (long)a3, (long)a4, 0, 0, nr)
#define LINUX_SYSCALL5(nr, a1, a2, a3, a4, a5) linux_syscall((long)a1, (long)a2, (long)a3, (long)a4, (long)a5, 0, nr)
#define LINUX_SYSCALL6(nr, a1, a2, a3, a4, a5, a6) linux_syscall((long)a1, (long)a2, (long)a3, (long)a4, (long)a5, (long)a6, nr)
#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n
#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0)
#define __SYSCALL_CONCAT_X(a,b) a##b
#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b)
#define LINUX_SYSCALL(...) __SYSCALL_CONCAT(LINUX_SYSCALL,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
long linux_syscall(long a1, long a2, long a3, long a4, long a5, long a6, int nr);
#ifndef BUILDING_BASE_C
VISIBLE
int __linux_syscall(int nr, ...);
#endif /* BUILDING_BASE_C */
#ifdef __x86_64__
# define LL_ARG(x) (x)
#else
# define LL_ARG(x) ((union { long long ll; long l[2]; }){ .ll = x }).l[0], \
((union { long long ll; long l[2]; }){ .ll = x }).l[1]
#endif
long __darling_bsd_syscall(int nr, ...);
long __unknown_syscall(int nr, ...);
#endif

View File

@ -0,0 +1,153 @@
#include "bsdthread_create.h"
#include "bsdthread_register.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/errno.h>
#include "../mman/mman.h"
#include "../simple.h"
#include "../elfcalls_wrapper.h"
#include "../machdep/tls.h"
#include "../mach/mach_traps.h"
#include <darlingserver/rpc.h>
#include "../guarded/table.h"
extern void *memset(void *s, int c, size_t n);
#define PTHREAD_START_CUSTOM 0x01000000
#define PTHREAD_START_SETSCHED 0x02000000
#define PTHREAD_START_DETACHED 0x04000000
#define PTHREAD_START_POLICY_BITSHIFT 16
#define PTHREAD_START_POLICY_MASK 0xff
#define PTHREAD_START_IMPORTANCE_MASK 0xffff
#define STACK_GUARD_SIZE 4096
static bool _uses_threads = false;
// http://www.tldp.org/FAQ/Threads-FAQ/clone.c
static void rpc_guard(int fd) {
guard_entry_options_t options;
options.close = __dserver_close_socket;
guard_table_add(fd, guard_flag_prevent_close | guard_flag_close_on_fork, &options);
};
static void rpc_unguard(int fd) {
guard_table_remove(fd);
};
static const struct darling_thread_create_callbacks callbacks = {
.thread_self_trap = &thread_self_trap_impl,
.thread_set_tsd_base = &sys_thread_set_tsd_base,
.rpc_guard = rpc_guard,
.rpc_unguard = rpc_unguard,
};
long sys_bsdthread_create(void* thread_start, void* arg,
void* stack, void* pthread, uint32_t flags)
{
#ifndef VARIANT_DYLD // dyld doesn't create threads
int ret;
unsigned long stacksize = 0;
_uses_threads = true;
#ifndef BSDTHREAD_WRAP_LINUX_PTHREAD
if (!(flags & PTHREAD_START_CUSTOM))
{
// We have to allocate stack ourselves
pthread = stack = thread_stack_allocate(stacksize);
}
ret = darling_thread_create((void**) stack, pthread_entry_point_wrapper, thread_start,
arg, stacksize, flags);
#else
return __darling_thread_create(((uintptr_t)stack), pthread_obj_size,
pthread_entry_point_wrapper, thread_start, arg, (uintptr_t) stack, flags,
&callbacks, pthread);
#endif
if (ret < 0)
return errno_linux_to_bsd(ret);
return pthread;
#else
return -ENOSYS;
#endif
}
void* thread_stack_allocate(unsigned long stacksize)
{
unsigned long allocsize;
void* stack;
// The pthread object is placed above stack area
allocsize = stacksize + pthread_obj_size + STACK_GUARD_SIZE;
allocsize = (allocsize + 4095) & ~4095; // round up to page size
stack = (void**) sys_mmap(NULL, allocsize, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
// Protect the stack guard
sys_mprotect(stack, STACK_GUARD_SIZE, PROT_NONE);
if (((intptr_t)stack) < 0 && ((intptr_t)stack) >= -4095)
return NULL;
return (void*) (((uintptr_t)stack) + stacksize + STACK_GUARD_SIZE);
}
#if 0
int darling_thread_create(void** stack, void* entry_point, uintptr_t arg3,
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6)
{
int ret;
#if defined(__x86_64__)
// Store these arguments to pthread_entry point on the stack
stack[-1] = entry_point;
stack[-2] = arg3;
stack[-3] = arg4;
stack[-4] = arg5;
stack[-5] = arg6;
__asm__ __volatile__ (
"syscall\n" // invoke sys_clone
"testl %0, %0\n" // if in parent thread, jump away
"jne 1f\n"
"subq $40, %%rsp\n" // protect what we have stored on stack
"call _thread_self_trap\n" // get thread_self Mach port
"addq $40, %%rsp\n"
"movl %%eax, %%esi\n" // thread_self is 2nd arg to pthread_entry_point
"movq %%rsp, %%rdi\n" // pthread_self as 1st arg
"movq -16(%%rsp), %%rdx\n" // thread_start as 3rd arg
"movq -32(%%rsp), %%r8\n" // stack_size as 5th arg
"movq -24(%%rsp), %%rcx\n" // thread arg as 4th arg
"movq -40(%%rsp), %%r9\n" // flags as 6th arg
"movq -8(%%rsp), %%rbx\n"
"jmp *%%rbx\n"
"1:\n"
: "=a"(ret)
: "0" (__NR_clone),
"D"(LINUX_CLONE_THREAD | LINUX_CLONE_VM | LINUX_CLONE_SIGHAND
| LINUX_CLONE_FILES | LINUX_CLONE_FS | LINUX_CLONE_SYSVSEM),
"S"(stack));
#elif defined(__i386__)
# warning Missing clone call assembly!
#else
# warning Missing clone call assembly!
#endif
return ret;
}
#endif
bool uses_threads(void)
{
return _uses_threads;
}

View File

@ -0,0 +1,34 @@
#ifndef BSDTHREAD_CREATE_H
#define BSDTHREAD_CREATE_H
#include <stdint.h>
#include <stdbool.h>
long sys_bsdthread_create(void* thread_start, void* arg, void* stack,
void* pthread, uint32_t flags);
int darling_thread_create(void** stack, void* entry_point, uintptr_t arg3,
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6);
void* thread_stack_allocate(unsigned long stacksize);
bool uses_threads(void);
#define LINUX_CLONE_VM 0x00000100
#define LINUX_CLONE_FS 0x00000200
#define LINUX_CLONE_FILES 0x00000400
#define LINUX_CLONE_SIGHAND 0x00000800
#define LINUX_CLONE_PTRACE 0x00002000
#define LINUX_CLONE_VFORK 0x00004000
#define LINUX_CLONE_PARENT 0x00008000
#define LINUX_CLONE_THREAD 0x00010000
#define LINUX_CLONE_NEWNS 0x00020000
#define LINUX_CLONE_SYSVSEM 0x00040000
#define LINUX_CLONE_SETTLS 0x00080000
#define LINUX_CLONE_PARENT_SETTID 0x00100000
#define LINUX_CLONE_CHILD_CLEARTID 0x00200000
#define LINUX_CLONE_DETACHED 0x00400000
#define LINUX_CLONE_UNTRACED 0x00800000
#define LINUX_CLONE_CHILD_SETTID 0x01000000
#endif

View File

@ -0,0 +1,5 @@
#include "bsdthread_ctl.h"
long sys_bsdthread_ctl(long command, void* arg1, void* arg2, void* arg3) {
return 0;
};

View File

@ -0,0 +1,6 @@
#ifndef _DARLING_EMULATION_BSDTHREAD_BSDTHREAD_CTL_H
#define _DARLING_EMULATION_BSDTHREAD_BSDTHREAD_CTL_H
long sys_bsdthread_ctl(long command, void* arg1, void* arg2, void* arg3);
#endif // _DARLING_EMULATION_BSDTHREAD_BSDTHREAD_CTL_H

View File

@ -0,0 +1,72 @@
#include "bsdthread_register.h"
#include "../base.h"
#include "../errno.h"
#include <sys/errno.h>
#include "../signal/sigexc.h"
#include <darlingserver/rpc.h>
#include <stdint.h>
#include <pthread/tsd_private.h>
#include <linux-syscalls/linux.h>
#include "../simple.h"
int pthread_obj_size;
bsdthread_entry_t pthread_entry_point;
bsdwqthread_entry_t wqueue_entry_point;
#define PTHREAD_FEATURE_DISPATCHFUNC 1
#define PTHREAD_FEATURE_QOS_MAINTENANCE 0x10
#define PTHREAD_FEATURE_QOS_DEFAULT 0x40000000
#define WORKQ_FEATURE_FINEPRIO 0x02
#define WORKQ_FEATURE_KEVENT 0x40
struct _pthread_registration_data {
uint64_t version;
uint64_t dispatch_queue_offset;
uint64_t main_qos;
uint32_t tsd_offset;
uint32_t return_to_kernel_offset;
uint32_t mach_thread_self_offset;
} __attribute__ ((packed));
static struct _pthread_registration_data g_pth_regdata;
long sys_bsdthread_register(void* thread_start, void* wqthread, int pthsize,
const struct _pthread_registration_data* pth_regdata,
unsigned long pth_regdata_len, unsigned long long dpq_offset)
{
pthread_obj_size = pthsize;
pthread_entry_point = (bsdthread_entry_t) thread_start;
wqueue_entry_point = (bsdwqthread_entry_t) wqthread;
g_pth_regdata = *pth_regdata;
uintptr_t pthread_handle = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
uintptr_t dispatch_qaddr = pthread_handle + g_pth_regdata.tsd_offset + g_pth_regdata.dispatch_queue_offset;
if (dserver_rpc_set_thread_handles(pthread_handle, dispatch_qaddr) < 0) {
__simple_abort();
}
return /* WORKQ_FEATURE_KEVENT | WORKQ_FEATURE_FINEPRIO | PTHREAD_FEATURE_QOS_MAINTENANCE
| PTHREAD_FEATURE_DISPATCHFUNC | PTHREAD_FEATURE_QOS_DEFAULT */ 0;
}
void pthread_entry_point_wrapper(void* self, int thread_port, void* funptr,
void* funarg, unsigned long stack_addr, unsigned int flags)
{
sigexc_thread_setup();
uintptr_t pthread_handle = (unsigned long) self;
uintptr_t dispatch_qaddr = pthread_handle + g_pth_regdata.tsd_offset + g_pth_regdata.dispatch_queue_offset;
if (dserver_rpc_set_thread_handles(pthread_handle, dispatch_qaddr) < 0) {
__simple_abort();
}
pthread_entry_point(self, thread_port, funptr, funarg, stack_addr, flags);
}
void wqueue_entry_point_wrapper(void* self, int thread_port, void* stackaddr,
void* item, int reuse, int nevents)
{
sigexc_thread_setup();
wqueue_entry_point(self, thread_port, stackaddr, item, reuse, nevents);
}

View File

@ -0,0 +1,23 @@
#ifndef BSDTHREAD_REGISTER_H
#define BSDTHREAD_REGISTER_H
typedef void (*bsdthread_entry_t)(void* /* self */, int /* thread_port */, void* /* funptr */,
void* /* funarg */, unsigned long /* stacksize */, unsigned int /* flags */);
typedef void (*bsdwqthread_entry_t)(void* /* self */, int /* thread_port */, void* /* stackaddr */,
void* /* item */, int /* reuse */, int /* nevents */);
extern int pthread_obj_size;
extern bsdthread_entry_t pthread_entry_point;
extern bsdwqthread_entry_t wqueue_entry_point;
struct _pthread_registration_data;
long sys_bsdthread_register(void* thread_start, void* wqthread, int pthsize,
const struct _pthread_registration_data* pth_regdata,
unsigned long pth_regdata_len, unsigned long long dpq_offset);
void pthread_entry_point_wrapper(void* self, int thread_port, void* funptr,
void* funarg, unsigned long stacksize, unsigned int flags);
void wqueue_entry_point_wrapper(void* self, int thread_port, void* stackaddr,
void* item, int reuse, int nevents);
#endif

View File

@ -0,0 +1,49 @@
#include "bsdthread_terminate.h"
#include "bsdthread_register.h"
#include "../base.h"
#include "../errno.h"
#include <sys/errno.h>
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include <stdint.h>
#include "../elfcalls_wrapper.h"
#include "../guarded/table.h"
#include "../mach/lkm.h"
int bsdthread_terminate_trap(
uintptr_t stackaddr,
unsigned long freesize,
int thread,
int sem);
int semaphore_signal_trap_impl(int signal_name);
extern void _xtrace_thread_exit(void);
long sys_bsdthread_terminate(void* stackaddr, unsigned long freesize, int port,
int join_sem)
{
#ifndef VARIANT_DYLD
#ifdef BSDTHREAD_WRAP_LINUX_PTHREAD
// Implemented in libdyld
extern int __darling_thread_terminate(void* stackaddr,
unsigned long freesize, unsigned long pthobj_size);
semaphore_signal_trap_impl(join_sem);
// point of no return; let xtrace know
_xtrace_thread_exit();
// we can also unguard the RPC FD for this thread now
guard_table_remove(mach_driver_get_fd());
return __darling_thread_terminate(stackaddr, freesize, pthread_obj_size);
#else
return bsdthread_terminate_trap((uintptr_t) stackaddr, freesize,
port, join_sem);
#endif
#else
return -ENOSYS;
#endif
}

View File

@ -0,0 +1,9 @@
#ifndef BSDTHREAD_TERMINATE_H
#define BSDTHREAD_TERMINATE_H
#include <stdint.h>
long sys_bsdthread_terminate(void* stackaddr, unsigned long freesize, int port,
int join_sem);
#endif

View File

@ -0,0 +1,11 @@
#ifndef _BSDTHREAD_CANCELLABLE_H
#define _BSDTHREAD_CANCELLABLE_H
#include <sys/errno.h>
#include "pthread_canceled.h"
#define CANCELATION_POINT() \
if (sys_pthread_canceled(0) == 0) \
return -EINTR;
#endif

View File

@ -0,0 +1,28 @@
#include "disable_threadsignal.h"
#include "../base.h"
#include "../errno.h"
#include "../signal/duct_signals.h"
#include "../signal/sigprocmask.h"
#include <sys/errno.h>
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include "pthread_canceled.h"
#ifndef SIG_BLOCK
# define SIG_BLOCK 1
#endif
long sys_disable_threadsignal(int disable)
{
if (!disable)
return -ENOTSUP;
sigset_t set = ~0;
// Disable cancelation
sys_pthread_canceled(2);
// Signal config is per-thread on Linux
return sys_sigprocmask(SIG_BLOCK, &set, NULL);
}

View File

@ -0,0 +1,7 @@
#ifndef DISABLE_THREADSIGNAL_H
#define DISABLE_THREADSIGNAL_H
long sys_disable_threadsignal(int disable);
#endif

View File

@ -0,0 +1,30 @@
#ifndef _PER_THREAD_WD_H
#define _PER_THREAD_WD_H
#include <pthread/tsd_private.h>
#include "../common_at.h"
// We use the following static TSD keys (see tsd_private.h):
// 100 = is 101 set? (Because 0 could be a valid FD, theoretically.)
// 101 = per thread wd file descriptor
//
// NOTE: The file descriptor in 101 will get leaked unless __pthread_fchdir(-1)
// is called, but this is such a rare scenario that we disregard it.
// It is be too hard to fix, because static TSD keys (such as the ones we use)
// don't have destructors.
static inline int get_perthread_wd(void)
{
if (_pthread_getspecific_direct(100))
return _pthread_getspecific_direct(101);
else
return LINUX_AT_FDCWD;
}
static inline void set_perthread_wd(int fd)
{
_pthread_setspecific_direct(100, 1);
_pthread_setspecific_direct(101, fd);
}
#endif

View File

@ -0,0 +1,22 @@
#include "pthread_canceled.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include "bsdthread_create.h"
#include <sys/errno.h>
#include <darlingserver/rpc.h>
long sys_pthread_canceled(int action)
{
if (action == 0 && !uses_threads())
return -EINVAL;
int ret = dserver_rpc_pthread_canceled(action);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
}

View File

@ -0,0 +1,7 @@
#ifndef PTHREAD_CANCELED_H
#define PTHREAD_CANCELED_H
long sys_pthread_canceled(int action);
#endif

View File

@ -0,0 +1,25 @@
#include "pthread_chdir.h"
#include "../base.h"
#include "../errno.h"
#include <stddef.h>
#include "../mach/lkm.h"
#include "../fcntl/open.h"
#include "../unistd/close.h"
#include "per_thread_wd.h"
long sys_pthread_chdir(const char* path)
{
int rv, newfd, oldfd;
newfd = sys_open(path, BSD_O_RDONLY | BSD_O_DIRECTORY | BSD_O_CLOEXEC, 0);
if (newfd < 0)
return newfd;
oldfd = get_perthread_wd();
if (oldfd != LINUX_AT_FDCWD)
close_internal(oldfd);
set_perthread_wd(newfd);
return 0;
}

View File

@ -0,0 +1,7 @@
#ifndef PTHREAD_CHDIR_H
#define PTHREAD_CHDIR_H
long sys_pthread_chdir(const char* path);
#endif

View File

@ -0,0 +1,32 @@
#include "pthread_fchdir.h"
#include "../base.h"
#include "../errno.h"
#include <stddef.h>
#include "../mach/lkm.h"
#include "../fcntl/open.h"
#include "../fcntl/fcntl.h"
#include "../unistd/close.h"
#include "../unistd/dup.h"
#include "per_thread_wd.h"
long sys_pthread_fchdir(int newfd)
{
int fd = get_perthread_wd();
if (fd != LINUX_AT_FDCWD)
close_internal(fd);
if (newfd == -1)
newfd = LINUX_AT_FDCWD; // return to per-process wd
else
{
newfd = sys_dup(newfd);
if (newfd < 0)
return newfd;
sys_fcntl(newfd, F_SETFD, FD_CLOEXEC);
}
set_perthread_wd(newfd);
return 0;
}

View File

@ -0,0 +1,7 @@
#ifndef PTHREAD_FCHDIR_H
#define PTHREAD_FCHDIR_H
long sys_pthread_fchdir(int fd);
#endif

View File

@ -0,0 +1,19 @@
#include "pthread_kill.h"
#include "../base.h"
#include "../errno.h"
#include "../signal/duct_signals.h"
#include <sys/errno.h>
#include <stddef.h>
#include "../simple.h"
#include <darlingserver/rpc.h>
long sys_pthread_kill(int thread_port, int sig)
{
int ret = dserver_rpc_pthread_kill(thread_port, signum_bsd_to_linux(sig));
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
}

View File

@ -0,0 +1,7 @@
#ifndef PTHREAD_KILL_H
#define PTHREAD_KILL_H
long sys_pthread_kill(int thread_port, int sig);
#endif

View File

@ -0,0 +1,17 @@
#include "pthread_markcancel.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include <darlingserver/rpc.h>
long sys_pthread_markcancel(unsigned int thread_port)
{
int ret = dserver_rpc_pthread_markcancel(thread_port);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
}

View File

@ -0,0 +1,7 @@
#ifndef PTHREAD_MARKCANCEL_H
#define PTHREAD_MARKCANCEL_H
long sys_pthread_markcancel(unsigned int thread_port);
#endif

View File

@ -0,0 +1,410 @@
#include "workq_kernreturn.h"
#include "bsdthread_register.h"
#include "bsdthread_create.h"
#include "../base.h"
#include "../errno.h"
#include <sys/errno.h>
#include <linux-syscalls/linux.h>
#include <stddef.h>
#include <pthread/tsd_private.h>
#include "../ext/futex.h"
#include "../simple.h"
#include <sys/queue.h>
#include <os/lock.h>
#include <elfcalls/threads.h>
#include "../machdep/tls.h"
#include "../mach/mach_traps.h"
#define __PTHREAD_EXPOSE_INTERNALS__ 1
#include <pthread/priority_private.h>
// much easier to include than libpthread's `internal.h`
#include "../../../../startup/mldr/elfcalls/dthreads.h"
#include <darlingserver/rpc.h>
#include "../guarded/table.h"
#include "../elfcalls_wrapper.h"
#define WQ_MAX_THREADS 64
#define WQOPS_QUEUE_ADD 1
#define WQOPS_QUEUE_REMOVE 2
#define WQOPS_THREAD_RETURN 4
#define WQOPS_THREAD_SETCONC 8
#define WQOPS_THREAD_KEVENT_RETURN 0x40
#define WQOPS_QUEUE_NEWSPISUPP 0x10
#define WQOPS_QUEUE_REQTHREADS 0x20
#define WQOPS_QUEUE_REQTHREADS2 0x30
#define WQOPS_SET_EVENT_MANAGER_PRIORITY 0x80
#define WQOPS_SETUP_DISPATCH 0x400
// Flags for the newly spawned thread:
// WQ_FLAG_THREAD_NEWSPI
// WQ_FLAG_THREAD_REUSE (0 if thread is newly spawned)
// item is unused in "new SPI"
#define WQ_FLAG_THREAD_PRIO_SCHED 0x00008000
#define WQ_FLAG_THREAD_PRIO_QOS 0x00004000
#define WQ_FLAG_THREAD_PRIO_MASK 0x00000fff
#define WQ_FLAG_THREAD_OVERCOMMIT 0x00010000
#define WQ_FLAG_THREAD_REUSE 0x00020000
#define WQ_FLAG_THREAD_NEWSPI 0x00040000
#define WQ_FLAG_THREAD_KEVENT 0x00080000
#define WQ_FLAG_THREAD_EVENT_MANAGER 0x00100000
#define WQ_FLAG_THREAD_TSD_BASE_SET 0x00200000
#define WQ_FLAG_THREAD_WORKLOOP 0x00400000
#define WQ_FLAG_THREAD_OUTSIDEQOS 0x00800000
#define WORKQ_EXIT_THREAD_NKEVENT (-1)
static int workq_sem = WQ_MAX_THREADS; // max 64 threads in use
static os_unfair_lock workq_parked_lock = OS_UNFAIR_LOCK_INIT;
// static int workq_parked_threads = 0; // num spawned, but unused threads
static int workq_parked[WQ_MAX_THREADS];
static int workq_parked_prio[WQ_MAX_THREADS];
TAILQ_HEAD(tailhead, parked_thread) workq_parked_head = TAILQ_HEAD_INITIALIZER(workq_parked_head);
struct parked_thread
{
int sem, flags;
struct wq_kevent_data* event;
TAILQ_ENTRY(parked_thread) entries;
};
static void list_add(struct parked_thread* head, struct parked_thread* item);
static void list_remove(struct parked_thread* head, struct parked_thread* item);
struct timespec
{
long tv_sec;
long tv_nsec;
};
void __attribute__((weak)) os_unfair_lock_unlock(os_unfair_lock_t lock) {}
void __attribute__((weak)) os_unfair_lock_lock(os_unfair_lock_t lock) {}
//void* __attribute__((weak)) __attribute__((visibility("default"))) pthread_getspecific(unsigned long key) { return NULL; }
//int __attribute__((weak)) __attribute__((visibility("default"))) pthread_setspecific(unsigned long key, const void* value) { return 1; }
static int priority_to_class(int prio);
// This is horrible, but it may work
static struct wq_kevent_data* wq_event_pending = NULL;
static void rpc_guard(int fd) {
guard_entry_options_t options;
options.close = __dserver_close_socket;
guard_table_add(fd, guard_flag_prevent_close | guard_flag_close_on_fork, &options);
};
static void rpc_unguard(int fd) {
guard_table_remove(fd);
};
static const struct darling_thread_create_callbacks callbacks = {
.thread_self_trap = &thread_self_trap_impl,
.thread_set_tsd_base = &sys_thread_set_tsd_base,
.rpc_guard = rpc_guard,
.rpc_unguard = rpc_unguard,
};
static int extract_wq_flags(int priority) {
int flags = 0;
int qos = _pthread_priority_thread_qos(priority);
flags = WQ_FLAG_THREAD_NEWSPI | qos | WQ_FLAG_THREAD_PRIO_QOS;
if (priority & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG) {
flags |= WQ_FLAG_THREAD_OVERCOMMIT;
}
return flags;
};
long sys_workq_kernreturn(int options, void* item, int affinity, int prio)
{
#ifndef VARIANT_DYLD
struct wq_kevent_data* wq_event = NULL;
// __simple_printf("workq_kernreturn: 0x%x, %p, 0x%x, 0x%x\n", options, item, affinity, prio);
// item is only used with WQOPS_QUEUE_ADD
switch (options)
{
case WQOPS_THREAD_KEVENT_RETURN:
{
struct kevent_qos_s* keventlist = item;
int nkevents = affinity;
// __simple_printf("kevent return, obj=%p, nkevents=%d\n", wq_event, nkevents);
if (wq_event_pending != NULL)
{
int* sem;
if (nkevents > 0)
memmove(wq_event_pending->events, keventlist, nkevents * sizeof(struct kevent_qos_s));
wq_event_pending->nevents = nkevents;
sem = &wq_event_pending->sem;
wq_event_pending = NULL;
sem_up(sem);
}
else
__simple_printf("wq_event is NULL, something is going to get stuck forever\n");
}
case WQOPS_THREAD_RETURN:
{
// Signalizes that the thread has completed its job
// and can be either recycled or terminated
int thread_self;
struct parked_thread me;
dthread_t dthread;
bool terminating = false;
os_unfair_lock_lock(&workq_parked_lock);
// Semaphore locked state (wait for wakeup)
me.sem = 0;
// extract initial flags
// (in case we only get created and used once and then terminate; `_pthread_wqthread` requires a valid `flags` argument)
dthread = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
prio = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS);
// doesn't extract `WQ_FLAG_THREAD_KEVENT` if we had it set, but that shouldn't matter
// like i said before, the only case where we actually need these flags to be set here is when the thread is going to die immediately after creation
me.flags = extract_wq_flags(prio);
// Enqueue for future WQOPS_QUEUE_REQTHREADS
TAILQ_INSERT_HEAD(&workq_parked_head, &me, entries);
// Decrease the amount of running threads
sem_up(&workq_sem);
os_unfair_lock_unlock(&workq_parked_lock);
// Wait until someone calls WQOPS_QUEUE_REQTHREADS
// and wakes us up
if (!sem_down(&me.sem, 15))
{
// Make sure we haven't just been woken up before locking the queue
// and remove us from the queue if not.
os_unfair_lock_lock(&workq_parked_lock);
if (me.sem > 0)
{
os_unfair_lock_unlock(&workq_parked_lock);
goto wakeup;
}
TAILQ_REMOVE(&workq_parked_head, &me, entries);
os_unfair_lock_unlock(&workq_parked_lock);
terminating = true;
// resume the thread; it'll call `_pthread_wqthread_exit` and kill itself
goto resume_thread;
}
wakeup: // we actually want to go back into the thread to do work
// __simple_printf("Thread %d woken up, prio=%d\n", thread_self, me.flags & WQ_FLAG_THREAD_PRIOMASK);
if (me.event)
wq_event_pending = me.event;
resume_thread: // we want the thread to resume, but it might be just to die
// reset stack and call entry point again with WQ_FLAG_THREAD_REUSE
thread_self = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF);
dthread = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
#ifdef __x86_64__
// arguments are in rdi, rsi, rdx, rcx, r8, r9
__asm__ __volatile__ (
// "int3\n"
"movl %3, %%r8d\n" // 5th argument
"movl %5, %%r9d\n" // 6th argument
"movq %0, %%rsp\n"
"subq $32, %%rsp\n"
"jmpq *%2\n"
:: "D" (dthread), "S" (thread_self), "a" (wqueue_entry_point),
"r" (me.flags | WQ_FLAG_THREAD_REUSE), "c" ((!terminating && me.event) ? me.event->events : NULL),
"r" (terminating ? WORKQ_EXIT_THREAD_NKEVENT : (me.event ? me.event->nevents : 0)), "d" (dthread->stackbottom)
);
#elif defined(__i386__)
// Arguments are in eax, ebx, ecx, edx, edi, esi
__asm__ __volatile__ (
"movl %0, %%esp\n"
"subl $32, %%esp\n"
"jmpl *%2\n"
:: "a" (dthread), "b" (thread_self), "S" (wqueue_entry_point),
"D" (me.flags | WQ_FLAG_THREAD_REUSE), "d" ((!terminating && me.event) ? me.event->events : NULL),
"S" (terminating ? WORKQ_EXIT_THREAD_NKEVENT : (me.event ? me.event->nevents : 0)), "c" (dthread->stackbottom)
);
#else
# error Missing assembly!
#endif
__builtin_unreachable();
return 0;
}
case WQOPS_SET_EVENT_MANAGER_PRIORITY:
case WQOPS_QUEUE_NEWSPISUPP:
return 0;
case WQOPS_QUEUE_REQTHREAD_FOR_KEVENT:
{
wq_event = (struct wq_kevent_data*) item;
affinity = 1;
}
case WQOPS_QUEUE_REQTHREADS2: // with prop bucket
case WQOPS_QUEUE_REQTHREADS:
{
// affinity contains thread count
int i, flags = extract_wq_flags(prio);
if (wq_event != NULL)
flags |= WQ_FLAG_THREAD_KEVENT;
// __simple_printf("Thread requested with prio %d\n", prio & WQ_FLAG_THREAD_PRIOMASK);
for (i = 0; i < affinity; i++)
{
// Increase the amount of running threads
sem_down(&workq_sem, -1);
os_unfair_lock_lock(&workq_parked_lock);
if (workq_parked_head.tqh_first != NULL)
{
struct parked_thread* thread;
thread = workq_parked_head.tqh_first;
// Resume an existing thread
// __simple_printf("Resuming thread %d\n", id);
thread->flags = flags;
thread->event = wq_event;
// Dequeue
TAILQ_REMOVE(&workq_parked_head, thread, entries);
// Resume the thread
sem_up(&thread->sem);
os_unfair_lock_unlock(&workq_parked_lock);
continue;
}
os_unfair_lock_unlock(&workq_parked_lock);
// __simple_printf("Spawning a new thread, nevents=%d\n", (wq_event != NULL) ? wq_event->nevents : -1);
wq_event_pending = wq_event;
__darling_thread_create(512*1024, pthread_obj_size, wqueue_entry_point_wrapper, 0,
(wq_event != NULL) ? wq_event->events : NULL, flags,
(wq_event != NULL) ? wq_event->nevents : 0,
&callbacks, NULL);
/*if (ret < 0)
{
__simple_printf("Failed to spawn a new thread, err %d\n", -ret);
return ret;
}*/
}
return 0;
}
case WQOPS_SETUP_DISPATCH: {
// TODO: actually do something with the info passed in
// XNU just tacks it onto the process its called for and uses it later when someone asks for it
/*
struct workq_dispatch_config cfg = {0};
// `affinity` contains the size of the config structure passed in
memcpy(&cfg, item, (affinity < sizeof(struct workq_dispatch_config)) ? affinity : sizeof(struct workq_dispatch_config));
*/
return 0;
} break;
default:
return -ENOTSUP;
}
#else
return -ENOSYS;
#endif
}
int sem_down(int* sem, int timeout)
{
int result;
struct timespec ts = { timeout, 0 };
try_again:
result = __sync_add_and_fetch(sem, -1);
if (result < 0)
{
*sem = -1;
result = __linux_futex(sem, FUTEX_WAIT, -1, (timeout != -1) ? &ts : NULL, 0, 0);
if (result == -1)
return 0;
goto try_again;
}
return 1;
}
void sem_up(int* sem)
{
int result;
result = __sync_add_and_fetch(sem, 1);
if (result == 0)
{
*sem = 1;
__linux_futex(sem, FUTEX_WAKE, 1, NULL, 0, 0);
}
}
#define __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE 0x20
#define __PTHREAD_PRIORITY_CBIT_USER_INITIATED 0x10
#define __PTHREAD_PRIORITY_CBIT_DEFAULT 0x8
#define __PTHREAD_PRIORITY_CBIT_UTILITY 0x4
#define __PTHREAD_PRIORITY_CBIT_BACKGROUND 0x2
#define __PTHREAD_PRIORITY_CBIT_MAINTENANCE 0x1
#define __PTHREAD_PRIORITY_CBIT_UNSPECIFIED 0x0
#define QOS_CLASS_USER_INTERACTIVE 0x21
#define QOS_CLASS_USER_INITIATED 0x19
#define QOS_CLASS_DEFAULT 0x15
#define QOS_CLASS_UTILITY 0x11
#define QOS_CLASS_BACKGROUND 0x09
#define QOS_CLASS_MAINTENANCE 0x05
#define QOS_CLASS_UNSPECIFIED 0x0
static int priority_to_class(int prio)
{
int dec_prio = (prio & 0xff00) >> 8;
switch (dec_prio)
{
case __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE:
return __PTHREAD_PRIORITY_CBIT_MAINTENANCE;
case __PTHREAD_PRIORITY_CBIT_USER_INITIATED:
return QOS_CLASS_USER_INITIATED;
case __PTHREAD_PRIORITY_CBIT_DEFAULT:
return QOS_CLASS_DEFAULT;
case __PTHREAD_PRIORITY_CBIT_UTILITY:
return QOS_CLASS_UTILITY;
case __PTHREAD_PRIORITY_CBIT_BACKGROUND:
return QOS_CLASS_BACKGROUND;
case __PTHREAD_PRIORITY_CBIT_MAINTENANCE:
return QOS_CLASS_MAINTENANCE;
default:
return QOS_CLASS_UNSPECIFIED;
}
}

View File

@ -0,0 +1,24 @@
#ifndef WORKQ_KERNRETURN_H
#define WORKQ_KERNRETURN_H
#define PRIVATE 1
#include <sys/event.h>
// Darling specific
#define WQOPS_QUEUE_REQTHREAD_FOR_KEVENT 0x100020
struct wq_kevent_data
{
struct kevent_qos_s* events;
int nevents;
int sem;
};
struct timespec;
long sys_workq_kernreturn(int options, void* item, int affinity, int prio);
int sem_down(int* sem, int timeout);
void sem_up(int* sem);
#endif

View File

@ -0,0 +1,10 @@
#include "workq_open.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
long sys_workq_open(void)
{
return 0;
}

View File

@ -0,0 +1,7 @@
#ifndef WORKQ_OPEN_H
#define WORKQ_OPEN_H
long sys_workq_open(void);
#endif

View File

@ -0,0 +1,23 @@
#include "common_at.h"
#include "bsdthread/per_thread_wd.h"
int atflags_bsd_to_linux(int flags)
{
int linux_flags = 0;
if (flags & BSD_AT_SYMLINK_NOFOLLOW)
linux_flags |= LINUX_AT_SYMLINK_NOFOLLOW;
if (flags & BSD_AT_REMOVEDIR)
linux_flags |= LINUX_AT_REMOVEDIR;
if (flags & BSD_AT_SYMLINK_FOLLOW)
linux_flags |= LINUX_AT_SYMLINK_FOLLOW;
return linux_flags;
}
int atfd(int fd)
{
if (fd == BSD_AT_FDCWD)
return get_perthread_wd();
return fd;
}

View File

@ -0,0 +1,21 @@
#ifndef _COMMON_AT_H
#define _COMMON_AT_H
// Common declarations for the *at family of system calls
#define LINUX_AT_FDCWD -100
#define LINUX_AT_SYMLINK_NOFOLLOW 0x100
#define LINUX_AT_REMOVEDIR 0x200
#define LINUX_AT_SYMLINK_FOLLOW 0x400
#define BSD_AT_FDCWD -2
#define BSD_AT_SYMLINK_NOFOLLOW 0x20
#define BSD_AT_REMOVEDIR 0x80
#define BSD_AT_SYMLINK_FOLLOW 0x40
int atflags_bsd_to_linux(int flags);
int atfd(int fd);
#endif

View File

@ -0,0 +1,38 @@
#include "fpathconf.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include <sys/errno.h>
enum {
BSD_PC_LINK_MAX = 1,
BSD_PC_MAX_CANON,
BSD_PC_MAX_INPUT,
BSD_PC_NAME_MAX,
BSD_PC_PATH_MAX,
BSD_PC_PIPE_BUF,
BSD_PC_CHOWN_RESTRICTED,
BSD_PC_NO_TRUNC,
BSD_PC_VDISABLE
};
long sys_fpathconf(int fd, int name)
{
static const short values[] = {
[BSD_PC_LINK_MAX] = 8,
[BSD_PC_MAX_CANON] = 255,
[BSD_PC_MAX_INPUT] = 255,
[BSD_PC_NAME_MAX] = 255,
[BSD_PC_PATH_MAX] = 4096,
[BSD_PC_PIPE_BUF] = 4096,
[BSD_PC_CHOWN_RESTRICTED] = 1,
[BSD_PC_NO_TRUNC] = 1,
[BSD_PC_VDISABLE] = 0
};
if (name < 1 || name >= sizeof(values) / sizeof(values[0]))
return -EINVAL;
else
return values[name];
}

View File

@ -0,0 +1,7 @@
#ifndef LINUX_FPATHCONF_H
#define LINUX_FPATHCONF_H
long sys_fpathconf(int fd, int name);
#endif

View File

@ -0,0 +1,11 @@
#include "pathconf.h"
#include "fpathconf.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
long sys_pathconf(const char* file, int name)
{
return sys_fpathconf(-1, name);
}

View File

@ -0,0 +1,7 @@
#ifndef LINUX_PATHCONF_H
#define LINUX_PATHCONF_H
long sys_pathconf(const char* file, int name);
#endif

View File

@ -0,0 +1,137 @@
#include "getdirentries.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include <sys/dirent.h>
//#include "../simple.h"
#define LINUX_SEEK_SET 0
#define LINUX_SEEK_CUR 1
extern __SIZE_TYPE__ strlen(const char* s);
extern char* strcpy(char* dest, const char* src);
extern int strcmp(const char* str1, const char* str2);
#ifndef min
# define min(a,b) ((a) < (b)) ? (a) : (b)
#endif
#define ALIGN(x, alignment) (((x) + (alignment - 1)) & ~(alignment - 1))
#define BSD_DIRENT_MIN_SIZE ALIGN(sizeof(struct bsd_dirent) + 2, 4)
#define BSD_DIRENT64_MIN_SIZE ALIGN(sizeof(struct bsd_dirent64) + 2, 4)
#define LINUX_DIRENT64_MIN_SIZE ALIGN(sizeof(struct linux_dirent64) + 2, 8)
static inline void round_to_4(unsigned short* reclen)
{
if (*reclen & 3)
{
*reclen += 3;
*reclen /= 4;
*reclen *= 4;
}
}
long sys_getdirentries(int fd, char* ibuf, unsigned int len, long* basep)
{
int ret, bpos = 0, opos = 0;
unsigned int max_entry_count = len / BSD_DIRENT_MIN_SIZE;
// don't want to blow up the stack
if (max_entry_count > 20)
max_entry_count = 20;
char buf[max_entry_count * LINUX_DIRENT64_MIN_SIZE];
if (basep)
*basep = 0;
ret = LINUX_SYSCALL(__NR_getdents64, fd, buf, sizeof(buf));
if (ret < 0)
return errno_linux_to_bsd(ret);
while (bpos < ret && opos < len)
{
struct linux_dirent64* l64;
struct bsd_dirent* bsd;
int slen;
l64 = (struct linux_dirent64*) (buf + bpos);
bsd = (struct bsd_dirent*) (ibuf + opos);
slen = strlen(l64->d_name);
if (len-opos < sizeof(struct bsd_dirent) + slen + 1)
break;
bsd->d_ino = l64->d_ino;
bsd->d_type = l64->d_type;
strcpy(bsd->d_name, l64->d_name);
bsd->d_reclen = sizeof(struct bsd_dirent) + slen + 1;
bsd->d_namlen = slen;
round_to_4(&bsd->d_reclen);
opos += bsd->d_reclen;
bpos += l64->d_reclen;
}
return opos;
}
struct dirent64 __DARWIN_STRUCT_DIRENTRY;
long sys_getdirentries64(int fd, char* ibuf, unsigned int len, long* basep)
{
int ret, bpos = 0, opos = 0;
unsigned int max_entry_count = len / BSD_DIRENT64_MIN_SIZE;
// don't want to blow up the stack
if (max_entry_count > 20)
max_entry_count = 20;
char buf[max_entry_count * LINUX_DIRENT64_MIN_SIZE];
if (basep)
*basep = 0;
ret = LINUX_SYSCALL(__NR_getdents64, fd, buf, sizeof(buf));
if (ret < 0)
return errno_linux_to_bsd(ret);
while (bpos < ret && opos < len)
{
struct linux_dirent64* l64;
struct bsd_dirent64* bsd;
int slen;
l64 = (struct linux_dirent64*) (buf + bpos);
bsd = (struct bsd_dirent64*) (ibuf + opos);
slen = strlen(l64->d_name);
if (len-opos < sizeof(struct bsd_dirent64) + slen + 1)
break;
bsd->d_ino = l64->d_ino;
bsd->d_type = l64->d_type;
strcpy(bsd->d_name, l64->d_name);
bsd->d_reclen = sizeof(struct bsd_dirent64) + slen + 1;
bsd->d_namlen = slen;
bsd->d_seekoff = 0;
round_to_4(&bsd->d_reclen);
opos += bsd->d_reclen;
bpos += l64->d_reclen;
}
/*
if (bpos < ret) {
__simple_printf("bpos < ret; %d < %d", bpos, ret);
}
*/
return opos;
}

View File

@ -0,0 +1,36 @@
#ifndef LINUX_GETDIRENTRIES_H
#define LINUX_GETDIRENTRIES_H
long sys_getdirentries(int fd, char* buf, unsigned int len, long* basep);
long sys_getdirentries64(int fd, char* buf, unsigned int len, long* basep);
struct linux_dirent64
{
unsigned long long d_ino;
unsigned long long d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[];
};
struct bsd_dirent
{
unsigned int d_ino;
unsigned short d_reclen;
unsigned char d_type;
unsigned char d_namlen;
char d_name[];
};
struct bsd_dirent64
{
unsigned long long d_ino;
unsigned long long d_seekoff;
unsigned short d_reclen;
unsigned short d_namlen;
unsigned char d_type;
char d_name[];
};
#endif

View File

@ -0,0 +1,134 @@
#ifndef DUCT_ERRNO_H
#define DUCT_ERRNO_H
#define LINUX_EPERM 1
#define LINUX_ENOENT 2
#define LINUX_ESRCH 3
#define LINUX_EINTR 4
#define LINUX_EIO 5
#define LINUX_ENXIO 6
#define LINUX_ENOEXEC 8
#define LINUX_EBADF 9
#define LINUX_ECHILD 10
#define LINUX_EAGAIN 11
#define LINUX_ENOMEM 12
#define LINUX_EACCES 13
#define LINUX_EFAULT 14
#define LINUX_ENOTBLK 15
#define LINUX_EBUSY 16
#define LINUX_EEXIST 17
#define LINUX_EXDEV 18
#define LINUX_ENODEV 19
#define LINUX_ENOTDIR 20
#define LINUX_EISDIR 21
#define LINUX_EINVAL 22
#define LINUX_ENFILE 23
#define LINUX_EMFILE 24
#define LINUX_ENOTTY 25
#define LINUX_ETXTBSY 26
#define LINUX_EFBIG 27
#define LINUX_ENOSPC 28
#define LINUX_ESPIPE 29
#define LINUX_EROFS 30
#define LINUX_EMLINK 31
#define LINUX_EPIPE 32
#define LINUX_EDOM 33
#define LINUX_ERANGE 34
#define LINUX_EDEADLK 35
#define LINUX_ENAMETOOLONG 36
#define LINUX_ENOLCK 37
#define LINUX_ENOSYS 38
#define LINUX_ENOTEMPTY 39
#define LINUX_ELOOP 40
#define LINUX_ENOMSG 42
#define LINUX_EIDRM 43
#define LINUX_ECHRNG 44
#define LINUX_ELNRNG 48
#define LINUX_EUNATCH 49
#define LINUX_ENOCSI 50
#define LINUX_EBADE 52
#define LINUX_EBADR 53
#define LINUX_EXFULL 54
#define LINUX_ENOANO 55
#define LINUX_EBADRQC 56
#define LINUX_EBADSLT 57
#define LINUX_EBFONT 59
#define LINUX_ENOSTR 60
#define LINUX_ENODATA 61
#define LINUX_ETIME 62
#define LINUX_ENOSR 63
#define LINUX_ENONET 64
#define LINUX_ENOPKG 65
#define LINUX_EREMOTE 66
#define LINUX_ENOLINK 67
#define LINUX_EADV 68
#define LINUX_ESRMNT 69
#define LINUX_ECOMM 70
#define LINUX_EPROTO 71
#define LINUX_EMULTIHOP 72
#define LINUX_EDOTDOT 73
#define LINUX_EBADMSG 74
#define LINUX_EOVERFLOW 75
#define LINUX_ENOTUNIQ 76
#define LINUX_EBADFD 77
#define LINUX_EREMCHG 78
#define LINUX_ELIBACC 79
#define LINUX_ELIBBAD 80
#define LINUX_ELIBSCN 81
#define LINUX_ELIBMAX 82
#define LINUX_ELIBEXEC 83
#define LINUX_EILSEQ 84
#define LINUX_ERESTART 85
#define LINUX_ESTRPIPE 86
#define LINUX_EUSERS 87
#define LINUX_ENOTSOCK 88
#define LINUX_EDESTADDRREQ 89
#define LINUX_EMSGSIZE 90
#define LINUX_EPROTOTYPE 91
#define LINUX_ENOPROTOOPT 92
#define LINUX_EPROTONOSUPPORT 93
#define LINUX_ESOCKTNOSUPPORT 94
#define LINUX_EOPNOTSUPP 95
#define LINUX_EPFNOSUPPORT 96
#define LINUX_EAFNOSUPPORT 97
#define LINUX_EADDRINUSE 98
#define LINUX_EADDRNOTAVAIL 99
#define LINUX_ENETDOWN 100
#define LINUX_ENETUNREACH 101
#define LINUX_ENETRESET 102
#define LINUX_ECONNABORTED 103
#define LINUX_ECONNRESET 104
#define LINUX_ENOBUFS 105
#define LINUX_EISCONN 106
#define LINUX_ENOTCONN 107
#define LINUX_ESHUTDOWN 108
#define LINUX_ETOOMANYREFS 109
#define LINUX_ETIMEDOUT 110
#define LINUX_ECONNREFUSED 111
#define LINUX_EHOSTDOWN 112
#define LINUX_EHOSTUNREACH 113
#define LINUX_EALREADY 114
#define LINUX_EINPROGRESS 115
#define LINUX_ESTALE 116
#define LINUX_EUCLEAN 117
#define LINUX_ENOTNAM 118
#define LINUX_ENAVAIL 119
#define LINUX_EISNAM 120
#define LINUX_EREMOTEIO 121
#define LINUX_EDQUOT 122
#define LINUX_ENOMEDIUM 123
#define LINUX_EMEDIUMTYPE 124
#define LINUX_ECANCELED 125
#define LINUX_ENOKEY 126
#define LINUX_EKEYEXPIRED 127
#define LINUX_EKEYREVOKED 128
#define LINUX_EKEYREJECTED 129
#define LINUX_EOWNERDEAD 130
#define LINUX_ENOTRECOVERABLE 131
#define LINUX_ERFKILL 132
#define LINUX_EHWPOISON 133
#define LINUX_ENOTSUP EOPNOTSUPP
#include <sys/errno.h>
#endif

View File

@ -0,0 +1,105 @@
#include "elfcalls_wrapper.h"
#include <elfcalls.h>
#include <dlfcn.h>
#include "simple.h"
extern struct elf_calls* _elfcalls;
struct elf_calls* elfcalls(void)
{
if (!_elfcalls)
{
//void* module = dlopen("/usr/lib/darling/libelfloader.dylib", RTLD_NOW);
// if (!module)
// __simple_printf("Load error: %s\n", dlerror());
// struct elf_calls** ptr = (struct elf_calls**) dlsym(module, "_elfcalls");
// __simple_printf("_elfcalls is at %p\n", ptr);
// __simple_printf("*_elfcalls = %p\n", *ptr);
//_elfcalls = *(struct elf_calls**) dlsym(module, "_elfcalls");
__simple_printf("elfcalls not found?\n");
__simple_abort();
}
return _elfcalls;
}
void native_exit(int ec)
{
if (_elfcalls)
_elfcalls->exit(ec);
}
long native_sysconf(int name)
{
if (_elfcalls)
return _elfcalls->sysconf(name);
return -1;
}
void* __darling_thread_create(unsigned long stack_size, unsigned long pthobj_size,
void* entry_point, uintptr_t arg3,
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6,
darling_thread_create_callbacks_t callbacks, void* dthread)
{
return elfcalls()->darling_thread_create(stack_size, pthobj_size, entry_point,
arg3, arg4, arg5, arg6, callbacks, dthread);
}
int __darling_thread_terminate(void* stackaddr,
unsigned long freesize, unsigned long pthobj_size)
{
return elfcalls()->darling_thread_terminate(stackaddr, freesize, pthobj_size);
}
void* __darling_thread_get_stack(void)
{
return elfcalls()->darling_thread_get_stack();
}
void* native_dlopen(const char* path)
{
return elfcalls()->dlopen(path);
}
char* native_dlerror(void)
{
return elfcalls()->dlerror();
}
void* native_dlsym(void* module, const char* name)
{
return elfcalls()->dlsym(module, name);
}
int native_dlclose(void* module)
{
return elfcalls()->dlclose(module);
}
const void* __dserver_socket_address(void) {
return elfcalls()->dserver_socket_address();
};
int __dserver_per_thread_socket(void) {
return elfcalls()->dserver_per_thread_socket();
};
void __dserver_per_thread_socket_refresh(void) {
return elfcalls()->dserver_per_thread_socket_refresh();
};
void __dserver_close_socket(int socket) {
return elfcalls()->dserver_close_socket(socket);
};
int __dserver_get_process_lifetime_pipe() {
return elfcalls()->dserver_get_process_lifetime_pipe();
}
int __dserver_process_lifetime_pipe_refresh(void) {
return elfcalls()->dserver_process_lifetime_pipe_refresh();
};
void __dserver_close_process_lifetime_pipe(int fd) {
return elfcalls()->dserver_close_process_lifetime_pipe(fd);
};

View File

@ -0,0 +1,45 @@
#ifndef _ELFCALLS_WRAPPER_H
#define _ELFCALLS_WRAPPER_H
#include <elfcalls.h>
#ifdef __cplusplus
extern "C" {
#endif
// Native library loading
void* native_dlopen(const char* path);
char* native_dlerror(void);
void* native_dlsym(void* module, const char* name);
int native_dlclose(void* module);
void native_exit(int ec);
long native_sysconf(int name);
// Native thread wrapping
void* __darling_thread_create(unsigned long stack_size, unsigned long pthobj_size,
void* entry_point, uintptr_t arg3,
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6,
darling_thread_create_callbacks_t callbacks, void* dthread);
int __darling_thread_terminate(void* stackaddr,
unsigned long freesize, unsigned long pthobj_size);
void* __darling_thread_get_stack(void);
const void* __dserver_socket_address(void);
int __dserver_per_thread_socket(void);
void __dserver_per_thread_socket_refresh(void);
void __dserver_close_socket(int socket);
int __dserver_get_process_lifetime_pipe(void);
int __dserver_process_lifetime_pipe_refresh(void);
void __dserver_close_process_lifetime_pipe(int fd);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,110 @@
#include "errno.h"
#include "base.h"
#include "duct_errno.h"
#include <stddef.h>
static const int linux_to_darwin[512] = {
[LINUX_EPERM] = EPERM,
[LINUX_ENOENT] = ENOENT,
[LINUX_ESRCH] = ESRCH,
[LINUX_EINTR] = EINTR,
[LINUX_EIO] = EIO,
[LINUX_ENXIO] = ENXIO,
[LINUX_ENOEXEC] = ENOEXEC,
[LINUX_EBADF] = EBADF,
[LINUX_ECHILD] = ECHILD,
[LINUX_EDEADLK] = EDEADLK,
[LINUX_ENOMEM] = ENOMEM,
[LINUX_EACCES] = EACCES,
[LINUX_EFAULT] = EFAULT,
[LINUX_ENOTBLK] = ENOTBLK,
[LINUX_EBUSY] = EBUSY,
[LINUX_EEXIST] = EEXIST,
[LINUX_EXDEV] = EXDEV,
[LINUX_ENODEV] = ENODEV,
[LINUX_ENOTDIR] = ENOTDIR,
[LINUX_EISDIR] = EISDIR,
[LINUX_EINVAL] = EINVAL,
[LINUX_ENFILE] = ENFILE,
[LINUX_EMFILE] = EMFILE,
[LINUX_ENOTTY] = ENOTTY,
[LINUX_ETXTBSY] = ETXTBSY,
[LINUX_EFBIG] = EFBIG,
[LINUX_ENOSPC] = ENOSPC,
[LINUX_ESPIPE] = ESPIPE,
[LINUX_EROFS] = EROFS,
[LINUX_EMLINK] = EMLINK,
[LINUX_EPIPE] = EPIPE,
[LINUX_EDOM] = EDOM,
[LINUX_ERANGE] = ERANGE,
[LINUX_EAGAIN] = EAGAIN,
[LINUX_EINPROGRESS] = EINPROGRESS,
[LINUX_EALREADY] = EALREADY,
[LINUX_ENOTSOCK] = ENOTSOCK,
[LINUX_EDESTADDRREQ] = EDESTADDRREQ,
[LINUX_EMSGSIZE] = EMSGSIZE,
[LINUX_EPROTOTYPE] = EPROTOTYPE,
[LINUX_ENOPROTOOPT] = ENOPROTOOPT,
[LINUX_EPROTONOSUPPORT] = EPROTONOSUPPORT,
[LINUX_ESOCKTNOSUPPORT] = ESOCKTNOSUPPORT,
[LINUX_ENOTSUP] = ENOTSUP,
[LINUX_EPFNOSUPPORT] = EPFNOSUPPORT,
[LINUX_EAFNOSUPPORT] = EAFNOSUPPORT,
[LINUX_EADDRINUSE] = EADDRINUSE,
[LINUX_EADDRNOTAVAIL] = EADDRNOTAVAIL,
[LINUX_ENETDOWN] = ENETDOWN,
[LINUX_ENETUNREACH] = ENETUNREACH,
[LINUX_ENETRESET] = ENETRESET,
[LINUX_ECONNABORTED] = ECONNABORTED,
[LINUX_ECONNRESET] = ECONNRESET,
[LINUX_ENOBUFS] = ENOBUFS,
[LINUX_EISCONN] = EISCONN,
[LINUX_ENOTCONN] = ENOTCONN,
[LINUX_ESHUTDOWN] = ESHUTDOWN,
[LINUX_ETOOMANYREFS] = ETOOMANYREFS,
[LINUX_ETIMEDOUT] = ETIMEDOUT,
[LINUX_ECONNREFUSED] = ECONNREFUSED,
[LINUX_ELOOP] = ELOOP,
[LINUX_ENAMETOOLONG] = ENAMETOOLONG,
[LINUX_EHOSTDOWN] = EHOSTDOWN,
[LINUX_EHOSTUNREACH] = EHOSTUNREACH,
[LINUX_ENOTEMPTY] = ENOTEMPTY,
[LINUX_EUSERS] = EUSERS,
[LINUX_EDQUOT] = EDQUOT,
[LINUX_ESTALE] = ESTALE,
[LINUX_EREMOTE] = EREMOTE,
[LINUX_ENOLCK] = ENOLCK,
[LINUX_ENOSYS] = ENOSYS,
[LINUX_EOVERFLOW] = EOVERFLOW,
[LINUX_ECANCELED] = ECANCELED,
[LINUX_EIDRM] = EIDRM,
[LINUX_ENOMSG] = ENOMSG,
[LINUX_EILSEQ] = EILSEQ,
[LINUX_EBADMSG] = EBADMSG,
[LINUX_EMULTIHOP] = EMULTIHOP,
[LINUX_ENODATA] = ENODATA,
[LINUX_ENOLINK] = ENOLINK,
[LINUX_ENOSR] = ENOSR,
[LINUX_ENOSTR] = ENOSTR,
[LINUX_EPROTO] = EPROTO,
[LINUX_ETIME] = ETIME,
[LINUX_EOPNOTSUPP] = EOPNOTSUPP,
};
const size_t length_of_translation_array = sizeof(linux_to_darwin)/sizeof(const int);
int errno_linux_to_bsd(int err)
{
int v = err;
if (v < 0)
v = -v;
if ((v < length_of_translation_array) && (linux_to_darwin[v]))
{
v = linux_to_darwin[v];
return (err < 0) ? -v : v;
}
return err;
}

View File

@ -0,0 +1,7 @@
#ifndef LINUX_ERRNO_H
#define LINUX_ERRNO_H
int errno_linux_to_bsd(int err);
#endif

View File

@ -0,0 +1,3 @@
This directory allows access to system calls not available on OS X (e.g.
epoll), which are used internally by Darling's components.

View File

@ -0,0 +1,22 @@
#include "./sys/linux_time.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int clock_gettime (int __clockid, struct timespec* __res)
{
int rv;
rv = LINUX_SYSCALL(__NR_clock_gettime, __clockid, __res);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,25 @@
#include "./sys/linux_time.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int clock_nanosleep (int __clockid, int __flags,
const struct timespec* __req,
struct timespec* __rem)
{
int rv;
rv = LINUX_SYSCALL(__NR_clock_nanosleep, __clockid, __flags,
__req, __rem);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,27 @@
#include "./sys/epoll.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int epoll_create (int __size)
{
#if defined(__NR_epoll_create)
int rv;
rv = LINUX_SYSCALL(__NR_epoll_create, __size);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
#else
// The size argument in __NR_epoll_create is ignored
return epoll_create1(0);
#endif
}

View File

@ -0,0 +1,22 @@
#include "./sys/epoll.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int epoll_create1 (int __flags)
{
int rv;
rv = LINUX_SYSCALL(__NR_epoll_create1, __flags);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,24 @@
#include "./sys/epoll.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int epoll_ctl (int __epfd, int __op, int __fd,
struct epoll_event *__event)
{
int rv;
rv = LINUX_SYSCALL(__NR_epoll_ctl, __epfd, __op, __fd,
__event);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,30 @@
#include "./sys/epoll.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
#include <string.h>
extern long cerror(int __err);
VISIBLE
int epoll_wait (int __epfd, struct epoll_event *__events,
int __maxevents, int __timeout)
{
int rv;
#if defined(__NR_epoll_wait)
rv = LINUX_SYSCALL(__NR_epoll_wait, __epfd, __events, __maxevents,
__timeout);
#else
rv = LINUX_SYSCALL(__NR_epoll_pwait, __epfd, __events, __maxevents,
__timeout, NULL);
#endif
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,29 @@
#include "./sys/eventfd.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int __linux_eventfd (int __count, int __flags)
{
int rv;
#if defined(__x86_64__) || defined(__i386__)
rv = LINUX_SYSCALL(__flags ? __NR_eventfd2 : __NR_eventfd, __count,
__flags);
#else
// It's not clear if 0 is offically a valid flag argument.
// But we don't really have a choice.
rv = LINUX_SYSCALL(__NR_eventfd2, __count, __flags);
#endif
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,15 @@
#include "./sys/eventfd.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
extern long read(int fd, void *buf, unsigned long count);
VISIBLE
int eventfd_read (int __fd, eventfd_t *__value)
{
return read(__fd, __value, sizeof(eventfd_t)) == sizeof(eventfd_t)
? 0 : -1;
}

View File

@ -0,0 +1,15 @@
#include "./sys/eventfd.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
extern long write(int fd, const void *buf, unsigned long count);
VISIBLE
int eventfd_write (int __fd, eventfd_t __value)
{
return write(__fd, &__value, sizeof(eventfd_t)) == sizeof(eventfd_t)
? 0 : -1;
}

View File

@ -0,0 +1,47 @@
#include "fanotify.h"
#include "../errno.h"
#include "../vchroot_expand.h"
#include "../bsdthread/per_thread_wd.h"
#include <sys/errno.h>
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
int fanotify_init(unsigned flags, unsigned event_f_flags)
{
int rv = LINUX_SYSCALL(__NR_fanotify_init, flags, event_f_flags);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}
int fanotify_mark(int fanotify_fd, unsigned flags, unsigned long long mask, int dfd, const char *pathname)
{
struct vchroot_expand_args vc;
if (!pathname)
return -EFAULT;
vc.flags = 0;
vc.dfd = dfd;
strcpy(vc.path, pathname);
int rv = vchroot_expand(&vc);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
rv = LINUX_SYSCALL(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, vc.path);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,20 @@
#ifndef _EXT_FANOTIFY_H
#define _EXT_FANOTIFY_H
#include "../base.h"
#ifdef __cplusplus
extern "C" {
#endif
VISIBLE
int fanotify_init(unsigned flags, unsigned event_f_flags);
VISIBLE
int fanotify_mark(int fanotify_fd, unsigned flags, unsigned long long mask, int dfd, const char *pathname);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,236 @@
#include "file_handle.h"
#include "../errno.h"
#include "../base.h"
#include "../vchroot_expand.h"
#include "../bsdthread/per_thread_wd.h"
#include "../fcntl/open.h"
#include "../simple.h"
#include <sys/errno.h>
#include "../unistd/close.h"
#include "../mach/lkm.h"
#include "../duct_errno.h"
#include "../unistd/access.h"
#include <linux-syscalls/linux.h>
#include <os/lock.h>
extern void free(void* ptr);
struct SavedRef
{
char* path;
int gen;
};
#define MOUNT_ID_SAVED (-100)
static struct SavedRef g_savedRefs[200];
static int g_nextSavedRef = 0, g_nextGen = 0;
static os_unfair_lock g_savedRefLock = OS_UNFAIR_LOCK_INIT;
void __attribute__((weak)) os_unfair_lock_unlock(os_unfair_lock_t lock) {}
void __attribute__((weak)) os_unfair_lock_lock(os_unfair_lock_t lock) {}
VISIBLE
int sys_name_to_handle(const char* name, RefData* ref, int follow)
{
int ret;
struct vchroot_expand_args vc;
vc.flags = follow ? VCHROOT_FOLLOW : 0;
vc.dfd = get_perthread_wd();
strcpy(vc.path, name);
ret = vchroot_expand(&vc);
if (ret < 0)
return errno_linux_to_bsd(ret);
ref->fh.handle_bytes = sizeof(RefData) - offsetof(RefData, fh.f_handle);
ret = LINUX_SYSCALL(__NR_name_to_handle_at, LINUX_AT_FDCWD, vc.path, &ref->fh, &ref->mount_id, 0);
// This is unfortunately the case for overlayfs, which doesn't support "nfs_export" along with "metacopy"
if (ret == -LINUX_EOPNOTSUPP && sys_access(name, 0) == 0)
{
os_unfair_lock_lock(&g_savedRefLock);
if (g_savedRefs[g_nextSavedRef].path)
free(g_savedRefs[g_nextSavedRef].path);
ref->gen = g_nextGen++;
g_savedRefs[g_nextSavedRef].path = strdup(name);
g_savedRefs[g_nextSavedRef].gen = ref->gen;
ref->mount_id = MOUNT_ID_SAVED;
ref->index = g_nextSavedRef;
g_nextSavedRef = (g_nextSavedRef + 1) % (sizeof(g_savedRefs) / sizeof(g_savedRefs[0]));
os_unfair_lock_unlock(&g_savedRefLock);
ret = 0;
}
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
}
VISIBLE
int sys_handle_to_name(RefData* ref, char name[4096])
{
if (ref->mount_id == MOUNT_ID_SAVED)
{
int ret = -ENOENT;
os_unfair_lock_lock(&g_savedRefLock);
if (g_savedRefs[ref->index].gen == ref->gen)
{
strlcpy(name, g_savedRefs[ref->index].path, 4096);
ret = sys_access(name, 0);
}
os_unfair_lock_unlock(&g_savedRefLock);
return ret;
}
// Now we need to find out the path of ref->mount_id
struct simple_readline_buf rbuf;
char line[1024];
int fd_m = sys_open("/proc/self/mountinfo", BSD_O_RDONLY, 0);
if (fd_m < 0)
return fd_m;
const char* mount_path = NULL;
__simple_readline_init(&rbuf);
while (__simple_readline(fd_m, &rbuf, line, sizeof(line)))
{
char *p, *saveptr;
p = strtok_r(line, " ", &saveptr);
if (p == NULL)
continue;
if (__simple_atoi(p, NULL) != ref->mount_id)
continue;
for (int i = 0; i < 4; i++)
{
p = strtok_r(NULL, " ", &saveptr);
if (p == NULL)
{
close_internal(fd_m);
return -ENOENT;
}
}
mount_path = p;
break;
}
close_internal(fd_m);
if (mount_path == NULL)
return -ENOENT;
// We have the path of the mount, lets get a file descriptor
#if defined(__NR_open)
fd_m = LINUX_SYSCALL(__NR_open, mount_path, LINUX_O_RDONLY, 0);
#else
fd_m = LINUX_SYSCALL(__NR_openat, LINUX_AT_FDCWD, mount_path, LINUX_O_RDONLY, 0);
#endif
if (fd_m < 0)
return fd_m;
struct handle_to_path_args args;
args.mfd = fd_m;
memcpy(args.fh, &ref->fh, sizeof(RefData) - offsetof(RefData, fh));
int ret = lkm_call(NR_handle_to_path, &args);
close_internal(fd_m);
if (ret < 0)
return errno_linux_to_bsd(ret);
struct vchroot_unexpand_args uargs;
strcpy(uargs.path, args.path);
ret = vchroot_unexpand(&uargs);
if (ret < 0)
return errno_linux_to_bsd(ret);
strcpy(name, uargs.path);
return 0;
}
// Requires CAP_DAC_READ_SEARCH
VISIBLE
int sys_open_by_handle(RefData* ref, int flags)
{
int linux_flags = oflags_bsd_to_linux(flags);
if (sizeof(void*) == 4)
linux_flags |= LINUX_O_LARGEFILE;
// Now we need to find out the path of ref->mount_id
struct simple_readline_buf rbuf;
char line[1024];
int fd_m = sys_open("/proc/self/mountinfo", BSD_O_RDONLY, 0);
if (fd_m < 0)
return fd_m;
const char* mount_path = NULL;
__simple_readline_init(&rbuf);
while (__simple_readline(fd_m, &rbuf, line, sizeof(line)))
{
char *p, *saveptr;
p = strtok_r(line, " ", &saveptr);
if (p == NULL)
continue;
if (__simple_atoi(p, NULL) != ref->mount_id)
continue;
for (int i = 0; i < 4; i++)
{
p = strtok_r(NULL, " ", &saveptr);
if (p == NULL)
{
close_internal(fd_m);
return -ENOENT;
}
}
mount_path = p;
break;
}
close_internal(fd_m);
if (mount_path == NULL)
return -ENOENT;
// We have the path of the mount, lets get a file descriptor
fd_m = sys_open(mount_path, BSD_O_RDONLY, 0);
if (fd_m < 0)
return fd_m;
// And now, finally, open the file by handle relative to the mount
int ret = LINUX_SYSCALL(__NR_open_by_handle_at, fd_m, &ref->fh, linux_flags);
close_internal(fd_m);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
}

View File

@ -0,0 +1,57 @@
#ifndef EXT_FILE_HANDLE_H
#define EXT_FILE_HANDLE_H
#include <stdint.h>
struct file_handle
{
uint32_t handle_bytes;
int handle_type;
uint8_t f_handle[1];
};
typedef struct {
union
{
uint8_t opaque[80];
struct
{
int mount_id;
union
{
struct file_handle fh;
struct
{
int index;
int gen;
};
};
};
};
} RefData;
// Like open_by_handle_at, but provides a path and doesn't need CAP_DAC_READ_SEARCH
struct handle_to_path_args
{
int mfd; // in
//int mntid; // in
char fh[80]; // in
char path[4096]; // out
};
#ifdef __cplusplus
extern "C" {
#endif
int sys_name_to_handle(const char* name, RefData* ref, int follow);
//int sys_open_by_handle(RefData* ref, int flags);
int sys_handle_to_name(RefData* ref, char name[4096]);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,43 @@
#include "for-libelfloader.h"
#include "../base.h"
#include "../errno.h"
#include "../bsdthread/cancelable.h"
#include "../bsdthread/per_thread_wd.h"
#include "../fcntl/open.h"
VISIBLE
long _open_for_libelfloader(const char* path, int flags, unsigned int mode) {
int linux_flags;
int wd;
int ret;
CANCELATION_POINT();
linux_flags = oflags_bsd_to_linux(flags);
wd = oflags_bsd_to_linux(flags);
if (sizeof(void*) == 4) {
linux_flags |= LINUX_O_LARGEFILE;
}
ret = LINUX_SYSCALL(__NR_openat, wd, path, linux_flags, mode);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
};
VISIBLE
long _access_for_libelfloader(const char* path, int mode) {
int ret;
int wd;
wd = get_perthread_wd();
ret = LINUX_SYSCALL(__NR_faccessat, wd, path, mode, 0);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
};

View File

@ -0,0 +1,14 @@
#ifndef _DARLING_EMULATION_FOR_LIBELFLOADER_H_
#define _DARLING_EMULATION_FOR_LIBELFLOADER_H_
#include <darling/emulation/base.h>
// these are non-vchrooted calls for libelfloader
VISIBLE
long _open_for_libelfloader(const char* path, int flags, unsigned int mode);
VISIBLE
long _access_for_libelfloader(const char* path, int mode);
#endif // _DARLING_EMULATION_FOR_LIBELFLOADER_H_

View File

@ -0,0 +1,22 @@
#include "for-libkqueue.h"
#include <darlingserver/rpc.h>
#include <linux-syscalls/linux.h>
#include "../errno.h"
int _dserver_rpc_kqchan_mach_port_open_4libkqueue(uint32_t port_name, void* receive_buffer, uint64_t receive_buffer_size, uint64_t saved_filter_flags, int* out_socket) {
return dserver_rpc_kqchan_mach_port_open(port_name, receive_buffer, receive_buffer_size, saved_filter_flags, out_socket);
};
int _dserver_rpc_kqchan_proc_open_4libkqueue(int32_t pid, uint32_t flags, int* out_socket) {
return dserver_rpc_kqchan_proc_open(pid, flags, out_socket);
};
int _dup_4libkqueue(int fd) {
int ret;
ret = LINUX_SYSCALL1(__NR_dup, fd);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
};

View File

@ -0,0 +1,17 @@
#ifndef _DARLING_EMULATION_FOR_LIBKQUEUE_H_
#define _DARLING_EMULATION_FOR_LIBKQUEUE_H_
#include <stdint.h>
#include <darling/emulation/base.h>
VISIBLE
int _dserver_rpc_kqchan_mach_port_open_4libkqueue(uint32_t port_name, void* receive_buffer, uint64_t receive_buffer_size, uint64_t saved_filter_flags, int* out_socket);
VISIBLE
int _dserver_rpc_kqchan_proc_open_4libkqueue(int32_t pid, uint32_t flags, int* out_socket);
VISIBLE
int _dup_4libkqueue(int fd);
#endif // _DARLING_EMULATION_FOR_LIBKQUEUE_H_

View File

@ -0,0 +1,41 @@
#include "for-xtrace.h"
#include "../mman/mman.h"
#include "../misc/abort_with_payload.h"
#include "../fcntl/open.h"
#include "../unistd/close.h"
VISIBLE
void* _mmap_for_xtrace(void* start, unsigned long len, int prot, int flags, int fd, long pos) {
return sys_mmap(start, len, prot, flags, fd, pos);
};
VISIBLE
long _munmap_for_xtrace(void* addr, unsigned long len) {
return sys_munmap(addr, len);
};
VISIBLE
long _abort_with_payload_for_xtrace(unsigned int reason_namespace, unsigned long long reason_code, void *payload, unsigned int payload_size, const char *reason_string, unsigned long long reason_flags) {
return sys_abort_with_payload(reason_namespace, reason_code, payload, payload_size, reason_string, reason_flags);
};
// __write_for_xtrace is in unistd/write.c
long _open_for_xtrace(const char* filename, int flags, unsigned int mode) {
return sys_open_nocancel(filename, flags, mode);
};
long _close_for_xtrace(int fd) {
return sys_close_nocancel(fd);
};
extern size_t default_sigaltstack_size;
long _sigaltstack_set_default_size_for_xtrace(size_t new_size) {
default_sigaltstack_size = new_size;
return 0;
};
long _sigaltstack_for_xtrace(const struct bsd_stack* ss, struct bsd_stack* oss) {
return sys_sigaltstack(ss, oss);
};

View File

@ -0,0 +1,33 @@
#ifndef _DARLING_EMULATION_FOR_XTRACE_H_
#define _DARLING_EMULATION_FOR_XTRACE_H_
#include <darling/emulation/base.h>
#include <darling/emulation/mman/duct_mman.h>
#include <darling/emulation/signal/sigaltstack.h>
VISIBLE
void* _mmap_for_xtrace(void* start, unsigned long len, int prot, int flags, int fd, long pos);
VISIBLE
long _munmap_for_xtrace(void* addr, unsigned long len);
VISIBLE
long _abort_with_payload_for_xtrace(unsigned int reason_namespace, unsigned long long reason_code, void *payload, unsigned int payload_size, const char *reason_string, unsigned long long reason_flags);
VISIBLE
long __write_for_xtrace(int fd, const void* mem, int len);
VISIBLE
long _open_for_xtrace(const char* filename, int flags, unsigned int mode);
VISIBLE
long _close_for_xtrace(int fd);
VISIBLE
long _sigaltstack_set_default_size_for_xtrace(size_t new_size);
// used to bypass the sigaltstack size requirements imposed by libc
VISIBLE
long _sigaltstack_for_xtrace(const struct bsd_stack* ss, struct bsd_stack* oss);
#endif // _DARLING_EMULATION_FOR_XTRACE_H_

View File

@ -0,0 +1,28 @@
#include "futex.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int __linux_futex (int *uaddr, int op, int val, const struct timespec *timeout,
int *uaddr2, int val3)
{
int rv;
rv = LINUX_SYSCALL(__NR_futex, uaddr, op, val, timeout, uaddr2, val3);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}
VISIBLE
int __linux_futex_reterr(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3) {
int rv = LINUX_SYSCALL(__NR_futex, uaddr, op, val, timeout, uaddr2, val3);
return (rv < 0) ? errno_linux_to_bsd(rv) : rv;
};

View File

@ -0,0 +1,14 @@
#ifndef EXT_FUTEX_H
#define EXT_FUTEX_H
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
struct timespec;
int __linux_futex (int *uaddr, int op, int val, const struct timespec *timeout,
int *uaddr2, int val3);
int __linux_futex_reterr(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3);
#endif

View File

@ -0,0 +1,39 @@
#include "./sys/inotify.h"
#include "../errno.h"
#include "../base.h"
#include "../vchroot_expand.h"
#include "../bsdthread/per_thread_wd.h"
#include <sys/errno.h>
#include "../errno.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int inotify_add_watch (int __fd, const char *__name, uint32_t __mask)
{
int rv;
struct vchroot_expand_args vc;
if (!__name)
return -EFAULT;
vc.flags = 0;
vc.dfd = get_perthread_wd();
strcpy(vc.path, __name);
rv = vchroot_expand(&vc);
if (rv < 0)
return errno_linux_to_bsd(rv);
rv = LINUX_SYSCALL(__NR_inotify_add_watch, __fd, vc.path, __mask);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,26 @@
#include "./sys/inotify.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int inotify_init (void)
{
#if defined(__NR_inotify_init)
int rv;
rv = LINUX_SYSCALL(__NR_inotify_init);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
#else
inotify_init1(0);
#endif
}

View File

@ -0,0 +1,22 @@
#include "./sys/inotify.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int inotify_init1 (int __flags)
{
int rv;
rv = LINUX_SYSCALL(__NR_inotify_init1, __flags);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,22 @@
#include "./sys/inotify.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int inotify_rm_watch (int __fd, int __wd)
{
int rv;
rv = LINUX_SYSCALL(__NR_inotify_rm_watch, __fd, __wd);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,22 @@
#include "mremap.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
long __linux_mremap(void* old_addr, unsigned long old_size, unsigned long new_size, int flags, void* new_address)
{
long rv;
rv = LINUX_SYSCALL(__NR_mremap, old_addr, old_size, new_size, flags, new_address);
if (rv < 0 && rv >= -4095)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,7 @@
#ifndef EXT_MREMAP_H
#define EXT_MREMAP_H
long __linux_mremap(void* old_addr, unsigned long old_size, unsigned long new_size, int flags, void* new_address);
#endif

View File

@ -0,0 +1,21 @@
#include "sys/utsname.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
extern void cerror(int e);
int __linux_nanosleep(struct timespec* ts, struct timespec* rem)
{
int rv;
rv = LINUX_SYSCALL(__NR_nanosleep, ts, rem);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,8 @@
#include "../base.h"
#include <linux-syscalls/linux.h>
void __linux_sched_yield(void)
{
LINUX_SYSCALL0(__NR_sched_yield);
}

View File

@ -0,0 +1,44 @@
#include "../fcntl/fcntl.h"
#include "./sys/signalfd.h"
#include "../errno.h"
#include "../base.h"
#include "../signal/duct_signals.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int signalfd (int __fd, const sigset_t *__mask, int __flags)
{
int rv, linux_flags = 0;
linux_sigset_t linux_mask;
sigset_bsd_to_linux(__mask, &linux_mask);
if (__flags & O_CLOEXEC)
linux_flags |= 02000000;
if (__flags & O_NONBLOCK)
linux_flags |= 04000;
#ifdef __NR_signalfd4
rv = LINUX_SYSCALL(__NR_signalfd4, __fd, &linux_mask, 8, linux_flags);
#else
rv = LINUX_SYSCALL(__NR_signalfd, __fd, &linux_mask, 8);
// handle flags
if (rv >= 0)
{
if (__flags & O_CLOEXEC)
sys_fcntl(rv, F_SETFD, BSD_FD_CLOEXEC);
if (__flags & O_NONBLOCK)
sys_fcntl(rv, F_SETFL, BSD_O_NONBLOCK);
}
#endif
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,61 @@
#ifndef LINUX_EPOLL_H
#define LINUX_EPOLL_H
#include <stdint.h>
#define epoll_create __linux_epoll_create
#define epoll_create1 __linux_epoll_create1
#define epoll_ctl __linux_epoll_ctl
#define epoll_wait __linux_epoll_wait
#define epoll_pwait __linux_epoll_pwait
#ifndef __THROW
# define __THROW
#endif
enum EPOLL_EVENTS
{
EPOLLIN = 0x001,
EPOLLPRI = 0x002,
EPOLLOUT = 0x004,
EPOLLRDNORM = 0x040,
EPOLLRDBAND = 0x080,
EPOLLWRNORM = 0x100,
EPOLLWRBAND = 0x200,
EPOLLMSG = 0x400,
EPOLLERR = 0x008,
EPOLLHUP = 0x010,
EPOLLRDHUP = 0x2000,
EPOLLWAKEUP = 1u << 29,
EPOLLONESHOT = 1u << 30,
EPOLLET = 1u << 31
};
#define EPOLL_CTL_ADD 1
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
typedef union epoll_data
{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event
{
uint32_t events;
epoll_data_t data;
} __attribute__((packed));
extern int epoll_create (int __size) __THROW;
extern int epoll_ctl (int __epfd, int __op, int __fd,
struct epoll_event *__event) __THROW;
extern int epoll_wait (int __epfd, struct epoll_event *__events,
int __maxevents, int __timeout);
#endif

View File

@ -0,0 +1,32 @@
#ifndef EXT_EVENTFD_H
#define EXT_EVENTFD_H
#include <stdint.h>
#ifndef __THROW
# define __THROW
#endif
// #define eventfd __linux_eventfd
#define eventfd_read __linux_eventfd_read
#define eventfd_write __linux_eventfd_write
enum {
EFD_SEMAPHORE = 00000001,
EFD_CLOEXEC = 02000000,
EFD_NONBLOCK = 00004000
};
typedef uint64_t eventfd_t;
extern int __linux_eventfd (int __count, int __flags) __THROW;
static inline int eventfd (int __count, int __flags)
{
return __linux_eventfd(__count, __flags);
}
extern int eventfd_read (int __fd, eventfd_t *__value);
extern int eventfd_write (int __fd, eventfd_t __value);
#endif

View File

@ -0,0 +1,70 @@
#ifndef EXT_INOTIFY_H
#define EXT_INOTIFY_H
#include <stdint.h>
#ifndef __THROW
# define __THROW
#endif
#define inotify_init __linux_inotify_init
#define inotify_init1 __linux_inotify_init1
#define inotify_add_watch __linux_inotify_add_watch
#define inotify_rm_watch __linux_inotify_rm_watch
struct inotify_event
{
int wd;
uint32_t mask;
uint32_t cookie;
uint32_t len;
char name[];
};
#define IN_ACCESS 0x00000001
#define IN_MODIFY 0x00000002
#define IN_ATTRIB 0x00000004
#define IN_CLOSE_WRITE 0x00000008
#define IN_CLOSE_NOWRITE 0x00000010
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
#define IN_OPEN 0x00000020
#define IN_MOVED_FROM 0x00000040
#define IN_MOVED_TO 0x00000080
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
#define IN_CREATE 0x00000100
#define IN_DELETE 0x00000200
#define IN_DELETE_SELF 0x00000400
#define IN_MOVE_SELF 0x00000800
#define IN_UNMOUNT 0x00002000
#define IN_Q_OVERFLOW 0x00004000
#define IN_IGNORED 0x00008000
#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO)
#define IN_ONLYDIR 0x01000000
#define IN_DONT_FOLLOW 0x02000000
#define IN_EXCL_UNLINK 0x04000000
#define IN_MASK_ADD 0x20000000
#define IN_ISDIR 0x40000000
#define IN_ONESHOT 0x80000000
#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \
| IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \
| IN_MOVED_TO | IN_CREATE | IN_DELETE \
| IN_DELETE_SELF | IN_MOVE_SELF)
#define IN_NONBLOCK 00004000
extern int inotify_init (void) __THROW;
extern int inotify_init1 (int __flags) __THROW;
extern int inotify_add_watch (int __fd, const char *__name, uint32_t __mask)
__THROW;
extern int inotify_rm_watch (int __fd, int __wd) __THROW;
#endif

View File

@ -0,0 +1,22 @@
#ifndef EXT_TIME_H
#define EXT_TIME_H
#include "timerfd.h"
#ifndef CLOCK_REALTIME
# define CLOCK_REALTIME 0
# define CLOCK_MONOTONIC 1
/* TODO: Other clocks */
#endif
#define TIMER_ABSTIME 1
#define clock_gettime __linux_clock_gettime
#define clock_nanosleep __linux_clock_nanosleep
extern int clock_gettime(int __clockid, struct timespec* __res);
extern int clock_nanosleep(int __clockid, int __flags,
const struct timespec* __req, struct timespec* __rem);
#endif

View File

@ -0,0 +1,36 @@
#ifndef EXT_SIGNALFD_H
#define EXT_SIGNALFD_H
#include <stdint.h>
#include <signal.h>
#include <fcntl.h>
#define SFD_CLOEXEC O_CLOEXEC
#define SFD_NONBLOCK O_NONBLOCK
#define signalfd __linux_signalfd
struct signalfd_siginfo
{
uint32_t ssi_signo;
int32_t ssi_errno;
int32_t ssi_code;
uint32_t ssi_pid;
uint32_t ssi_uid;
int32_t ssi_fd;
uint32_t ssi_tid;
uint32_t ssi_band;
uint32_t ssi_overrun;
uint32_t ssi_trapno;
int32_t ssi_status;
int32_t ssi_int;
uint64_t ssi_ptr;
uint64_t ssi_utime;
uint64_t ssi_stime;
uint64_t ssi_addr;
uint8_t __pad[48];
};
extern int signalfd (int __fd, const sigset_t *__mask, int __flags);
#endif

View File

@ -0,0 +1,68 @@
#ifndef EXT_TIMERFD_H
#define EXT_TIMERFD_H
#include <sys/types.h>
/*
* The contents of this file will probably change or go away
* when OS X implements this POSIX API.
*/
enum
{
TFD_TIMER_ABSTIME = 1 << 0
};
enum
{
TFD_CLOEXEC = 02000000,
TFD_NONBLOCK = 00004000
};
#ifndef __THROW
# define __THROW
#endif
#if !defined(__timespec_defined) && !defined(_STRUCT_TIMESPEC)
# define __timespec_defined 1
# define _STRUCT_TIMESPEC struct timespec
struct timespec
{
long tv_sec;
long tv_nsec;
};
#endif
struct itimerspec
{
struct timespec it_interval;
struct timespec it_value;
};
#define timerfd_create __linux_timerfd_create
#define timerfd_settime __linux_timerfd_settime
#define timerfd_gettime __linux_timerfd_gettime
#ifndef CLOCK_MONOTONIC
# define CLOCK_REALTIME 0
# define CLOCK_MONOTONIC 1
# define CLOCK_PROCESS_CPUTIME_ID 2
# define CLOCK_THREAD_CPUTIME_ID 3
# define CLOCK_MONOTONIC_RAW 4
# define CLOCK_REALTIME_COARSE 5
# define CLOCK_MONOTONIC_COARSE 6
# define CLOCK_BOOTTIME 7
# define CLOCK_REALTIME_ALARM 8
# define CLOCK_BOOTTIME_ALARM 9
# define CLOCK_TAI 11
#endif
extern int timerfd_create (int __clock_id, int __flags) __THROW;
extern int timerfd_settime (int __ufd, int __flags,
const struct itimerspec *__utmr,
struct itimerspec *__otmr) __THROW;
extern int timerfd_gettime (int __ufd, struct itimerspec *__otmr) __THROW;
#endif

View File

@ -0,0 +1,19 @@
#ifndef EXT_UNAME_H
#define EXT_UNAME_H
#define LINUX_UTSNAME_LENGTH 65
struct linux_utsname
{
char sysname[LINUX_UTSNAME_LENGTH];
char nodename[LINUX_UTSNAME_LENGTH];
char release[LINUX_UTSNAME_LENGTH];
char version[LINUX_UTSNAME_LENGTH];
char machine[LINUX_UTSNAME_LENGTH];
char domainname[LINUX_UTSNAME_LENGTH];
};
int __linux_uname(struct linux_utsname* p);
#endif

View File

@ -0,0 +1,19 @@
#include "sysinfo.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
int __linux_sysinfo(struct sysinfo* info)
{
int rv;
rv = LINUX_SYSCALL(__NR_sysinfo, info);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,24 @@
#ifndef _SYSINFO_H
#define _SYSINFO_H
struct sysinfo
{
long uptime;
unsigned long loads[3];
unsigned long totalram;
unsigned long freeram;
unsigned long sharedram;
unsigned long bufferram;
unsigned long totalswap;
unsigned long freeswap;
unsigned short procs;
unsigned long totalhigh;
unsigned long freehigh;
unsigned int mem_unit;
char _f[20-2*sizeof(long)-sizeof(int)];
};
int __linux_sysinfo(struct sysinfo* info);
#endif

View File

@ -0,0 +1,22 @@
#include "syslog.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int __linux_syslog (int type, char* bufp, int len)
{
int rv;
rv = LINUX_SYSCALL(__NR_syslog, type, bufp, len);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,10 @@
#ifndef EXT_SYSLOG_H
#define EXT_SYSLOG_H
#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10
int __linux_syslog (int type, char* bufp, int len);
#endif

View File

@ -0,0 +1,22 @@
#include "./sys/timerfd.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int timerfd_create (int __clock_id, int __flags)
{
int rv;
rv = LINUX_SYSCALL(__NR_timerfd_create, __clock_id, __flags);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,22 @@
#include "./sys/timerfd.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int timerfd_gettime (int __fd, struct itimerspec* __otmr)
{
int rv;
rv = LINUX_SYSCALL(__NR_timerfd_gettime, __fd, __otmr);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,24 @@
#include "./sys/timerfd.h"
#include "../errno.h"
#include "../base.h"
#include <linux-syscalls/linux.h>
extern long cerror(int __err);
VISIBLE
int timerfd_settime (int __fd, int __flags,
const struct itimerspec* __utmr,
struct itimerspec* __otmr)
{
int rv;
rv = LINUX_SYSCALL(__NR_timerfd_settime, __fd, __flags, __utmr, __otmr);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,21 @@
#include "sys/utsname.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
extern void cerror(int e);
int __linux_uname(struct linux_utsname* p)
{
int rv;
rv = LINUX_SYSCALL(__NR_uname, p);
if (rv < 0)
{
cerror(errno_linux_to_bsd(-rv));
return -1;
}
return rv;
}

View File

@ -0,0 +1,153 @@
#include "fcntl.h"
#include "open.h"
#include "../base.h"
#include "../simple.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include <sys/errno.h>
#include "../bsdthread/cancelable.h"
#include "../fdpath.h"
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0x0100
#endif
#ifndef O_DIRECTORY
# define O_DIRECTORY 0x100000
#endif
#ifndef MAXPATHLEN
# define MAXPATHLEN 1024
#endif
int oflags_bsd_to_linux(int flags);
int oflags_linux_to_bsd(int flags);
extern int sprintf(char *str, const char *format, ...);
long sys_readlink(const char* path, char* buf, unsigned long bsize);
extern void kqueue_dup(int oldfd, int newfd);
static short int flock_type_linux_to_bsd(short int linux) {
switch (linux) {
case LINUX_F_RDLCK: return F_RDLCK;
case LINUX_F_WRLCK: return F_WRLCK;
case LINUX_F_UNLCK: return F_UNLCK;
default: return -1;
};
};
static short int flock_type_bsd_to_linux(short int bsd) {
switch (bsd) {
case F_RDLCK: return LINUX_F_RDLCK;
case F_WRLCK: return LINUX_F_WRLCK;
case F_UNLCK: return LINUX_F_UNLCK;
default: return -1;
};
};
static int cmd_bsd_to_linux(int bsd) {
switch (bsd) {
case F_DUPFD: return LINUX_F_DUPFD;
case F_GETFD: return LINUX_F_GETFD;
case F_SETFD: return LINUX_F_SETFD;
case F_GETFL: return LINUX_F_GETFL;
case F_SETFL: return LINUX_F_SETFL;
case F_GETOWN: return LINUX_F_GETOWN;
case F_SETOWN: return LINUX_F_SETOWN;
case F_SETLK: return LINUX_F_SETLK;
case F_SETLKW: return LINUX_F_SETLKW;
case F_GETLK: return LINUX_F_GETLK;
case F_DUPFD_CLOEXEC: return LINUX_F_DUPFD_CLOEXEC;
default: return -1;
};
};
long sys_fcntl(int fd, int cmd, long arg)
{
CANCELATION_POINT();
return sys_fcntl_nocancel(fd, cmd, arg);
}
long sys_fcntl_nocancel(int fd, int cmd, long arg)
{
int ret, linux_cmd = cmd_bsd_to_linux(cmd);
long original_arg = arg;
switch (cmd)
{
case F_CHECK_LV:
return 0;
case F_SETFD:
if (arg & ~FD_CLOEXEC)
return -EINVAL;
break;
case F_SETFL:
arg = oflags_bsd_to_linux(arg);
break;
case F_GETPATH:
{
ret = fdpath(fd, arg, MAXPATHLEN);
if (ret < 0)
return errno_linux_to_bsd(ret);
return 0;
}
case F_SETLK:
case F_SETLKW:
case F_GETLK: {
struct bsd_flock* bsd_struct = arg;
struct linux_flock* linux_struct = __builtin_alloca(sizeof(struct linux_flock));
linux_struct->l_type = flock_type_bsd_to_linux(bsd_struct->l_type);
linux_struct->l_whence = bsd_struct->l_whence;
linux_struct->l_start = bsd_struct->l_start;
linux_struct->l_len = bsd_struct->l_len;
linux_struct->l_pid = bsd_struct->l_pid;
arg = linux_struct;
} break;
case F_FULLFSYNC: {
ret = LINUX_SYSCALL1(__NR_fsync, fd);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return 0;
};
// TODO: implement remaining commands
default:
if (linux_cmd == -1)
return -EINVAL;
}
#ifdef __NR_fcntl64
ret = LINUX_SYSCALL(__NR_fcntl64, fd, linux_cmd, arg);
#else
ret = LINUX_SYSCALL(__NR_fcntl, fd, linux_cmd, arg);
#endif
if (ret < 0)
{
ret = errno_linux_to_bsd(ret);
return ret;
}
switch (cmd)
{
case F_GETFL:
ret = oflags_linux_to_bsd(ret);
break;
case F_SETLK:
case F_SETLKW:
case F_GETLK: {
struct bsd_flock* bsd_struct = original_arg;
struct linux_flock* linux_struct = arg;
bsd_struct->l_type = flock_type_linux_to_bsd(linux_struct->l_type);
bsd_struct->l_whence = linux_struct->l_whence;
bsd_struct->l_start = linux_struct->l_start;
bsd_struct->l_len = linux_struct->l_len;
bsd_struct->l_pid = linux_struct->l_pid;
} break;
case F_DUPFD:
case F_DUPFD_CLOEXEC:
kqueue_dup(fd, ret);
break;
}
return ret;
}

View File

@ -0,0 +1,86 @@
#ifndef LINUX_FCNTL_H
#define LINUX_FCNTL_H
long sys_fcntl(int fd, int cmd, long arg);
long sys_fcntl_nocancel(int fd, int cmd, long arg);
enum {
LINUX_F_DUPFD = 0,
LINUX_F_GETFD,
LINUX_F_SETFD,
LINUX_F_GETFL,
LINUX_F_SETFL,
LINUX_F_GETLK,
LINUX_F_SETLK,
LINUX_F_SETLKW,
LINUX_F_SETOWN,
LINUX_F_GETOWN,
LINUX_F_SETSIG,
LINUX_F_GETSIG,
LINUX_F_GETLK64,
LINUX_F_SETLK64,
LINUX_F_SETLKW64,
LINUX_F_SETOWN_EX,
LINUX_F_GETOWN_EX,
LINUX_F_GETOWNER_UIDS,
LINUX_F_DUPFD_CLOEXEC = 1030,
};
enum {
F_DUPFD = 0,
F_GETFD,
F_SETFD,
F_GETFL,
F_SETFL,
F_GETOWN,
F_SETOWN,
F_GETLK,
F_SETLK,
F_SETLKW,
F_SETLKWTIMEOUT,
F_FLUSH_DATA = 40,
F_CHKCLEAN,
F_PREALLOCATE,
F_SETSIZE,
F_RDADVISE,
F_RDAHEAD,
F_GETPATH = 50,
F_FULLFSYNC = 51,
F_DUPFD_CLOEXEC = 67,
F_CHECK_LV = 98,
};
enum {
LINUX_F_RDLCK = 0,
LINUX_F_WRLCK,
LINUX_F_UNLCK,
};
enum {
F_RDLCK = 1,
F_UNLCK,
F_WRLCK,
};
#ifndef FD_CLOEXEC
# define FD_CLOEXEC 1
#endif
struct bsd_flock {
long long l_start;
long long l_len;
int l_pid;
short l_type;
short l_whence;
};
struct linux_flock {
short int l_type;
short int l_whence;
long int l_start;
long int l_len;
int l_pid;
};
#endif

View File

@ -0,0 +1,107 @@
#include "open.h"
#include "openat.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
//#include "../../../../platform-include/sys/fcntl.h"
#include "../../../../external/libc/include/fcntl.h"
#include "../bsdthread/per_thread_wd.h"
#include "../bsdthread/cancelable.h"
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0x0100
#endif
#ifndef O_CLOEXEC
# define O_CLOEXEC 0x1000000
#endif
#ifndef O_DIRECTORY
# define O_DIRECTORY 0x100000
#endif
#ifndef LINUX_O_PATH
#define LINUX_O_PATH 0x200000
#endif
int oflags_bsd_to_linux(int flags);
extern int strcmp(const char *s1, const char *s2);
long sys_open(const char* filename, int flags, unsigned int mode)
{
CANCELATION_POINT();
return sys_openat_nocancel(get_perthread_wd(), filename, flags, mode);
}
long sys_open_nocancel(const char* filename, int flags, unsigned int mode)
{
return sys_openat_nocancel(get_perthread_wd(), filename, flags, mode);
}
int oflags_bsd_to_linux(int flags)
{
int linux_flags = 0;
if (flags & BSD_O_RDONLY) /* always false */
linux_flags |= LINUX_O_RDONLY;
if (flags & BSD_O_WRONLY)
linux_flags |= LINUX_O_WRONLY;
if (flags & BSD_O_RDWR)
linux_flags |= LINUX_O_RDWR;
if (flags & BSD_O_NONBLOCK)
linux_flags |= LINUX_O_NONBLOCK;
if (flags & BSD_O_APPEND)
linux_flags |= LINUX_O_APPEND;
if (flags & BSD_O_CREAT)
linux_flags |= LINUX_O_CREAT;
if (flags & BSD_O_TRUNC)
linux_flags |= LINUX_O_TRUNC;
if (flags & BSD_O_EXCL)
linux_flags |= LINUX_O_EXCL;
if (flags & BSD_O_CLOEXEC)
linux_flags |= LINUX_O_CLOEXEC;
if (flags & BSD_O_NOFOLLOW || flags & BSD_O_SYMLINK)
linux_flags |= LINUX_O_NOFOLLOW;
if (flags & BSD_O_DIRECTORY)
linux_flags |= LINUX_O_DIRECTORY;
if (flags & BSD_O_CLOEXEC)
linux_flags |= LINUX_O_CLOEXEC;
if (flags & BSD_O_NOCTTY)
linux_flags |= LINUX_O_NOCTTY;
if (flags & BSD_O_SYMLINK)
linux_flags |= LINUX_O_PATH;
return linux_flags;
}
int oflags_linux_to_bsd(int flags)
{
int bsd_flags = 0;
if (flags & LINUX_O_RDONLY) /* always false */
bsd_flags |= BSD_O_RDONLY;
if (flags & LINUX_O_WRONLY)
bsd_flags |= BSD_O_WRONLY;
if (flags & LINUX_O_RDWR)
bsd_flags |= BSD_O_RDWR;
if (flags & LINUX_O_NONBLOCK)
bsd_flags |= BSD_O_NONBLOCK;
if (flags & LINUX_O_APPEND)
bsd_flags |= BSD_O_APPEND;
if (flags & LINUX_O_CREAT)
bsd_flags |= BSD_O_CREAT;
if (flags & LINUX_O_TRUNC)
bsd_flags |= BSD_O_TRUNC;
if (flags & LINUX_O_EXCL)
bsd_flags |= BSD_O_EXCL;
if (flags & LINUX_O_CLOEXEC)
bsd_flags |= BSD_O_CLOEXEC;
if (flags & LINUX_O_NOFOLLOW)
bsd_flags |= BSD_O_NOFOLLOW;
if (flags & LINUX_O_DIRECTORY)
bsd_flags |= BSD_O_DIRECTORY;
if (flags & LINUX_O_CLOEXEC)
bsd_flags |= BSD_O_CLOEXEC;
if (flags & LINUX_O_NOCTTY)
bsd_flags |= BSD_O_NOCTTY;
return bsd_flags;
}

View File

@ -0,0 +1,43 @@
#ifndef LINUX_OPEN_H
#define LINUX_OPEN_H
long sys_open(const char* filename, int flags, unsigned int mode);
long sys_open_nocancel(const char* filename, int flags, unsigned int mode);
#define LINUX_O_RDONLY 00
#define LINUX_O_WRONLY 01
#define LINUX_O_RDWR 02
#define LINUX_O_CREAT 0100
#define LINUX_O_EXCL 0200
#define LINUX_O_NOCTTY 0400
#define LINUX_O_TRUNC 01000
#define LINUX_O_APPEND 02000
#define LINUX_O_NONBLOCK 04000
#define LINUX_O_SYNC 04010000
#define LINUX_O_ASYNC 020000
#define LINUX_O_CLOEXEC 02000000
#define LINUX_O_LARGEFILE 0100000
#define LINUX_O_NOFOLLOW 0400000
#define LINUX_O_DIRECTORY 0200000
#define BSD_O_RDONLY 0
#define BSD_O_WRONLY 1
#define BSD_O_RDWR 2
#define BSD_O_NONBLOCK 4
#define BSD_O_APPEND 8
#define BSD_O_SHLOCK 0x10
#define BSD_O_EXLOCK 0x20
#define BSD_O_ASYNC 0x40
#define BSD_O_NOFOLLOW 0x100
#define BSD_O_CREAT 0x200
#define BSD_O_TRUNC 0x400
#define BSD_O_EXCL 0x800
#define BSD_O_NOCTTY 0x20000
#define BSD_O_DIRECTORY 0x100000
#define BSD_O_SYMLINK 0x200000
#define BSD_O_CLOEXEC 0x1000000
int oflags_bsd_to_linux(int flags);
#endif

View File

@ -0,0 +1,88 @@
#include "openat.h"
#include "open.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include "../../../../external/libc/include/fcntl.h"
#include "../common_at.h"
#include "../simple.h"
#include "../vchroot_expand.h"
#include "../bsdthread/cancelable.h"
#include <darlingserver/rpc.h>
#ifndef O_NOFOLLOW
# define O_NOFOLLOW 0x0100
#endif
#ifndef O_CLOEXEC
# define O_CLOEXEC 0x1000000
#endif
#ifndef O_DIRECTORY
# define O_DIRECTORY 0x100000
#endif
extern int strcmp(const char *s1, const char *s2);
extern char* strcpy(char* dst, const char* src);
long sys_openat(int fd, const char* filename, int flags, unsigned int mode)
{
CANCELATION_POINT();
return sys_openat_nocancel(fd, filename, flags, mode);
}
long sys_openat_nocancel(int fd, const char* filename, int flags, unsigned int mode)
{
int ret, linux_flags;
if (!filename)
return -EFAULT;
linux_flags = oflags_bsd_to_linux(flags);
if (sizeof(void*) == 4)
{
linux_flags |= LINUX_O_LARGEFILE;
}
// XNU /dev/random behaves like Linux /dev/urandom
if (strcmp(filename, "/dev/random") == 0)
filename = "/dev/urandom";
// Expected by launchd and CF
else if (strcmp(filename, "/dev/autofs_nowait") == 0)
filename = "/dev/null";
else if (strcmp(filename, "/dev/console") == 0) {
// redirect console output to darlingserver
int err = dserver_rpc_console_open(&ret);
if (err < 0) {
__simple_printf("dserver_rpc_console_open failed internally: %d", err);
__simple_abort();
}
if (err > 0) {
ret = errno_linux_to_bsd(-err);
}
return ret;
}
struct vchroot_expand_args vc;
vc.flags = (flags & BSD_O_SYMLINK || flags & BSD_O_NOFOLLOW) ? 0 : VCHROOT_FOLLOW;
vc.dfd = atfd(fd);
strcpy(vc.path, filename);
ret = vchroot_expand(&vc);
if (ret < 0) {
return errno_linux_to_bsd(ret);
}
// when we're given O_SYMLINK, `oflags_bsd_to_linux` translates it into
// O_NOFOLLOW and O_PATH
// this is the only way to open the symlink itself on Linux
// unfortunately, this presents additional challenges
// only a select few Linux syscalls support O_PATH descriptors, which means
// that for other syscalls, we either have to check for this and use an
// `l` variant (e.g. `llistxattr` instead of `listxatrr`) or we're screwed
ret = LINUX_SYSCALL(__NR_openat, vc.dfd, vc.path, linux_flags, mode);
if (ret < 0)
ret = errno_linux_to_bsd(ret);
return ret;
}

View File

@ -0,0 +1,8 @@
#ifndef LINUX_OPENAT_H
#define LINUX_OPENAT_H
long sys_openat(int fd, const char* filename, int flags, unsigned int mode);
long sys_openat_nocancel(int fd, const char* filename, int flags, unsigned int mode);
#endif

View File

@ -0,0 +1,16 @@
#include "fdpath.h"
#include "mach/lkm.h"
#include "vchroot_expand.h"
int fdpath(int fd, char* buf, size_t bufsiz)
{
struct vchroot_fdpath_args args = {
.fd = fd,
.path = buf,
.maxlen = bufsiz
};
// return lkm_call(NR_vchroot_fdpath, &args);
return vchroot_fdpath(&args);
}

View File

@ -0,0 +1,8 @@
#ifndef _FDPATH_H
#define _FDPATH_H
#include <stddef.h>
int fdpath(int fd, char* buf, size_t bufsiz);
#endif

View File

@ -0,0 +1,12 @@
#include "guarded_close_np.h"
#include "../base.h"
#include "../errno.h"
#include <linux-syscalls/linux.h>
#include "../unistd/close.h"
long sys_guarded_close_np(int fd, uint64_t* guardid)
{
*guardid = 0;
return sys_close(fd);
}

Some files were not shown because too many files have changed in this diff Show More