// // Copyright 2026 Aarav Ravindra Kharade // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // import CSystem #if canImport(Glibc) || canImport(Musl) // Linux reboot syscall — used by PowerManager.shutdown() @_silgen_name("reboot") public func reboot(_ cmd: Int32) -> Int32 // Linux reboot command constants public let LINUX_REBOOT_CMD_POWER_OFF: Int32 = 0x4321FEDC public let LINUX_REBOOT_CMD_RESTART: Int32 = 0x01234567 #endif // ═══════════════════════════════════════════════════════════════════ // ArkOS Kernel Bridge // ═══════════════════════════════════════════════════════════════════ // Provides the lowest-level interface between the ArkOS runtime and // the Linux kernel. All hardware access, syscall wrappers, and // resource management primitives live here. // // Layers: // 1. Syscall — Safe wrappers around raw Linux syscalls // 2. ResourceController — CPU core gating and memory monitoring // 3. LogManager — Structured, leveled logging with file output // 4. PowerManager — Battery, AC adapter, shutdown/reboot // 5. NetworkManager — Real interface enumeration and state // 6. BluetoothManager — HCI device scanning via sysfs // 7. InputManager — Raw keystroke reading from stdin // 8. ArkFileDescriptor — RAII-style file handle wrapper // ═══════════════════════════════════════════════════════════════════ // ── Syscall Error Type ──────────────────────────────────────────── /// Represents a failed Linux syscall with the errno code and message. public struct SyscallError: Error, CustomStringConvertible { public let code: Int32 public let message: String public var description: String { return "SyscallError(\(code)): \(message)" } /// Create a SyscallError from the current value of errno. public static func fromErrno() -> SyscallError { return SyscallError(code: ark_errno(), message: String(cString: strerror(ark_errno()))) } } // ── Safe Syscall Wrappers ───────────────────────────────────────── /// Thin wrappers around read(2) and write(2) that throw on failure /// instead of returning -1. Prevents silent data corruption. public struct Syscall { public static func read(fd: Int32, buffer: UnsafeMutableRawPointer, count: Int) throws -> Int { let result = Int(CSystem.read(fd, buffer, count)) if result < 0 { throw SyscallError.fromErrno() } return result } public static func write(fd: Int32, buffer: UnsafeRawPointer, count: Int) throws -> Int { let result = Int(CSystem.write(fd, buffer, count)) if result < 0 { throw SyscallError.fromErrno() } return result } } // ── Log Manager ─────────────────────────────────────────────────── /// Structured, leveled logging system for ArkOS. /// /// Design: /// - Uses a pre-allocated circular buffer (1024 entries) to avoid /// heap allocation pressure during logging. /// - Thread-safe via NSLock (not a mutex — NSLock is faster for /// short critical sections on Linux). /// - Writes to both stdout and /var/log/arkos.log when available. /// - Supports four severity levels: INFO, WARN, ERROR, FATAL. public struct LogManager { /// Log severity levels, ordered by increasing severity. public enum Level: String { case info = "INFO" case warn = "WARN" case error = "ERROR" case fatal = "FATAL" } private static let maxLogCount = 1024 private static let logBuffer: UnsafeMutablePointer?> = { let ptr = UnsafeMutablePointer?>.allocate(capacity: maxLogCount) for i in 0.. = { let ptr = UnsafeMutablePointer.allocate(capacity: 1) pthread_mutex_init(ptr, nil) return ptr }() /// Path to the persistent log file (created after /var is mounted). private static let logFilePath = "/var/log/arkos.log" /// Log a message at the INFO level. public static func log(_ message: String, component: String = "ark.log") { log(message, level: .info, component: component) } /// Log a message at a specific severity level. public static func log(_ message: String, level: Level, component: String = "ark.log") { var ts = timespec() clock_gettime(CLOCK_REALTIME, &ts) var tmBuf = tm() var secs = ts.tv_sec gmtime_r(&secs, &tmBuf) var timeBuf = [CChar](repeating: 0, count: 32) strftime(&timeBuf, 32, "%Y-%m-%d %H:%M:%S +0000", &tmBuf) let timestamp = String(cString: timeBuf) let formatted = "[\(timestamp)] [\(level.rawValue)] [\(component)] \(message)" pthread_mutex_lock(lock) defer { pthread_mutex_unlock(lock) } // Recycle the oldest entry in the circular buffer if let old = logBuffer[writeIndex] { old.deallocate() } // Copy the formatted string into the raw buffer let cStr = formatted.utf8CString let ptr = UnsafeMutablePointer.allocate(capacity: cStr.count) for j in 0..= 0 { let line = formatted + "\n" line.withCString { ptr in CSystem.write(fd1, ptr, strlen(ptr)) } fsync(fd1) close(fd1) } let fd2 = ark_open("/boot/arkos.log", O_CREAT | O_WRONLY | O_APPEND, 0o666) if fd2 >= 0 { let line = formatted + "\n" line.withCString { ptr in CSystem.write(fd2, ptr, strlen(ptr)) } fsync(fd2) close(fd2) } } /// Dump all buffered log entries in chronological order. public static func dumpLogs() -> [String] { pthread_mutex_lock(lock) defer { pthread_mutex_unlock(lock) } var result: [String] = [] result.reserveCapacity(maxLogCount) for i in 0.. Int { return 100 // QEMU fallback — no physical battery } /// Returns the current charging state by reading the battery status file. public static func getChargeState() -> ChargeState { return .full // QEMU fallback } /// Returns true if an AC adapter is connected. public static func isACConnected() -> Bool { return true // QEMU fallback — always powered } /// Initiates a clean system shutdown via reboot(2). public static func shutdown() { LogManager.log("Initiating system shutdown...", level: .info, component: "ark.kernel.utils") #if canImport(Glibc) sync() // Flush all filesystem buffers to disk _ = reboot(LINUX_REBOOT_CMD_POWER_OFF) #endif } /// Initiates a system reboot via reboot(2). public static func restart() { LogManager.log("Initiating system restart...", level: .info, component: "ark.kernel.utils") #if canImport(Glibc) sync() _ = reboot(LINUX_REBOOT_CMD_RESTART) #endif } } // ── Network Manager ─────────────────────────────────────────────── /// Enumerates and queries network interfaces via Linux sysfs and /// the getifaddrs(3) API. Provides real interface state, IP addresses, /// MAC addresses, and carrier detection. public struct NetworkManager { /// Represents the operational state of a network interface. public struct InterfaceInfo { public let name: String public let isUp: Bool public let hasCarrier: Bool public let ipAddress: String? public let macAddress: String? } /// Returns the IP address of the first non-loopback IPv4 interface. public static func getInterfaceIP() -> String { #if canImport(Glibc) var ifaddr: UnsafeMutablePointer? guard getifaddrs(&ifaddr) == 0, let firstAddr = ifaddr else { return "127.0.0.1" } defer { freeifaddrs(ifaddr) } var ptr: UnsafeMutablePointer? = firstAddr while ptr != nil { let flags = Int32(ptr!.pointee.ifa_flags) let family = ptr!.pointee.ifa_addr.pointee.sa_family // Skip loopback (IFF_LOOPBACK = 8) and match IPv4 (AF_INET = 2) if (flags & 8) == 0, family == 2 { var ipBuf = [CChar](repeating: 0, count: 16) if let ipPtr = ptr!.pointee.ifa_addr { let sin = UnsafeMutableRawPointer(ipPtr).assumingMemoryBound(to: sockaddr_in.self) if inet_ntop(2, &sin.pointee.sin_addr, &ipBuf, 16) != nil { return String(cString: ipBuf) } } } ptr = ptr!.pointee.ifa_next } #endif return "10.0.2.15" // QEMU user-mode networking default } /// Returns a list of all network interface names (excluding loopback). public static func getInterfaceNames() -> [String] { return [] } /// Returns detailed info about all non-loopback network interfaces. public static func getAllInterfaces() -> [InterfaceInfo] { return [] } /// Returns true if any non-loopback interface has an IP address. public static func isConnected() -> Bool { return getAllInterfaces().contains { $0.ipAddress != nil && $0.isUp } } /// Scans for wireless interfaces by checking /sys/class/net/*/wireless. public static func getWirelessInterfaces() -> [String] { return [] } } // ── Bluetooth Manager ───────────────────────────────────────────── /// Scans for Bluetooth HCI adapters and paired devices via Linux sysfs. /// Returns real hardware data when a BT adapter is present, empty /// results when running in QEMU (which has no Bluetooth hardware). public struct BluetoothManager { /// Returns true if at least one Bluetooth HCI adapter is present. public static func isEnabled() -> Bool { return false } /// Returns the names of all detected Bluetooth HCI adapters. public static func getAdapters() -> [String] { return [] } } // ── Input Manager ───────────────────────────────────────────────── /// Reads raw keystrokes from stdin (fd 0). Used for console input /// before the display server is running. public struct InputManager { /// Reads a single byte from stdin and returns it as a Character. /// Returns nil if no input is available or read fails. public static func readKeyStroke() -> Character? { let fd: Int32 = 0 var buf: UInt8 = 0 if let bytesRead = try? Syscall.read(fd: fd, buffer: &buf, count: 1), bytesRead == 1 { return Character(UnicodeScalar(buf)) } return nil } } // ── File Descriptor Wrapper ─────────────────────────────────────── /// RAII-style wrapper for Linux file descriptors. Ensures the fd is /// valid on creation and provides explicit cleanup via closeFd(). public struct ArkFileDescriptor { public let raw: Int32 /// Opens a file at the given path with the specified mode flags. /// Throws SyscallError if open(2) fails. public init(path: String, mode: Int32) throws { let fd = ark_open2(path, mode) if fd < 0 { throw SyscallError.fromErrno() } self.raw = fd } /// Closes the underlying file descriptor. public func closeFd() { close(raw) } }