Clover.app v1.14

Bootloader installation is now performed by CloverDaemonNew (one command line in less).
This commit is contained in:
vectorsigma72 2020-01-03 20:37:27 +01:00
parent 37338e285b
commit aa207eaa44
11 changed files with 633 additions and 908 deletions

View File

@ -7,7 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
95337172237070CD003F1AF4 /* Cloverhelper in Copy tools */ = {isa = PBXBuildFile; fileRef = 9533716F237070B3003F1AF4 /* Cloverhelper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
9533718323709517003F1AF4 /* bootsectors-install in Resources */ = {isa = PBXBuildFile; fileRef = 9533718223709517003F1AF4 /* bootsectors-install */; };
9533718523709A36003F1AF4 /* bootsectors-install in Copy CloverV2 */ = {isa = PBXBuildFile; fileRef = 9533718223709517003F1AF4 /* bootsectors-install */; };
953BC20323720C0A0039755D /* FixedWidthViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 953BC20223720C0A0039755D /* FixedWidthViews.swift */; };
@ -47,20 +46,6 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
9533716E237070B3003F1AF4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 958505B4236594C000BCB4A3 /* Cloverhelper.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 958505A92364D36400BCB4A3;
remoteInfo = Cloverhelper;
};
95337170237070BB003F1AF4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 958505B4236594C000BCB4A3 /* Cloverhelper.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 958505A82364D36400BCB4A3;
remoteInfo = Cloverhelper;
};
9542ABBC2373780C00DC03E6 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 9542ABB82373780C00DC03E6 /* boot1-inst.xcodeproj */;
@ -143,7 +128,6 @@
95509171238B1E3A00933A7E /* daemonInstaller in Copy tools */,
9546AE1B23806299007155A6 /* CloverLogOut in Copy tools */,
9542ABC02373783400DC03E6 /* boot1-install in Copy tools */,
95337172237070CD003F1AF4 /* Cloverhelper in Copy tools */,
9552D748236F33CA00C93377 /* CloverDaemonNew in Copy tools */,
);
name = "Copy tools";
@ -322,7 +306,6 @@
9569EC8C238DD7C6003AD72C /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Settings.strings; sourceTree = "<group>"; };
9569EC8E238DD7C8003AD72C /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Settings.strings; sourceTree = "<group>"; };
9569EC90238DD7CA003AD72C /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Settings.strings; sourceTree = "<group>"; };
958505B4236594C000BCB4A3 /* Cloverhelper.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Cloverhelper.xcodeproj; path = cloverhelper/Cloverhelper.xcodeproj; sourceTree = "<group>"; };
958861D9235F75FB00B64173 /* Driver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Driver.swift; sourceTree = "<group>"; };
95C515212369BAF500E4A3A8 /* NVRAM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NVRAM.swift; sourceTree = "<group>"; };
95C5152E236A0A7400E4A3A8 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
@ -356,14 +339,6 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9533716B237070B3003F1AF4 /* Products */ = {
isa = PBXGroup;
children = (
9533716F237070B3003F1AF4 /* Cloverhelper */,
);
name = Products;
sourceTree = "<group>";
};
9542ABB92373780C00DC03E6 /* Products */ = {
isa = PBXGroup;
children = (
@ -428,7 +403,6 @@
95E68AC8235B862F002B37A5 /* Clover */,
95524B83238051F3005F6425 /* CloverLogOut.xcodeproj */,
9542ABB82373780C00DC03E6 /* boot1-inst.xcodeproj */,
958505B4236594C000BCB4A3 /* Cloverhelper.xcodeproj */,
95C51577236B21AE00E4A3A8 /* CloverRunAtLogin.xcodeproj */,
9552D740236F33A700C93377 /* CloverDaemonNew.xcodeproj */,
95509169238B1DFA00933A7E /* daemonInstaller.xcodeproj */,
@ -514,7 +488,6 @@
dependencies = (
95509170238B1E1C00933A7E /* PBXTargetDependency */,
9546AE1923806286007155A6 /* PBXTargetDependency */,
95337171237070BB003F1AF4 /* PBXTargetDependency */,
9552D747236F33B900C93377 /* PBXTargetDependency */,
9542ABBF2373781300DC03E6 /* PBXTargetDependency */,
95C5157E236B21D400E4A3A8 /* PBXTargetDependency */,
@ -597,10 +570,6 @@
ProductGroup = 9552D741236F33A700C93377 /* Products */;
ProjectRef = 9552D740236F33A700C93377 /* CloverDaemonNew.xcodeproj */;
},
{
ProductGroup = 9533716B237070B3003F1AF4 /* Products */;
ProjectRef = 958505B4236594C000BCB4A3 /* Cloverhelper.xcodeproj */;
},
{
ProductGroup = 95524B84238051F3005F6425 /* Products */;
ProjectRef = 95524B83238051F3005F6425 /* CloverLogOut.xcodeproj */;
@ -622,13 +591,6 @@
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
9533716F237070B3003F1AF4 /* Cloverhelper */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = Cloverhelper;
remoteRef = 9533716E237070B3003F1AF4 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
9542ABBD2373780C00DC03E6 /* boot1-install */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
@ -753,11 +715,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
95337171237070BB003F1AF4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = Cloverhelper;
targetProxy = 95337170237070BB003F1AF4 /* PBXContainerItemProxy */;
};
9542ABBF2373781300DC03E6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "boot1-install";
@ -1064,7 +1021,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.13;
CURRENT_PROJECT_VERSION = 1.14;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Clover/Frameworks",
@ -1080,7 +1037,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Clover/Frameworks",
);
MARKETING_VERSION = 1.13;
MARKETING_VERSION = 1.14;
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1100,7 +1057,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1.13;
CURRENT_PROJECT_VERSION = 1.14;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Clover/Frameworks",
@ -1115,7 +1072,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Clover/Frameworks",
);
MARKETING_VERSION = 1.13;
MARKETING_VERSION = 1.14;
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@ -803,7 +803,10 @@ class InstallerViewController: NSViewController {
let supportedFS = ["exfat", "fat32", "hfs"]
if !supportedFS.contains(filesystem) {
NSSound.beep()
post(text: "Error: can't install on \(filesystem.uppercased()) filesystem.", add: false, color: nil, scroll: false)
post(text: "Error: can't install on \(filesystem.uppercased()) filesystem.",
add: false,
color: nil,
scroll: false)
return
}
AppSD.isInstalling = true
@ -922,7 +925,6 @@ class InstallerViewController: NSViewController {
if settingDict.write(toFile: "/tmp/Cloverapp", atomically: false) {
AppSD.isInstalling = true
DispatchQueue.main.async {
self.spinner.startAnimation(nil)
self.installButton.isEnabled = false
@ -935,8 +937,8 @@ class InstallerViewController: NSViewController {
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"
let helperPath = Bundle.main.executablePath!.deletingLastPath.addPath("CloverDaemonNew")
let script = "do shell script \"'\(helperPath)' --CLOVER\" with prompt \"\(msg)\" with administrator privileges"
task.launchPath = "/usr/bin/osascript"
task.arguments = ["-e", script]
let pipe: Pipe = Pipe()

View File

@ -850,9 +850,9 @@ class InstallerOutViewController: NSViewController {
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) {
self.view.window?.level = .normal
}
let helperPath = Bundle.main.executablePath!.deletingLastPath.addPath("Cloverhelper")
let helperPath = Bundle.main.executablePath!.deletingLastPath.addPath("CloverDaemonNew")
let script = "do shell script \"'\(helperPath)'\" with administrator privileges"
let script = "do shell script \"'\(helperPath)' --CLOVER\" with administrator privileges"
var err : NSDictionary? = nil
let result : NSAppleEventDescriptor = NSAppleScript(source: script)!.executeAndReturnError(&err)

View File

@ -15,6 +15,7 @@
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 */; };
95620BCD23BF71A500CCBFB2 /* BootInstaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95620BCC23BF71A500CCBFB2 /* BootInstaller.swift */; };
95A9A87E23B63F570060F1CA /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A9A87D23B63F570060F1CA /* Constants.swift */; };
/* End PBXBuildFile section */
@ -28,6 +29,7 @@
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 = "<group>"; };
95620BCC23BF71A500CCBFB2 /* BootInstaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BootInstaller.swift; sourceTree = "<group>"; };
95A9A87D23B63F570060F1CA /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -71,6 +73,7 @@
953B8DEF2370BB5C007E36E3 /* NVRAM.swift */,
953B8DED2370BB1A007E36E3 /* bdmesg.swift */,
953B8DF12370BF5A007E36E3 /* Extensions.swift */,
95620BCC23BF71A500CCBFB2 /* BootInstaller.swift */,
);
path = CloverDaemonNew;
sourceTree = "<group>";
@ -142,6 +145,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
95620BCD23BF71A500CCBFB2 /* BootInstaller.swift in Sources */,
953B8DF22370BF5B007E36E3 /* Extensions.swift in Sources */,
953D98872377094A003B369E /* Disks.swift in Sources */,
953DBFDF236F037400B0C4FB /* main.swift in Sources */,

