mirror of
https://github.com/darlinghq/darling-xnu.git
synced 2024-11-26 22:10:24 +00:00
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:
parent
89fa103bd5
commit
4d0d5857b9
80
darling/src/libsystem_kernel/CMakeLists.txt
Normal file
80
darling/src/libsystem_kernel/CMakeLists.txt
Normal 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)
|
333
darling/src/libsystem_kernel/emulation/linux/CMakeLists.txt
Normal file
333
darling/src/libsystem_kernel/emulation/linux/CMakeLists.txt
Normal 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)
|
||||
|
@ -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;
|
||||
};
|
@ -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
|
38
darling/src/libsystem_kernel/emulation/linux/base.c
Normal file
38
darling/src/libsystem_kernel/emulation/linux/base.c
Normal 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
|
||||
|
40
darling/src/libsystem_kernel/emulation/linux/base.h
Normal file
40
darling/src/libsystem_kernel/emulation/linux/base.h
Normal 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,5 @@
|
||||
#include "bsdthread_ctl.h"
|
||||
|
||||
long sys_bsdthread_ctl(long command, void* arg1, void* arg2, void* arg3) {
|
||||
return 0;
|
||||
};
|
@ -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
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef DISABLE_THREADSIGNAL_H
|
||||
#define DISABLE_THREADSIGNAL_H
|
||||
|
||||
long sys_disable_threadsignal(int disable);
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef PTHREAD_CANCELED_H
|
||||
#define PTHREAD_CANCELED_H
|
||||
|
||||
long sys_pthread_canceled(int action);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef PTHREAD_CHDIR_H
|
||||
#define PTHREAD_CHDIR_H
|
||||
|
||||
long sys_pthread_chdir(const char* path);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef PTHREAD_FCHDIR_H
|
||||
#define PTHREAD_FCHDIR_H
|
||||
|
||||
long sys_pthread_fchdir(int fd);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef PTHREAD_KILL_H
|
||||
#define PTHREAD_KILL_H
|
||||
|
||||
long sys_pthread_kill(int thread_port, int sig);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef PTHREAD_MARKCANCEL_H
|
||||
#define PTHREAD_MARKCANCEL_H
|
||||
|
||||
long sys_pthread_markcancel(unsigned int thread_port);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef WORKQ_OPEN_H
|
||||
#define WORKQ_OPEN_H
|
||||
|
||||
long sys_workq_open(void);
|
||||
|
||||
#endif
|
||||
|
23
darling/src/libsystem_kernel/emulation/linux/common_at.c
Normal file
23
darling/src/libsystem_kernel/emulation/linux/common_at.c
Normal 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;
|
||||
}
|
21
darling/src/libsystem_kernel/emulation/linux/common_at.h
Normal file
21
darling/src/libsystem_kernel/emulation/linux/common_at.h
Normal 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
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef LINUX_FPATHCONF_H
|
||||
#define LINUX_FPATHCONF_H
|
||||
|
||||
long sys_fpathconf(int fd, int name);
|
||||
|
||||
#endif
|
||||
|
11
darling/src/libsystem_kernel/emulation/linux/conf/pathconf.c
Normal file
11
darling/src/libsystem_kernel/emulation/linux/conf/pathconf.c
Normal 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);
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
#ifndef LINUX_PATHCONF_H
|
||||
#define LINUX_PATHCONF_H
|
||||
|
||||
long sys_pathconf(const char* file, int name);
|
||||
|
||||
#endif
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
134
darling/src/libsystem_kernel/emulation/linux/duct_errno.h
Normal file
134
darling/src/libsystem_kernel/emulation/linux/duct_errno.h
Normal 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
|
105
darling/src/libsystem_kernel/emulation/linux/elfcalls_wrapper.c
Normal file
105
darling/src/libsystem_kernel/emulation/linux/elfcalls_wrapper.c
Normal 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);
|
||||
};
|
@ -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
|
||||
|
110
darling/src/libsystem_kernel/emulation/linux/errno.c
Normal file
110
darling/src/libsystem_kernel/emulation/linux/errno.c
Normal 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;
|
||||
}
|
||||
|
7
darling/src/libsystem_kernel/emulation/linux/errno.h
Normal file
7
darling/src/libsystem_kernel/emulation/linux/errno.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef LINUX_ERRNO_H
|
||||
#define LINUX_ERRNO_H
|
||||
|
||||
int errno_linux_to_bsd(int err);
|
||||
|
||||
#endif
|
||||
|
3
darling/src/libsystem_kernel/emulation/linux/ext/README
Normal file
3
darling/src/libsystem_kernel/emulation/linux/ext/README
Normal 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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
24
darling/src/libsystem_kernel/emulation/linux/ext/epoll_ctl.c
Normal file
24
darling/src/libsystem_kernel/emulation/linux/ext/epoll_ctl.c
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
29
darling/src/libsystem_kernel/emulation/linux/ext/eventfd.c
Normal file
29
darling/src/libsystem_kernel/emulation/linux/ext/eventfd.c
Normal 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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
47
darling/src/libsystem_kernel/emulation/linux/ext/fanotify.c
Normal file
47
darling/src/libsystem_kernel/emulation/linux/ext/fanotify.c
Normal 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;
|
||||
}
|
20
darling/src/libsystem_kernel/emulation/linux/ext/fanotify.h
Normal file
20
darling/src/libsystem_kernel/emulation/linux/ext/fanotify.h
Normal 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
|
236
darling/src/libsystem_kernel/emulation/linux/ext/file_handle.c
Normal file
236
darling/src/libsystem_kernel/emulation/linux/ext/file_handle.c
Normal 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;
|
||||
}
|
||||
|
@ -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
|
@ -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;
|
||||
};
|
@ -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_
|
@ -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;
|
||||
};
|
@ -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_
|
@ -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);
|
||||
};
|
@ -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_
|
28
darling/src/libsystem_kernel/emulation/linux/ext/futex.c
Normal file
28
darling/src/libsystem_kernel/emulation/linux/ext/futex.c
Normal 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;
|
||||
};
|
14
darling/src/libsystem_kernel/emulation/linux/ext/futex.h
Normal file
14
darling/src/libsystem_kernel/emulation/linux/ext/futex.h
Normal 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
22
darling/src/libsystem_kernel/emulation/linux/ext/mremap.c
Normal file
22
darling/src/libsystem_kernel/emulation/linux/ext/mremap.c
Normal 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
21
darling/src/libsystem_kernel/emulation/linux/ext/nanosleep.c
Normal file
21
darling/src/libsystem_kernel/emulation/linux/ext/nanosleep.c
Normal 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;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#include "../base.h"
|
||||
#include <linux-syscalls/linux.h>
|
||||
|
||||
void __linux_sched_yield(void)
|
||||
{
|
||||
LINUX_SYSCALL0(__NR_sched_yield);
|
||||
}
|
||||
|
44
darling/src/libsystem_kernel/emulation/linux/ext/signalfd.c
Normal file
44
darling/src/libsystem_kernel/emulation/linux/ext/signalfd.c
Normal 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;
|
||||
}
|
||||
|
61
darling/src/libsystem_kernel/emulation/linux/ext/sys/epoll.h
Normal file
61
darling/src/libsystem_kernel/emulation/linux/ext/sys/epoll.h
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
19
darling/src/libsystem_kernel/emulation/linux/ext/sysinfo.c
Normal file
19
darling/src/libsystem_kernel/emulation/linux/ext/sysinfo.c
Normal 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;
|
||||
}
|
||||
|
24
darling/src/libsystem_kernel/emulation/linux/ext/sysinfo.h
Normal file
24
darling/src/libsystem_kernel/emulation/linux/ext/sysinfo.h
Normal 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
|
||||
|
22
darling/src/libsystem_kernel/emulation/linux/ext/syslog.c
Normal file
22
darling/src/libsystem_kernel/emulation/linux/ext/syslog.c
Normal 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;
|
||||
}
|
||||
|
10
darling/src/libsystem_kernel/emulation/linux/ext/syslog.h
Normal file
10
darling/src/libsystem_kernel/emulation/linux/ext/syslog.h
Normal 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
21
darling/src/libsystem_kernel/emulation/linux/ext/uname.c
Normal file
21
darling/src/libsystem_kernel/emulation/linux/ext/uname.c
Normal 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;
|
||||
}
|
||||
|
153
darling/src/libsystem_kernel/emulation/linux/fcntl/fcntl.c
Normal file
153
darling/src/libsystem_kernel/emulation/linux/fcntl/fcntl.c
Normal 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;
|
||||
}
|
||||
|
86
darling/src/libsystem_kernel/emulation/linux/fcntl/fcntl.h
Normal file
86
darling/src/libsystem_kernel/emulation/linux/fcntl/fcntl.h
Normal 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
|
||||
|
107
darling/src/libsystem_kernel/emulation/linux/fcntl/open.c
Normal file
107
darling/src/libsystem_kernel/emulation/linux/fcntl/open.c
Normal 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;
|
||||
}
|
43
darling/src/libsystem_kernel/emulation/linux/fcntl/open.h
Normal file
43
darling/src/libsystem_kernel/emulation/linux/fcntl/open.h
Normal 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
|
||||
|
88
darling/src/libsystem_kernel/emulation/linux/fcntl/openat.c
Normal file
88
darling/src/libsystem_kernel/emulation/linux/fcntl/openat.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
16
darling/src/libsystem_kernel/emulation/linux/fdpath.c
Normal file
16
darling/src/libsystem_kernel/emulation/linux/fdpath.c
Normal 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);
|
||||
}
|
||||
|
8
darling/src/libsystem_kernel/emulation/linux/fdpath.h
Normal file
8
darling/src/libsystem_kernel/emulation/linux/fdpath.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef _FDPATH_H
|
||||
#define _FDPATH_H
|
||||
#include <stddef.h>
|
||||
|
||||
int fdpath(int fd, char* buf, size_t bufsiz);
|
||||
|
||||
#endif
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user