import Foundation fileprivate enum StdStream { case out case err fileprivate var fileDescriptor: FileDescriptor { switch self { case .out: return FileDescriptor(STDOUT_FILENO, "stdout") case .err: return FileDescriptor(STDERR_FILENO, "stderr") } } fileprivate func silent(_ action: () -> T) -> T { var original: FileDescriptor? do { original = try self.mute() } catch { NSLog(error.localizedDescription) } let result = action() do { if let original { try self.unmute(from: original) } } catch { NSLog(error.localizedDescription) } return result } // Redirects the specified file descriptor output to /dev/null and returns the duplicated original descriptor. fileprivate func mute() throws -> FileDescriptor { do { let copy = try self.fileDescriptor.duplicate() let null = try FileDescriptor(path: "/dev/null", flags: O_WRONLY) defer { try? null.close() } try null.duplicate(to: self.fileDescriptor) return copy } catch { throw FileDescriptor.Error("Can’t mute “\(self.fileDescriptor)” descriptor: \(error.localizedDescription)") } } fileprivate func unmute(from fileDescriptor: FileDescriptor) throws { do { try fileDescriptor.duplicate(to: self.fileDescriptor) } catch { throw FileDescriptor.Error("Can’t unmute “\(self.fileDescriptor)” from “\(fileDescriptor)” descriptor: \(error.localizedDescription)") } } } fileprivate struct FileDescriptor: CustomStringConvertible { fileprivate init(_ identifier: Int32, _ path: String? = nil) { self.identifier = identifier self.path = path } fileprivate let identifier: Int32 fileprivate let path: String? fileprivate var description: String { self.path ?? "\(identifier)" } } extension FileDescriptor { fileprivate struct Error: Swift.Error, LocalizedError { init(_ reason: String) { self.reason = reason } fileprivate let reason: String fileprivate var errorDescription: String? { self.reason } } } extension FileDescriptor { /// Wraps around `open` function, opens a file and creates a new descriptor that can be used for reading, writing, or both, depending on the flags specified. /// Note: improper use of the open function can lead to resource leaks if file descriptors are not properly closed after use, and careful attention should /// be paid to handling file permissions and modes to ensure security and proper access control. fileprivate init(path: String, flags: Int32) throws { let result = Darwin.open("/dev/null", flags) if result == -1 { throw Error("Can’t create “\(path)” descriptor: \(String(cString: strerror(errno)))") } self = Self(result, path) } /// Wraps around `close` function, closes an open file descriptor, freeing the file descriptor for reuse. Note: closing a file descriptor that /// is already closed or was never open can result in an error, and any subsequent operations on that file descriptor will fail. fileprivate func close() throws { let result = Darwin.close(self.identifier) if result == -1 { throw Error("Can’t create “\(path)” descriptor: \(String(cString: strerror(errno)))") } } /// Wraps around `dup`, duplicates an existing file descriptor, returning a new file descriptor that refers to the same open file description. /// Note: the new file descriptor will share the same file offset, file status flags, and file access mode as the original. fileprivate func duplicate() throws -> Self { let result = Darwin.dup(self.identifier) if result == -1 { throw Error("Can’t duplicate “\(self)” descriptor: \(String(cString: strerror(errno)))") } return Self(result, self.path) } /// Wraps around `dup2`, duplicates an existing file descriptor to a specified file descriptor number, closing the specified descriptor first if it is already open. /// Note: `dup2` guarantees the duplication even if the specified file descriptor is already in use, which may lead to unexpected behavior if not handled properly. fileprivate func duplicate(to newDescriptor: Self) throws { let result = Darwin.dup2(self.identifier, newDescriptor.identifier) if result == -1 { throw Error("Can’t duplicate “\(self)” to “\(newDescriptor)” descriptor: \(String(cString: strerror(errno)))") } do { try self.close() } catch { throw Error("Can’t duplicate “\(self)” to “\(newDescriptor)” descriptor: \(error.localizedDescription)") } } }