View File

@ -0,0 +1,605 @@
//
// BootInstaller.swift
// CloverDaemonNew
//
// Created by vector sigma on 03/01/2020.
// Copyright © 2020 CloverHackyColor. All rights reserved.
//
import Foundation
class Installer: NSObject {
let ktempLogPath = "/tmp/cltmplog"
private var realTime : Bool = true
private var gTargetVolume : String? = nil
public var realTimeOutPut:Bool {
get {
return self.realTime
}
set {
self.realTime = newValue
}
}
private func cleanUp() {
let t = Process()
t.environment = ProcessInfo().environment
if #available(OSX 10.13, *) {
t.executableURL = URL(fileURLWithPath: "/bin/bash")
} else {
t.launchPath = "/bin/bash"
}
t.arguments = ["-c", "rm -f /tmp/Clover* && rm -f /tmp/boot0* && rm -f /tmp/boot1*"]
t.launch()
}
private func saveLog() {
if (self.gTargetVolume != nil)
&& fm.fileExists(atPath: self.gTargetVolume!)
&& fm.fileExists(atPath: ktempLogPath) {
let finalLogPath = self.gTargetVolume!.addPath("EFI/CLOVER/Clover.app_install.log")
do {
let data = try Data(contentsOf: URL(fileURLWithPath: finalLogPath))
(data as NSData).write(toFile: finalLogPath, atomically: false)
} catch {
print(error)
}
}
}
private func addToLog(_ str: String) {
let output : String = str.hasSuffix("\n") ? str : "\n\(str)"
if let data = output.data(using: .utf8) {
if fm.fileExists(atPath: ktempLogPath) {
if let fh = try? FileHandle(forWritingTo: URL(fileURLWithPath: ktempLogPath)) {
fh.seekToEndOfFile()
fh.write(data)
fh.closeFile()
}
} else {
(data as NSData).write(toFile: ktempLogPath, atomically: false)
}
}
}
private func log(_ msg: String) {
self.addToLog(msg)
print(msg)
}
private func exit(_ msg: String) {
print(msg)
self.addToLog(msg)
self.saveLog()
self.cleanUp()
Darwin.exit(EXIT_FAILURE)
}
private func copyReplace(src: String, dst: String, attr: [FileAttributeKey: Any]?, log: Bool) -> Bool {
var attributes : [FileAttributeKey: Any]? = attr
let upperDir = dst.deletingLastPath
if log {
if upperDir == "/" {
self.log("+ \(dst)")
} else {
self.log("+ ../\(upperDir.lastPath)/\(dst.lastPath)")
}
}
if !fm.fileExists(atPath: src) {
self.log("Error: \(src) doesn't exist.")
return false
}
// if attr is nil take attributes from source
if attr == nil {
do {
attributes = try fm.attributesOfItem(atPath: src)
} catch {
print("Warning: can't get attributes from '\(src)'")
}
}
// remove destination if already exist
if fm.fileExists(atPath: dst) {
do {
try fm.removeItem(atPath: dst)
} catch {
print(error)
return false
}
}
// create upper directory if needed
if !fm.fileExists(atPath: upperDir) {
do {
try fm.createDirectory(atPath: upperDir,
withIntermediateDirectories: true,
attributes: attributes)
} catch {
print(error)
return false
}
}
// copy file to destination
do {
try fm.copyItem(atPath: src, toPath: dst)
} catch {
print(error)
return false
}
return true
}
private func createDirectory(at path: String, attr: [FileAttributeKey: Any]?, exitOnError: Bool) {
var isDir : ObjCBool = false
if fm.fileExists(atPath: path, isDirectory: &isDir) {
if isDir.boolValue {
return
} else {
do {
try fm.removeItem(atPath: path)
} catch {
exit("\(error)")
}
}
}
do {
try fm.createDirectory(atPath: path,
withIntermediateDirectories: true,
attributes: attr)
} catch {
exit("\(error)")
}
}
// MARK: Install
func install() {
let df = DateFormatter()
df.locale = Locale(identifier: "en_US")
df.dateFormat = "yyyy-MM-dd hh:mm:ss"
let now = df.string(from: Date())
if fm.fileExists(atPath: ktempLogPath) {
try? fm.removeItem(atPath: ktempLogPath)
}
guard let CloverappDict = NSDictionary(contentsOfFile: "/tmp/Cloverapp") as? [String:AnyObject] else {
exit("Error: can't load Cloverapp dictionary.")
return // make the compiler happy
}
cleanUp()
let bootSectorsInstall = "/tmp/bootsectors-install"
let targetVol = CloverappDict["targetVol"] as! String
let disk = CloverappDict["disk"] as! String
let filesystem = CloverappDict["filesystem"] as! String
let shemeMap = CloverappDict["shemeMap"] as! String
let boot0 = CloverappDict["boot0"] as? String
let boot1 = CloverappDict["boot1"] as? String
let boot2 = CloverappDict["boot2"] as? String
let CloverV2 = CloverappDict["CloverV2"] as! String
let boot1installPath = CloverappDict["boot1install"] as? String
let bootSectorsInstallSrc = CloverappDict["bootsectors-install"] as? String
let backUpPath = CloverappDict["BackUpPath"] as? String
let version = CloverappDict["version"] as! String
let isESP = (CloverappDict["isESP"] as! NSNumber).boolValue
let alt : Bool = (CloverappDict["alt"] as? NSNumber)?.boolValue ?? false
log("\(version) (v\(daemonVersion)), \(now)")
log("SELF = \(CommandLine.arguments[0])")
if geteuid() != 0 {
exit("Error: you don't have root permissions.")
}
if (backUpPath != nil) {
log("Backup made at:\n\(backUpPath!).")
}
if fm.fileExists(atPath: bootSectorsInstall) {
do {
try fm.removeItem(atPath: bootSectorsInstall)
} catch {
exit("Error: can't remove old bootsectors-install.")
}
}
if (bootSectorsInstallSrc != nil) {
log("bootSectorsInstallSrc = \(bootSectorsInstallSrc!)")
}
// MARK: Preferences dict init
let preferences = NSMutableDictionary()
// MARK: Attributes init
let attributes : [FileAttributeKey: Any] = [FileAttributeKey.posixPermissions: 0777]
// MARK: Check Volume
self.gTargetVolume = targetVol
if !fm.fileExists(atPath: targetVol) {
exit("Error: target volume \"\(targetVol)\" doesn't exist.")
}
if !fm.fileExists(atPath: CloverV2) {
exit("Error: cannot found CloverV2 directory.")
}
log("Target volume: \(targetVol)")
if !fm.isWritableFile(atPath: targetVol) {
exit("Error: target volume \"\(targetVol)\" is not writable.")
}
// MARK: Check paths
var boot0Path: String? = nil
var boot1Path: String? = nil
var boot2Path: String? = nil
if (boot0 != nil) {
log("boot0: \(boot0!)")
preferences.setValue(boot0!, forKey: "boot0")
boot0Path = CloverV2.addPath("BootSectors").addPath(boot0!)
if !fm.fileExists(atPath: boot0Path!) {
exit("Error: cannot found \"\(boot0!)\".")
}
}
if (boot1 != nil) {
log("boot1: \(boot1!)")
boot1Path = CloverV2.addPath("BootSectors").addPath(boot1!)
if !fm.fileExists(atPath: boot1Path!) {
exit("Error: cannot found \"\(boot1!)\".")
}
}
if (boot2 != nil) {
log("boot2: \(boot2!)")
preferences.setValue(boot2!, forKey: "boot2")
boot2Path = CloverV2.addPath("Bootloaders/x64").addPath(boot2!)
if !fm.fileExists(atPath: boot2Path!) {
exit("Error: cannot found \"\(boot2!)\".")
}
}
// MARK: Create Directories
createDirectory(at: targetVol.addPath("EFI/CLOVER"), attr: attributes, exitOnError: true)
createDirectory(at: targetVol.addPath("EFI/BOOT"), attr: attributes, exitOnError: true)
createDirectory(at: targetVol.addPath("EFI/CLOVER/misc"), attr: attributes, exitOnError: true)
let subDirs = ["ACPI/origin",
"ACPI/patched",
"ACPI/WINDOWS",
"kexts/10",
"kexts/10_recovery",
"kexts/10_installer",
"kexts/10.11",
"kexts/10.12",
"kexts/10.13",
"kexts/10.14",
"kexts/10.15",
"kexts/Other",
"ROM"]
for dir in subDirs {
createDirectory(at: targetVol.addPath("EFI/CLOVER").addPath(dir),
attr: attributes,
exitOnError: true)
}
for dir in subDirs {
if !fm.fileExists(atPath: targetVol.addPath("EFI/CLOVER/OEM")) {
createDirectory(at: targetVol.addPath("EFI/CLOVER/OEM/SystemProductName").addPath(dir),
attr: attributes,
exitOnError: true)
if dir != "ROM" {
createDirectory(at: targetVol.addPath("EFI/CLOVER/OEM/SystemProductName/UEFI").addPath(dir),
attr: attributes,
exitOnError: true)
}
}
}
// MARK: Install Clover and drivers
self.log("\nInstalling/Updating Clover:")
if !copyReplace(src: CloverV2.addPath("EFI/BOOT/BOOTX64.efi"),
dst: targetVol.addPath("EFI/BOOT/BOOTX64.efi"),
attr: attributes,
log: true) {
exit("Error: cannot copy BOOTX64.efi to destination.")
}
if !copyReplace(src: CloverV2.addPath("EFI/CLOVER/CLOVERX64.efi"),
dst: targetVol.addPath("EFI/CLOVER/CLOVERX64.efi"),
attr: attributes,
log: true) {
exit("Error: cannot copy CLOVERX64.efi to destination.")
}
self.log("\nInstalling/Updating drivers:")
if let toDelete = CloverappDict["toDelete"] as? [String] {
for dpath in toDelete {
if fm.fileExists(atPath: dpath) {
self.log("- ../\(dpath.deletingLastPath.lastPath)/\(dpath.lastPath)")
do {
try fm.removeItem(atPath: dpath)
} catch {
exit("\(error)")
}
}
}
}
let UEFIdest = targetVol.addPath("EFI/CLOVER/drivers/UEFI")
let BIOSdest = targetVol.addPath("EFI/CLOVER/drivers/BIOS")
if let UEFI = CloverappDict["UEFI"] as? [String] {
for dpath in UEFI {
if !copyReplace(src: dpath,
dst: UEFIdest.addPath(dpath.lastPath),
attr: attributes,
log: true) {
exit("Error: cannot copy '\(dpath)' to destination.")
}
}
}
if let BIOS = CloverappDict["BIOS"] as? [String] {
for dpath in BIOS {
if !copyReplace(src: dpath,
dst: BIOSdest.addPath(dpath.lastPath),
attr: attributes,
log: true) {
exit("Error: cannot copy '\(dpath)' to destination.")
}
}
}
// MARK: Install tools
let cv2tools = CloverV2.addPath("EFI/CLOVER/tools")
if fm.fileExists(atPath: cv2tools) {
self.log("\nInstalling/Updating tools:")
var tools : [String] = [String]()
do {
tools = try fm.contentsOfDirectory(atPath: cv2tools)
} catch { }
for t in tools {
if t.fileExtension == "efi" {
if !copyReplace(src: cv2tools.addPath(t),
dst: targetVol.addPath("EFI/CLOVER/tools").addPath(t),
attr: attributes,
log: true) {
exit("Error: cannot copy '\(cv2tools.addPath(t))' to destination.")
}
}
}
}
// MARK: Install docs
let cv2docs = CloverV2.addPath("EFI/CLOVER/doc")
if fm.fileExists(atPath: cv2docs) {
self.log("\nInstalling/Updating docs:")
var docs : [String] = [String]()
do {
docs = try fm.contentsOfDirectory(atPath: cv2docs)
} catch { }
for d in docs {
if d.fileExtension == "efi" {
var a : [FileAttributeKey: Any]? = nil
do {
a = try fm.attributesOfItem(atPath: cv2docs.addPath(d))
} catch { }
if !copyReplace(src: cv2docs.addPath(d),
dst: targetVol.addPath("EFI/CLOVER/doc").addPath(d),
attr: a,
log: true) {
// do not fail the installation fro a document. So just log:
self.log("Error: cannot copy '\(cv2tools.addPath(d))' to destination.")
}
}
}
}
// MARK: Create config.plist
let configPath = targetVol.addPath("EFI/CLOVER/config.plist")
let configSamplePath = CloverV2.addPath("EFI/CLOVER/config-sample.plist")
if !fm.fileExists(atPath: configPath) {
if !copyReplace(src: configSamplePath,
dst: configPath,
attr: attributes,
log: true) {
self.log("Error: cannot copy '\(configSamplePath)' to destination.")
}
}
// MARK: Install theme
// install the theme defined in config.plist
// Also do nothing if the theme directory already exist
// as Clover is already installed and user as its own free will,
// even to run w/o a theme
if let config = NSDictionary(contentsOfFile: configPath) {
let themesSourceDir = CloverV2.addPath("themespkg")
let themesDestDir = targetVol.addPath("EFI/CLOVER/themes")
if !fm.fileExists(atPath: themesDestDir) {
if let GUI = config.object(forKey: "GUI") as? NSDictionary {
if let Theme = GUI.object(forKey: "Theme") as? String {
if fm.fileExists(atPath: themesSourceDir.addPath(Theme)) {
self.log("\nInstalling Theme \"\(Theme)\":")
if !copyReplace(src: themesSourceDir.addPath(Theme),
dst: themesDestDir.addPath(Theme),
attr: attributes,
log: true) {
// do not fail for a theme, just log:
self.log("Error: cannot copy '\(themesSourceDir.addPath(Theme))' to destination.")
}
} else {
self.log("Warning: cannot found Theme '\(Theme)' defined in config.")
}
}
}
}
} else {
self.log("Warning: cannot read '\(configPath)' into a valid Dictionary.")
}
// MARK: Stage 2 Installation
if boot2Path != nil {
self.log("\nInstalling stage 2..")
if !copyReplace(src: boot2Path!,
dst: targetVol.addPath("boot"),
attr: attributes,
log: true) {
self.log("Error: cannot copy '\(boot2Path!)' to destination.")
}
if alt {
preferences.setValue(true, forKey: "boot2Alt")
let bootX64path = CloverV2.addPath("Bootloaders/x64")
var loaders : [String] = [String]()
do {
loaders = try fm.contentsOfDirectory(atPath: bootX64path)
} catch { }
for boot in loaders {
if boot.hasPrefix("boot") {
self.log("\nInstalling stage 2 \"\(boot) (alt)\".")
if !copyReplace(src: bootX64path.addPath(boot),
dst: targetVol.addPath(boot),
attr: attributes,
log: true) {
exit("Error: cannot copy '\(bootX64path.addPath(boot))' to destination.")
}
}
}
}
// ------------- end stage 2
}
// MARK: Write Preferences
preferences.write(toFile: targetVol.addPath("EFI/CLOVER/pref.plist"), atomically: true)
try? fm.setAttributes(attributes, ofItemAtPath: targetVol.addPath("EFI/CLOVER/pref.plist"))
saveLog()
// MARK: Boot sectors installation
if (boot0Path != nil && boot1Path != nil && bootSectorsInstallSrc != nil) {
if !copyReplace(src: bootSectorsInstallSrc!,
dst: bootSectorsInstall,
attr: nil,
log: false) {
exit("Error: cannot copy '\(bootSectorsInstallSrc!)' to destination.")
}
if !copyReplace(src: boot0Path!,
dst: "/tmp".addPath(boot0!),
attr: nil,
log: false) {
exit("Error: cannot copy '\(boot0Path!)' to destination.")
}
if !copyReplace(src: boot1Path!,
dst: "/tmp".addPath(boot1!),
attr: nil,
log: false) {
exit("Error: cannot copy '\(boot1Path!)' to destination.")
}
if !copyReplace(src: boot1installPath!,
dst: "/tmp/boot1-install",
attr: nil,
log: false) {
exit("Error: cannot copy '\(boot1installPath!)' to destination.")
}
let esp = isESP ? "ESP" : "OTHER"
let task = Process()
task.environment = ProcessInfo().environment
if #available(OSX 10.13, *) {
task.executableURL = URL(fileURLWithPath: bootSectorsInstall)
} else {
task.launchPath = bootSectorsInstall
}
task.arguments = [ disk, filesystem, shemeMap, boot0!, boot1!, esp ]
let pipe = Pipe()
if self.realTime {
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)
self.log(output)
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)
if task.terminationStatus != 0 {
self.exit("Error: failed installing boot sectors.")
}
}
task.launch()
task.waitUntilExit()
} else {
task.standardOutput = pipe
task.standardError = pipe
let fh = pipe.fileHandleForReading
task.terminationHandler = { (t) in
if t.terminationStatus != 0 {
self.exit("Error: failed installing boot sectors.")
}
}
task.launch()
task.waitUntilExit()
// TODO: make output in real time
let data = fh.readDataToEndOfFile()
if let out = String(data: data, encoding: .utf8) {
self.log(out)
}
}
} else {
saveLog()
if (isESP) {
let task = Process()
task.environment = ProcessInfo().environment
if #available(OSX 10.13, *) {
task.executableURL = URL(fileURLWithPath: "/usr/sbin/diskutil")
} else {
task.launchPath = "/usr/sbin/diskutil"
}
task.arguments = [ "umount", "force", disk ]
task.launch()
}
cleanUp()
}
Darwin.exit(EXIT_SUCCESS)
// ------------- end
}
}

