diff --git a/CloverApp/Clover.xcodeproj/project.pbxproj b/CloverApp/Clover.xcodeproj/project.pbxproj index 488d9cfef..c3be25f20 100644 --- a/CloverApp/Clover.xcodeproj/project.pbxproj +++ b/CloverApp/Clover.xcodeproj/project.pbxproj @@ -21,7 +21,9 @@ 9552D748236F33CA00C93377 /* CloverDaemonNew in Copy tools */ = {isa = PBXBuildFile; fileRef = 9552D745236F33A700C93377 /* CloverDaemonNew */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 9555AF26238EE53300108C33 /* InstallerOutline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9555AF25238EE53300108C33 /* InstallerOutline.swift */; }; 9555AF28238EFDAD00108C33 /* DriversCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9555AF27238EFDAD00108C33 /* DriversCollection.swift */; }; + 955689DB23A2728000AD323C /* IO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955689DA23A2728000AD323C /* IO.swift */; }; 9556CAF5238DF75600082671 /* InstallerOutline.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9556CAF3238DF75600082671 /* InstallerOutline.xib */; }; + 9558518E23BA3486002CB3D8 /* Speaker.png in Resources */ = {isa = PBXBuildFile; fileRef = 9558518D23BA3485002CB3D8 /* Speaker.png */; }; 955F7C6D238DCD170019D088 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 955F7C6C238DCD160019D088 /* DiskArbitration.framework */; }; 9560906A238C61E200ACD7F7 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 95609068238C61E200ACD7F7 /* MainMenu.xib */; }; 956090B7238C890600ACD7F7 /* Installer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 956090B9238C890600ACD7F7 /* Installer.xib */; }; @@ -199,7 +201,9 @@ 9552D740236F33A700C93377 /* CloverDaemonNew.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CloverDaemonNew.xcodeproj; path = CloverDaemonNew/CloverDaemonNew.xcodeproj; sourceTree = ""; }; 9555AF25238EE53300108C33 /* InstallerOutline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstallerOutline.swift; sourceTree = ""; }; 9555AF27238EFDAD00108C33 /* DriversCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DriversCollection.swift; sourceTree = ""; }; + 955689DA23A2728000AD323C /* IO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IO.swift; sourceTree = ""; }; 9556CAF4238DF75600082671 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/InstallerOutline.xib; sourceTree = ""; }; + 9558518D23BA3485002CB3D8 /* Speaker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Speaker.png; sourceTree = ""; }; 955F7C6C238DCD160019D088 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; }; 95609069238C61E200ACD7F7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 9560906C238C624200ACD7F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = ""; }; @@ -401,6 +405,14 @@ name = Products; sourceTree = ""; }; + 9558518C23BA3472002CB3D8 /* images */ = { + isa = PBXGroup; + children = ( + 9558518D23BA3485002CB3D8 /* Speaker.png */, + ); + path = images; + sourceTree = ""; + }; 95C51578236B21AE00E4A3A8 /* Products */ = { isa = PBXGroup; children = ( @@ -442,6 +454,7 @@ 95C51535236B1F7700E4A3A8 /* RunAtLogin.swift */, 95E68ACB235B862F002B37A5 /* ViewController.swift */, 95E68ADE235B86A1002B37A5 /* bdmesg.swift */, + 955689DA23A2728000AD323C /* IO.swift */, 95E68ADD235B86A1002B37A5 /* Disks.swift */, 95E68ADB235B86A1002B37A5 /* Extensions.swift */, 954BBE98238196EE0032425F /* Locale.swift */, @@ -455,6 +468,7 @@ 95609068238C61E200ACD7F7 /* MainMenu.xib */, 95E68AD9235B8666002B37A5 /* Installer */, 95E68ACD235B8632002B37A5 /* Assets.xcassets */, + 9558518C23BA3472002CB3D8 /* images */, 954DECD423899F5F006A9876 /* Bootmanager.png */, 95E68AD2235B8632002B37A5 /* Info.plist */, 95E68AD3235B8632002B37A5 /* Clover.entitlements */, @@ -517,7 +531,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1120; - LastUpgradeCheck = 1120; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = CloverHackyColor; TargetAttributes = { 95E68AC5235B862F002B37A5 = { @@ -658,6 +672,7 @@ buildActionMask = 2147483647; files = ( 9556CAF5238DF75600082671 /* InstallerOutline.xib in Resources */, + 9558518E23BA3486002CB3D8 /* Speaker.png in Resources */, 956090B7238C890600ACD7F7 /* Installer.xib in Resources */, 954DECD523899F5F006A9876 /* Bootmanager.png in Resources */, 95E68ACE235B8632002B37A5 /* Assets.xcassets in Resources */, @@ -730,6 +745,7 @@ 95C515222369BAF500E4A3A8 /* NVRAM.swift in Sources */, 95C51536236B1F7700E4A3A8 /* RunAtLogin.swift in Sources */, 95E68AE0235B86A1002B37A5 /* Extensions.swift in Sources */, + 955689DB23A2728000AD323C /* IO.swift in Sources */, 9555AF26238EE53300108C33 /* InstallerOutline.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -970,6 +986,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IBC_WARNINGS = NO; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -1026,6 +1043,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IBC_WARNINGS = NO; MACOSX_DEPLOYMENT_TARGET = 10.9; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -1039,18 +1057,19 @@ 95E68AD7235B8632002B37A5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Clover/Clover.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1.12; + CURRENT_PROJECT_VERSION = 1.13; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Clover/Frameworks", ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/Frameworks/ObjectiveGit.framework/Headers/"; IBC_WARNINGS = YES; INFOPLIST_FILE = Clover/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1061,7 +1080,7 @@ "$(inherited)", "$(PROJECT_DIR)/Clover/Frameworks", ); - MARKETING_VERSION = 1.12; + MARKETING_VERSION = 1.13; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1074,18 +1093,19 @@ 95E68AD8235B8632002B37A5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Clover/Clover.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 1.12; + CURRENT_PROJECT_VERSION = 1.13; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Clover/Frameworks", ); + HEADER_SEARCH_PATHS = "$(SRCROOT)/Frameworks/ObjectiveGit.framework/Headers/"; INFOPLIST_FILE = Clover/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1095,7 +1115,7 @@ "$(inherited)", "$(PROJECT_DIR)/Clover/Frameworks", ); - MARKETING_VERSION = 1.12; + MARKETING_VERSION = 1.13; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/CloverApp/Clover.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/CloverApp/Clover.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000..f9b0d7c5e --- /dev/null +++ b/CloverApp/Clover.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/CloverApp/Clover/AppDelegate.swift b/CloverApp/Clover/AppDelegate.swift index b3062d119..053f61d42 100644 --- a/CloverApp/Clover/AppDelegate.swift +++ b/CloverApp/Clover/AppDelegate.swift @@ -95,6 +95,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { selector: #selector(self.reFreshDisksList), name: Notification.Name("DiskDisappeared"), object: nil) + NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.reFreshDisksList), name: NSWorkspace.didMountNotification, @@ -139,17 +140,22 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate { self.popover?.delegate = self } - if #available(OSX 10.10, *) { - if let button = sender as? NSStatusBarButton { - self.popover?.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.maxY) - } - } else { - if let v = sender as? NSView { - self.popover?.show(relativeTo: v.bounds, of: v, preferredEdge: NSRectEdge.maxY) - } + DispatchQueue.main.async { + (self.popover?.contentViewController as? SettingsViewController)?.setUpInfo() } - NSApp.activate(ignoringOtherApps: true) + DispatchQueue.main.async { + if #available(OSX 10.10, *) { + if let button = sender as? NSStatusBarButton { + self.popover?.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.maxY) + } + } else { + if let v = sender as? NSView { + self.popover?.show(relativeTo: v.bounds, of: v, preferredEdge: NSRectEdge.maxY) + } + } + NSApp.activate(ignoringOtherApps: true) + } } func popoverShouldDetach(_ popover: NSPopover) -> Bool { diff --git a/CloverApp/Clover/Base.lproj/Settings.xib b/CloverApp/Clover/Base.lproj/Settings.xib index a52121edd..381afdf77 100644 --- a/CloverApp/Clover/Base.lproj/Settings.xib +++ b/CloverApp/Clover/Base.lproj/Settings.xib @@ -1,8 +1,8 @@ - + - + @@ -12,34 +12,16 @@ - + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -77,7 +41,7 @@ - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -163,7 +77,7 @@ - + @@ -172,7 +86,7 @@ - + @@ -181,48 +95,11 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + @@ -266,7 +134,7 @@ - + - + @@ -312,7 +180,7 @@ - - - - - - - - - - - - - - - - + @@ -379,7 +222,7 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -425,21 +697,35 @@ + + + + + + + + - + + + + + + + @@ -451,6 +737,9 @@ + + + diff --git a/CloverApp/Clover/IO.swift b/CloverApp/Clover/IO.swift new file mode 100644 index 000000000..682546f9f --- /dev/null +++ b/CloverApp/Clover/IO.swift @@ -0,0 +1,161 @@ +// +// IO.swift +// Clover +// +// Created by vector sigma on 12/12/2019. +// Copyright © 2019 CloverHackyColor. All rights reserved. +// + +import Foundation + +// MARK: get IODeviceTree:/efi dictionary +fileprivate func getEFItree() -> NSMutableDictionary? { + var ref: io_registry_entry_t + var masterPort = mach_port_t() + var oResult: kern_return_t + var result: kern_return_t + oResult = IOMasterPort(bootstrap_port, &masterPort) + + if oResult != KERN_SUCCESS { + return nil + } + + ref = IORegistryEntryFromPath(masterPort, "IODeviceTree:/efi") + if ref == 0 { + return nil + } + var dict : Unmanaged? + result = IORegistryEntryCreateCFProperties(ref, &dict, kCFAllocatorDefault, 0) + if result != KERN_SUCCESS { + IOObjectRelease(ref) + return nil + } + IOObjectRelease(ref) + return dict?.takeRetainedValue() +} + +/// Get firmware-vendor string. +func getFirmawareVendor() -> String? { + if let data = getEFItree()?.object(forKey: "firmware-vendor") as? Data { + var cleanedData = Data() + for i in 0.. NSDictionary? { + var ref: io_registry_entry_t + var masterPort = mach_port_t() + var oResult: kern_return_t + var result: kern_return_t + oResult = IOMasterPort(bootstrap_port, &masterPort) + + if oResult != KERN_SUCCESS { + return nil + } + + ref = IORegistryEntryFromPath(masterPort, "IODeviceTree:/efi/platform") + if ref == 0 { + return nil + } + var dict : Unmanaged? + result = IORegistryEntryCreateCFProperties(ref, &dict, kCFAllocatorDefault, 0) + if result != KERN_SUCCESS { + IOObjectRelease(ref) + return nil + } + IOObjectRelease(ref) + return dict?.takeRetainedValue() +} + +/// Get OEMVendor string. +func getOEMVendor() -> String? { + if let data = getEFIPlatform()?.object(forKey: "OEMVendor") as? Data { + return String(bytes: data, encoding: .utf8) + } + return nil +} + +/// Get OEMProduct string. +func getOEMProduct() -> String? { + if let data = getEFIPlatform()?.object(forKey: "OEMProduct") as? Data { + return String(bytes: data, encoding: .utf8) + } + return nil +} + +/// Get OEMBoard string. +func getOEMBoard() -> String? { + if let data = getEFIPlatform()?.object(forKey: "OEMBoard") as? Data { + return String(bytes: data, encoding: .utf8) + } + return nil +} + +/// Get SystemSerialNumber string. +func getSystemSerialNumber() -> String? { + if let data = getEFIPlatform()?.object(forKey: "SystemSerialNumber") as? Data { + var cleanedData = Data() + for i in 0.. String? { + if let data = getEFIPlatform()?.object(forKey: "Model") as? Data { + var cleanedData = Data() + for i in 0.. String? { + if let data = getEFIPlatform()?.object(forKey: "board-id") as? Data { + var cleanedData = Data() + for i in 0.. Bool { + var isUEFI = true + let fwname = getFirmawareVendor()?.lowercased() + + if fwname!.lowercased().hasPrefix("edk") + || fwname!.lowercased().hasPrefix("chameleon") + || fwname!.lowercased().hasPrefix("enoch") + || fwname!.lowercased().hasPrefix("duet") + || fwname!.lowercased().hasPrefix("clover") { + isUEFI = false + } + + return !isUEFI +} diff --git a/CloverApp/Clover/Installer/Installer.swift b/CloverApp/Clover/Installer/Installer.swift index 94aad3485..1a8dd37ae 100644 --- a/CloverApp/Clover/Installer/Installer.swift +++ b/CloverApp/Clover/Installer/Installer.swift @@ -20,6 +20,7 @@ class InstallerWindowController: NSWindowController, NSWindowDelegate { self.viewController = newValue } } + func windowShouldClose(_ sender: NSWindow) -> Bool { if AppSD.isInstalling { return false @@ -742,28 +743,28 @@ class InstallerViewController: NSViewController { let attributes = [/*NSAttributedString.Key.font: font,*/ NSAttributedString.Key.foregroundColor: textColor] let astr = NSAttributedString(string: text, attributes: attributes) - //DispatchQueue.global(qos: .background).async { - DispatchQueue.main.async { - if add { - self.infoText.textStorage?.append(astr) - } else { - self.infoText.string = "" - self.infoText.textStorage?.append(astr) - } - - if scroll { - let loc = self.infoText.string.lengthOfBytes(using: String.Encoding.utf8) - let range = NSRange(location: loc, length: 0) - self.infoText.scrollRangeToVisible(range) - } else { - self.infoText.scroll(NSPoint.zero) - } - } - //} + if add { + self.infoText.textStorage?.append(astr) + } else { + self.infoText.string = "" + self.infoText.textStorage?.append(astr) + } + + if scroll { + let loc = self.infoText.string.lengthOfBytes(using: String.Encoding.utf8) + let range = NSRange(location: loc, length: 0) + self.infoText.scrollRangeToVisible(range) + } else { + self.infoText.scroll(NSPoint.zero) + } } // MARK: Installation @IBAction func installPressed(_ sender: NSButton!) { + if AppSD.isInstalling { + NSSound.beep() + return + } /* NSString *targetVol = [CloverappDict objectForKey:@"targetVol"]; @@ -776,6 +777,9 @@ class InstallerViewController: NSViewController { NSString *cloverv2 = [CloverappDict objectForKey:@"CloverV2"]; NSString *boot1installPath = [CloverappDict objectForKey:@"boot1install"]; NSString *bootSectorsInstallSrc = [CloverappDict objectForKey:@"bootsectors-install"]; + NSString *backUpPath = [CloverappDict objectForKey:@"BackUpPath"]; + NSString *version = [CloverappDict objectForKey:@"version"]; + BOOL isESP = [[CloverappDict objectForKey:@"isESP"] boolValue]; */ let Cloverapp = NSMutableDictionary() @@ -785,6 +789,7 @@ class InstallerViewController: NSViewController { // minimum required arguments Cloverapp.setValue(self.targetVol, forKey: "targetVol") + Cloverapp.setValue(self.view.window!.title, forKey: "version") let disk = getBSDName(of: self.targetVol) ?? "" Cloverapp.setValue(disk, forKey: "disk") @@ -801,6 +806,9 @@ class InstallerViewController: NSViewController { post(text: "Error: can't install on \(filesystem.uppercased()) filesystem.", add: false, color: nil, scroll: false) return } + AppSD.isInstalling = true + self.installButton.isEnabled = false + self.spinner.startAnimation(nil) // drivers for sect in self.driversUEFI { @@ -845,35 +853,58 @@ class InstallerViewController: NSViewController { } // backup in ~/Desktop/EFI_Backup_date + self.post(text: "Checking files...\n", add: false, color: nil, scroll: false) if fm.fileExists(atPath: self.targetVol.addPath("EFI/CLOVER")) { + self.post(text: "doing the backup...\n", add: false, color: nil, scroll: false) + let df = DateFormatter() - df.dateFormat = "yyyy-MM-dd hh:mm:ss" + df.dateFormat = "yyyy-MM-dd_hh-mm-ss" let now = df.string(from: Date()) let revIn = findCloverRevision(at: self.targetVol.addPath("EFI")) ?? "0000" - let backUpPath = NSHomeDirectory().addPath("Desktop/CloverBackUp/EFI_r\(revIn)_\(now)") - do { - if !fm.fileExists(atPath: backUpPath.deletingLastPath) { - try fm.createDirectory(atPath: backUpPath.deletingLastPath, - withIntermediateDirectories: false, - attributes: nil) + let mediaName = getMediaName(from: getBSDParent(of: disk) ?? "") ?? "NoName" + let backUpPath = NSHomeDirectory().addPath("Desktop/CloverBackUp/\(mediaName)/r\(revIn)_\(now)/EFI") + if #available(OSX 10.10, *) { + DispatchQueue.global(qos: .userInteractive).async { + do { + if !fm.fileExists(atPath: backUpPath.deletingLastPath) { + try fm.createDirectory(atPath: backUpPath.deletingLastPath, + withIntermediateDirectories: true, + attributes: nil) + } + try fm.copyItem(atPath: self.targetVol.addPath("EFI"), + toPath: backUpPath) + //post(text: "backup made at '\(backUpPath)'.\n", add: true, color: nil, scroll: false) + Cloverapp.setValue(backUpPath, forKey: "BackUpPath") + self.installClover(disk: disk, settingDict: Cloverapp) + } catch { + DispatchQueue.main.async { + self.post(text: "The backup failed:\n", add: true, color: nil, scroll: false) + self.post(text: error.localizedDescription, add: false, color: nil, scroll: false) + AppSD.isInstalling = false + self.installButton.isEnabled = true + self.spinner.stopAnimation(nil) + } + } } - try fm.copyItem(atPath: self.targetVol.addPath("EFI"), - toPath: backUpPath) - - self.installClover(disk: disk, settingDict: Cloverapp) - } catch { - post(text: error.localizedDescription, add: false, color: nil, scroll: false) } + } else { - self.installClover(disk: disk, settingDict: Cloverapp) + if #available(OSX 10.10, *) { + DispatchQueue.global(qos: .userInteractive).async { + self.installClover(disk: disk, settingDict: Cloverapp) + } + } } } func installClover(disk: String, settingDict : NSDictionary) { - self.post(text: "Installation begin..", add: false, color: nil, scroll: false) + self.post(text: "Installation begin..\n", add: true, color: nil, scroll: false) if !isMountPoint(path: self.targetVol) { - NSSound.beep() - self.post(text: "Can't find target volume, installation aborted.", add: true, color: nil, scroll: false) + DispatchQueue.main.async { + NSSound.beep() + self.post(text: "Can't find target volume, installation aborted.", add: true, color: nil, scroll: false) + } + return } @@ -889,70 +920,97 @@ class InstallerViewController: NSViewController { try? fm.removeItem(atPath: "/tmp/Cloverapp") if settingDict.write(toFile: "/tmp/Cloverapp", atomically: false) { - self.installButton.isEnabled = false AppSD.isInstalling = true - self.spinner.startAnimation(nil) - self.view.window?.level = .floating // just a hack to keep window in front momentarily + + DispatchQueue.main.async { + self.spinner.startAnimation(nil) + self.installButton.isEnabled = false + self.view.window?.level = .floating // just a hack to keep window in front momentarily + } + DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) { self.view.window?.level = .normal } - //DispatchQueue.global(qos: .background).async { - let task = Process() - let msg = "Install Clover".locale - let helperPath = Bundle.main.executablePath!.deletingLastPath.addPath("Cloverhelper") - - let script = "do shell script \"'\(helperPath)'\" with prompt \"\(msg)\" with administrator privileges" - - task.launchPath = "/usr/bin/osascript" - task.arguments = ["-e", script] - let pipe: Pipe = Pipe() - - let stdOutHandler = { (file: FileHandle!) -> Void in - let data = file.availableData - //file.closeFile() - let output = String(decoding: data, as: UTF8.self) - DispatchQueue.main.async { - self.view.window?.level = .normal // restore window level to normal - self.post(text: "\n" + output, add: true, color: nil, scroll: true) - } - } - - task.standardOutput = pipe - task.standardError = pipe - pipe.fileHandleForReading.readabilityHandler = stdOutHandler - - task.terminationHandler = { t in - - if t.terminationStatus == 0 { - DispatchQueue.main.async { - self.post(text: "\nInstallation succeded.", add: true, color: nil, scroll: true) - } - } else { - NSSound.beep() - DispatchQueue.main.async { - self.post(text: "\nInstallation failed.", add: true, color: nil, scroll: true) - } - } - - DispatchQueue.main.async { - AppSD.isInstalling = false - self.installButton.isEnabled = true - self.spinner.stopAnimation(nil) - if isMountPoint(path: self.targetVol) { - self.targetVol = getMountPoint(from: disk) ?? "" - } - AppSD.reFreshDisksList() - self.setPreferences(for: self.targetVol) - } - } - task.launch() - //} + + let task = Process() + let msg = "Install Clover".locale + let helperPath = Bundle.main.executablePath!.deletingLastPath.addPath("Cloverhelper") + let script = "do shell script \"'\(helperPath)'\" with prompt \"\(msg)\" with administrator privileges" + task.launchPath = "/usr/bin/osascript" + task.arguments = ["-e", script] + let pipe: Pipe = Pipe() + + task.standardOutput = pipe + task.standardError = pipe + let fh = pipe.fileHandleForReading + fh.waitForDataInBackgroundAndNotify() + + var op1 : NSObjectProtocol! + op1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSFileHandleDataAvailable, + object: fh, queue: nil) { + notification -> Void in + let data = fh.availableData + if data.count > 0 { + let output = String(decoding: data, as: UTF8.self) + DispatchQueue.main.async { + if self.view.window?.level != .normal { + self.view.window?.level = .normal + } + + self.post(text: "\n" + output, + add: true, + color: nil, + scroll: true) + } + fh.waitForDataInBackgroundAndNotify() + } else { + NotificationCenter.default.removeObserver(op1 as Any) + } + } + + var op2 : NSObjectProtocol! + op2 = NotificationCenter.default.addObserver(forName: Process.didTerminateNotification, + object: task, queue: nil) { + notification -> Void in + NotificationCenter.default.removeObserver(op2 as Any) + let success = (task.terminationStatus == 0) + DispatchQueue.main.async { + let message = success ? "Installation succeded".locale : "Installation failed".locale + self.post(text: "\n\(message).", add: true, color: nil, scroll: true) + + + NSSound(named: success ? "Glass" : "Basso")?.play() + let alert = NSAlert() + alert.messageText = message + alert.informativeText = success ? "😀" : "😱" + alert.alertStyle = success ? .informational : .critical + alert.addButton(withTitle: "Ok".locale) + + alert.beginSheetModal(for: self.view.window!) { (reponse) in + AppSD.isInstalling = false + self.installButton.isEnabled = true + self.spinner.stopAnimation(nil) + if isMountPoint(path: self.targetVol) { + self.targetVol = getMountPoint(from: disk) ?? "" + } + AppSD.reFreshDisksList() + self.setPreferences(for: self.targetVol) + } + } + } + + task.launch() + task.waitUntilExit() } else { - NSSound.beep() - self.post(text: "Can't write temporary files, installation aborted.", add: true, color: nil, scroll: false) + DispatchQueue.main.async { + NSSound.beep() + self.post(text: "Can't write temporary files, installation aborted.", add: true, color: nil, scroll: false) + } } + + } } diff --git a/CloverApp/Clover/Installer/InstallerOutline.swift b/CloverApp/Clover/Installer/InstallerOutline.swift index c8f1b3d7c..763b58b9b 100644 --- a/CloverApp/Clover/Installer/InstallerOutline.swift +++ b/CloverApp/Clover/Installer/InstallerOutline.swift @@ -720,6 +720,9 @@ class InstallerOutViewController: NSViewController { NSString *cloverv2 = [CloverappDict objectForKey:@"CloverV2"]; NSString *boot1installPath = [CloverappDict objectForKey:@"boot1install"]; NSString *bootSectorsInstallSrc = [CloverappDict objectForKey:@"bootsectors-install"]; + NSString *backUpPath = [CloverappDict objectForKey:@"BackUpPath"]; + NSString *version = [CloverappDict objectForKey:@"version"]; + BOOL isESP = [[CloverappDict objectForKey:@"isESP"] boolValue]; */ let Cloverapp = NSMutableDictionary() @@ -729,6 +732,7 @@ class InstallerOutViewController: NSViewController { // minimum required arguments Cloverapp.setValue(self.targetVol, forKey: "targetVol") + Cloverapp.setValue(self.view.window!.title, forKey: "version") let disk = getBSDName(of: self.targetVol) ?? "" Cloverapp.setValue(disk, forKey: "disk") @@ -789,23 +793,28 @@ class InstallerOutViewController: NSViewController { } // backup in ~/Desktop/EFI_Backup_date + post(text: "Checking files...\n", add: false, color: nil, scroll: false) if fm.fileExists(atPath: self.targetVol.addPath("EFI/CLOVER")) { let df = DateFormatter() - df.dateFormat = "yyyy-MM-dd hh:mm:ss" + df.dateFormat = "yyyy-MM-dd_hh-mm-ss" let now = df.string(from: Date()) let revIn = findCloverRevision(at: self.targetVol.addPath("EFI")) ?? "0000" - let backUpPath = NSHomeDirectory().addPath("Desktop/CloverBackUp/EFI_r\(revIn)_\(now)") + let mediaName = getMediaName(from: getBSDParent(of: disk) ?? "") ?? "NoName" + let backUpPath = NSHomeDirectory().addPath("Desktop/CloverBackUp/\(mediaName)/r\(revIn)_\(now)/EFI") + do { if !fm.fileExists(atPath: backUpPath.deletingLastPath) { try fm.createDirectory(atPath: backUpPath.deletingLastPath, - withIntermediateDirectories: false, + withIntermediateDirectories: true, attributes: nil) } try fm.copyItem(atPath: self.targetVol.addPath("EFI"), toPath: backUpPath) - + //post(text: "backup made at '\(backUpPath)'.\n", add: true, color: nil, scroll: false) + Cloverapp.setValue(backUpPath, forKey: "BackUpPath") self.installClover(disk: disk, settingDict: Cloverapp) } catch { + post(text: "The backup failed:\n", add: true, color: nil, scroll: false) post(text: error.localizedDescription, add: false, color: nil, scroll: false) } } else { @@ -814,7 +823,7 @@ class InstallerOutViewController: NSViewController { } func installClover(disk: String, settingDict : NSDictionary) { - self.post(text: "Installation begin..", add: false, color: nil, scroll: false) + self.post(text: "Installation begin..\n", add: true, color: nil, scroll: false) if !isMountPoint(path: self.targetVol) { NSSound.beep() self.post(text: "Can't find target volume, installation aborted.", add: true, color: nil, scroll: false) @@ -847,30 +856,29 @@ class InstallerOutViewController: NSViewController { var err : NSDictionary? = nil let result : NSAppleEventDescriptor = NSAppleScript(source: script)!.executeAndReturnError(&err) - if (err != nil) { - NSSound.beep() - self.post(text: result.stringValue ?? "", add: false, color: nil, scroll: true) - self.post(text: "\nInstallation failed.", add: true, color: nil, scroll: true) - AppSD.isInstalling = false - self.spinner.stopAnimation(nil) - AppSD.reFreshDisksList() - if isMountPoint(path: self.targetVol) { - self.targetVol = getMountPoint(from: disk) ?? "" - self.installButton.isEnabled = true - self.setPreferences(for: self.targetVol) - } - } else { - self.post(text: result.stringValue ?? "", add: false, color: nil, scroll: true) - self.post(text: "\nInstallation succeded.", add: true, color: nil, scroll: true) - AppSD.isInstalling = false - self.spinner.stopAnimation(nil) - AppSD.reFreshDisksList() - if isMountPoint(path: self.targetVol) { - self.targetVol = getMountPoint(from: disk) ?? "" - self.installButton.isEnabled = true - self.setPreferences(for: self.targetVol) - } + self.post(text: result.stringValue ?? "", add: false, color: nil, scroll: true) + self.spinner.stopAnimation(nil) + let message = (err == nil) ? "Installation succeded".locale : "Installation failed".locale + self.post(text: "\n\(message).", add: true, color: nil, scroll: true) + + let alert = NSAlert() + alert.messageText = message + if #available(OSX 10.10, *) { + alert.informativeText = (err == nil) ? "😀" : "😱" } + alert.alertStyle = (err == nil) ? .informational : .critical + alert.addButton(withTitle: "Close".locale) + alert.beginSheetModal(for: self.view.window!) { (reponse) in + + } + AppSD.isInstalling = false + self.installButton.isEnabled = true + self.spinner.stopAnimation(nil) + if isMountPoint(path: self.targetVol) { + self.targetVol = getMountPoint(from: disk) ?? "" + } + AppSD.reFreshDisksList() + self.setPreferences(for: self.targetVol) } else { NSSound.beep() self.post(text: "Can't write temporary files, installation aborted.", add: true, color: nil, scroll: false) diff --git a/CloverApp/Clover/Locale.swift b/CloverApp/Clover/Locale.swift index 790b74730..0611c7431 100644 --- a/CloverApp/Clover/Locale.swift +++ b/CloverApp/Clover/Locale.swift @@ -49,10 +49,20 @@ func localize(view: NSView) { if x.title.count > 0 { x.title = x.title.locale } + } else if o is NSTabView { + let x = (o as! NSTabView) + for i in x.tabViewItems { + i.label = i.label.locale + if let v = i.view { + localize(view: v) + } + } } if o.subviews.count > 0 { - localize(view: o) + for v in o.subviews { + localize(view: v) + } } } } diff --git a/CloverApp/Clover/NVRAM.swift b/CloverApp/Clover/NVRAM.swift index 4cdd8e263..84bf3a7a2 100644 --- a/CloverApp/Clover/NVRAM.swift +++ b/CloverApp/Clover/NVRAM.swift @@ -42,6 +42,7 @@ func setNVRAM(key: String, stringValue: String) { var cmd : String = "do shell script \"" cmd += "sudo \(nvram_cmd) \(key)=\(stringValue)" // sudo required otherwise wont work! cmd += "\" with administrator privileges" + //DispatchQueue.global(qos: .background).async { let script: NSAppleScript? = NSAppleScript(source: cmd) var error : NSDictionary? = nil diff --git a/CloverApp/Clover/Releases.swift b/CloverApp/Clover/Releases.swift index 529a41070..d68c0f6e1 100644 --- a/CloverApp/Clover/Releases.swift +++ b/CloverApp/Clover/Releases.swift @@ -74,7 +74,7 @@ func getLatestReleases(reply: @escaping (String?, String?, String?, String?) -> print("appvers: \(appvers)") */ reply(bootlink, bootvers, applink, appvers) - }); + }) task.resume() } diff --git a/CloverApp/Clover/SettingsView.swift b/CloverApp/Clover/SettingsView.swift index e013606e8..2ba15daf7 100644 --- a/CloverApp/Clover/SettingsView.swift +++ b/CloverApp/Clover/SettingsView.swift @@ -8,16 +8,55 @@ import Cocoa +class LITabView: NSTabView { + var tabIndex: Int = 0 + var lastTabIndex: Int { + get { + return self.tabIndex + } set { + self.tabIndex = newValue + } + } +} + + +class SoundSlider : NSSlider { + var field : NSTextField? +} + class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionDownloadDelegate { // MARK: Variables + @IBOutlet var tabViewInfo : LITabView! + // tab 0 @IBOutlet var currentRevField : NSTextField! @IBOutlet var bootDeviceField : NSTextField! @IBOutlet var configPathField : FWTextField! + // tab 1 + @IBOutlet var snField : NSTextField! + @IBOutlet var modelField : NSTextField! + @IBOutlet var boardIdField : NSTextField! + // tab 2 + @IBOutlet var oemVendorField : NSTextField! + @IBOutlet var oemProductField : NSTextField! + @IBOutlet var oemBoardIdField : NSTextField! + // tab 3 + @IBOutlet var nativeNVRAMField : NSTextField! + @IBOutlet var bootTypeField : NSTextField! + @IBOutlet var firmwareVendorfield : NSTextField! + + @IBOutlet var tabViewFunc : LITabView! + @IBOutlet var tabViewFuncSelector : NSSegmentedControl! + // tab 0 @IBOutlet var disksPopUp : NSPopUpButton! @IBOutlet var autoMountButton : NSButton! @IBOutlet var unmountButton : NSButton! + // tab 1 @IBOutlet var themeField : FWTextField! - @IBOutlet var soundField : FWTextField! + // tab 2 + @IBOutlet var soundDevicePopUp : NSPopUpButton! + @IBOutlet var soundVolumeSlider : SoundSlider! + @IBOutlet var soundVolumeField : NSTextField! + @IBOutlet var disbaleSleepProxyButton : NSButton! @IBOutlet var makeRootRWButton : NSButton! @IBOutlet var installDaemonButton : NSButton! @@ -50,6 +89,8 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD var loaded : Bool = false + + override func awakeFromNib() { super.awakeFromNib() if !self.loaded { @@ -65,20 +106,33 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD if #available(OSX 10.10, *) { super.viewDidLoad() } - - var osminorVersion : Int = 9 - if #available(OSX 10.10, *) { - osminorVersion = ProcessInfo().operatingSystemVersion.minorVersion - } let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String + " Beta" self.appVersionField.stringValue = "v\(appVersion)" localize(view: self.view) + self.view.wantsLayer = true self.view.layer?.backgroundColor = NSColor.clear.cgColor + + self.tabViewFuncSelector.setImage(getCoreTypeImage(named: "SidebarInternalDisk", isTemplate: true), forSegment: 0) + self.tabViewFuncSelector.setImage(getCoreTypeImage(named: "SidebarMoviesFolder", isTemplate: true), forSegment: 1) + self.tabViewFuncSelector.setImage(getCoreTypeImage(named: "SidebarMusicFolder", isTemplate: true), forSegment: 2) self.themeField.delegate = self - self.soundField.delegate = self + + self.soundVolumeSlider.field = self.soundVolumeField + self.soundVolumeField.stringValue = kNotAvailable.locale + self.soundDevicePopUp.removeAllItems() + self.soundDevicePopUp.addItem(withTitle: "...") + + let soundDevices = getSoundDevices() + if soundDevices.count > 0 { + for sd in soundDevices { + self.soundDevicePopUp.addItem(withTitle: "\(sd.name) (\(sd.output.locale))") + self.soundDevicePopUp.lastItem?.representedObject = sd + } + } + self.soundVolumeSlider.doubleValue = 0 self.progressBar.isHidden = true @@ -87,6 +141,26 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD self.autoMountButton.isEnabled = false self.autoMountButton.isHidden = true + + // tab 1 + self.snField.stringValue = getSystemSerialNumber() ?? kNotAvailable.locale + self.modelField.stringValue = getEFIModel() ?? kNotAvailable.locale + self.boardIdField.stringValue = getEFIBoardID() ?? kNotAvailable.locale + // tab 2 + self.oemVendorField.stringValue = getOEMVendor() ?? kNotAvailable.locale + self.oemProductField.stringValue = getOEMProduct() ?? kNotAvailable.locale + self.oemBoardIdField.stringValue = getOEMBoard() ?? kNotAvailable.locale + + self.setUpInfo() + self.setUpdateButton() + } + + func setUpInfo() { + var osminorVersion : Int = 9 + if #available(OSX 10.10, *) { + osminorVersion = ProcessInfo().operatingSystemVersion.minorVersion + } + self.setUpdateInformations() let nvram = getNVRAM() @@ -98,17 +172,34 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD self.themeField.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : "" self.themeField.cell?.representedObject = self.themeField.stringValue - nvdata = nvram?.object(forKey: "Clover.Sound") as? Data - if #available(OSX 10.10, *) { - self.soundField.placeholderString = kNotAvailable.locale - } - self.soundField.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : "" - self.soundField.cell?.representedObject = self.soundField.stringValue - nvdata = nvram?.object(forKey: "Clover.RootRW") as? Data var value : String = String(decoding: nvdata ?? Data(), as: UTF8.self) self.makeRootRWButton.state = (value == "true") ? .on : .off + nvdata = nvram?.object(forKey: "Clover.SoundIndex") as? Data + if (nvdata != nil) { + let soundIndex = nvdata!.reversed().reduce(0) { $0 << 8 + UInt64($1) } + if soundIndex >= 0 && soundIndex <= 20 { + for item in self.soundDevicePopUp.itemArray { + if let sd = item.representedObject as? SoundDevice { + if sd.index == Int(soundIndex) { + self.soundDevicePopUp.select(item) + break + } + } + } + } + } + + nvdata = nvram?.object(forKey: "Clover.SoundVolume") as? Data + if (nvdata != nil) { + let volume = nvdata!.reversed().reduce(0) { $0 << 8 + UInt64($1) } + if volume >= 0 && volume <= 100 { + self.soundVolumeSlider.field?.stringValue = "\(volume)%" + self.soundVolumeSlider.doubleValue = Double(volume) + } + } + // copy the Swift Framenworks for oldest OSes if osminorVersion < 15 { self.makeRootRWButton.isEnabled = false @@ -118,14 +209,31 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD nvdata = nvram?.object(forKey: "Clover.DisableSleepProxyClient") as? Data value = String(decoding: nvdata ?? Data(), as: UTF8.self) self.disbaleSleepProxyButton.state = (value == "true") ? .on : .off - + + + // tab 3 + let fwname = getFirmawareVendor() + self.firmwareVendorfield.stringValue = "Firmware: \(fwname ?? kNotAvailable.locale)" + + let emuvarPresent = nvram?.object(forKey: "EmuVariableUefiPresent") != nil + var nvramIsNative : String? = nil + let isUEFI : String = isLegacyFirmware() ? "No".locale.lowercased() : "Yes".locale.lowercased() + + + if isUEFI == "Yes".locale.lowercased() { + nvramIsNative = emuvarPresent ? "No".locale.lowercased() : "Yes".locale.lowercased() + } + + self.nativeNVRAMField.stringValue = "\("NVRAM is native:".locale) " + (nvramIsNative ?? "unknown".locale) + + self.bootTypeField.stringValue = "UEFI: \(isUEFI)" + let daemonExist = fm.fileExists(atPath: kDaemonPath) && fm.fileExists(atPath: kLaunchPlistPath) self.unInstallDaemonButton.isEnabled = daemonExist - self.setUpdateButton() self.searchESPDisks() - + let itervals = ["never", "daily", "weekly", "monthly"] self.timeIntervalPopUp.removeAllItems() for i in itervals { @@ -154,7 +262,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD } else { self.lastUpdateCheckField.stringValue = "\("last checked:".locale) \("never".locale)" } - + self.timerUpdate = Timer.scheduledTimer(timeInterval: 60 * 60, target: self, selector: #selector(self.setUpdateTimer), @@ -377,20 +485,55 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD // MARK: Controls actions @IBAction func installClover(_ sender: NSButton!) { - if #available(OSX 10.11, *) { - if (AppSD.installerWC == nil) { - AppSD.installerWC = InstallerWindowController.loadFromNib() - } - - AppSD.installerWC?.showWindow(self) - } else { - if (AppSD.installerOutWC == nil) { - AppSD.installerOutWC = InstallerOutWindowController.loadFromNib() - } - - AppSD.installerOutWC?.showWindow(self) + + let myPath = Bundle.main.bundlePath.lowercased() + var isXcode = false + var showAlert = false + if (myPath.range(of: "/deriveddata/") != nil) { + showAlert = true + isXcode = true + } else if (myPath.range(of: "/apptranslocation/") != nil) { + showAlert = true + } + + if showAlert { + let alert = NSAlert() + alert.alertStyle = .critical + let path = isXcode ? "Xcode" : "App Trans Location" + alert.messageText = "Running from \(path)" + + if isXcode { + alert.informativeText = "The Installer should not run from \(path) because it can reuse old resources like old built dependencies (in the DerivedData directory) instead ones from the app bundle in which you may had made changes.\nThis appear to be a bug in the Xcode build system, so please move Clover.app somewhere else for real installations, unless you are a Developer and you're just testing." + } else { + alert.informativeText = "The Installer cannot run from the \(path) and surely it will fail the installation.\nPlease move Clover.app somewhere else or use\n\nsudo spctl --master-disable\n\nThanks.\n\nP.S. Clover.app is not code signed because this require a paid Apple Developer certificate We cannot effort. If you have doubs, officiale releases are here:\n\n https://github.com/CloverHackyColor/CloverBootloader/releases\n\n..and you can build the app by your self if you prefear as this project is completely open source!" + } + + if isXcode { + alert.addButton(withTitle: "OK".locale) + alert.runModal() + } else { + alert.addButton(withTitle: "Close".locale) + alert.runModal() + return + } + + } + DispatchQueue.main.async { + if #available(OSX 10.11, *) { + if (AppSD.installerWC == nil) { + AppSD.installerWC = InstallerWindowController.loadFromNib() + } + + AppSD.installerWC?.showWindow(self) + } else { + if (AppSD.installerOutWC == nil) { + AppSD.installerOutWC = InstallerOutWindowController.loadFromNib() + } + + AppSD.installerOutWC?.showWindow(self) + } + NSApp.activate(ignoringOtherApps: true) } - NSApp.activate(ignoringOtherApps: true) } @IBAction func installDaemon(_ sender: NSButton!) { @@ -492,9 +635,9 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD func controlTextDidEndEditing(_ obj: Notification) { if let field = obj.object as? NSTextField { let delete : Bool = field.stringValue.count == 0 - if field == self.themeField || field == soundField { + if field == self.themeField { if let old = field.cell?.representedObject as? String { - let key = (field == self.themeField) ? "Clover.Theme" : "Clover.Sound" + let key = "Clover.Theme" if old != field.stringValue { if delete { deleteNVRAM(key: key) @@ -511,6 +654,62 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD } } + @IBAction func soundSliderDidMove(_ sender: SoundSlider!) { + sender.field?.stringValue = "\(Int(sender.doubleValue))%" + + let key = "Clover.SoundVolume" + var num = Int(sender.doubleValue) + let value = String(format: "%%%02x", UInt8(num)) + setNVRAM(key: key, stringValue: value) + num = 0 + DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { + if let nvram = getNVRAM() { + if let nvdata = nvram.object(forKey: key) as? Data { + let volume = nvdata.reversed().reduce(0) { $0 << 8 + UInt64($1) } + num = (volume >= 0 && volume <= 100) ? Int(num) : 0 + } + } + sender.field?.stringValue = "\(num)%" + sender.doubleValue = Double(num) + } + } + + @IBAction func soundDeviceSelected(_ sender: NSPopUpButton!) { + let key = "Clover.SoundIndex" + if let sd = sender.selectedItem?.representedObject as? SoundDevice { + let value = String(format: "%%%02x", UInt8(sd.index)) + setNVRAM(key: key, stringValue: value) + } + + DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) { + var index : Int = -1 + if let nvram = getNVRAM() { + if let nvdata = nvram.object(forKey: key) as? Data { + let val = nvdata.reversed().reduce(0) { $0 << 8 + UInt64($1) } + index = (val >= 0 && val < self.soundDevicePopUp.numberOfItems) ? Int(val) : -1 + } + } + + if index >= 0 { + var found = false + for item in self.soundDevicePopUp.itemArray { + if let sd = item.representedObject as? SoundDevice { + if sd.index == index { + found = true + self.soundDevicePopUp.select(item) + break + } + } + } + if !found { + self.soundDevicePopUp.selectItem(at: 0) + } + } else { + self.soundDevicePopUp.selectItem(at: 0) + } + } + } + @IBAction func disableSleepProxy(_ sender: NSButton!) { let key = "Clover.DisableSleepProxyClient" if sender.state == .on { @@ -532,7 +731,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD @IBAction func makeRootRW(_ sender: NSButton!) { let key = "Clover.RootRW" if sender.state == .on { - setNVRAM(key: key, stringValue: "true"/*, error: &error*/) + setNVRAM(key: key, stringValue: "true") } else { deleteNVRAM(key: key) } @@ -617,7 +816,6 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD let secElapsed = Date().timeIntervalSinceReferenceDate - lastCheckDate.timeIntervalSinceReferenceDate if secElapsed >= ti { - print(secElapsed) self.searchUpdate() } } @@ -720,7 +918,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD alert.messageText = "Clover.app v\(appvers!)" alert.informativeText = "\(currVerS) => \(appvers!)" alert.alertStyle = .informational - alert.addButton(withTitle: "Update".locale) + alert.addButton(withTitle: "Download".locale) alert.addButton(withTitle: "Close".locale) if alert.runModal() == .alertFirstButtonReturn { NSWorkspace.shared.open(url) @@ -877,7 +1075,55 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD } - +// MARK: - Tab animation +extension SettingsViewController: NSTabViewDelegate { + @IBAction func selectTabInfo(_ sender: NSSegmentedControl!) { + let count = self.tabViewInfo.tabViewItems.count + + let index = self.tabViewInfo.indexOfTabViewItem(self.tabViewInfo.selectedTabViewItem!) + + if sender.selectedSegment == 1 { + if index >= (count - 1) { + NSSound.beep() + return + } + self.tabViewInfo.selectNextTabViewItem(nil) + } else { + if index <= 0 { + NSSound.beep() + return + } + self.tabViewInfo.selectPreviousTabViewItem(nil) + } + } + + @IBAction func selectFuncTab(_ sender: NSSegmentedControl!) { + self.tabViewFunc.selectTabViewItem(at: sender.indexOfSelectedItem) + } + + func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) { + if (tabViewItem != nil) { + if let t = tabView as? LITabView { + let position = CABasicAnimation(keyPath: "position") + + if t.lastTabIndex > t.indexOfTabViewItem(tabViewItem!) { + position.fromValue = NSValue(point: CGPoint(x: CGFloat(tabViewItem!.view!.frame.origin.x - 520), y: CGFloat(tabViewItem!.view!.frame.origin.y))) + } else { + position.fromValue = NSValue(point: CGPoint(x: CGFloat(tabViewItem!.view!.frame.origin.x + 520), y: CGFloat(tabViewItem!.view!.frame.origin.y))) + } + position.toValue = NSValue(point: CGPoint(x: CGFloat(tabViewItem!.view!.frame.origin.x), y: CGFloat(tabViewItem!.view!.frame.origin.y))) + tabViewItem?.view?.layer?.add(position, forKey: "controlViewPosition") + tabViewItem?.view?.animations = [ + "frameOrigin" : position + ] + + tabViewItem?.view?.animator().frame.origin = CGPoint(x: CGFloat(tabViewItem!.view!.frame.origin.x), y: CGFloat(tabViewItem!.view!.frame.origin.y)) + t.lastTabIndex = t.indexOfTabViewItem(tabViewItem!) + } + + } + } +} // MARK: Settings Window controller class SettingsWindowController: NSWindowController, NSWindowDelegate { @@ -919,3 +1165,4 @@ class SettingsWindowController: NSWindowController, NSWindowDelegate { } } + diff --git a/CloverApp/Clover/Shared.swift b/CloverApp/Clover/Shared.swift index 1145c97c8..86e6ebaac 100644 --- a/CloverApp/Clover/Shared.swift +++ b/CloverApp/Clover/Shared.swift @@ -104,3 +104,13 @@ func findCloverHashCommit(at EFIdir: String) -> String? { } return nil } + +// MARK: get image from CoreType.bundle +func getCoreTypeImage(named: String, isTemplate: Bool) -> NSImage? { + var image : NSImage? = nil + if let ctb = Bundle.init(path: "/System/Library/CoreServices/CoreTypes.bundle") { + image = NSImage(byReferencingFile: ctb.path(forResource: named, ofType: "icns", inDirectory: nil) ?? "") + } + image?.isTemplate = isTemplate + return image +} diff --git a/CloverApp/Clover/bdmesg.swift b/CloverApp/Clover/bdmesg.swift index f590505ec..99cbf25e9 100644 --- a/CloverApp/Clover/bdmesg.swift +++ b/CloverApp/Clover/bdmesg.swift @@ -8,6 +8,7 @@ import Foundation +/// Get Clover boot-log (or compatible) func dumpBootlog() -> String? { var root: io_registry_entry_t var bootLog: CFTypeRef? = nil @@ -45,6 +46,7 @@ func dumpBootlog() -> String? { return log } +/// Get Find the Clover Revision from the boot-log func findCloverRevision() -> String? { let bdmesg = dumpBootlog() var rev : String? = nil @@ -60,6 +62,20 @@ func findCloverRevision() -> String? { return rev } +/// Determine if We're booted with Clover (legay or UEFI) +func bootByClover() -> Bool { + let bdmesg = dumpBootlog() + if (bdmesg != nil) { + for line in bdmesg!.components(separatedBy: .newlines) { + if (line.range(of: "Starting Clover revision: ") != nil) { + return true + } + } + } + return false +} + +/// Find the Clover hash commit (from the boot-log) func findCloverHash() -> String? { let bdmesg = dumpBootlog() var rev : String? = nil @@ -76,6 +92,7 @@ func findCloverHash() -> String? { return rev } +/// Find the UUID of the partition boot device Clover starts from. func findBootPartitionDevice() -> String? { var bsd :String? = nil if let bdmesg : String = dumpBootlog() { @@ -115,6 +132,7 @@ func findBootPartitionDevice() -> String? { return bsd } +/// Find the relative path of the config.plist loaded by Clover. func findConfigPath() -> String? { var path : String? = nil if let log : String = dumpBootlog() { @@ -140,3 +158,43 @@ func findConfigPath() -> String? { } return path } + +/// Struct for Start up Sound (name, output, index). +struct SoundDevice { + var name: String + var output: String + var index: Int +} + +/// Return an array of SoundDevice detected by Clover +func getSoundDevices() -> [SoundDevice] { + var devices = [SoundDevice]() + if let bdmesg = dumpBootlog() { + for line in bdmesg.components(separatedBy: .newlines) { + // Found Audio Device IDT 92HD91BXX (Headphones) at index 0 + if (line.range(of: "Found Audio Device ") != nil && line.range(of: " at index ") != nil) { + var name = line.components(separatedBy: "Found Audio Device ")[1].components(separatedBy: " at index")[0] + let output = name.components(separatedBy: "(")[1].components(separatedBy: ")")[0] + name = name.components(separatedBy: " (")[0] + let index = line.components(separatedBy: " at index ")[1] + if let i : Int = Int(index) { + // print("\(name) at index \(i) (\(output))") + if i >= 0 { + var found = false // avoid duplicates + for d in devices { + if d.name == name && d.output == output && d.index == i { + found = true + break + } + } + if !found { + let sd = SoundDevice(name: name, output: output, index: i) + devices.append(sd) + } + } + } + } + } + } + return devices +} diff --git a/CloverApp/Clover/images/Speaker.png b/CloverApp/Clover/images/Speaker.png new file mode 100644 index 000000000..afefe6419 Binary files /dev/null and b/CloverApp/Clover/images/Speaker.png differ diff --git a/CloverApp/CloverDaemonNew/CloverDaemonNew.xcodeproj/project.pbxproj b/CloverApp/CloverDaemonNew/CloverDaemonNew.xcodeproj/project.pbxproj index 65b6fdf1e..76c25beb1 100644 --- a/CloverApp/CloverDaemonNew/CloverDaemonNew.xcodeproj/project.pbxproj +++ b/CloverApp/CloverDaemonNew/CloverDaemonNew.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 953DBFDF236F037400B0C4FB /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 953DBFDE236F037400B0C4FB /* main.swift */; }; 954FF20E2371B13C00C3D94C /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 954FF20D2371B13C00C3D94C /* DiskArbitration.framework */; }; 954FF2102371B16300C3D94C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 954FF20F2371B16300C3D94C /* IOKit.framework */; }; + 956034F623B7185B00E138D9 /* IO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956034F523B7185A00E138D9 /* IO.swift */; }; + 95A9A87E23B63F570060F1CA /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A9A87D23B63F570060F1CA /* Constants.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -25,6 +27,8 @@ 953DBFDE236F037400B0C4FB /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 954FF20D2371B13C00C3D94C /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; }; 954FF20F2371B16300C3D94C /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + 956034F523B7185A00E138D9 /* IO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IO.swift; path = ../../Clover/IO.swift; sourceTree = ""; }; + 95A9A87D23B63F570060F1CA /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,6 +65,8 @@ isa = PBXGroup; children = ( 953DBFDE236F037400B0C4FB /* main.swift */, + 956034F523B7185A00E138D9 /* IO.swift */, + 95A9A87D23B63F570060F1CA /* Constants.swift */, 953D98862377094A003B369E /* Disks.swift */, 953B8DEF2370BB5C007E36E3 /* NVRAM.swift */, 953B8DED2370BB1A007E36E3 /* bdmesg.swift */, @@ -104,7 +110,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1120; - LastUpgradeCheck = 1120; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = CloverHackyColor; TargetAttributes = { 953DBFDA236F037400B0C4FB = { @@ -141,6 +147,8 @@ 953DBFDF236F037400B0C4FB /* main.swift in Sources */, 953B8DF02370BB5D007E36E3 /* NVRAM.swift in Sources */, 953B8DEE2370BB1A007E36E3 /* bdmesg.swift in Sources */, + 956034F623B7185B00E138D9 /* IO.swift in Sources */, + 95A9A87E23B63F570060F1CA /* Constants.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -265,6 +273,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -287,6 +296,7 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; GCC_WARN_UNUSED_VARIABLE = NO; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/CloverApp/CloverDaemonNew/CloverDaemonNew/Constants.swift b/CloverApp/CloverDaemonNew/CloverDaemonNew/Constants.swift new file mode 100644 index 000000000..4ce7bbf54 --- /dev/null +++ b/CloverApp/CloverDaemonNew/CloverDaemonNew/Constants.swift @@ -0,0 +1,20 @@ +// +// Constants.swift +// CloverDaemonNew +// +// Created by vector sigma on 26/12/2019. +// Copyright © 2019 CloverHackyColor. All rights reserved. +// + +import Foundation + +let wrapperPath = "/Library/Application Support/Clover/CloverWrapper.sh" +let frameworksPath = "/Library/Application Support/Clover/Frameworks" +let loginWindowPath = "/var/root/Library/Preferences/com.apple.loginwindow.plist" +let cloverLogOut = "/Library/Application Support/Clover/CloverLogOut" +let cloverDaemonNewPath = "/Library/Application Support/Clover/CloverDaemonNew" +let launchPlistPath = "/Library/LaunchDaemons/com.slice.CloverDaemonNew.plist" + +let oldLaunchPlistPath = "/Library/LaunchDaemons/com.projectosx.clover.daemon.plist" +let oldLaunchDaemonPath = "/Library/Application Support/Clover/CloverDaemon" +let oldLogoutHookPath = "/Library/Application Support/Clover/CloverDaemon-stopservice" diff --git a/CloverApp/CloverDaemonNew/CloverDaemonNew/main.swift b/CloverApp/CloverDaemonNew/CloverDaemonNew/main.swift index 066edeb50..5840d23d6 100644 --- a/CloverApp/CloverDaemonNew/CloverDaemonNew/main.swift +++ b/CloverApp/CloverDaemonNew/CloverDaemonNew/main.swift @@ -8,18 +8,11 @@ import Foundation +let daemonVersion = "1.0.9" + let fm = FileManager.default -let daemonVersion = "1.0.8" - -let wrapperPath = "/Library/Application Support/Clover/CloverWrapper.sh" -let frameworksPath = "/Library/Application Support/Clover/Frameworks" -let loginWindowPath = "/var/root/Library/Preferences/com.apple.loginwindow.plist" -let cloverLogOut = "/Library/Application Support/Clover/CloverLogOut" -let cloverDaemonNewPath = "/Library/Application Support/Clover/CloverDaemonNew" -let launchPlistPath = "/Library/LaunchDaemons/com.slice.CloverDaemonNew.plist" - -let oldLaunchPlistPath = "/Library/LaunchDaemons/com.projectosx.clover.daemon.plist" +var mountRWCalled = fm.isWritableFile(atPath: "/") func execAttr() -> [FileAttributeKey : Any] { var attributes = [FileAttributeKey : Any]() @@ -55,15 +48,6 @@ func run(cmd: String) { task.launch() } -func doJob() { - if let nvram = getNVRAM() { - checkSleepProxyClient(nvram: nvram) - } else { - print("nvram not present in this machine.") - } - exit(EXIT_SUCCESS) -} - func checkSleepProxyClient(nvram: NSDictionary) { let mDNSResponderPath = "/System/Library/LaunchDaemons/com.apple.mDNSResponder.plist" let disableOption = "-DisableSleepProxyClient" @@ -72,17 +56,17 @@ func checkSleepProxyClient(nvram: NSDictionary) { if let nvdata = nvram.object(forKey: "Clover.DisableSleepProxyClient") as? Data { value = String(decoding: nvdata, as: UTF8.self) - print("Clover.DisableSleepProxyClient=\(value)") + print("Clover.DisableSleepProxyClient=\(value).") } else { print("Clover.DisableSleepProxyClient is not set.") } if !fm.fileExists(atPath: mDNSResponderPath) { - print("Error: cannot found \(mDNSResponderPath)") + print("Error: cannot found \(mDNSResponderPath).") return } if !fm.isWritableFile(atPath: "/") { - print("Cannot go ahead as / is read-only") + print("Note: root filesystem is read-only.") return } @@ -132,40 +116,123 @@ func getLogOutHook() -> String? { } func removeCloverRCScripts() { + let oldFiles : [String] = ["/etc/rc.boot.d/10.save_and_rotate_boot_log.local", + "/etc/rc.boot.d/20.mount_ESP.local", + "/etc/rc.boot.d/70.disable_sleep_proxy_client.local.disabled", + "/etc/rc.boot.d/70.disable_sleep_proxy_client.local", + "/etc/rc.clover.lib", + "/etc/rc.shutdown.d/80.save_nvram_plist.local", + oldLaunchDaemonPath, + oldLaunchPlistPath, + oldLogoutHookPath] + if fm.fileExists(atPath: oldLaunchPlistPath) { print("unloading old CloverDaemon..") run(cmd: "launchctl unload \(oldLaunchPlistPath)") - try? fm.removeItem(atPath: oldLaunchPlistPath) - if fm.fileExists(atPath: "/Library/Application Support/Clover/CloverDaemon") { - try? fm.removeItem(atPath: "/Library/Application Support/Clover/CloverDaemon") - } - - if fm.fileExists(atPath: "/Library/Application Support/Clover/CloverDaemon-stopservice") { - try? fm.removeItem(atPath: "/Library/Application Support/Clover/CloverDaemon-stopservice") - } } - let oldRCScripts : [String] = ["/etc/rc.boot.d/10.save_and_rotate_boot_log.local", - "/etc/rc.boot.d/20.mount_ESP.local", - "/etc/rc.boot.d/70.disable_sleep_proxy_client.local.disabled", - "/etc/rc.boot.d/70.disable_sleep_proxy_client.local", - "/etc/rc.clover.lib", - "/etc/rc.shutdown.d/80.save_nvram_plist.local"]; - - for rc in oldRCScripts { - if fm.fileExists(atPath: rc) { + for f in oldFiles { + if fm.fileExists(atPath: f) { if !fm.isWritableFile(atPath: "/") { run(cmd: "mount -uw /") - sleep(2) + sleep(3) } - print("Removing \(rc).") + print("Removing \(f).") do { - try fm.removeItem(atPath: rc) + try fm.removeItem(atPath: f) } catch { print(error) } } } + + if getLogOutHook() == oldLogoutHookPath { + print("Removing old logoutHook (\(oldLogoutHookPath))..") + run(cmd: "defaults delete com.apple.loginwindow LogoutHook") + } +} + +func installHook() { + print("Installing the LogoutHook..") + // if a hook exist and is not our one, then add a wrapper + if let loh = getLogOutHook() { + if loh != cloverLogOut { + if fm.fileExists(atPath: loh) { + let wrapper = +""" +#!/bin/sh + +'\(cloverLogOut)' + +# This file is automatically generated by CloverDaemonNew because +# it has detected you added a logout script somewhere else. +# if you edit this file, be aware that if you start to boot in UEFI +# CloverDaemonNew will take care to restore your custom logout script, +# but your script must be the last line to be detected again. +# The script path must be escaped within '' if contains spaces in the middle. +# NOTE: if your will is to add multiple scripts, please add them to +# the following script (and so not in this script): + +'\(loh)' +""" + print("Detected user logout hook at \(loh), merging it with CloverLogOut in CloverWrapper.sh.") + do { + try wrapper.write(toFile: wrapperPath, atomically: false, encoding: .utf8) + try fm.setAttributes(execAttr(), ofItemAtPath: wrapperPath) + + run(cmd: "defaults write com.apple.loginwindow LogoutHook '\(wrapperPath)'") + } catch { + print(error) + } + } else { + print("Detected user logout hook at \(loh), but the executable did not exist, installing our.") + run(cmd: "defaults write com.apple.loginwindow LogoutHook '\(cloverLogOut)'") + } + } else { + print("LogoutHook is already set.") + } + } else { + print("LogoutHook is not set, writing it.") + run(cmd: "defaults write com.apple.loginwindow LogoutHook '\(cloverLogOut)'") + } +} + +func unInstallHook() { + // what to do? remove the logout hook if it's our + var uninstall = false + if let loh = getLogOutHook() { + if (loh == cloverLogOut || loh == oldLogoutHookPath){ + // it is CloverLogOut + print("Removing CloverLogOut hook as EmuVariableUefiPresent doesn't exixts.") + uninstall = true + } else if loh == wrapperPath { + print("Removing CloverWrapper.sh logout hook as EmuVariableUefiPresent doesn't exixts.") + // it is CloverWrapper.sh. We have to mantain user script! + // get the user script path: + var scriptPath : String? = nil + if let lines = try? String(contentsOf: URL(fileURLWithPath: wrapperPath), + encoding: .utf8).components(separatedBy: .newlines) { + if lines.count > 0 { + scriptPath = lines.last + } + } + + if scriptPath != nil { + if fm.fileExists(atPath: scriptPath!) { + print("..but taking user logout hook script at \(scriptPath!).") + run(cmd: "defaults write com.apple.loginwindow LogoutHook \(scriptPath!)") + } else { + uninstall = true + } + } else { + uninstall = true + } + } + } + + if uninstall { + run(cmd: "defaults delete com.apple.loginwindow LogoutHook") + } } func main() { @@ -222,8 +289,9 @@ func main() { } // check options in nvram - var mountRWCalled = fm.isWritableFile(atPath: "/") - + let fv = getFirmawareVendor() ?? "unknown" + var needsLogoutHook = isLegacyFirmware() + print("Firmware vendor is '\(fv)'.") if let nvram = getNVRAM() { if let nvdata = nvram.object(forKey: "Clover.RootRW") as? Data { let value = String(decoding: nvdata, as: UTF8.self) @@ -235,80 +303,16 @@ func main() { } } } - - // using the logout Hook only if EmuVariableUefiPresent - let loh = getLogOutHook() - if (nvram.object(forKey: "EmuVariableUefiPresent") != nil || - nvram.object(forKey: "TestEmuVariableUefiPresent") != nil) { - - // if a hook exist and is not our one, then add a wrapper - if (loh != nil) { - if loh! != cloverLogOut && fm.fileExists(atPath: loh!) { - let wrapper = - """ -#!/bin/sh - -'\(cloverLogOut)' - -# This file is automatically generated by CloverDaemonNew because -# it has detected you added a logout script somewhere else. -# if you edit this file, be aware that if you start to boot in UEFI -# CloverDaemonNew will take care to restore your custom logout script, -# but your script must be the last line to be detected again. -# The script path must be escaped within '' if contains spaces in the middle. -# NOTE: if your will is to add multiple scripts, please add them to -# the following script (and so not in this script): - -'\(loh!)' -""" - print("Detected user logout hook at \(loh!), merging with it with CloverLogOut in CloverWrapper.sh.") - do { - try wrapper.write(toFile: wrapperPath, atomically: false, encoding: .utf8) - try fm.setAttributes(execAttr(), ofItemAtPath: wrapperPath) - - run(cmd: "defaults write com.apple.loginwindow LogoutHook '\(wrapperPath)'") - } catch { - print(error) - } - } else { - run(cmd: "defaults write com.apple.loginwindow LogoutHook '\(cloverLogOut)'") - } + + + if !needsLogoutHook { + if (nvram.object(forKey: "EmuVariableUefiPresent") != nil || + nvram.object(forKey: "TestEmuVariableUefiPresent") != nil) { + print("Found EmuVariableUefiPresent in NVRAM.") + needsLogoutHook = true } else { - run(cmd: "defaults write com.apple.loginwindow LogoutHook '\(cloverLogOut)'") - } - - if !fm.isWritableFile(atPath: "/") { - if !mountRWCalled { - print("making '/' writable as EmuVariableUefiPresent is present to save nvram.") - } - run(cmd: "mount -uw /") - } - } else { - // what to do? remove the logout hook if it's our - if (loh != nil) { - if loh! == cloverLogOut { - // it is CloverLogOut - print("Removing CloverLogOut hook as EmuVariable is no longer present.") - run(cmd: "defaults delete com.apple.loginwindow LogoutHook") - } else if loh! == wrapperPath { - print("Removing CloverWrapper.sh logout hook as EmuVariable is no longer present.") - // it is CloverWrapper.sh. We have to mantain user script! - // get the user script path: - var script : String? = nil - if let lines = try? String(contentsOf: URL(fileURLWithPath: wrapperPath), - encoding: .utf8).components(separatedBy: .newlines) { - if lines.count > 0 { - script = lines.last - } - } - if script != nil { - print("..but taking user logout hook script at \(script!).") - run(cmd: "defaults write com.apple.loginwindow LogoutHook \(script!)") - } else { - run(cmd: "defaults delete com.apple.loginwindow LogoutHook") - } - } + print("EmuVariableUefiPresent doesn't exist.") } } @@ -409,6 +413,12 @@ func main() { } else { print("Error: nvram not present in this System.") } + + if needsLogoutHook { + installHook() + } else { + unInstallHook() + } print("Logout hook is: \(getLogOutHook() ?? "none")") signal(SIGTERM, SIG_IGN) //preferred @@ -417,7 +427,12 @@ func main() { now = df.string(from: Date()) print("") print("SIGTERM received at \(now)") - doJob() + if let nvram = getNVRAM() { + checkSleepProxyClient(nvram: nvram) + } else { + print("nvram not present in this machine.") + } + exit(EXIT_SUCCESS) } sigtermSource.resume() @@ -467,10 +482,11 @@ if CommandLine.arguments.contains("--install") { ofItemAtPath: cloverDaemonNewPath) - let logouthookSrc = myPath.deletingLastPath.addPath("CloverLogOut") + let logouthookSrc = myPath.deletingLastPath.addPath(cloverLogOut.lastPath) if fm.fileExists(atPath: cloverLogOut) { try fm.removeItem(atPath: cloverLogOut) } + if fm.fileExists(atPath: logouthookSrc) { try fm.copyItem(atPath: logouthookSrc, toPath: cloverLogOut) @@ -478,6 +494,22 @@ if CommandLine.arguments.contains("--install") { ofItemAtPath: cloverLogOut) } + var needsLogoutHook = isLegacyFirmware() + if !needsLogoutHook { + if let nvram = getNVRAM() { + if (nvram.object(forKey: "EmuVariableUefiPresent") != nil || + nvram.object(forKey: "TestEmuVariableUefiPresent") != nil) { + needsLogoutHook = true + } + } + } + + if needsLogoutHook { + installHook() + } else { + unInstallHook() + } + try fm.setAttributes(launchAttr(), ofItemAtPath: launchPlistPath) if fm.fileExists(atPath: launchPlistPath) { run(cmd: "launchctl unload \(launchPlistPath)") @@ -511,6 +543,8 @@ if CommandLine.arguments.contains("--install") { if fm.fileExists(atPath: frameworksPath) { try fm.removeItem(atPath: frameworksPath) } + + unInstallHook() exit(EXIT_SUCCESS) } catch { print(error) diff --git a/CloverApp/CloverLogOut/CloverLogOut.xcodeproj/project.pbxproj b/CloverApp/CloverLogOut/CloverLogOut.xcodeproj/project.pbxproj index 8b189572d..b7716bdaa 100644 --- a/CloverApp/CloverLogOut/CloverLogOut.xcodeproj/project.pbxproj +++ b/CloverApp/CloverLogOut/CloverLogOut.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 95524B8E2380522A005F6425 /* bdmesg.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95524B8D2380522A005F6425 /* bdmesg.swift */; }; 95524B9023805233005F6425 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95524B8F23805232005F6425 /* Extensions.swift */; }; 955F7C70238DCD440019D088 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 955F7C6F238DCD440019D088 /* DiskArbitration.framework */; }; + 95CD16DF23B7A01500303BDB /* IO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95CD16DE23B7A01500303BDB /* IO.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -37,6 +38,7 @@ 95524B8D2380522A005F6425 /* bdmesg.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = bdmesg.swift; path = ../../Clover/bdmesg.swift; sourceTree = ""; }; 95524B8F23805232005F6425 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = ../../Clover/Extensions.swift; sourceTree = ""; }; 955F7C6F238DCD440019D088 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; }; + 95CD16DE23B7A01500303BDB /* IO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = IO.swift; path = ../../Clover/IO.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -72,6 +74,7 @@ isa = PBXGroup; children = ( 95524B7C238051AC005F6425 /* main.swift */, + 95CD16DE23B7A01500303BDB /* IO.swift */, 954BBE962381964F0032425F /* Shared.swift */, 95524B8923805210005F6425 /* NVRAM.swift */, 95524B8B2380521D005F6425 /* Disks.swift */, @@ -152,6 +155,7 @@ 95524B8A23805210005F6425 /* NVRAM.swift in Sources */, 95524B8E2380522A005F6425 /* bdmesg.swift in Sources */, 95524B7D238051AC005F6425 /* main.swift in Sources */, + 95CD16DF23B7A01500303BDB /* IO.swift in Sources */, 95524B8C2380521D005F6425 /* Disks.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/CloverApp/CloverLogOut/CloverLogOut/main.swift b/CloverApp/CloverLogOut/CloverLogOut/main.swift index 725226a4e..9ac4415e0 100644 --- a/CloverApp/CloverLogOut/CloverLogOut/main.swift +++ b/CloverApp/CloverLogOut/CloverLogOut/main.swift @@ -8,7 +8,7 @@ import Foundation -let cmdVersion = "1.0.3" +let cmdVersion = "1.0.4" let savedNVRAMPath = "/tmp/NVRAM_saved" let NVRAMSavedToRoot = "/tmp/NVRAM_savedToRoot" @@ -45,24 +45,6 @@ func run(cmd: String) { } func saveNVRAM(nvram: NSMutableDictionary, volume: String) { - /* - if (nvram.object(forKey: "efi-backup-boot-device") != nil) { - nvram.removeObject(forKey: "efi-backup-boot-device") - } - - if (nvram.object(forKey: "efi-backup-boot-device-data") != nil) { - nvram.removeObject(forKey: "efi-backup-boot-device-data") - } - - if (nvram.object(forKey: "install-product-url") != nil) { - nvram.removeObject(forKey: "install-product-url") - } - - if (nvram.object(forKey: "previous-system-uuid") != nil) { - nvram.removeObject(forKey: "previous-system-uuid") - } - */ - let bsdname = getBSDName(of: volume) ?? "" let uuid = getVolumeUUID(from: bsdname) ?? kNotAvailable if nvram.write(toFile: volume.addPath("nvram.plist"), atomically: false) { @@ -112,118 +94,113 @@ func main() { df.locale = Locale(identifier: "en_US") var now = df.string(from: Date()) log("- CloverLogOut v\(cmdVersion): logout begin at \(now)") + if let nvram = getNVRAM() { - // Check if we're running from CloverEFI - if (nvram.object(forKey: "EmuVariableUefiPresent") != nil || - nvram.object(forKey: "TestEmuVariableUefiPresent") != nil) { - - // we already saved once? Check if the nvram is changed - if fm.fileExists(atPath: savedNVRAMPath) { - if let old = NSDictionary(contentsOfFile: savedNVRAMPath) { - if nvram.isEqual(to: old) { - /* - We are going to exit but if the nvram is already saved - and is saved in the ESP, then remove /.nvram.plist - */ - if !fm.fileExists(atPath: NVRAMSavedToRoot) { - if fm.fileExists(atPath: "/nvram.plist") { - do { - try fm.removeItem(atPath: "/nvram.plist") - } catch { - log("\(error)") - } + // we already saved once? Check if the nvram is changed + if fm.fileExists(atPath: savedNVRAMPath) { + if let old = NSDictionary(contentsOfFile: savedNVRAMPath) { + if nvram.isEqual(to: old) { + /* + We are going to exit but if the nvram is already saved + and is saved in the ESP, then remove /.nvram.plist + */ + if !fm.fileExists(atPath: NVRAMSavedToRoot) { + if fm.fileExists(atPath: "/nvram.plist") { + do { + try fm.removeItem(atPath: "/nvram.plist") + } catch { + log("\(error)") } } - log("nvram not changed, nothing to do.") // hope user didn't delete it :-) - log("- CloverLogOut: end at \(now)") - exit(EXIT_SUCCESS) } + log("nvram not changed, nothing to do.") // hope user didn't delete it :-) + log("- CloverLogOut: end at \(now)") + exit(EXIT_SUCCESS) } } - - - var disk : String? = nil - var espList = [String]() - - /* find all internal ESP in the System as we don't want - to save the nvram in a USB pen drive (user will lost the nvram if not plugged in) - */ - for esp in getAllESPs() { - if isInternalDevice(diskOrMtp: esp) { - espList.append(esp) - } + } + + + var disk : String? = nil + var espList = [String]() + + /* find all internal ESP in the System as we don't want + to save the nvram in a USB pen drive (user will lost the nvram if not plugged in) + */ + for esp in getAllESPs() { + if isInternalDevice(diskOrMtp: esp) { + espList.append(esp) } - - // find the boot partition device and check if it is a ESP - if let bd = findBootPartitionDevice() { - if espList.contains(bd) { - // boot device is a ESP :-) - disk = bd - log("Detected ESP \(bd) as boot device.") - } + } + + // find the boot partition device and check if it is a ESP + if let bd = findBootPartitionDevice() { + if espList.contains(bd) { + // boot device is a ESP :-) + disk = bd + log("Detected ESP \(bd) as boot device.") } - - if (disk == nil) { - // boot device not found - if espList.count > 0 { - // we have an internal ESP, using that - disk = espList[0] - log("Will use ESP \(disk!) as boot device is not found.") - } else { - // use root - disk = getBSDName(of: "/") - log("Will use / as no boot device nor an internal ESP are found.") - } - } - - if (disk != nil) { - // get the mount point or mount it - var mounted : Bool = false - if let mp = getMountPoint(from: disk!) { - log("\(disk!) was already mounted.") - saveNVRAM(nvram: nvram, volume: mp) - if espList.contains(disk!) { - disableInsexing(for: mp) - } - return - } - - if !mounted { - log("mounting \(disk!)..") - mount(disk: disk!, at: nil) { (result) in - if result == true { - sleep(1) - var attempts = 0 - repeat { - attempts+=1 - if let mp = getMountPoint(from: disk!) { - mounted = true - saveNVRAM(nvram: nvram, volume: mp) - if espList.contains(disk!) { - disableInsexing(for: mp) - } - sleep(1) - umount(disk: disk!, force: true) - break - } - } while (mounted || attempts == 5) - } - } - } - - if !mounted { - log("mount failed for \(disk!).") - saveNVRAM(nvram: nvram, volume: "/") - } + } + + if (disk == nil) { + // boot device not found + if espList.count > 0 { + // we have an internal ESP, using that + disk = espList[0] + log("Will use ESP on \(disk!) as boot device is not found (or is not internal).") } else { - // CloverDaemonNew should have made the fs read-write for us. + // use root + disk = getBSDName(of: "/") + log("Will use / as nor the boot device nor an internal ESP was found.") + } + } + + if (disk != nil) { + // get the mount point or mount it + var mounted : Bool = false + if let mp = getMountPoint(from: disk!) { + log("\(disk!) was already mounted.") + saveNVRAM(nvram: nvram, volume: mp) + if espList.contains(disk!) { + disableInsexing(for: mp) + } + return + } + + if !mounted { + log("mounting \(disk!)..") + mount(disk: disk!, at: nil) { (result) in + if result == true { + sleep(1) + var attempts = 0 + repeat { + attempts+=1 + if let mp = getMountPoint(from: disk!) { + mounted = true + saveNVRAM(nvram: nvram, volume: mp) + if espList.contains(disk!) { + disableInsexing(for: mp) + } + sleep(1) + umount(disk: disk!, force: true) + break + } + } while (mounted || attempts == 5) + } + } + } + + if !mounted { + log("mount failed for \(disk!).") saveNVRAM(nvram: nvram, volume: "/") } } else { - log("EmuVariableUefi is not present, nvram will not be saved.") + // CloverDaemonNew should have made the fs read-write for us. + saveNVRAM(nvram: nvram, volume: "/") } + } else { - log("Error: non nvram to be saved.") + log("Error: no nvram to be saved.") } now = df.string(from: Date()) diff --git a/CloverApp/CloverRunAtLogin/CloverRunAtLogin.xcodeproj/project.pbxproj b/CloverApp/CloverRunAtLogin/CloverRunAtLogin.xcodeproj/project.pbxproj index 1583248c9..9945bb74c 100644 --- a/CloverApp/CloverRunAtLogin/CloverRunAtLogin.xcodeproj/project.pbxproj +++ b/CloverApp/CloverRunAtLogin/CloverRunAtLogin.xcodeproj/project.pbxproj @@ -91,7 +91,7 @@ 956A7AA7238DAD700012F6B0 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1120; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = CloverHackyColor; TargetAttributes = { 956A7AAE238DAD700012F6B0 = { @@ -267,6 +267,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = CloverRunAtLogin/CloverRunAtLogin.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = CloverRunAtLogin/Info.plist; @@ -284,6 +285,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = CloverRunAtLogin/CloverRunAtLogin.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = CloverRunAtLogin/Info.plist; diff --git a/CloverApp/Lang.bundle/Contents/Resources/de.strings b/CloverApp/Lang.bundle/Contents/Resources/de.strings index 60c2da5b1..5dd4795d0 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/de.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/de.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Aktuelle Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "Config.plist Pfad:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover möchte %@ mounten"; "Clover wants to umount %@" = "Clover möchte %@ unmounten"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "Wahr"; "false" = "Falsch"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "CloverDaemonNew deinstallieren"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Auf Version r%d aktualisieren"; // "Update to r5101" "Check update:" = "Auf Update prüfen:"; "Check now" = "Jetzt prüfen"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/en.strings b/CloverApp/Lang.bundle/Contents/Resources/en.strings index 1e61a4da1..95b6def80 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/en.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/en.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; @@ -71,7 +94,7 @@ Can also be use if you don't want to upgrade MBR or PBR sectors."; "Clover legacy BIOS boot sectors" = "Clover EFI requires three essential files. (in simple terms) boot0 (On the drive's MBR) responsible for loading boot1. boot1 (On the partition's boot-sector) to finding boot2. -boot2 (On the partition's root directory) for loading /EFI/CLOVER/CLOVERIA32.efi or CLOVERX64.efi, and kernel etc."; +boot2 (On the partition's root directory) for loading CLOVERX64.efi, and kernel etc."; "boot0af" = "Used for BIOS booting on BIOS motherboards. boot0af (boot0 Active First) bootloader try to boot the active partition defined in MBR. If there is no active partition, it will try to boot the first EFI/FAT32/HFS partition (defined in the MBR and then the GPT) with a valid PBR signature. @@ -128,7 +151,7 @@ Volume and Audio device (for supported IOAudio devices only)."; "FirmwareVolume.efi" = "Create FirmwareVolume with cursor images for FileVault2."; -"FSInject.efi" = "Provide injection of kernel extensions from Clover folder."; +"FSInject.efi" = "Provide injection of kernel extensions from Clover folder and allow to force load them from both /System/Library/Extensions and /Library/Extensions."; "GrubEXFAT.efi" = "ExFAT filesystem driver from GRUB."; diff --git a/CloverApp/Lang.bundle/Contents/Resources/es.strings b/CloverApp/Lang.bundle/Contents/Resources/es.strings index 077b98a3a..5cef3f5d8 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/es.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/es.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/fr.strings b/CloverApp/Lang.bundle/Contents/Resources/fr.strings index 9006871ff..87e0e958d 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/fr.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/fr.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Version actuelle de Clover"; "Boot Device:" = "Périphérique De Démarrage:"; "config path:" = "voie d'acces vers config:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover desire monter %@"; "Clover wants to umount %@" = "Clover desire démonter %@"; @@ -24,6 +26,26 @@ "mount point" = "point d'acces"; "*auto mount" = "*monter automatiquement"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "vrai"; "false" = "faux"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Desinstaller CloverDaemonNew"; "Update" = "Mise à jour"; +"Download" = "Download"; "Update to r%d" = "Mise à jour de r%d"; // "Update to r5101" "Check update:" = "Verifier mise à jour:"; "Check now" = "Verifier maintenant"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/hr.strings b/CloverApp/Lang.bundle/Contents/Resources/hr.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/hr.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/hr.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/id.strings b/CloverApp/Lang.bundle/Contents/Resources/id.strings index e972d5007..b14798c8c 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/id.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/id.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Revisi Clover Terkini"; "Boot Device:" = "Device Boot:"; "config path:" = "Lokasi config:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover ingin mount %@"; "Clover wants to umount %@" = "Clover ingin umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Copot CloverDaemonNew"; "Update" = "Perbarui"; +"Download" = "Download"; "Update to r%d" = "Perbarui ke r%d"; // "Update to r5101" "Check update:" = "Periksa Pembaruan:"; "Check now" = "Periksa Sekarang"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/it.strings b/CloverApp/Lang.bundle/Contents/Resources/it.strings index d70651670..72982268c 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/it.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/it.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Revisione corrente"; "Boot Device:" = "Disco di avvio:"; "config path:" = "percorso config:"; +"Installation succeded" = "Installazione riuscita"; +"Installation failed" = "Installazione fallita"; "Clover wants to mount %@" = "Clover vuole montare %@"; "Clover wants to umount %@" = "Clover vuole smontare %@"; @@ -24,6 +26,26 @@ "mount point" = "punto di montaggio"; "*auto mount" = "*auto monta"; +"System Serial Number:" = "Numero Seriale di Sistema:"; +"Model:" = "Modello:"; +"board-id:" = "Identificativo Scheda:"; +"OEM Vendor:" = "Venditore OEM:"; +"OEM Product:" = "Prodotto OEM:"; +"OEM Board:" = "Scheda OEM:"; +"NVRAM is native:" = "NVRAM è nativa:"; +"unknown" = "sconosciuto"; +"Yes" = "Si"; +"No" = "No"; + +"Startup Sound" = "Suono all'avvio"; +"Device:" = "Dispositivo:"; +"Volume level:" = "Volume:"; +"LineOut" = "Line Out"; +"Speaker" = "Altoparlanti"; +"Headphones" = "Cuffie"; +"Garniture" = "Accessori"; +"Other" = "Altro"; + "true" = "vero"; "false" = "falso"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Disinstalla il demone CloverDaemonNew"; "Update" = "Aggiorna"; +"Download" = "Scarica"; "Update to r%d" = "Aggiorna a r%d"; // "Update to r5101" "Check update:" = "Controlla:"; "Check now" = "Controlla adesso"; @@ -71,7 +94,7 @@ Può essere usato anche se non si desidera aggiornare i settori MBR o PBR."; "Clover legacy BIOS boot sectors" = "Clover EFI richiede tre file essenziali. (in semplici termini) boot0 (Sul disco MBR) responsabile del caricamento del boot1. boot1 (Settore di avvio della partizione) per trovare il boot2. -boot2 (Nella cartella principale della partizione) per caricare /EFI/CLOVER/CLOVERIA32.efi o CLOVERX64.efi, e il kernel etc."; +boot2 (Nella cartella principale della partizione) per caricare CLOVERX64.efi, e il kernel etc."; "boot0af" = "Necessario per l'avvio da schede madri con BIOS. boot0af (boot0 active first) bootloader cerca di avviare la partizione attiva definita nella MBR. Se non vi è alcuna partizione attiva, tenterà di avviare la prima partizione EFI/FAT32/HFS (definita nella MBR e poi nella GPT) con una signature PBR valida. @@ -129,7 +152,7 @@ Necessario anche per accedere ad unità che utilizzano controller RAID, JMicron, "FirmwareVolume.efi" = "Crea il FirmwareVolume con ‘cursor images’ per FileVault2."; -"FSInject.efi" = "Abilita l’iniezione di estensioni del kernel dalle cartelle di Clover."; +"FSInject.efi" = "Abilita l’iniezione di estensioni del kernel dalle cartelle di Clover e consente di forzare il caricamento da /System/Library/Extensions e /Library/Extensions."; "GrubEXFAT.efi" = "Driver GRUB per il filesystem ExFAT."; diff --git a/CloverApp/Lang.bundle/Contents/Resources/ja.strings b/CloverApp/Lang.bundle/Contents/Resources/ja.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/ja.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/ja.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/ko.strings b/CloverApp/Lang.bundle/Contents/Resources/ko.strings index 9dee12e6e..b9483cfa5 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/ko.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/ko.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "현재 클로버 리비전"; "Boot Device:" = "부트 디스크:"; "config path:" = "config 경로:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "클로버는 다음 디스크를 마운트: %@"; "Clover wants to umount %@" = "클로버는 다음 디스크를 언마운트: %@"; @@ -24,6 +26,26 @@ "mount point" = "마운트 포인트"; "*auto mount" = "*자동 마운트"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; + +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "예"; "false" = "아니오"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "새로운 클로버데몬 제거"; "Update" = "업데이트"; +"Download" = "Download"; "Update to r%d" = "r%d로 업데이트"; // "Update to r5101" "Check update:" = "업데이트 확인:"; "Check now" = "지금 확인"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/lv.strings b/CloverApp/Lang.bundle/Contents/Resources/lv.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/lv.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/lv.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/nl.strings b/CloverApp/Lang.bundle/Contents/Resources/nl.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/nl.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/nl.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/pl.strings b/CloverApp/Lang.bundle/Contents/Resources/pl.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/pl.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/pl.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/pt-BR.strings b/CloverApp/Lang.bundle/Contents/Resources/pt-BR.strings index 5b3ef050c..b31fd4dd3 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/pt-BR.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/pt-BR.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/pt-PT.strings b/CloverApp/Lang.bundle/Contents/Resources/pt-PT.strings index a1e8f4bbf..1731f66b4 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/pt-PT.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/pt-PT.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Clover atual revisão"; "Boot device" = "Dispositivo de Boot"; "config path:" = "configurar caminho:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover pretende montar %@"; "Clover wants to umount %@" = "Clover pretende desmontar %@"; @@ -24,6 +26,26 @@ "mount point" = "ponto de montagem"; "auto mount" = "Montagem Auto"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "verdadeiro"; "false" = "falso"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Desinstalar CloverDaemonNew"; "Update" = "Atualizar"; +"Download" = "Download"; "Update to r%d" = "Atualizar para r%d"; // "Update to r5101" "Check update:" = "Verificar Atualizações:"; "Check now" = "Verificar agora"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/ro.strings b/CloverApp/Lang.bundle/Contents/Resources/ro.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/ro.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/ro.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/ru.strings b/CloverApp/Lang.bundle/Contents/Resources/ru.strings index 447d41063..97537e9b7 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/ru.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/ru.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Текущая ревизия Clover"; "Boot Device:" = "Загрузочное устройство:"; "config path:" = "путь к файлу config:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover желает смонтировать %@"; "Clover wants to umount %@" = "Clover желает размонтировать %@"; @@ -24,6 +26,26 @@ "mount point" = "название тома"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "истина"; "false" = "ложь"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Удалить CloverDaemonNew"; "Update" = "Oбновление"; +"Download" = "Download"; "Update to r%d" = "Обновление до r%d"; // "Update to r5101" "Check update:" = "Проверить обновления:"; "Check now" = "Проверь сейчас"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/sr.strings b/CloverApp/Lang.bundle/Contents/Resources/sr.strings index 4982f3612..4ad5a23ae 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/sr.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/sr.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Trenutna verzija Clover-a"; "Boot Device:" = "Uređaj za podizanje sastava:"; "config path:" = "Putanja za konfiguraciju:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover želi %@ mount"; "Clover wants to umount %@" = "Clover želi %@ unmount"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "tačno"; "false" = "Lažno"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Deinstalirati CloverDaemonNew"; "Update" = "Ažuriranje"; +"Download" = "Download"; "Update to r%d" = "Ažurirati Verziju r%d Aktuelnu"; // "Update to r5101" "Check update:" = "Proveriti trenutnu verziju:"; "Check now" = "Proveriti sada"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/tr.strings b/CloverApp/Lang.bundle/Contents/Resources/tr.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/tr.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/tr.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/uk.strings b/CloverApp/Lang.bundle/Contents/Resources/uk.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/uk.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/uk.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/vi.strings b/CloverApp/Lang.bundle/Contents/Resources/vi.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/vi.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/vi.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/zh-Hans.strings b/CloverApp/Lang.bundle/Contents/Resources/zh-Hans.strings index 02ca816e6..a2b280fa1 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/zh-Hans.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/zh-Hans.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "目前 Clover 版本"; "Boot Device:" = "引导设备:"; "config path:" = "config 路径:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover 想要挂载 %@"; "Clover wants to umount %@" = "Clover 想要卸载 %@"; @@ -24,6 +26,26 @@ "mount point" = "挂载点"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "是"; "false" = "否"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "卸载 CloverDaemonNew"; "Update" = "更新"; +"Download" = "Download"; "Update to r%d" = "更新到 r%d"; // "Update to r5101" "Check update:" = "检查更新:"; "Check now" = "现在检查"; diff --git a/CloverApp/Lang.bundle/Contents/Resources/zh-Hant.strings b/CloverApp/Lang.bundle/Contents/Resources/zh-Hant.strings index 1e61a4da1..679897553 100644 --- a/CloverApp/Lang.bundle/Contents/Resources/zh-Hant.strings +++ b/CloverApp/Lang.bundle/Contents/Resources/zh-Hant.strings @@ -16,6 +16,8 @@ "Current Clover revision" = "Current Clover revision"; "Boot Device:" = "Boot Device:"; "config path:" = "config path:"; +"Installation succeded" = "Installation succeded"; +"Installation failed" = "Installation failed"; "Clover wants to mount %@" = "Clover wants to mount %@"; "Clover wants to umount %@" = "Clover wants to umount %@"; @@ -24,6 +26,26 @@ "mount point" = "mount point"; "*auto mount" = "*auto mount"; +"System Serial Number:" = "System Serial Number:"; +"Model:" = "Model:"; +"board-id:" = "board-id:"; +"OEM Vendor:" = "OEM Vendor:"; +"OEM Product:" = "OEM Product:"; +"OEM Board:" = "OEM Board:"; +"NVRAM is native:" = "NVRAM is native:"; +"unknown" = "unknown"; +"Yes" = "Yes"; +"No" = "No"; + +"Startup Sound" = "Startup Sound"; +"Device:" = "Device:"; +"Volume level:" = "Volume level:"; +"LineOut" = "Line Out"; +"Speaker" = "Speaker"; +"Headphones" = "Headphones"; +"Garniture" = "Garniture"; +"Other" = "Other"; + "true" = "true"; "false" = "false"; @@ -39,6 +61,7 @@ "Uninstall CloverDaemonNew" = "Uninstall CloverDaemonNew"; "Update" = "Update"; +"Download" = "Download"; "Update to r%d" = "Update to r%d"; // "Update to r5101" "Check update:" = "Check update:"; "Check now" = "Check now"; diff --git a/CloverApp/bootsectors-install b/CloverApp/bootsectors-install index 33df56aae..f33602f31 100755 --- a/CloverApp/bootsectors-install +++ b/CloverApp/bootsectors-install @@ -1,5 +1,7 @@ #!/bin/bash +logPath="/tmp/cltmplog" +exec > >(tee -a $logPath) 2>&1 # Created by vector sigma on 04/11/2019. # Copyright © 2019 CloverHackyColor. All rights reserved. @@ -24,8 +26,20 @@ bootslice="${bootdev#*disk*s}" keepmounted=0 journaled=0 +saveLog() { +/usr/sbin/diskutil mount "$bootdev" > /dev/null 2>&1 +local mp=$(LC_ALL=C /sbin/mount | egrep "^$bootdev on" | sed 's/^.* on *//;s/ ([^(]*//') + +if [[ -n "$mp" ]]; then + if [[ -d "${mp}"/EFI/CLOVER ]] && [[ -f "${logPath}" ]]; then + cat "${logPath}" > "${mp}"/EFI/CLOVER/Clover.app_install.log + chmod 777 "${mp}"/EFI/CLOVER/Clover.app_install.log + fi +fi +} + echo -echo "Installing boot sectors (version of Wed 27 Nov 2019, 22:16)" +echo "Installing boot sectors (version of Wed 30 Dec 2019, 20:01)" echo echo "disk: ${disk}" echo "bootdev: ${bootdev}" @@ -45,7 +59,7 @@ fi if [ "${partition_scheme}" != FDisk_partition_scheme ] && \ [ "${partition_scheme}" != GUID_partition_scheme ]; then echo "Error: unsupported Partition Scheme Map \"${partition_scheme}\"." - exit 1 + saveLog && exit 1 fi @@ -53,22 +67,22 @@ if [ "${filesystem}" != fat32 ] && \ [ "${filesystem}" != exfat ] && \ [ "${filesystem}" != hfs ]; then echo "Error: unsupported filesystem \"${filesystem}\"" - exit 1 + saveLog && exit 1 fi if [[ ! -f "${boot0}" ]]; then echo "Error: cannot found /tmp/boot0[af-ss] sector." - exit 1 + saveLog && exit 1 fi if [[ ! -f "${boot1}" ]]; then echo "Error: cannot found /tmp/boot1[1f32-h-x] sector." - exit 1 + saveLog && exit 1 fi if [[ ! -f "${boot1install}" ]]; then echo "Error: cannot found /tmp/boot1-install." - exit 1 + saveLog && exit 1 fi # chmod +x "${boot1install}" @@ -148,17 +162,19 @@ MAKEACTIVE fi sleep 2 -# Now try to remount the partition -if [[ "${ESP}" != ESP ]]; then - if [[ -n "$mnt_pt" ]]; then - /usr/sbin/diskutil mount "$bootdev" - fi -fi +saveLog if [[ $journaled -ne 0 ]]; then /usr/sbin/diskutil enableJournal "${disk}" fi +# Now try to remount the partition +if [[ "${ESP}" == ESP ]]; then + /usr/sbin/diskutil unmount force $bootdev > /dev/null 2>&1 +else + /usr/sbin/diskutil mount "$bootdev" > /dev/null 2>&1 +fi + /bin/rm -rf /tmp/Clover* /bin/rm -rf /tmp/boot1* /bin/rm -rf /tmp/boot2* diff --git a/CloverApp/cloverhelper/Cloverhelper.xcodeproj/project.pbxproj b/CloverApp/cloverhelper/Cloverhelper.xcodeproj/project.pbxproj index c4723e18e..edf9aeaa0 100644 --- a/CloverApp/cloverhelper/Cloverhelper.xcodeproj/project.pbxproj +++ b/CloverApp/cloverhelper/Cloverhelper.xcodeproj/project.pbxproj @@ -100,7 +100,7 @@ 958505A12364D36300BCB4A3 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1120; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = CloverHackyColor; TargetAttributes = { 958505A82364D36400BCB4A3 = { @@ -250,6 +250,7 @@ 958505B12364D36400BCB4A3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -259,6 +260,7 @@ 958505B22364D36400BCB4A3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/CloverApp/cloverhelper/Cloverhelper/main.m b/CloverApp/cloverhelper/Cloverhelper/main.m index bbff9323b..a48d55d25 100644 --- a/CloverApp/cloverhelper/Cloverhelper/main.m +++ b/CloverApp/cloverhelper/Cloverhelper/main.m @@ -15,7 +15,7 @@ // TODO: redone in swift as swift command line are now small in size, with no hurry... #import -#define ktempLogPath @"/tmp/cloverapp.txt" +#define ktempLogPath "/tmp/cltmplog" #define kfm [NSFileManager defaultManager] #pragma mark - @@ -32,31 +32,70 @@ void cleanUp() { [task launch]; } -void exitWithMessage(const char *format, ...) -{ - va_list arg; - va_start (arg, format); - vfprintf (stdout, format, arg); - va_end (arg); +NSString *gTargetVolume; + +void saveLog() { + if (gTargetVolume != nil + && [kfm fileExistsAtPath:gTargetVolume] + && [kfm fileExistsAtPath:@ktempLogPath]) { + NSString *finalLogPath = + [gTargetVolume stringByAppendingPathComponent:@"EFI/CLOVER/Clover.app_install.log"]; + if ([kfm fileExistsAtPath: finalLogPath]) { + [kfm removeItemAtPath:finalLogPath error:nil]; + } + NSData *log = [NSData dataWithContentsOfFile:@ktempLogPath]; + if (log != nil) { + [log writeToFile:finalLogPath atomically:NO]; + } + } +} + +void addToLog(NSString *str) { + if (![kfm fileExistsAtPath:@ktempLogPath]) { + system([[NSString stringWithFormat:@"echo > %s", ktempLogPath] UTF8String]); + } + NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:@ktempLogPath]; + [fh seekToEndOfFile]; + [fh writeData:[str dataUsingEncoding:NSUTF8StringEncoding]]; + [fh closeFile]; +} + +void post(NSString *format, ...) { + va_list arguments; + va_start(arguments, format); + NSString *str = [[NSString alloc] initWithFormat:format arguments:arguments]; + addToLog(str); + va_end(arguments); + printf("%s", [str UTF8String]); + +} + +void exitWithMessage(NSString *format, ...) { + va_list arguments; + va_start(arguments, format); + NSString *str = [[NSString alloc] initWithFormat:format arguments:arguments]; + + va_end(arguments); + printf("%s", [str UTF8String]); + addToLog(str); + saveLog(); cleanUp(); exit(EXIT_FAILURE); } - BOOL copyReplace(NSString *source, NSString *dest, NSDictionary *attributes) { NSError *err = nil; NSString *upperDir = [dest stringByDeletingLastPathComponent]; if ([upperDir isEqualToString:@"/"]) { - printf("+ ../%s\n", [dest lastPathComponent].UTF8String); + post(@"+ ../%@\n", [dest lastPathComponent]); } else { - printf("+ ../%s/%s\n", - [[dest stringByDeletingLastPathComponent] lastPathComponent].UTF8String, - [dest lastPathComponent].UTF8String); + post(@"+ ../%@/%@\n", + [[dest stringByDeletingLastPathComponent] lastPathComponent], [dest lastPathComponent]); } if (![kfm fileExistsAtPath:source]) { - printf("Error: %s doesn't exist\n", source.UTF8String); + post(@"Error: %@ doesn't exist\n", source); return NO; } // remove destination if already exist @@ -83,7 +122,7 @@ BOOL copyReplace(NSString *source, NSString *dest, NSDictionary *attributes) { // print any errors if any if (err != nil) { - printf("%s\n", err.description.UTF8String); + post(@"%@\n", err.description); } return (err == nil); @@ -95,18 +134,29 @@ BOOL copyReplace(NSString *source, NSString *dest, NSDictionary *attributes) { int main(int argc, char * const * argv) { @autoreleasepool { + if ([kfm fileExistsAtPath:@ktempLogPath]) { + [kfm removeItemAtPath:@ktempLogPath error:nil]; + } - printf("My Path = %s\n", [[NSString stringWithFormat:@"%s", argv[0]] UTF8String]); + NSDateFormatter * df = [NSDateFormatter new]; + [df setDateFormat:@"yyyy-MMM-dd HH:mm:ss"]; + NSLocale *locale = [[NSLocale alloc] + initWithLocaleIdentifier:@"en_US"]; + [df setLocale:locale]; + NSString *dateString = [df stringFromDate:[NSDate new]]; + if (geteuid() != 0) { - exitWithMessage("Error: you don't have root permissions\n"); + exitWithMessage(@"Error: you don't have root permissions\n"); } NSDictionary *CloverappDict = [NSDictionary dictionaryWithContentsOfFile:@"/tmp/Cloverapp"]; if (CloverappDict == nil) { - exitWithMessage("Error: can't load Cloverapp dictionary\n"); + exitWithMessage(@"Error: can't load Cloverapp dictionary\n"); } cleanUp(); - + + NSString *bootSectorsInstall = @"/tmp/bootsectors-install"; + NSString *targetVol = [CloverappDict objectForKey:@"targetVol"]; NSString *disk = [CloverappDict objectForKey:@"disk"]; NSString *filesystem = [CloverappDict objectForKey:@"filesystem"]; @@ -117,18 +167,25 @@ int main(int argc, char * const * argv) { NSString *cloverv2 = [CloverappDict objectForKey:@"CloverV2"]; NSString *boot1installPath = [CloverappDict objectForKey:@"boot1install"]; NSString *bootSectorsInstallSrc = [CloverappDict objectForKey:@"bootsectors-install"]; - NSString *bootSectorsInstall = @"/tmp/bootsectors-install"; + NSString *backUpPath = [CloverappDict objectForKey:@"BackUpPath"]; + NSString *version = [CloverappDict objectForKey:@"version"]; BOOL isESP = [[CloverappDict objectForKey:@"isESP"] boolValue]; + + post(@"%@, %@\n\n", version, dateString); + post(@"My Path = %s\n", argv[0]); + if (backUpPath != nil) { + post(@"Backup made at:\n%@.\n", backUpPath); + } if ([kfm fileExistsAtPath:bootSectorsInstall]) { - printf("Note: found old bootsectors-install..removing it..\n"); + post(@"Note: found old bootsectors-install..removing it..\n"); if (![kfm removeItemAtPath:bootSectorsInstall error:nil]) { - exitWithMessage("Error: can't remove old bootsectors-install."); + exitWithMessage(@"Error: can't remove old bootsectors-install."); } } if (bootSectorsInstallSrc != nil) { - printf("bootSectorsInstallSrc = %s\n", [bootSectorsInstallSrc UTF8String]); + post(@"bootSectorsInstallSrc = %@\n", bootSectorsInstallSrc); } BOOL alt = NO; @@ -146,19 +203,20 @@ int main(int argc, char * const * argv) { BOOL isDir = NO; if (targetVol == nil) { - exitWithMessage("Error: option targetVol [path to volume] not specified\n"); + exitWithMessage(@"Error: option targetVol [path to volume] not specified\n"); } + gTargetVolume = targetVol; if (![kfm fileExistsAtPath:targetVol]) { - exitWithMessage("Error: target volume \"%s\" doesn't exist.\n", targetVol.UTF8String); + exitWithMessage(@"Error: target volume \"%@\" doesn't exist.\n", targetVol); } if (cloverv2 == nil || ![kfm fileExistsAtPath:cloverv2]) { - exitWithMessage("Error: cannot found CloverV2 directory\n"); + exitWithMessage(@"Error: cannot found CloverV2 directory\n"); } - printf("Target volume: %s\n", targetVol.UTF8String); - + post(@"Target volume: %@\n", targetVol); + /* // check if target volume is writable NSString *volEnds = targetVol; if (![volEnds hasSuffix:@"/"]) { @@ -167,35 +225,35 @@ int main(int argc, char * const * argv) { if (![kfm isWritableFileAtPath:volEnds]) { - exitWithMessage("Error: target volume \"%s\" is not writable.\n", targetVol.UTF8String); + exitWithMessage(@"Error: target volume \"%@\" is not writable.\n", targetVol); } - + */ #pragma mark Check paths // check other options before proceed NSString *boot0Path = nil, *boot1Path = nil, *boot2Path = nil; if (boot0 != nil) { - printf("boot0: %s\n", boot0.UTF8String); + post(@"boot0: %@\n", boot0); [preferences setValue:boot0 forKey:@"boot0"]; boot0Path = [[cloverv2 stringByAppendingPathComponent:@"BootSectors"] stringByAppendingPathComponent:boot0]; if (![kfm fileExistsAtPath:boot0Path]) { - exitWithMessage("Error: cannot found \"%s\".\n", boot0.UTF8String); + exitWithMessage(@"Error: cannot found \"%@\".\n", boot0); } } if (boot1 != nil) { - printf("boot1: %s\n", boot1.UTF8String); + post(@"boot1: %@\n", boot1); boot1Path = [[cloverv2 stringByAppendingPathComponent:@"BootSectors"] stringByAppendingPathComponent:boot1]; if (![kfm fileExistsAtPath:boot1Path]) { - exitWithMessage("Error: cannot found \"%s\".\n", boot1.UTF8String); + exitWithMessage(@"Error: cannot found \"%@\".\n", boot1); } } if (boot2 != nil) { - printf("boot2: %s\n", boot2.UTF8String); + post(@"boot2: %@\n", boot2); [preferences setValue:boot2 forKey:@"boot2"]; boot2Path = [[cloverv2 stringByAppendingPathComponent:@"Bootloaders/x64"] stringByAppendingPathComponent:boot2]; if (![kfm fileExistsAtPath:boot2Path]) { - exitWithMessage("Error: cannot found \"%s\".\n", boot2.UTF8String); + exitWithMessage(@"Error: cannot found \"%@\".\n", boot2); } } @@ -216,7 +274,7 @@ int main(int argc, char * const * argv) { } if (err != nil) { - exitWithMessage("%s\n", err.description.UTF8String); + exitWithMessage(@"%@\n", err.description); } #pragma mark Create directories @@ -225,6 +283,9 @@ int main(int argc, char * const * argv) { @"EFI/CLOVER/ACPI/origin", @"EFI/CLOVER/ACPI/patched", @"EFI/CLOVER/ACPI/WINDOWS", + @"EFI/CLOVER/kexts/10", + @"EFI/CLOVER/kexts/10_recovery", + @"EFI/CLOVER/kexts/10_installer", @"EFI/CLOVER/kexts/10.11", @"EFI/CLOVER/kexts/10.12", @"EFI/CLOVER/kexts/10.13", @@ -241,26 +302,26 @@ int main(int argc, char * const * argv) { if (![kfm fileExistsAtPath:fp]) { [kfm createDirectoryAtPath:fp withIntermediateDirectories:YES attributes:attributes error:&err]; if (err != nil) { - exitWithMessage("%s\n", err.description.UTF8String); + exitWithMessage(@"%@\n", err.description); } } } #pragma mark Install Clover and drivers - printf("\nInstalling/Updating Clover:\n"); + post(@"\nInstalling/Updating Clover:\n"); if (!copyReplace([cloverv2 stringByAppendingPathComponent:@"EFI/BOOT/BOOTX64.efi"], [targetVol stringByAppendingPathComponent:@"EFI/BOOT/BOOTX64.efi"], attributes)) { - exitWithMessage("Error: cannot copy BOOTX64.efi to destination.\n"); + exitWithMessage(@"Error: cannot copy BOOTX64.efi to destination.\n"); } if (!copyReplace([cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/CLOVERX64.efi"], [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/CLOVERX64.efi"], attributes)) { - exitWithMessage("Error: cannot copy CLOVERX64.efi to destination.\n"); + exitWithMessage(@"Error: cannot copy CLOVERX64.efi to destination.\n"); } - printf("\nInstalling/Updating drivers:\n"); + post(@"\nInstalling/Updating drivers:\n"); NSArray * toDelete = [CloverappDict objectForKey:@"toDelete"]; NSArray * UEFI = [CloverappDict objectForKey:@"UEFI"]; NSArray * BIOS = [CloverappDict objectForKey:@"BIOS"]; @@ -272,7 +333,7 @@ int main(int argc, char * const * argv) { NSString *dpath = [UEFI objectAtIndex:i]; NSString *dname = [dpath lastPathComponent]; if (!copyReplace(dpath, [UEFIdest stringByAppendingPathComponent:dname], attributes)) { - exitWithMessage("Error: cannot copy %s to destination.\n", dpath.UTF8String); + exitWithMessage(@"Error: cannot copy %@ to destination.\n", dpath); } } } @@ -282,7 +343,7 @@ int main(int argc, char * const * argv) { NSString *dpath = [BIOS objectAtIndex:i]; NSString *dname = [dpath lastPathComponent]; if (!copyReplace(dpath, [BIOSdest stringByAppendingPathComponent:dname], attributes)) { - exitWithMessage("Error: cannot copy %s to destination.\n"); + exitWithMessage(@"Error: cannot copy %@ to destination.\n", dpath); } } } @@ -292,12 +353,12 @@ int main(int argc, char * const * argv) { NSString *dpath = [toDelete objectAtIndex:i]; err = nil; if ([kfm fileExistsAtPath:dpath]) { - printf("- ../%s/%s\n", - [[dpath stringByDeletingLastPathComponent] lastPathComponent].UTF8String, - [dpath lastPathComponent].UTF8String); + post(@"- ../%@/%@\n", + [[dpath stringByDeletingLastPathComponent] lastPathComponent], + [dpath lastPathComponent]); [kfm removeItemAtPath:dpath error:&err]; if (err != nil) { - exitWithMessage("%s\n", err.description.UTF8String); + exitWithMessage(@"%@\n", err.description); } } } @@ -306,7 +367,7 @@ int main(int argc, char * const * argv) { #pragma mark Install tools NSString *cv2tools = [cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/tools"]; if ([kfm fileExistsAtPath:cv2tools]) { - printf("\nInstalling/Updating tools:\n"); + post(@"\nInstalling/Updating tools:\n"); err = nil; NSArray *tools = [kfm contentsOfDirectoryAtPath:cv2tools error:&err]; if (err == nil && tools != nil) { @@ -317,7 +378,7 @@ int main(int argc, char * const * argv) { [[targetVol stringByAppendingPathComponent:@"EFI/CLOVER/tools"] stringByAppendingPathComponent:t], attributes)) { - exitWithMessage("Error: cannot copy %s to destination.\n", t.UTF8String); + exitWithMessage(@"Error: cannot copy %@ to destination.\n", t); } } } @@ -328,7 +389,7 @@ int main(int argc, char * const * argv) { #pragma mark Install docs NSString *cv2docs = [cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/doc"]; if ([kfm fileExistsAtPath:cv2tools]) { - printf("\nInstalling/Updating doc:\n"); + post(@"\nInstalling/Updating doc:\n"); err = nil; NSArray *docs = [kfm contentsOfDirectoryAtPath:cv2docs error:&err]; if (err == nil && docs != nil) { @@ -342,9 +403,9 @@ int main(int argc, char * const * argv) { stringByAppendingPathComponent:d], docattr)) { - //exitWithMessage("Error: cannot copy %s to destination.\n", d.UTF8String); + //exitWithMessage(@"Error: cannot copy %@ to destination.\n", d); // ... will not fail for a doc.. - printf("Error: cannot copy %s to destination.\n", d.UTF8String); + post(@"Error: cannot copy %@ to destination.\n", d); } } } @@ -356,7 +417,7 @@ int main(int argc, char * const * argv) { NSString *configPath = [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/config.plist"]; NSString *configSamplePath = [cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/config-sample.plist"]; if (![kfm fileExistsAtPath:configPath]) { - printf("\nInstalling config.plist:\n"); + post(@"\nInstalling config.plist:\n"); copyReplace(configSamplePath, configPath, attributes); } @@ -376,7 +437,7 @@ int main(int argc, char * const * argv) { // don't overwrite the theme if already exist as one from CTM can be newer if (theme != nil && ![kfm fileExistsAtPath: [themesDestDir stringByAppendingPathComponent:theme]]) { - printf("\nInstalling Theme \"%s\":\n", theme.UTF8String); + post(@"\nInstalling Theme \"%@\":\n", theme); copyReplace([themesSourceDir stringByAppendingPathComponent:theme], [themesDestDir stringByAppendingPathComponent:theme], attributes); @@ -385,9 +446,9 @@ int main(int argc, char * const * argv) { #pragma mark Stage 2 installation if (boot2Path != nil) { - printf("\nInstalling stage 2..\n"); + post(@"\nInstalling stage 2..\n"); if (!copyReplace(boot2Path, [targetVol stringByAppendingPathComponent:@"boot"], attributes)) { - exitWithMessage("Error: cannot copy bootloader to detination.\n"); + exitWithMessage(@"Error: cannot copy bootloader to detination.\n"); } if (alt) { @@ -398,7 +459,7 @@ int main(int argc, char * const * argv) { for (int i = 0; i < [files count]; i++) { NSString *f = [files objectAtIndex:i]; if ([f hasPrefix:@"boot"]) { - printf("\nInstalling stage 2 \"%s (alt)\".\n", f.UTF8String); + post(@"\nInstalling stage 2 \"%@ (alt)\".\n", f); copyReplace([altPath stringByAppendingPathComponent: f], [targetVol stringByAppendingPathComponent:f], attributes); @@ -414,6 +475,7 @@ int main(int argc, char * const * argv) { [kfm setAttributes:attributes ofItemAtPath:prefPath error:nil]; } + saveLog(); #pragma mark Boot sectors installation if (boot0Path != nil && boot1Path != nil && bootSectorsInstallSrc != nil) { // copy bootsectors-install @@ -447,7 +509,7 @@ int main(int argc, char * const * argv) { task.terminationHandler = ^(NSTask *theTask) { if (theTask.terminationStatus != 0) { - exitWithMessage("Error: failed installing boot sectors."); + exitWithMessage(@"Error: failed installing boot sectors.\n"); } }; [task launch]; @@ -456,10 +518,11 @@ int main(int argc, char * const * argv) { if (data) { NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - printf("%s\n", [output UTF8String]); + post(@"%@\n", output); } } else { + saveLog(); if (isESP) { NSTask *task = [[NSTask alloc] init]; [task setEnvironment:[[NSProcessInfo new] environment]]; diff --git a/CloverApp/daemonInstaller/daemonInstaller.xcodeproj/project.pbxproj b/CloverApp/daemonInstaller/daemonInstaller.xcodeproj/project.pbxproj index 64afe4679..9ad5f254e 100644 --- a/CloverApp/daemonInstaller/daemonInstaller.xcodeproj/project.pbxproj +++ b/CloverApp/daemonInstaller/daemonInstaller.xcodeproj/project.pbxproj @@ -88,7 +88,7 @@ 95509157238B132100933A7E /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1120; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = CloverHackyColor; TargetAttributes = { 9550915E238B132100933A7E = { @@ -238,6 +238,7 @@ 95509167238B132100933A7E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; @@ -246,6 +247,7 @@ 95509168238B132100933A7E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; };