From d5907da8111ec6c32dd0798573b391b56ba978c3 Mon Sep 17 00:00:00 2001 From: Trung Nguyen <57174311+trungnt2910@users.noreply.github.com> Date: Mon, 10 Feb 2025 13:17:58 +1100 Subject: [PATCH 1/2] libs: Add back checks needed for Haiku - Checks for non-POSIX headers: `HAVE_SYS_STATFS_H` and `HAVE_MNTENT_H`. - Checks for `sizeof(dirent::d_name)`. - Checks for non-standard `struct statvfs::f_basetype` member. These were removed in #103441 but required for Haiku builds. --- src/native/libs/Common/pal_config.h.in | 5 +++++ src/native/libs/configure.cmake | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/native/libs/Common/pal_config.h.in b/src/native/libs/Common/pal_config.h.in index c8e43fa37dd6a7..5901173e1c7ea0 100644 --- a/src/native/libs/Common/pal_config.h.in +++ b/src/native/libs/Common/pal_config.h.in @@ -32,6 +32,7 @@ #cmakedefine01 HAVE_MNTINFO #cmakedefine01 HAVE_STATFS_FSTYPENAME #cmakedefine01 HAVE_STATVFS_FSTYPENAME +#cmakedefine01 HAVE_STATVFS_BASETYPE #cmakedefine01 HAVE_NON_LEGACY_STATFS #cmakedefine01 HAVE_STRCPY_S #cmakedefine01 HAVE_STRLCPY @@ -88,6 +89,7 @@ #cmakedefine01 HAVE_NETPACKET_PACKET_H #cmakedefine01 HAVE_NET_IF_ARP_H #cmakedefine01 HAVE_SYS_MNTENT_H +#cmakedefine01 HAVE_MNTENT_H #cmakedefine01 HAVE_NET_IFMEDIA_H #cmakedefine01 HAVE_IOS_NET_IFMEDIA_H #cmakedefine01 HAVE_LINUX_RTNETLINK_H @@ -128,6 +130,7 @@ #cmakedefine01 HAVE_TERMIOS_H #cmakedefine01 HAVE_DLFCN_H #cmakedefine01 HAVE_PTHREAD_H +#cmakedefine01 HAVE_SYS_STATFS_H #cmakedefine01 HAVE_SYS_STATVFS_H #cmakedefine01 HAVE_NET_IF_H #cmakedefine01 HAVE_SYS_PROCINFO_H @@ -141,6 +144,8 @@ #cmakedefine01 HAVE_MAKEDEV_SYSMACROSH #cmakedefine01 HAVE_GETGRGID_R #cmakedefine01 HAVE_TERMIOS2 +#cmakedefine01 HAVE_DIRENT_NAME_SIZE +#cmakedefine01 DIRENT_NAME_SIZE #ifndef HOST_WASI #cmakedefine01 HAVE_GETRUSAGE diff --git a/src/native/libs/configure.cmake b/src/native/libs/configure.cmake index fc7332a54f9fac..bd348980539412 100644 --- a/src/native/libs/configure.cmake +++ b/src/native/libs/configure.cmake @@ -324,7 +324,17 @@ check_struct_has_member( "sys/mount.h" HAVE_STATVFS_FSTYPENAME) +check_struct_has_member( + "struct statvfs" + f_basetype + "sys/statvfs.h" + HAVE_STATVFS_BASETYPE) + set(CMAKE_EXTRA_INCLUDE_FILES dirent.h) +check_type_size( + "((struct dirent*)0)->d_name" + DIRENT_NAME_SIZE) +set(CMAKE_EXTRA_INCLUDE_FILES) # statfs: Find whether this struct exists if (HAVE_STATFS_FSTYPENAME OR HAVE_STATVFS_FSTYPENAME) @@ -882,6 +892,10 @@ check_include_files( "dlfcn.h" HAVE_DLFCN_H) +check_include_files( + "sys/statfs.h" + HAVE_SYS_STATFS_H) + check_include_files( "sys/statvfs.h" HAVE_SYS_STATVFS_H) @@ -955,6 +969,10 @@ check_include_files( "sys/mntent.h" HAVE_SYS_MNTENT_H) +check_include_files( + "mntent.h" + HAVE_MNTENT_H) + check_include_files( "stdint.h;net/if_media.h" HAVE_NET_IFMEDIA_H) From 1d6ffaba39a431bceb0304d685ddfa394d6cbac7 Mon Sep 17 00:00:00 2001 From: Trung Nguyen <57174311+trungnt2910@users.noreply.github.com> Date: Wed, 1 May 2024 00:18:55 +1000 Subject: [PATCH 2/2] Haiku: Initial runtime support This contains a part of the code required to build CoreCLR and get `paltests` to pass on Haiku. This commit covers native support code for the host and runtime libraries, which is located in `src/native/**`. Co-authored-by: Jessica Hamilton --- src/native/corehost/hostmisc/pal.unix.cpp | 51 +++++++++++++++- src/native/eventpipe/ds-ipc-pal-socket.c | 2 +- .../libs/System.Native/pal_dynamicload.c | 3 + src/native/libs/System.Native/pal_io.c | 49 +++++++++++++-- src/native/libs/System.Native/pal_memory.c | 2 +- src/native/libs/System.Native/pal_mount.c | 60 ++++++++++++++++++- .../libs/System.Native/pal_networkchange.c | 6 +- .../libs/System.Native/pal_networking.c | 11 ++++ .../pal_x509.c | 9 ++- src/native/minipal/getexepath.h | 13 ++++ 10 files changed, 193 insertions(+), 13 deletions(-) diff --git a/src/native/corehost/hostmisc/pal.unix.cpp b/src/native/corehost/hostmisc/pal.unix.cpp index 0ffc859cb9a5a0..f51e5e4b573c90 100644 --- a/src/native/corehost/hostmisc/pal.unix.cpp +++ b/src/native/corehost/hostmisc/pal.unix.cpp @@ -30,7 +30,11 @@ #include #include #include -#endif +#elif defined(TARGET_HAIKU) +#include +#include +#include +#endif // TARGET_HAIKU #if !HAVE_DIRENT_D_TYPE #define DT_UNKNOWN 0 @@ -136,6 +140,7 @@ bool pal::getcwd(pal::string_t* recv) return true; } +#if !defined(TARGET_HAIKU) namespace { bool get_loaded_library_from_proc_maps(const pal::char_t* library_name, pal::dll_t* dll, pal::string_t* path) @@ -183,6 +188,7 @@ namespace return true; } } +#endif // !TARGET_HAIKU bool pal::get_loaded_library( const char_t* library_name, @@ -197,6 +203,33 @@ bool pal::get_loaded_library( #endif library_name_local.append(library_name); +#if defined(TARGET_HAIKU) + // Haiku does not have RTLD_NOLOAD so dlopen will attempt to load the library + // instead of fetching a handle to the already loaded one. + int32 cookie = 0; + image_info info; + + while (get_next_image_info(0, &cookie, &info) == B_OK) + { + if (info.type != B_LIBRARY_IMAGE) + continue; + + pal::string_t path_local(info.name); + size_t pos = path_local.rfind(DIR_SEPARATOR); + if (pos == std::string::npos) + continue; + + pos = path_local.find(library_name, pos); + if (pos != std::string::npos) + { + *dll = (pal::dll_t)(intptr_t)info.id; + path->assign(path_local); + return true; + } + } + + return false; +#else dll_t dll_maybe = dlopen(library_name_local.c_str(), RTLD_LAZY | RTLD_NOLOAD); if (dll_maybe == nullptr) { @@ -223,6 +256,7 @@ bool pal::get_loaded_library( *dll = dll_maybe; path->assign(info.dli_fname); return true; +#endif // !TARGET_HAIKU } bool pal::load_library(const string_t* path, dll_t* dll) @@ -768,6 +802,21 @@ pal::string_t pal::get_current_os_rid_platform() return ridOS; } +#elif defined(TARGET_HAIKU) +pal::string_t pal::get_current_os_rid_platform() +{ + pal::string_t ridOS; + struct utsname utsname_obj; + if (uname(&utsname_obj) < 0) + { + return ridOS; + } + + ridOS.append(_X("haiku.")) + .append(utsname_obj.release); // e.g. haiku.1 + + return ridOS; +} #else // For some distros, we don't want to use the full version from VERSION_ID. One example is // Red Hat Enterprise Linux, which includes a minor version in their VERSION_ID but minor diff --git a/src/native/eventpipe/ds-ipc-pal-socket.c b/src/native/eventpipe/ds-ipc-pal-socket.c index 104879298e92af..c9764e6a3ffd6a 100644 --- a/src/native/eventpipe/ds-ipc-pal-socket.c +++ b/src/native/eventpipe/ds-ipc-pal-socket.c @@ -433,7 +433,7 @@ inline int ipc_socket_set_permission (ds_ipc_socket_t s) { -#if defined(DS_IPC_PAL_AF_UNIX) && !(defined(__APPLE__) || defined(__FreeBSD__)) +#if defined(DS_IPC_PAL_AF_UNIX) && !(defined(__APPLE__) || defined(__FreeBSD__) || defined(__HAIKU__)) int result_fchmod; DS_ENTER_BLOCKING_PAL_SECTION; do { diff --git a/src/native/libs/System.Native/pal_dynamicload.c b/src/native/libs/System.Native/pal_dynamicload.c index 76f9c56678af5c..1f46763fbdb01a 100644 --- a/src/native/libs/System.Native/pal_dynamicload.c +++ b/src/native/libs/System.Native/pal_dynamicload.c @@ -21,6 +21,7 @@ void* SystemNative_LoadLibrary(const char* filename) // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO. // * For macOS, use constant value absolute path "/usr/lib/libc.dylib". // * For FreeBSD, use constant value "libc.so.7". + // * For Haiku, use constant value "libroot.so". // * For rest of Unices, use constant value "libc.so". if (strcmp(filename, "libc") == 0) { @@ -28,6 +29,8 @@ void* SystemNative_LoadLibrary(const char* filename) filename = "/usr/lib/libc.dylib"; #elif defined(__FreeBSD__) filename = "libc.so.7"; +#elif defined(__HAIKU__) + filename = "libroot.so"; #elif defined(LIBC_SO) filename = LIBC_SO; #else diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 3777ad55151f9d..9b73aef2d41b99 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -46,7 +46,7 @@ #include #elif HAVE_STATFS_MOUNT // BSD #include -#elif HAVE_SYS_STATVFS_H && !HAVE_NON_LEGACY_STATFS // SunOS +#elif HAVE_SYS_STATVFS_H && !HAVE_NON_LEGACY_STATFS && HAVE_STATVFS_BASETYPE // SunOS #include #include #if HAVE_STATFS_VFS @@ -58,6 +58,10 @@ #include #endif +#ifdef TARGET_HAIKU +#include +#endif // TARGET_HAIKU + #ifdef _AIX #include // Somehow, AIX mangles the definition for this behind a C++ def @@ -399,7 +403,7 @@ int32_t SystemNative_IsMemfdSupported(void) } #endif - // Note that the name has no affect on file descriptor behavior. From linux manpage: + // Note that the name has no affect on file descriptor behavior. From linux manpage: // Names do not affect the behavior of the file descriptor, and as such multiple files can have the same name without any side effects. int32_t fd = (int32_t)syscall(__NR_memfd_create, "test", MFD_CLOEXEC | MFD_ALLOW_SEALING); if (fd < 0) return 0; @@ -515,8 +519,13 @@ int32_t SystemNative_GetReadDirRBufferSize(void) #endif // dirent should be under 2k in size assert(result < 2048); +#if HAVE_DIRENT_NAME_SIZE // add some extra space so we can align the buffer to dirent. return (int32_t)(result + dirent_alignment - 1); +#else + // add some extra space for the name. + return sizeof(struct dirent) + NAME_MAX + dirent_alignment - 1; +#endif // HAVE_DIRENT_NAME_SIZE #else return 0; #endif @@ -882,8 +891,14 @@ void SystemNative_GetDeviceIdentifiers(uint64_t dev, uint32_t* majorNumber, uint { #if !defined(TARGET_WASI) dev_t castedDev = (dev_t)dev; +#if !defined(TARGET_HAIKU) *majorNumber = (uint32_t)major(castedDev); *minorNumber = (uint32_t)minor(castedDev); +#else + // Haiku has no concept of major/minor numbers, but it does have device IDs. + *majorNumber = 0; + *minorNumber = (uint32_t)dev; +#endif // TARGET_HAIKU #else /* TARGET_WASI */ dev_t castedDev = (dev_t)dev; *majorNumber = 0; @@ -894,7 +909,12 @@ void SystemNative_GetDeviceIdentifiers(uint64_t dev, uint32_t* majorNumber, uint int32_t SystemNative_MkNod(const char* pathName, uint32_t mode, uint32_t major, uint32_t minor) { #if !defined(TARGET_WASI) +#if !defined(TARGET_HAIKU) dev_t dev = (dev_t)makedev(major, minor); +#else + (void)major; + dev_t dev = (dev_t)minor; +#endif // !TARGET_HAIKU int32_t result; while ((result = mknod(pathName, (mode_t)mode, dev)) < 0 && errno == EINTR); @@ -1641,7 +1661,7 @@ static int16_t ConvertLockType(int16_t managedLockType) } } -#if !HAVE_NON_LEGACY_STATFS || defined(TARGET_APPLE) || defined(TARGET_FREEBSD) +#if !HAVE_NON_LEGACY_STATFS || defined(TARGET_APPLE) || defined(TARGET_FREEBSD) || defined(TARGET_HAIKU) static uint32_t MapFileSystemNameToEnum(const char* fileSystemName) { uint32_t result = 0; @@ -1800,9 +1820,30 @@ uint32_t SystemNative_GetFileSystemType(intptr_t fd) uint32_t result = (uint32_t)statfsArgs.f_type; return result; #endif +#elif defined(TARGET_HAIKU) + struct stat st; + int fstatRes; + while ((fstatRes = fstat(ToFileDescriptor(fd), &st)) == -1 && errno == EINTR) + { } + if (fstatRes == -1) return 0; + + struct fs_info info; + int fsStatDevRes; + while ((fsStatDevRes = fs_stat_dev(st.st_dev, &info)) == -1 && errno == EINTR) + { } + if (fsStatDevRes == -1) return 0; + + if (strcmp(info.fsh_name, "bfs") == 0) + { + // Haiku names its own BFS filesystem "bfs", but on Linux and some other UNIXes + // it is called "befs" to avoid confusion with Boot File System. + strncpy(info.fsh_name, "befs", sizeof(info.fsh_name) - 1); + } + + return MapFileSystemNameToEnum(info.fsh_name); #elif defined(TARGET_WASI) return EINTR; -#elif !HAVE_NON_LEGACY_STATFS +#elif !HAVE_NON_LEGACY_STATFS && HAVE_STATVFS_BASETYPE int statfsRes; struct statvfs statfsArgs; while ((statfsRes = fstatvfs(ToFileDescriptor(fd), &statfsArgs)) == -1 && errno == EINTR) ; diff --git a/src/native/libs/System.Native/pal_memory.c b/src/native/libs/System.Native/pal_memory.c index c5398b441989ae..339f6b44830bf1 100644 --- a/src/native/libs/System.Native/pal_memory.c +++ b/src/native/libs/System.Native/pal_memory.c @@ -17,7 +17,7 @@ #elif HAVE_MALLOC_USABLE_SIZE_NP #include #define MALLOC_SIZE(s) malloc_usable_size(s) -#elif defined(TARGET_SUNOS) +#elif defined(TARGET_SUNOS) || defined(TARGET_HAIKU) #define MALLOC_SIZE(s) (*((size_t*)(s)-1)) #else #error "Platform doesn't support malloc_usable_size or malloc_size" diff --git a/src/native/libs/System.Native/pal_mount.c b/src/native/libs/System.Native/pal_mount.c index 2453bdfe9ede3f..d68ac8dd761929 100644 --- a/src/native/libs/System.Native/pal_mount.c +++ b/src/native/libs/System.Native/pal_mount.c @@ -13,16 +13,24 @@ #if HAVE_MNTINFO #include #else +#if HAVE_SYS_STATFS_H #include +#endif #if HAVE_SYS_MNTENT_H #include #include -#include -#else +#elif HAVE_MNTENT_H #include #endif +#include #define STRING_BUFFER_SIZE 8192 +#ifdef __HAIKU__ +#include +#include +#include +#endif // __HAIKU__ + // Android does not define MNTOPT_RO #ifndef MNTOPT_RO #define MNTOPT_RO "r" @@ -68,7 +76,7 @@ int32_t SystemNative_GetAllMountPoints(MountPointFound onFound, void* context) return result; } -#else +#elif HAVE_MNTENT_H int result = -1; FILE* fp = setmntent("/proc/mounts", MNTOPT_RO); if (fp != NULL) @@ -91,6 +99,38 @@ int32_t SystemNative_GetAllMountPoints(MountPointFound onFound, void* context) return result; } +#elif defined(__HAIKU__) + int32 cookie = 0; + dev_t currentDev; + + while ((long)(currentDev = next_dev(&cookie)) >= 0) + { + struct fs_info info; + if (fs_stat_dev(currentDev, &info) != B_OK) + { + continue; + } + + char name[STRING_BUFFER_SIZE]; + // Two bytes for the name as we're storing "." + char buf[sizeof(struct dirent) + 2]; + struct dirent *entry = (struct dirent *)&buf; + strncpy(entry->d_name, ".", 2); + entry->d_pdev = currentDev; + entry->d_pino = info.root; + + if (get_path_for_dirent(entry, name, sizeof(name)) != B_OK) + { + continue; + } + + onFound(context, name); + } + + return 0; +} +#else +#error "Don't know how to enumerate mount points on this platform" #endif int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInformation* mpi) @@ -140,6 +180,9 @@ SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer #if HAVE_NON_LEGACY_STATFS struct statfs stats; int result = statfs(name, &stats); +#elif defined(__HAIKU__) + struct fs_info stats; + int result = fs_stat_dev(dev_for_path(name), &stats); #else struct statvfs stats; int result = statvfs(name, &stats); @@ -166,6 +209,17 @@ SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer assert(formatType != NULL); *formatType = (int64_t)(stats.f_type); SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), ""); +#elif defined(__HAIKU__) + if (bufferLength < B_OS_NAME_LENGTH) + { + result = ERANGE; + *formatType = 0; + } + else + { + SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), stats.fsh_name); + *formatType = -1; + } #else *formatType = 0; #endif diff --git a/src/native/libs/System.Native/pal_networkchange.c b/src/native/libs/System.Native/pal_networkchange.c index b4386a762f3f08..c3950890fdb59a 100644 --- a/src/native/libs/System.Native/pal_networkchange.c +++ b/src/native/libs/System.Native/pal_networkchange.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,9 @@ Error SystemNative_CreateNetworkChangeListenerSocket(intptr_t* retSocket) #elif HAVE_RT_MSGHDR int32_t sock = socket(PF_ROUTE, SOCK_RAW, 0); +#else + int32_t sock = -1; + errno = EAFNOSUPPORT; #endif if (sock == -1) { @@ -177,6 +181,6 @@ Error SystemNative_ReadEvents(intptr_t sock, NetworkChangeEvent onNetworkChange) (void)onNetworkChange; // unreachable abort(); - return Error_SUCCESS; + return Error_EINVAL; } #endif diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index ab996e2c4ff7d7..ed3c90d6d6c14e 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -662,6 +662,11 @@ int32_t SystemNative_GetDomainName(uint8_t* name, int32_t nameLength) // Copy the domain name SafeStringCopy((char*)name, namelen, uts.domainname); return 0; +#elif defined(__HAIKU__) + // Haiku does not support NIS domains. + (void)nameLength; + *name = '\0'; + return 0; #else // GetDomainName is not supported on this platform. errno = ENOTSUP; @@ -2140,10 +2145,13 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionLevel, int32_t socket // case SocketOptionName_SO_TCP_BSDURGENT: +#ifdef TCP_KEEPCNT case SocketOptionName_SO_TCP_KEEPALIVE_RETRYCOUNT: *optName = TCP_KEEPCNT; return true; +#endif +#if defined(TCP_KEEPALIVE) || defined(TCP_KEEPIDLE) case SocketOptionName_SO_TCP_KEEPALIVE_TIME: *optName = #if HAVE_TCP_H_TCP_KEEPALIVE @@ -2152,10 +2160,13 @@ static bool TryGetPlatformSocketOption(int32_t socketOptionLevel, int32_t socket TCP_KEEPIDLE; #endif return true; +#endif +#ifdef TCP_KEEPINTVL case SocketOptionName_SO_TCP_KEEPALIVE_INTERVAL: *optName = TCP_KEEPINTVL; return true; +#endif #ifdef TCP_FASTOPEN case SocketOptionName_SO_TCP_FASTOPEN: diff --git a/src/native/libs/System.Security.Cryptography.Native/pal_x509.c b/src/native/libs/System.Security.Cryptography.Native/pal_x509.c index 2f07a3cd2da2a8..eda352a88b5c64 100644 --- a/src/native/libs/System.Security.Cryptography.Native/pal_x509.c +++ b/src/native/libs/System.Security.Cryptography.Native/pal_x509.c @@ -10,6 +10,11 @@ #include #include +#if !HAVE_DIRENT_NAME_SIZE +#undef DIRENT_NAME_SIZE +#define DIRENT_NAME_SIZE NAME_MAX +#endif // !HAVE_DIRENT_NAME_SIZE + c_static_assert(PAL_X509_V_OK == X509_V_OK); c_static_assert(PAL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); c_static_assert(PAL_X509_V_ERR_UNABLE_TO_GET_CRL == X509_V_ERR_UNABLE_TO_GET_CRL); @@ -450,7 +455,7 @@ static DIR* OpenUserStore(const char* storePath, char** pathTmp, size_t* pathTmp // d_name is a fixed length char[], not a char*. // Leave one byte for '\0' and one for '/' - size_t allocSize = storePathLen + sizeof(ent->d_name) + 2; + size_t allocSize = storePathLen + DIRENT_NAME_SIZE + 2; char* tmp = (char*)calloc(allocSize, sizeof(char)); if (!tmp) { @@ -479,7 +484,7 @@ static X509* ReadNextPublicCert(DIR* dir, X509Stack* tmpStack, char* pathTmp, si while ((next = readdir(dir)) != NULL) { - size_t len = strnlen(next->d_name, sizeof(next->d_name)); + size_t len = strnlen(next->d_name, DIRENT_NAME_SIZE); if (len > 4 && 0 == strncasecmp(".pfx", next->d_name + len - 4, 4)) { diff --git a/src/native/minipal/getexepath.h b/src/native/minipal/getexepath.h index d2a7484da9da57..c0642812477fee 100644 --- a/src/native/minipal/getexepath.h +++ b/src/native/minipal/getexepath.h @@ -17,6 +17,9 @@ #include #elif defined(_WIN32) #include +#elif defined(__HAIKU__) +#include +#include #elif HAVE_GETAUXVAL #include #endif @@ -61,6 +64,16 @@ static inline char* minipal_getexepath(void) return NULL; } + return realpath(path, NULL); +#elif defined(__HAIKU__) + char path[B_PATH_NAME_LENGTH]; + status_t status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, path, B_PATH_NAME_LENGTH); + if (status != B_OK) + { + errno = status; + return NULL; + } + return realpath(path, NULL); #elif defined(_WIN32) char path[MAX_PATH];