View File

@ -8,7 +8,7 @@
import Foundation
let daemonVersion = "1.0.9"
let daemonVersion = "1.1.0"
let fm = FileManager.default
@ -435,7 +435,7 @@ func main() {
exit(EXIT_SUCCESS)
}
sigtermSource.resume()
RunLoop.current.run()
//dispatchMain()
}
@ -443,7 +443,7 @@ func main() {
let myPath = CommandLine.arguments[0]
let myName = (myPath as NSString).lastPathComponent
if CommandLine.arguments.contains("--install") {
if CommandLine.arguments[1] == "--install" {
print("Installing daemon...")
// build the launch daemon
let launch = NSMutableDictionary()
@ -520,7 +520,7 @@ if CommandLine.arguments.contains("--install") {
} catch {
print(error)
}
} else if CommandLine.arguments.contains("--uninstall") {
} else if CommandLine.arguments[1] == "--uninstall" {
print("uninstalling daemon...")
do {
if fm.fileExists(atPath: launchPlistPath) {
@ -549,6 +549,11 @@ if CommandLine.arguments.contains("--install") {
} catch {
print(error)
}
} else if CommandLine.arguments[1] == "--CLOVER" {
let installer = Installer()
installer.realTimeOutPut = true
installer.install()
RunLoop.current.run()
} else {
main()
}

View File

@ -1,9 +1,10 @@
#!/bin/bash
# Created by vector sigma on 04/11/2019.
# Copyright © 2019 CloverHackyColor. All rights reserved.
logPath="/tmp/cltmplog"
exec > >(tee -a $logPath) 2>&1
# Created by vector sigma on 04/11/2019.
# Copyright © 2019 CloverHackyColor. All rights reserved.
cd /tmp

View File

@ -1,294 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
958505AD2364D36400BCB4A3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 958505AC2364D36400BCB4A3 /* main.m */; };
95E61978236F87D100D20FCB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95E61977236F87D100D20FCB /* Foundation.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
958505A72364D36400BCB4A3 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
958505A92364D36400BCB4A3 /* Cloverhelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Cloverhelper; sourceTree = BUILT_PRODUCTS_DIR; };
958505AC2364D36400BCB4A3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
95E61977236F87D100D20FCB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
958505A62364D36400BCB4A3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
95E61978236F87D100D20FCB /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
958505A02364D36300BCB4A3 = {
isa = PBXGroup;
children = (
958505AB2364D36400BCB4A3 /* Cloverhelper */,
958505AA2364D36400BCB4A3 /* Products */,
95E61976236F87D100D20FCB /* Frameworks */,
);
sourceTree = "<group>";
};
958505AA2364D36400BCB4A3 /* Products */ = {
isa = PBXGroup;
children = (
958505A92364D36400BCB4A3 /* Cloverhelper */,
);
name = Products;
sourceTree = "<group>";
};
958505AB2364D36400BCB4A3 /* Cloverhelper */ = {
isa = PBXGroup;
children = (
958505AC2364D36400BCB4A3 /* main.m */,
);
path = Cloverhelper;
sourceTree = "<group>";
};
95E61976236F87D100D20FCB /* Frameworks */ = {
isa = PBXGroup;
children = (
95E61977236F87D100D20FCB /* Foundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
958505A82364D36400BCB4A3 /* Cloverhelper */ = {
isa = PBXNativeTarget;
buildConfigurationList = 958505B02364D36400BCB4A3 /* Build configuration list for PBXNativeTarget "Cloverhelper" */;
buildPhases = (
958505A52364D36400BCB4A3 /* Sources */,
958505A62364D36400BCB4A3 /* Frameworks */,
958505A72364D36400BCB4A3 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = Cloverhelper;
productName = cloverhelper;
productReference = 958505A92364D36400BCB4A3 /* Cloverhelper */;
productType = "com.apple.product-type.tool";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
958505A12364D36300BCB4A3 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1130;
ORGANIZATIONNAME = CloverHackyColor;
TargetAttributes = {
958505A82364D36400BCB4A3 = {
CreatedOnToolsVersion = 11.2;
};
};
};
buildConfigurationList = 958505A42364D36300BCB4A3 /* Build configuration list for PBXProject "Cloverhelper" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 958505A02364D36300BCB4A3;
productRefGroup = 958505AA2364D36400BCB4A3 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
958505A82364D36400BCB4A3 /* Cloverhelper */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
958505A52364D36400BCB4A3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
958505AD2364D36400BCB4A3 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
958505AE2364D36400BCB4A3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
958505AF2364D36400BCB4A3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
};
name = Release;
};
958505B12364D36400BCB4A3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
958505B22364D36400BCB4A3 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
MACOSX_DEPLOYMENT_TARGET = 10.11;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
958505A42364D36300BCB4A3 /* Build configuration list for PBXProject "Cloverhelper" */ = {
isa = XCConfigurationList;
buildConfigurations = (
958505AE2364D36400BCB4A3 /* Debug */,
958505AF2364D36400BCB4A3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
958505B02364D36400BCB4A3 /* Build configuration list for PBXNativeTarget "Cloverhelper" */ = {
isa = XCConfigurationList;
buildConfigurations = (
958505B12364D36400BCB4A3 /* Debug */,
958505B22364D36400BCB4A3 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 958505A12364D36300BCB4A3 /* Project object */;
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:cloverhelper.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -1,540 +0,0 @@
//
// main.m
// Cloverhelper
//
// Created by vector sigma on 26/10/2019.
// Copyright © 2019 CloverHackyColor. All rights reserved.
//
/*
This command line must be run as root and it is responsible for creating the Clover tree
and to install boot sectors and drivers.
*/
// TODO: redone in swift as swift command line are now small in size, with no hurry...
#import <Foundation/Foundation.h>
#define ktempLogPath "/tmp/cltmplog"
#define kfm [NSFileManager defaultManager]
#pragma mark -
#pragma mark copy and replace files
#pragma mark -
void cleanUp() {
NSTask *task = [[NSTask alloc] init];
[task setEnvironment:[[NSProcessInfo new] environment]];
[task setLaunchPath:@"/bin/bash"];
[task setArguments:@[ @"-c", @"rm -f /tmp/Clover* && rm -f /tmp/boot0* && rm -f /tmp/boot1*" ]];
[task launch];
}
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:@"/"]) {
post(@"+ ../%@\n", [dest lastPathComponent]);
} else {
post(@"+ ../%@/%@\n",
[[dest stringByDeletingLastPathComponent] lastPathComponent], [dest lastPathComponent]);
}
if (![kfm fileExistsAtPath:source]) {
post(@"Error: %@ doesn't exist\n", source);
return NO;
}
// remove destination if already exist
if ([kfm fileExistsAtPath:dest]) {
[kfm removeItemAtPath:dest error:&err];
}
// create upper directory if needed
if (err == nil) {
if (![kfm fileExistsAtPath:upperDir]) {
[kfm createDirectoryAtPath:upperDir
withIntermediateDirectories:YES
attributes:attributes
error:&err];
}
}
// copy the new item
if (err == nil) {
if ([kfm copyItemAtPath:source toPath:dest error:&err] && attributes) {
[kfm setAttributes:attributes ofItemAtPath:dest error:nil];
}
}
// print any errors if any
if (err != nil) {
post(@"%@\n", err.description);
}
return (err == nil);
}
#pragma mark -
#pragma mark Main
#pragma mark -
int main(int argc, char * const * argv) {
@autoreleasepool {
if ([kfm fileExistsAtPath:@ktempLogPath]) {
[kfm removeItemAtPath:@ktempLogPath error:nil];
}
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");
}
NSDictionary *CloverappDict = [NSDictionary dictionaryWithContentsOfFile:@"/tmp/Cloverapp"];
if (CloverappDict == nil) {
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"];
NSString *shemeMap = [CloverappDict objectForKey:@"shemeMap"];
NSString *boot0 = [CloverappDict objectForKey:@"boot0"];
NSString *boot1 = [CloverappDict objectForKey:@"boot1"];
NSString *boot2 = [CloverappDict objectForKey:@"boot2"];
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];
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]) {
post(@"Note: found old bootsectors-install..removing it..\n");
if (![kfm removeItemAtPath:bootSectorsInstall error:nil]) {
exitWithMessage(@"Error: can't remove old bootsectors-install.");
}
}
if (bootSectorsInstallSrc != nil) {
post(@"bootSectorsInstallSrc = %@\n", bootSectorsInstallSrc);
}
BOOL alt = NO;
if ([CloverappDict objectForKey:@"alt"] != nil) {
alt = [[CloverappDict objectForKey:@"alt"] boolValue];
}
#pragma mark Preferences dict init
NSMutableDictionary *preferences = [NSMutableDictionary new];
#pragma mark Attributes init
NSDictionary * attributes = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithShort:0777], NSFilePosixPermissions, nil];
#pragma mark Check Volume
BOOL isDir = NO;
if (targetVol == nil) {
exitWithMessage(@"Error: option targetVol [path to volume] not specified\n");
}
gTargetVolume = targetVol;
if (![kfm fileExistsAtPath:targetVol]) {
exitWithMessage(@"Error: target volume \"%@\" doesn't exist.\n", targetVol);
}
if (cloverv2 == nil || ![kfm fileExistsAtPath:cloverv2]) {
exitWithMessage(@"Error: cannot found CloverV2 directory\n");
}
post(@"Target volume: %@\n", targetVol);
/*
// check if target volume is writable
NSString *volEnds = targetVol;
if (![volEnds hasSuffix:@"/"]) {
volEnds = [targetVol stringByAppendingString:@"/"];
}
if (![kfm isWritableFileAtPath:volEnds]) {
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) {
post(@"boot0: %@\n", boot0);
[preferences setValue:boot0 forKey:@"boot0"];
boot0Path = [[cloverv2 stringByAppendingPathComponent:@"BootSectors"] stringByAppendingPathComponent:boot0];
if (![kfm fileExistsAtPath:boot0Path]) {
exitWithMessage(@"Error: cannot found \"%@\".\n", boot0);
}
}
if (boot1 != nil) {
post(@"boot1: %@\n", boot1);
boot1Path = [[cloverv2 stringByAppendingPathComponent:@"BootSectors"] stringByAppendingPathComponent:boot1];
if (![kfm fileExistsAtPath:boot1Path]) {
exitWithMessage(@"Error: cannot found \"%@\".\n", boot1);
}
}
if (boot2 != nil) {
post(@"boot2: %@\n", boot2);
[preferences setValue:boot2 forKey:@"boot2"];
boot2Path = [[cloverv2 stringByAppendingPathComponent:@"Bootloaders/x64"] stringByAppendingPathComponent:boot2];
if (![kfm fileExistsAtPath:boot2Path]) {
exitWithMessage(@"Error: cannot found \"%@\".\n", boot2);
}
}
NSError *err = nil;
if ([kfm fileExistsAtPath:
[targetVol stringByAppendingPathComponent:@"EFI/CLOVER"] isDirectory:&isDir]) {
if (!isDir) {
[kfm removeItemAtPath:
[targetVol stringByAppendingPathComponent:@"EFI/CLOVER"] error:&err];
}
}
if (![kfm fileExistsAtPath:[targetVol stringByAppendingPathComponent:@"EFI/CLOVER"]]) {
[kfm createDirectoryAtPath:[targetVol stringByAppendingPathComponent:@"EFI/CLOVER"]
withIntermediateDirectories:YES
attributes:attributes
error:&err];
}
if (err != nil) {
exitWithMessage(@"%@\n", err.description);
}
#pragma mark Create directories
NSArray *sub = [NSArray arrayWithObjects:
@"EFI/BOOT",
@"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",
@"EFI/CLOVER/kexts/10.14",
@"EFI/CLOVER/kexts/10.15",
@"EFI/CLOVER/kexts/Other",
@"EFI/CLOVER/misc",
@"EFI/CLOVER/ROM",
nil];
for (int i = 0; i < [sub count]; i++) {
err = nil;
NSString *fp = [targetVol stringByAppendingPathComponent:[sub objectAtIndex:i]];
if (![kfm fileExistsAtPath:fp]) {
[kfm createDirectoryAtPath:fp withIntermediateDirectories:YES attributes:attributes error:&err];
if (err != nil) {
exitWithMessage(@"%@\n", err.description);
}
}
}
#pragma mark Install Clover and drivers
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");
}
if (!copyReplace([cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/CLOVERX64.efi"],
[targetVol stringByAppendingPathComponent:@"EFI/CLOVER/CLOVERX64.efi"],
attributes)) {
exitWithMessage(@"Error: cannot copy CLOVERX64.efi to destination.\n");
}
post(@"\nInstalling/Updating drivers:\n");
NSArray * toDelete = [CloverappDict objectForKey:@"toDelete"];
NSArray * UEFI = [CloverappDict objectForKey:@"UEFI"];
NSArray * BIOS = [CloverappDict objectForKey:@"BIOS"];
NSString *UEFIdest = [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/drivers/UEFI"];
NSString *BIOSdest = [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/drivers/BIOS"];
if (UEFI != nil) {
for (int i = 0; i < [UEFI count]; i++) {
NSString *dpath = [UEFI objectAtIndex:i];
NSString *dname = [dpath lastPathComponent];
if (!copyReplace(dpath, [UEFIdest stringByAppendingPathComponent:dname], attributes)) {
exitWithMessage(@"Error: cannot copy %@ to destination.\n", dpath);
}
}
}
if (BIOS != nil) {
for (int i = 0; i < [BIOS count]; i++) {
NSString *dpath = [BIOS objectAtIndex:i];
NSString *dname = [dpath lastPathComponent];
if (!copyReplace(dpath, [BIOSdest stringByAppendingPathComponent:dname], attributes)) {
exitWithMessage(@"Error: cannot copy %@ to destination.\n", dpath);
}
}
}
if (toDelete != nil) {
for (int i = 0; i < [toDelete count]; i++) {
NSString *dpath = [toDelete objectAtIndex:i];
err = nil;
if ([kfm fileExistsAtPath:dpath]) {
post(@"- ../%@/%@\n",
[[dpath stringByDeletingLastPathComponent] lastPathComponent],
[dpath lastPathComponent]);
[kfm removeItemAtPath:dpath error:&err];
if (err != nil) {
exitWithMessage(@"%@\n", err.description);
}
}
}
}
#pragma mark Install tools
NSString *cv2tools = [cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/tools"];
if ([kfm fileExistsAtPath:cv2tools]) {
post(@"\nInstalling/Updating tools:\n");
err = nil;
NSArray *tools = [kfm contentsOfDirectoryAtPath:cv2tools error:&err];
if (err == nil && tools != nil) {
for (int i = 0; i < [tools count]; i++) {
NSString *t = [tools objectAtIndex:i];
if ([[t pathExtension] isEqualToString:@"efi"]) {
if (!copyReplace([cv2tools stringByAppendingPathComponent:t],
[[targetVol stringByAppendingPathComponent:@"EFI/CLOVER/tools"]
stringByAppendingPathComponent:t],
attributes)) {
exitWithMessage(@"Error: cannot copy %@ to destination.\n", t);
}
}
}
}
}
err = nil;
#pragma mark Install docs
NSString *cv2docs = [cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/doc"];
if ([kfm fileExistsAtPath:cv2tools]) {
post(@"\nInstalling/Updating doc:\n");
err = nil;
NSArray *docs = [kfm contentsOfDirectoryAtPath:cv2docs error:&err];
if (err == nil && docs != nil) {
for (int i = 0; i < [docs count]; i++) {
NSString *d = [docs objectAtIndex:i];
if (![d hasPrefix:@"."]) {
NSString *docpath = [cv2docs stringByAppendingPathComponent:d];
NSDictionary *docattr = [kfm attributesOfItemAtPath:docpath error:nil];
if (!copyReplace(docpath,
[[targetVol stringByAppendingPathComponent:@"EFI/CLOVER/doc"]
stringByAppendingPathComponent:d],
docattr)) {
//exitWithMessage(@"Error: cannot copy %@ to destination.\n", d);
// ... will not fail for a doc..
post(@"Error: cannot copy %@ to destination.\n", d);
}
}
}
}
}
err = nil;
#pragma mark Create config.plist
NSString *configPath = [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/config.plist"];
NSString *configSamplePath = [cloverv2 stringByAppendingPathComponent:@"EFI/CLOVER/config-sample.plist"];
if (![kfm fileExistsAtPath:configPath]) {
post(@"\nInstalling config.plist:\n");
copyReplace(configSamplePath, configPath, attributes);
}
#pragma mark Install theme
// install the theme defined in config if doesn't exist
NSDictionary *config = [NSDictionary dictionaryWithContentsOfFile:configPath];
NSString *themesSourceDir = [cloverv2 stringByAppendingPathComponent:@"themespkg"];
NSString *themesDestDir = [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/themes"];
if (config != nil && ![kfm fileExistsAtPath:themesDestDir]) {
NSString *theme = nil;
NSDictionary *GUI = [config objectForKey:@"GUI"];
if (GUI != nil) {
theme = [GUI objectForKey:@"Theme"];
}
// don't overwrite the theme if already exist as one from CTM can be newer
if (theme != nil && ![kfm fileExistsAtPath:
[themesDestDir stringByAppendingPathComponent:theme]]) {
post(@"\nInstalling Theme \"%@\":\n", theme);
copyReplace([themesSourceDir stringByAppendingPathComponent:theme],
[themesDestDir stringByAppendingPathComponent:theme],
attributes);
}
}
#pragma mark Stage 2 installation
if (boot2Path != nil) {
post(@"\nInstalling stage 2..\n");
if (!copyReplace(boot2Path, [targetVol stringByAppendingPathComponent:@"boot"], attributes)) {
exitWithMessage(@"Error: cannot copy bootloader to detination.\n");
}
if (alt) {
[preferences setValue:[NSNumber numberWithBool:YES] forKey:@"boot2Alt"];
NSString *altPath = [boot2Path stringByDeletingLastPathComponent];
NSArray *files = [kfm contentsOfDirectoryAtPath:altPath error:nil];
if (files) {
for (int i = 0; i < [files count]; i++) {
NSString *f = [files objectAtIndex:i];
if ([f hasPrefix:@"boot"]) {
post(@"\nInstalling stage 2 \"%@ (alt)\".\n", f);
copyReplace([altPath stringByAppendingPathComponent: f],
[targetVol stringByAppendingPathComponent:f],
attributes);
}
}
}
}
}
#pragma mark Write Preferences
NSString *prefPath = [targetVol stringByAppendingPathComponent:@"EFI/CLOVER/pref.plist"];
if ([preferences writeToFile:prefPath atomically:YES]) {
[kfm setAttributes:attributes ofItemAtPath:prefPath error:nil];
}
saveLog();
#pragma mark Boot sectors installation
if (boot0Path != nil && boot1Path != nil && bootSectorsInstallSrc != nil) {
// copy bootsectors-install
[kfm copyItemAtPath:bootSectorsInstallSrc toPath:bootSectorsInstall error:nil];
NSDictionary *bsiAttr = [kfm attributesOfItemAtPath:bootSectorsInstallSrc error:nil];
[kfm setAttributes:bsiAttr ofItemAtPath:bootSectorsInstall error:nil];
// copy boot0
[kfm copyItemAtPath:boot0Path toPath:[@"/tmp" stringByAppendingPathComponent:boot0] error:nil];
// copy boot1
[kfm copyItemAtPath:boot1Path toPath:[@"/tmp" stringByAppendingPathComponent:boot1] error:nil];
[kfm copyItemAtPath:boot1installPath toPath:@"/tmp/boot1-install" error:nil];
/*
/tmp/bootsectors-install disk4s1 hfs FDisk_partition_scheme boot0af boot1h
*/
NSTask *task = [[NSTask alloc] init];
NSPipe *pipe = [NSPipe new];
task.standardOutput = pipe;
task.standardError = pipe;
NSFileHandle * fh = [pipe fileHandleForReading];
[task setEnvironment:[[NSProcessInfo new] environment]];
[task setLaunchPath:bootSectorsInstall];
NSString *esp = isESP ? @"ESP" : @"OTHER";
[task setArguments:@[ disk, filesystem, shemeMap, boot0, boot1, esp ]];
task.terminationHandler = ^(NSTask *theTask) {
if (theTask.terminationStatus != 0) {
exitWithMessage(@"Error: failed installing boot sectors.\n");
}
};
[task launch];
//[task waitUntilExit];
NSData *data = [fh readDataToEndOfFile];
if (data) {
NSString *output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
post(@"%@\n", output);
}
} else {
saveLog();
if (isESP) {
NSTask *task = [[NSTask alloc] init];
[task setEnvironment:[[NSProcessInfo new] environment]];
[task setLaunchPath:@"/usr/sbin/diskutil"];
[task setArguments:@[ @"umount", @"force", disk ]];
[task launch];
}
}
cleanUp();
exit(EXIT_SUCCESS);
}
return 0;
}