// RUN: %target-run-simple-swift %t // REQUIRES: executable_test // UNSUPPORTED: OS=windows-msvc import StdlibUnittest #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) import Darwin #elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku) import Glibc #else #error("Unsupported platform") #endif chdir(CommandLine.arguments[1]) var POSIXTests = TestSuite("POSIXTests") let semaphoreName = "TestSem" #if os(Android) // In Android, the cwd is the root directory, which is not writable. let fn: String = { let capacity = Int(PATH_MAX) let resolvedPath = UnsafeMutablePointer.allocate(capacity: capacity) resolvedPath.initialize(repeating: 0, count: capacity) defer { resolvedPath.deinitialize(count: capacity) resolvedPath.deallocate() } guard let _ = realpath("/proc/self/exe", resolvedPath) else { fatalError("Couldn't obtain executable path") } let length = strlen(resolvedPath) precondition(length != 0, "Couldn't obtain valid executable path") // Search backwards for the last /, and turn it into a null byte. for idx in stride(from: length-1, through: 0, by: -1) { if Unicode.Scalar(UInt8(resolvedPath[idx])) == Unicode.Scalar("/") { resolvedPath[idx] = 0 break } precondition(idx != 0, "Couldn't obtain valid executable directory") } return String(cString: resolvedPath) + "/test.txt" }() #else let fn = "test.txt" #endif POSIXTests.setUp { sem_unlink(semaphoreName) unlink(fn) } // Failed semaphore creation. #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS POSIXTests.test("sem_open fail") { let sem = sem_open(semaphoreName, 0) expectEqual(SEM_FAILED, sem) expectEqual(ENOENT, errno) } #endif // Successful semaphore creation. #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS POSIXTests.test("sem_open success") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) expectEqual(0, res2) } #endif // Successful semaphore creation with O_EXCL. #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS POSIXTests.test("sem_open O_EXCL success") { let sem = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) expectNotEqual(SEM_FAILED, sem) let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) expectEqual(0, res2) } #endif // Successful creation and re-obtaining of existing semaphore. #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS POSIXTests.test("sem_open existing") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) let sem2 = sem_open(semaphoreName, 0) // Here, we'd like to test that the semaphores are the same, but it's quite // difficult. expectNotEqual(SEM_FAILED, sem2) let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) expectEqual(0, res2) } #endif // Fail because the semaphore already exists. #if !os(Android) // Android doesn’t implement sem_open and always return ENOSYS POSIXTests.test("sem_open existing O_EXCL fail") { let sem = sem_open(semaphoreName, O_CREAT, 0o777, 1) expectNotEqual(SEM_FAILED, sem) let sem2 = sem_open(semaphoreName, O_CREAT | O_EXCL, 0o777, 1) expectEqual(SEM_FAILED, sem2) expectEqual(EEXIST, errno) let res = sem_close(sem!) expectEqual(0, res) let res2 = sem_unlink(semaphoreName) expectEqual(0, res2) } #endif // Fail because the file descriptor is invalid. POSIXTests.test("ioctl(CInt, UInt, CInt): fail") { let fd = open(fn, 0) expectEqual(-1, fd) expectEqual(ENOENT, errno) // A simple check to verify that ioctl is available let _ = ioctl(fd, 0, 0) expectEqual(EBADF, errno) } #if os(Linux) || os(Android) // Successful creation of a socket and listing interfaces POSIXTests.test("ioctl(CInt, UInt, UnsafeMutableRawPointer): listing interfaces success") { // Create a socket let sock = socket(PF_INET, 1, 0) expectGT(Int(sock), 0) // List interfaces var ic = ifconf() let io = ioctl(sock, UInt(SIOCGIFCONF), &ic); expectGE(io, 0) //Cleanup let res = close(sock) expectEqual(0, res) } #endif // Fail because file doesn't exist. POSIXTests.test("fcntl(CInt, CInt): fail") { let fd = open(fn, 0) expectEqual(-1, fd) expectEqual(ENOENT, errno) let _ = fcntl(fd, F_GETFL) expectEqual(EBADF, errno) } // Change modes on existing file. POSIXTests.test("fcntl(CInt, CInt): F_GETFL/F_SETFL success with file") { // Create and open file. let fd = open(fn, O_CREAT, 0o666) expectGT(Int(fd), 0) var flags = fcntl(fd, F_GETFL) expectGE(Int(flags), 0) // Change to APPEND mode... var rc = fcntl(fd, F_SETFL, O_APPEND) expectEqual(0, rc) flags = fcntl(fd, F_GETFL) expectEqual(flags | O_APPEND, flags) // Change back... rc = fcntl(fd, F_SETFL, 0) expectEqual(0, rc) flags = fcntl(fd, F_GETFL) expectGE(Int(flags), 0) // Clean up... rc = close(fd) expectEqual(0, rc) rc = unlink(fn) expectEqual(0, rc) } POSIXTests.test("fcntl(CInt, CInt, CInt): block and unblocking sockets success") { // Create socket, note: socket created by default in blocking mode... let sock = socket(PF_INET, 1, 0) expectGT(Int(sock), 0) var flags = fcntl(sock, F_GETFL) expectGE(Int(flags), 0) // Change mode of socket to non-blocking... var rc = fcntl(sock, F_SETFL, flags | O_NONBLOCK) expectEqual(0, rc) flags = fcntl(sock, F_GETFL) expectEqual((flags | O_NONBLOCK), flags) // Change back to blocking... rc = fcntl(sock, F_SETFL, flags & ~O_NONBLOCK) expectEqual(0, rc) flags = fcntl(sock, F_GETFL) expectGE(Int(flags), 0) // Clean up... rc = close(sock) expectEqual(0, rc) } POSIXTests.test("fcntl(CInt, CInt, UnsafeMutableRawPointer): locking and unlocking success") { // Create the file and add data to it... var fd = open(fn, O_CREAT | O_WRONLY, 0o666) expectGT(Int(fd), 0) let data = "Testing 1 2 3" let bytesWritten = write(fd, data, data.utf8.count) expectEqual(data.utf8.count, bytesWritten) var rc = close(fd) expectEqual(0, rc) // Re-open the file... fd = open(fn, 0) expectGT(Int(fd), 0) // Lock for reading... var flck = flock() flck.l_type = Int16(F_RDLCK) #if os(Android) // In Android l_len is __kernel_off_t which is not the same size as off_t in // 64 bits. flck.l_len = __kernel_off_t(data.utf8.count) #else flck.l_len = off_t(data.utf8.count) #endif rc = fcntl(fd, F_SETLK, &flck) expectEqual(0, rc) // Unlock for reading... flck = flock() flck.l_type = Int16(F_UNLCK) rc = fcntl(fd, F_SETLK, &flck) expectEqual(0, rc) // Clean up... rc = close(fd) expectEqual(0, rc) rc = unlink(fn) expectEqual(0, rc) } runAllTests()