blob: fa42dd6af40ca7fec5c612b56b8743687cebd0dd [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
import CoreFoundation
public struct OperatingSystemVersion {
public var majorVersion: Int
public var minorVersion: Int
public var patchVersion: Int
public init() {
self.init(majorVersion: 0, minorVersion: 0, patchVersion: 0)
}
public init(majorVersion: Int, minorVersion: Int, patchVersion: Int) {
self.majorVersion = majorVersion
self.minorVersion = minorVersion
self.patchVersion = patchVersion
}
}
open class ProcessInfo: NSObject {
public static let processInfo = ProcessInfo()
internal override init() {
}
open var environment: [String : String] {
let equalSign = Character("=")
let strEncoding = String.defaultCStringEncoding
let envp = _CFEnviron()
var env: [String : String] = [:]
var idx = 0
while let entry = envp.advanced(by: idx).pointee {
if let entry = String(cString: entry, encoding: strEncoding),
let i = entry.firstIndex(of: equalSign) {
let key = String(entry.prefix(upTo: i))
let value = String(entry.suffix(from: i).dropFirst())
env[key] = value
}
idx += 1
}
return env
}
open var arguments: [String] {
return CommandLine.arguments // seems reasonable to flip the script here...
}
open var hostName: String {
if let name = Host.current().name {
return name
} else {
return "localhost"
}
}
open var processName: String = _CFProcessNameString()._swiftObject
open var processIdentifier: Int32 {
#if os(Windows)
return Int32(GetProcessId(GetCurrentProcess()))
#else
return Int32(getpid())
#endif
}
open var globallyUniqueString: String {
let uuid = CFUUIDCreate(kCFAllocatorSystemDefault)
return CFUUIDCreateString(kCFAllocatorSystemDefault, uuid)._swiftObject
}
open var operatingSystemVersionString: String {
let fallback = "Unknown"
#if os(Linux)
let version = try? String(contentsOf: URL(fileURLWithPath: "/proc/version_signature", isDirectory: false), encoding: .utf8)
return version ?? fallback
#else
return CFCopySystemVersionString()?._swiftObject ?? fallback
#endif
}
open var operatingSystemVersion: OperatingSystemVersion {
// The following fallback values match Darwin Foundation
let fallbackMajor = -1
let fallbackMinor = 0
let fallbackPatch = 0
let versionString: String
#if canImport(Darwin)
guard let systemVersionDictionary = _CFCopySystemVersionDictionary() else {
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
}
let productVersionKey = unsafeBitCast(_kCFSystemVersionProductVersionKey, to: UnsafeRawPointer.self)
guard let productVersion = unsafeBitCast(CFDictionaryGetValue(systemVersionDictionary, productVersionKey), to: NSString?.self) else {
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
}
versionString = productVersion._swiftObject
#elseif os(Windows)
guard let ntdll = ("ntdll.dll".withCString(encodedAs: UTF16.self) {
LoadLibraryExW($0, nil, DWORD(LOAD_LIBRARY_SEARCH_SYSTEM32))
}) else {
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
}
defer { FreeLibrary(ntdll) }
typealias RTLGetVersionTy = @convention(c) (UnsafeMutablePointer<RTL_OSVERSIONINFOW>) -> NTSTATUS
guard let pfnRTLGetVersion = unsafeBitCast(GetProcAddress(ntdll, "RtlGetVersion"), to: Optional<RTLGetVersionTy>.self) else {
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
}
var osVersionInfo = RTL_OSVERSIONINFOW()
osVersionInfo.dwOSVersionInfoSize = DWORD(MemoryLayout<RTL_OSVERSIONINFOW>.size)
guard pfnRTLGetVersion(&osVersionInfo) == 0 else {
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
}
return OperatingSystemVersion(
majorVersion: Int(osVersionInfo.dwMajorVersion),
minorVersion: Int(osVersionInfo.dwMinorVersion),
patchVersion: Int(osVersionInfo.dwBuildNumber)
)
#else
var utsNameBuffer = utsname()
guard uname(&utsNameBuffer) == 0 else {
return OperatingSystemVersion(majorVersion: fallbackMajor, minorVersion: fallbackMinor, patchVersion: fallbackPatch)
}
let release = withUnsafePointer(to: &utsNameBuffer.release.0) {
return String(cString: $0)
}
let idx = release.firstIndex(of: "-") ?? release.endIndex
versionString = String(release[..<idx])
#endif
let versionComponents = versionString.split(separator: ".").map(String.init).compactMap({ Int($0) })
let majorVersion = versionComponents.dropFirst(0).first ?? fallbackMajor
let minorVersion = versionComponents.dropFirst(1).first ?? fallbackMinor
let patchVersion = versionComponents.dropFirst(2).first ?? fallbackPatch
return OperatingSystemVersion(majorVersion: majorVersion, minorVersion: minorVersion, patchVersion: patchVersion)
}
internal let _processorCount = __CFProcessorCount()
open var processorCount: Int {
return Int(_processorCount)
}
internal let _activeProcessorCount = __CFActiveProcessorCount()
open var activeProcessorCount: Int {
return Int(_activeProcessorCount)
}
internal let _physicalMemory = __CFMemorySize()
open var physicalMemory: UInt64 {
return _physicalMemory
}
open func isOperatingSystemAtLeast(_ version: OperatingSystemVersion) -> Bool {
let ourVersion = operatingSystemVersion
if ourVersion.majorVersion < version.majorVersion {
return false
}
if ourVersion.majorVersion > version.majorVersion {
return true
}
if ourVersion.minorVersion < version.minorVersion {
return false
}
if ourVersion.minorVersion > version.minorVersion {
return true
}
if ourVersion.patchVersion < version.patchVersion {
return false
}
if ourVersion.patchVersion > version.patchVersion {
return true
}
return true
}
open var systemUptime: TimeInterval {
return CFGetSystemUptime()
}
open var userName: String {
return NSUserName()
}
open var fullUserName: String {
return NSFullUserName()
}
}
// SPI for TestFoundation
internal extension ProcessInfo {
var _processPath: String {
return String(cString: _CFProcessPath())
}
}