|
1 | 1 | import Foundation |
| 2 | +import MachO |
| 3 | +import Darwin |
2 | 4 |
|
3 | 5 | struct Statistics { |
4 | 6 |
|
@@ -110,21 +112,39 @@ struct SystemControl { |
110 | 112 | return data |
111 | 113 | } |
112 | 114 |
|
113 | | - static func string(mib: [Int32]) throws -> String { |
114 | | - guard let string = try bytes(mib: mib).withUnsafeBufferPointer({ dataPointer -> String? in |
115 | | - dataPointer.baseAddress.flatMap { String(validatingUTF8: $0) } |
116 | | - }) else { |
117 | | - throw CodingError.encodingFailed |
118 | | - } |
119 | | - return string |
120 | | - } |
121 | | - |
122 | 115 | static func value<T>(mib: [Int32]) throws -> T { |
123 | 116 | return try bytes(mib: mib).withUnsafeBufferPointer({ (buffer) throws -> T in |
124 | 117 | guard let baseAddress = buffer.baseAddress else { throw KernError.unexpected } |
125 | 118 | return baseAddress.withMemoryRebound(to: T.self, capacity: 1, { $0.pointee }) |
126 | 119 | }) |
127 | 120 | } |
| 121 | + |
| 122 | + static func string(forKeys keys: [Int32]) throws -> String { |
| 123 | + var keys = keys |
| 124 | + var size = 0 |
| 125 | + if sysctl(&keys, u_int(keys.count), nil, &size, nil, 0) != 0 { |
| 126 | + throw SysctlError.sysctlFailed("Failed to get size of sysctl data.") |
| 127 | + } |
| 128 | + |
| 129 | + var data = [CChar](repeating: 0, count: size) |
| 130 | + if sysctl(&keys, u_int(keys.count), &data, &size, nil, 0) != 0 { |
| 131 | + throw SysctlError.sysctlFailed("Failed to get sysctl data.") |
| 132 | + } |
| 133 | + |
| 134 | + guard let result = String(cString: data, encoding: .utf8) else { |
| 135 | + throw SysctlError.invalidUTF8("Failed to convert sysctl data to string.") |
| 136 | + } |
| 137 | + return result.trimmingCharacters(in: .whitespacesAndNewlines) |
| 138 | + } |
| 139 | + |
| 140 | + static func integer<T: FixedWidthInteger>(forName name: String) throws -> T { |
| 141 | + var size = MemoryLayout<T>.stride |
| 142 | + var value = T(0) |
| 143 | + if sysctlbyname(name, &value, &size, nil, 0) != 0 { |
| 144 | + throw SysctlError.sysctlFailed("Failed to read \(name).") |
| 145 | + } |
| 146 | + return value |
| 147 | + } |
128 | 148 | } |
129 | 149 |
|
130 | 150 | struct MemoryInfo { |
@@ -238,13 +258,112 @@ struct System { |
238 | 258 | } |
239 | 259 | return currentTime.tv_sec - bootTime |
240 | 260 | } |
241 | | - |
| 261 | + |
242 | 262 | static func machine() throws -> String { |
243 | | - return try SystemControl.string(mib: [CTL_HW, HW_MACHINE]) |
| 263 | + return (try? SystemControl.string(forKeys: [CTL_HW, HW_MACHINE])) ?? "unknown" |
244 | 264 | } |
245 | 265 |
|
246 | 266 | static func model() throws -> String { |
247 | | - return try SystemControl.string(mib: [CTL_HW, HW_MODEL]) |
| 267 | +#if os(iOS) || os(tvOS) || os(watchOS) |
| 268 | + return (try? SystemControl.string(forKeys: [CTL_HW, HW_MACHINE])) ?? "unknown" |
| 269 | +#else |
| 270 | + return (try? SystemControl.string(forKeys: [CTL_HW, HW_MODEL])) ?? "unknown" |
| 271 | +#endif |
| 272 | + } |
| 273 | +} |
| 274 | + |
| 275 | +struct CPU { |
| 276 | + static func architecture() -> String { |
| 277 | + do { |
| 278 | + let cpuType: cpu_type_t = try SystemControl.integer(forName: "hw.cputype") |
| 279 | + let cpuSubType: cpu_subtype_t = try SystemControl.integer(forName: "hw.cpusubtype") |
| 280 | + |
| 281 | + return architectureString(cpuType: cpuType, cpuSubType: cpuSubType) |
| 282 | + } catch { |
| 283 | + return "unknown" |
| 284 | + } |
| 285 | + } |
| 286 | + |
| 287 | + private static func architectureString(cpuType: cpu_type_t, cpuSubType: cpu_subtype_t) -> String { |
| 288 | + switch cpuType { |
| 289 | + case CPU_TYPE_X86: |
| 290 | + switch cpuSubType { |
| 291 | + case CPU_SUBTYPE_X86_64_H: |
| 292 | + return "x86_64h" |
| 293 | + case CPU_SUBTYPE_X86_64_ALL: |
| 294 | + return "x86_64" |
| 295 | + default: |
| 296 | + return "x86" |
| 297 | + } |
| 298 | + case CPU_TYPE_X86_64: |
| 299 | + return "x86_64" |
| 300 | + |
| 301 | + case CPU_TYPE_ARM: |
| 302 | + switch cpuSubType { |
| 303 | + case CPU_SUBTYPE_ARM_V6: |
| 304 | + return "armv6" |
| 305 | + case CPU_SUBTYPE_ARM_V7: |
| 306 | + return "armv7" |
| 307 | + case CPU_SUBTYPE_ARM_V7S: |
| 308 | + return "armv7s" |
| 309 | + case CPU_SUBTYPE_ARM_V7K: |
| 310 | + return "armv7k" |
| 311 | + default: |
| 312 | + return "arm" |
| 313 | + } |
| 314 | + |
| 315 | + case CPU_TYPE_ARM64, CPU_TYPE_ARM64_32: |
| 316 | + switch cpuSubType { |
| 317 | + case CPU_SUBTYPE_ARM64_V8: |
| 318 | + return "armv8" |
| 319 | + case CPU_SUBTYPE_ARM64E: |
| 320 | + return "arm64e" |
| 321 | + default: |
| 322 | + return "arm64" |
| 323 | + } |
| 324 | + |
| 325 | + default: |
| 326 | + return "unknown (type=\(cpuType), subType=\(cpuSubType))" |
| 327 | + } |
| 328 | + } |
| 329 | +} |
| 330 | + |
| 331 | +struct OSInfo { |
| 332 | + static var name: String { |
| 333 | + #if os(macOS) |
| 334 | + return "macOS" |
| 335 | + #elseif os(tvOS) |
| 336 | + return "tvOS" |
| 337 | + #elseif os(watchOS) |
| 338 | + return "watchOS" |
| 339 | + #elseif os(iOS) && !targetEnvironment(macCatalyst) |
| 340 | + return UIDevice.current.systemName |
| 341 | + #elseif os(iOS) && targetEnvironment(macCatalyst) |
| 342 | + return "Catalyst" |
| 343 | + #else |
| 344 | + return "unknownOS" |
| 345 | + #endif |
| 346 | + } |
| 347 | + |
| 348 | + static var version: String { |
| 349 | + #if os(iOS) && !targetEnvironment(macCatalyst) |
| 350 | + return UIDevice.current.systemVersion |
| 351 | + #elseif os(watchOS) |
| 352 | + let version = ProcessInfo.processInfo.operatingSystemVersion |
| 353 | + return "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" |
| 354 | + #else |
| 355 | + let version = ProcessInfo.processInfo.operatingSystemVersion |
| 356 | + return "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" |
| 357 | + #endif |
| 358 | + } |
| 359 | + |
| 360 | + static var buildNumber: String { |
| 361 | + let mib = [CTL_KERN, KERN_OSVERSION] |
| 362 | + do { |
| 363 | + return try SystemControl.string(forKeys: mib) |
| 364 | + } catch { |
| 365 | + return "unknown" |
| 366 | + } |
248 | 367 | } |
249 | 368 | } |
250 | 369 |
|
|
0 commit comments