diff --git a/CoreFoundation/Base.subproj/CFPlatform.c b/CoreFoundation/Base.subproj/CFPlatform.c index 9929123bc7..bf332973eb 100644 --- a/CoreFoundation/Base.subproj/CFPlatform.c +++ b/CoreFoundation/Base.subproj/CFPlatform.c @@ -119,6 +119,12 @@ static inline void _CFSetProgramNameFromPath(const char *path) { __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath); } +#if TARGET_OS_BSD && defined(__OpenBSD__) +#include +#include +#include +#endif + const char *_CFProcessPath(void) { if (__CFProcessPath) return __CFProcessPath; @@ -175,6 +181,53 @@ const char *_CFProcessPath(void) { } return __CFProcessPath; #else // TARGET_OS_BSD + char *argv0 = NULL; + + // Get argv[0]. +#if defined(__OpenBSD__) + int mib[2] = {CTL_VM, VM_PSSTRINGS}; + struct _ps_strings _ps; + size_t len = sizeof(_ps); + + if (sysctl(mib, 2, &_ps, &len, NULL, 0) != -1) { + struct ps_strings *ps = _ps.val; + char *res = realpath(ps->ps_argvstr[0], NULL); + argv0 = res? res: strdup(ps->ps_argvstr[0]); + } +#endif + + if (!__CFProcessIsRestricted() && argv0 && argv0[0] == '/') { + _CFSetProgramNameFromPath(argv0); + free(argv0); + return __CFProcessPath; + } + + // Search PATH. + if (argv0) { + char *paths = getenv("PATH"); + char *p = NULL; + while ((p = strsep(&paths, ":")) != NULL) { + char pp[PATH_MAX]; + int l = snprintf(pp, PATH_MAX, "%s/%s", p, argv0); + if (l >= PATH_MAX) { + continue; + } + char *res = realpath(pp, NULL); + if (!res) { + continue; + } + if (!__CFProcessIsRestricted() && access(res, X_OK) == 0) { + _CFSetProgramNameFromPath(res); + free(argv0); + free(res); + return __CFProcessPath; + } + free(res); + } + free(argv0); + } + + // See if the shell will help. if (!__CFProcessIsRestricted()) { char *path = getenv("_"); if (path != NULL) { @@ -1574,6 +1627,9 @@ CF_CROSS_PLATFORM_EXPORT int _CFThreadSetName(_CFThreadRef thread, const char *_ return 0; #elif TARGET_OS_LINUX return pthread_setname_np(thread, name); +#elif TARGET_OS_BSD + pthread_set_name_np(thread, name); + return 0; #endif } @@ -1593,6 +1649,9 @@ CF_CROSS_PLATFORM_EXPORT int _CFThreadGetName(char *buf, int length) { return 0; #elif TARGET_OS_LINUX return pthread_getname_np(pthread_self(), buf, length); +#elif TARGET_OS_BSD + pthread_get_name_np(pthread_self(), buf, length); + return 0; #elif TARGET_OS_WIN32 *buf = '\0'; @@ -1630,6 +1689,9 @@ CF_EXPORT char **_CFEnviron(void) { #elif TARGET_OS_WIN32 return _environ; #else +#if TARGET_OS_BSD + extern char **environ; +#endif return environ; #endif } diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index 62569e27db..103b5d8a6b 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -51,7 +51,9 @@ add_compile_options($<$:-fblocks>) if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") add_compile_options($<$:/EHsc>) else() - add_compile_options($<$:-fexceptions>) + if(NOT CMAKE_SYSTEM_NAME STREQUAL OpenBSD) + add_compile_options($<$:-fexceptions>) + endif() endif() if(NOT "${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC") diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_Binary.c b/CoreFoundation/PlugIn.subproj/CFBundle_Binary.c index 881605a43a..4c5d21b434 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_Binary.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle_Binary.c @@ -470,7 +470,11 @@ CF_PRIVATE Boolean _CFBundleDlfcnCheckLoaded(CFBundleRef bundle) { char buff[CFMaxPathSize]; if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { +#if !defined(__OpenBSD__) int mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST; +#else + int mode = RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST; +#endif void *handle = dlopen(buff, mode); if (handle) { if (!bundle->_handleCookie) { diff --git a/CoreFoundation/PlugIn.subproj/CFBundle_Main.c b/CoreFoundation/PlugIn.subproj/CFBundle_Main.c index c8e14800bd..3820903d7e 100644 --- a/CoreFoundation/PlugIn.subproj/CFBundle_Main.c +++ b/CoreFoundation/PlugIn.subproj/CFBundle_Main.c @@ -107,7 +107,11 @@ static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { // get cookie for already-loaded main bundle #if defined(BINARY_SUPPORT_DLFCN) if (!_mainBundle->_handleCookie) { +#if !defined(__OpenBSD__) _mainBundle->_handleCookie = dlopen(NULL, RTLD_NOLOAD | RTLD_FIRST); +#else + _mainBundle->_handleCookie = dlopen(NULL, RTLD_FIRST); +#endif #if LOG_BUNDLE_LOAD printf("main bundle %p getting handle %p\n", _mainBundle, _mainBundle->_handleCookie); #endif /* LOG_BUNDLE_LOAD */ diff --git a/CoreFoundation/Stream.subproj/CFStream.c b/CoreFoundation/Stream.subproj/CFStream.c index 1a8bacc0db..5cee669075 100644 --- a/CoreFoundation/Stream.subproj/CFStream.c +++ b/CoreFoundation/Stream.subproj/CFStream.c @@ -1675,11 +1675,7 @@ static void _perform(void* info) static void* _legacyStreamRunLoop_workThread(void* arg) { -#if TARGET_OS_LINUX - pthread_setname_np(pthread_self(), "com.apple.CFStream.LegacyThread"); -#else - pthread_setname_np("com.apple.CFStream.LegacyThread"); -#endif + _CFThreadSetName(pthread_self(), "com.apple.CFStream.LegacyThread"); sLegacyRL = CFRunLoopGetCurrent(); #if defined(LOG_STREAM) diff --git a/Sources/Foundation/FileManager+POSIX.swift b/Sources/Foundation/FileManager+POSIX.swift index 28fd292c58..a400abb830 100644 --- a/Sources/Foundation/FileManager+POSIX.swift +++ b/Sources/Foundation/FileManager+POSIX.swift @@ -70,6 +70,32 @@ extension FileManager { } urls = mountPoints(statBuf, Int(fsCount)) } +#elseif os(OpenBSD) + func mountPoints(_ statBufs: UnsafePointer, _ fsCount: Int) -> [URL] { + var urls: [URL] = [] + + for fsIndex in 0..) -> String in + return string(withFileSystemRepresentation: ptr, length: strlen(ptr)) + } + urls.append(URL(fileURLWithPath: mountPoint, isDirectory: true)) + } + return urls + } + + var fsCount = getfsstat(nil, 0, MNT_WAIT) + guard fsCount > 0 else { + return nil + } + let statBuf = UnsafeMutablePointer.allocate(capacity: Int(fsCount)) + defer { statBuf.deallocate() } + fsCount = getfsstat(statBuf, Int(fsCount) * MemoryLayout.stride, MNT_WAIT) + guard fsCount > 0 else { + return nil + } + urls = mountPoints(statBuf, Int(fsCount)) #else #error("Requires a platform-specific implementation") #endif diff --git a/Sources/Foundation/Host.swift b/Sources/Foundation/Host.swift index f7a86e3314..d21f9b702a 100644 --- a/Sources/Foundation/Host.swift +++ b/Sources/Foundation/Host.swift @@ -183,7 +183,12 @@ open class Host: NSObject { let family = ifa_addr.pointee.sa_family if family == sa_family_t(AF_INET) || family == sa_family_t(AF_INET6) { let sa_len: socklen_t = socklen_t((family == sa_family_t(AF_INET6)) ? MemoryLayout.size : MemoryLayout.size) - if getnameinfo(ifa_addr, sa_len, address, socklen_t(NI_MAXHOST), nil, 0, NI_NUMERICHOST) == 0 { +#if os(OpenBSD) + let hostlen = size_t(NI_MAXHOST) +#else + let hostlen = socklen_t(NI_MAXHOST) +#endif + if getnameinfo(ifa_addr, sa_len, address, hostlen, nil, 0, NI_NUMERICHOST) == 0 { _addresses.append(String(cString: address)) } } @@ -303,7 +308,12 @@ open class Host: NSObject { } let sa_len: socklen_t = socklen_t((family == AF_INET6) ? MemoryLayout.size : MemoryLayout.size) let lookupInfo = { (content: inout [String], flags: Int32) in - if getnameinfo(info.ai_addr, sa_len, host, socklen_t(NI_MAXHOST), nil, 0, flags) == 0 { +#if os(OpenBSD) + let hostlen = size_t(NI_MAXHOST) +#else + let hostlen = socklen_t(NI_MAXHOST) +#endif + if getnameinfo(info.ai_addr, sa_len, host, hostlen, nil, 0, flags) == 0 { content.append(String(cString: host)) } } diff --git a/Sources/Foundation/NSError.swift b/Sources/Foundation/NSError.swift index b26e67aac3..dc1f57afa1 100644 --- a/Sources/Foundation/NSError.swift +++ b/Sources/Foundation/NSError.swift @@ -1344,6 +1344,7 @@ extension POSIXError { /// Bad message. public static var EBADMSG: POSIXError.Code { return .EBADMSG } + #if !os(OpenBSD) /// Reserved. public static var EMULTIHOP: POSIXError.Code { return .EMULTIHOP } @@ -1358,13 +1359,16 @@ extension POSIXError { /// Not a STREAM. public static var ENOSTR: POSIXError.Code { return .ENOSTR } + #endif /// Protocol error. public static var EPROTO: POSIXError.Code { return .EPROTO } + #if !os(OpenBSD) /// STREAM ioctl timeout. public static var ETIME: POSIXError.Code { return .ETIME } #endif + #endif #if canImport(Darwin) /// No such policy registered. diff --git a/Sources/Foundation/NSLock.swift b/Sources/Foundation/NSLock.swift index 68d1214770..6cc1813c39 100644 --- a/Sources/Foundation/NSLock.swift +++ b/Sources/Foundation/NSLock.swift @@ -249,7 +249,12 @@ open class NSRecursiveLock: NSObject, NSLocking { #endif withUnsafeMutablePointer(to: &attrib) { attrs in pthread_mutexattr_init(attrs) - pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE)) +#if os(OpenBSD) + let type = Int32(PTHREAD_MUTEX_RECURSIVE.rawValue) +#else + let type = Int32(PTHREAD_MUTEX_RECURSIVE) +#endif + pthread_mutexattr_settype(attrs, type) pthread_mutex_init(mutex, attrs) } #if os(macOS) || os(iOS) diff --git a/Sources/Foundation/Port.swift b/Sources/Foundation/Port.swift index 72694c47d9..cc13055717 100644 --- a/Sources/Foundation/Port.swift +++ b/Sources/Foundation/Port.swift @@ -83,19 +83,22 @@ public protocol PortDelegate: AnyObject { func handle(_ message: PortMessage) } -#if canImport(Glibc) && !os(Android) +#if canImport(Glibc) && !os(Android) && !os(OpenBSD) import Glibc fileprivate let SOCK_STREAM = Int32(Glibc.SOCK_STREAM.rawValue) fileprivate let SOCK_DGRAM = Int32(Glibc.SOCK_DGRAM.rawValue) fileprivate let IPPROTO_TCP = Int32(Glibc.IPPROTO_TCP) #endif -#if canImport(Glibc) && os(Android) +#if canImport(Glibc) && os(Android) || os(OpenBSD) import Glibc fileprivate let SOCK_STREAM = Int32(Glibc.SOCK_STREAM) fileprivate let SOCK_DGRAM = Int32(Glibc.SOCK_DGRAM) fileprivate let IPPROTO_TCP = Int32(Glibc.IPPROTO_TCP) fileprivate let INADDR_ANY: in_addr_t = 0 +#if os(OpenBSD) +fileprivate let INADDR_LOOPBACK = 0x7f000001 +#endif #endif diff --git a/Sources/Foundation/Thread.swift b/Sources/Foundation/Thread.swift index cf01fad149..9f2f6a1344 100644 --- a/Sources/Foundation/Thread.swift +++ b/Sources/Foundation/Thread.swift @@ -135,13 +135,13 @@ open class Thread : NSObject { var ti = end_at - start_at let end_ut = start_ut + ti while (0.0 < ti) { - var __ts__ = timespec(tv_sec: Int.max, tv_nsec: 0) + var __ts__ = timespec(tv_sec: time_t.max, tv_nsec: 0) if ti < Double(Int.max) { var integ = 0.0 let frac: Double = withUnsafeMutablePointer(to: &integ) { integp in return modf(ti, integp) } - __ts__.tv_sec = Int(integ) + __ts__.tv_sec = time_t(integ) __ts__.tv_nsec = Int(frac * 1000000000.0) } let _ = withUnsafePointer(to: &__ts__) { ts in @@ -170,13 +170,13 @@ open class Thread : NSObject { let start_ut = CFGetSystemUptime() let end_ut = start_ut + ti while 0.0 < ti { - var __ts__ = timespec(tv_sec: Int.max, tv_nsec: 0) + var __ts__ = timespec(tv_sec: time_t.max, tv_nsec: 0) if ti < Double(Int.max) { var integ = 0.0 let frac: Double = withUnsafeMutablePointer(to: &integ) { integp in return modf(ti, integp) } - __ts__.tv_sec = Int(integ) + __ts__.tv_sec = time_t(integ) __ts__.tv_nsec = Int(frac * 1000000000.0) } let _ = withUnsafePointer(to: &__ts__) { ts in diff --git a/Tests/Foundation/HTTPServer.swift b/Tests/Foundation/HTTPServer.swift index e3d0a7b256..412bb54656 100644 --- a/Tests/Foundation/HTTPServer.swift +++ b/Tests/Foundation/HTTPServer.swift @@ -27,6 +27,10 @@ import Dispatch typealias SOCKET = Int32 #endif +#if os(OpenBSD) +let INADDR_LOOPBACK = 0x7f000001 +#endif + private let serverDebug = (ProcessInfo.processInfo.environment["SCLF_HTTP_SERVER_DEBUG"] == "YES") private func debugLog(_ msg: String) { diff --git a/Tests/Foundation/Tests/TestThread.swift b/Tests/Foundation/Tests/TestThread.swift index c0b5435804..05cfb06fb7 100644 --- a/Tests/Foundation/Tests/TestThread.swift +++ b/Tests/Foundation/Tests/TestThread.swift @@ -56,6 +56,9 @@ class TestThread : XCTestCase { #if os(Linux) || os(Android) // Linux sets the initial thread name to the process name. XCTAssertEqual(Thread.current.name, "TestFoundation") testInternalThreadName("TestFoundation") +#elseif os(OpenBSD) // OpenBSD sets the initial thread name to this. + XCTAssertEqual(Thread.current.name, "Original thread") + testInternalThreadName("Original thread") #else // No name is set initially XCTAssertEqual(Thread.current.name, "") @@ -160,8 +163,16 @@ class TestThread : XCTestCase { ("test_currentThread", test_currentThread), ("test_threadStart", test_threadStart), ("test_mainThread", test_mainThread), - ("test_callStackSymbols", testExpectedToFailOnAndroid(test_callStackSymbols, "Android doesn't support backtraces at the moment.")), - ("test_callStackReturnAddresses", testExpectedToFailOnAndroid(test_callStackReturnAddresses, "Android doesn't support backtraces at the moment.")), + ("test_callStackSymbols", testExpectedToFailOnOpenBSD( + testExpectedToFailOnAndroid( + test_callStackSymbols, + "Android doesn't support backtraces at the moment."), + "And not currently on OpenBSD.")), + ("test_callStackReturnAddresses", testExpectedToFailOnOpenBSD( + testExpectedToFailOnAndroid( + test_callStackReturnAddresses, + "Android doesn't support backtraces at the moment."), + "And not currently on OpenBSD.")), ("test_sleepForTimeInterval", test_sleepForTimeInterval), ("test_sleepUntilDate", test_sleepUntilDate), ("test_threadName", test_threadName), diff --git a/Tests/Foundation/Utilities.swift b/Tests/Foundation/Utilities.swift index 29ab7d6bea..5596863fd9 100644 --- a/Tests/Foundation/Utilities.swift +++ b/Tests/Foundation/Utilities.swift @@ -557,6 +557,14 @@ func shouldAttemptAndroidXFailTests(_ reason: String) -> Bool { #endif } +func shouldAttemptOpenBSDXFailTests(_ reason: String) -> Bool { + #if os(OpenBSD) + return shouldAttemptXFailTests(reason) + #else + return true + #endif +} + #if !DARWIN_COMPATIBILITY_TESTS func testCaseExpectedToFail(_ allTests: [(String, (T) -> () throws -> Void)], _ reason: String) -> XCTestCaseEntry { return testCase(allTests.map { ($0.0, testExpectedToFail($0.1, "This test suite is disabled: \(reason)")) }) @@ -581,6 +589,10 @@ func testExpectedToFailOnAndroid(_ test: @escaping (T) -> () throws -> Void, testExpectedToFailWithCheck(check: shouldAttemptAndroidXFailTests(_:), test, reason) } +func testExpectedToFailOnOpenBSD(_ test: @escaping (T) -> () throws -> Void, _ reason: String) -> (T) -> () throws -> Void { + testExpectedToFailWithCheck(check: shouldAttemptOpenBSDXFailTests(_:), test, reason) +} + func testExpectedToFailWithCheck(check: (String) -> Bool, _ test: @escaping (T) -> () throws -> Void, _ reason: String) -> (T) -> () throws -> Void { if check(reason) { return test diff --git a/cmake/modules/SwiftSupport.cmake b/cmake/modules/SwiftSupport.cmake index 70b9d31cf1..a3c519c5dd 100644 --- a/cmake/modules/SwiftSupport.cmake +++ b/cmake/modules/SwiftSupport.cmake @@ -23,6 +23,8 @@ function(get_swift_host_arch result_var_name) set("${result_var_name}" "armv7" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv7-a") set("${result_var_name}" "armv7" PARENT_SCOPE) + elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "amd64") + set("${result_var_name}" "amd64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "AMD64") set("${result_var_name}" "x86_64" PARENT_SCOPE) elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "IA64")