Clover.app v1.13

Fixed detection of legacy firmware for CloverDaemonNew.
Detection of System Serial and OEM manufacturer informations.
Startup sound settings in the interface.
Installer inform with a sound and an alert window the installation result.
Installer now produce the installation log.
Installer is now thread safe.
The UI is modified to make room forall the new functionalities.
This commit is contained in:
vectorsigma72 2020-01-01 15:42:47 +01:00
parent e168d7c74f
commit 1d7e7327c0
46 changed files with 2197 additions and 685 deletions

View File

@ -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 = "<group>"; };
9555AF25238EE53300108C33 /* InstallerOutline.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InstallerOutline.swift; sourceTree = "<group>"; };
9555AF27238EFDAD00108C33 /* DriversCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DriversCollection.swift; sourceTree = "<group>"; };
955689DA23A2728000AD323C /* IO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IO.swift; sourceTree = "<group>"; };
9556CAF4238DF75600082671 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/InstallerOutline.xib; sourceTree = "<group>"; };
9558518D23BA3485002CB3D8 /* Speaker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Speaker.png; sourceTree = "<group>"; };
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 = "<group>"; };
9560906C238C624200ACD7F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
@ -401,6 +405,14 @@
name = Products;
sourceTree = "<group>";
};
9558518C23BA3472002CB3D8 /* images */ = {
isa = PBXGroup;
children = (
9558518D23BA3485002CB3D8 /* Speaker.png */,
);
path = images;
sourceTree = "<group>";
};
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)";

View File

@ -0,0 +1,8 @@
<?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>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@ -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 {

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15504"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -12,34 +12,16 @@
<window title="Clover" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="342" height="632"/>
<rect key="contentRect" x="196" y="240" width="342" height="651"/>
<rect key="screenRect" x="0.0" y="0.0" width="1600" height="877"/>
<value key="minSize" type="size" width="342" height="614"/>
<value key="maxSize" type="size" width="342" height="614"/>
<value key="minSize" type="size" width="342" height="651"/>
<value key="maxSize" type="size" width="342" height="651"/>
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="342" height="632"/>
<rect key="frame" x="0.0" y="0.0" width="342" height="651"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f5t-Ia-85K">
<rect key="frame" x="21" y="603" width="304" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Current revision" id="Re2-vf-XQ6">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G6z-Xp-lnm">
<rect key="frame" x="21" y="580" width="303" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot Device:" id="omZ-xs-Wjn">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7kg-2N-6IM">
<rect key="frame" x="165" y="134" width="164" height="32"/>
<rect key="frame" x="165" y="149" width="164" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Check now" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UyZ-5I-L9X">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -49,26 +31,8 @@
<action selector="checkNow:" target="tSJ-3G-dnL" id="UY0-EP-xVG"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" placeholderIntrinsicWidth="300" placeholderIntrinsicHeight="16" translatesAutoresizingMaskIntoConstraints="NO" id="5CM-EI-thb">
<rect key="frame" x="21" y="541" width="304" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="config path:" id="iii-3P-wo8">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RIu-Gh-Uqo">
<rect key="frame" x="17" y="396" width="308" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="NVRAM/bdmesg" id="8j2-3s-fjm">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xbi-A5-m33">
<rect key="frame" x="14" y="191" width="311" height="16"/>
<rect key="frame" x="14" y="206" width="311" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Update" id="58l-pb-zEc">
<font key="font" metaFont="system"/>
@ -77,7 +41,7 @@
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g5h-bF-3le">
<rect key="frame" x="14" y="43" width="311" height="18"/>
<rect key="frame" x="14" y="32" width="311" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Run at login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="J8R-ej-fRl">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -87,66 +51,16 @@
<action selector="runAtLogin:" target="tSJ-3G-dnL" id="Kfi-uU-9Tq"/>
</connections>
</button>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="vOr-f4-3wc">
<rect key="frame" x="19" y="417" width="304" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="NvE-a0-QjT">
<rect key="frame" x="16" y="245" width="307" height="5"/>
<rect key="frame" x="16" y="260" width="307" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="E8G-Gr-UlY">
<rect key="frame" x="16" y="65" width="307" height="5"/>
<rect key="frame" x="16" y="54" width="307" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3iW-Mp-ZEr">
<rect key="frame" x="17" y="372" width="102" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Theme:" id="7yo-8b-ZHc">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jR0-Lr-IYX">
<rect key="frame" x="18" y="346" width="101" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Sound:" id="UHz-ZM-JLi">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Zs-Un-dNa" customClass="FWTextField" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="125" y="369" width="198" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="DVf-rV-Hrc">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="199"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="WMZ-zj-8k6" customClass="FWTextField" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="125" y="343" width="198" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="o0i-cN-QJu">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="199"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1qf-uO-CvA" customClass="FWPopUpButton" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="14" y="138" width="155" height="25"/>
<rect key="frame" x="14" y="153" width="155" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="lkK-DQ-QK6">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
@ -163,7 +77,7 @@
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="nx7-BI-FIh">
<rect key="frame" x="14" y="171" width="311" height="14"/>
<rect key="frame" x="14" y="186" width="311" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Check update:" id="fMZ-r2-dlm">
<font key="font" metaFont="menu" size="11"/>
@ -172,7 +86,7 @@
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="HPk-Vu-vf0">
<rect key="frame" x="14" y="76" width="311" height="14"/>
<rect key="frame" x="14" y="91" width="311" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Label" id="v3d-HG-AeW">
<font key="font" metaFont="menu" size="11"/>
@ -181,48 +95,11 @@
</textFieldCell>
</textField>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="bsQ-GS-duU">
<rect key="frame" x="16" y="485" width="307" height="5"/>
<rect key="frame" x="70" y="497" width="213" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mcY-kx-lap" customClass="FWPopUpButton" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="135" y="457" width="191" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="Hzi-CJ-xVH">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<menu key="menu" id="Vb3-8W-CMc"/>
</popUpButtonCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="189"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="mountESP:" target="tSJ-3G-dnL" id="Wd0-O9-Tfa"/>
</connections>
</popUpButton>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Zc5-Dl-jIh">
<rect key="frame" x="197" y="420" width="131" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="umount" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhl-e0-nVD">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="umount:" target="tSJ-3G-dnL" id="KqE-Db-Uf1"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="M1w-uF-TFN">
<rect key="frame" x="17" y="464" width="114" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Mount" id="s5K-bS-gZa">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zDK-XE-o2Z">
<rect key="frame" x="17" y="491" width="312" height="32"/>
<rect key="frame" x="10" y="59" width="318" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="E23-ao-JFs">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -233,7 +110,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2NR-5W-4rg">
<rect key="frame" x="10" y="106" width="319" height="32"/>
<rect key="frame" x="10" y="121" width="319" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Button" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="EJg-qm-L18">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -243,21 +120,12 @@
<action selector="updateClover:" target="tSJ-3G-dnL" id="kpg-zk-tVv"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Sj4-Yw-RpL">
<rect key="frame" x="17" y="452" width="38" height="11"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="(ESP)" id="TTH-hz-cX2">
<font key="font" metaFont="label" size="9"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="2pM-fw-w5V">
<rect key="frame" x="16" y="213" width="307" height="5"/>
<rect key="frame" x="16" y="228" width="307" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jbm-8q-WaH">
<rect key="frame" x="17" y="224" width="109" height="17"/>
<rect key="frame" x="17" y="239" width="109" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="CloverDaemon" id="gez-2n-CkL">
<font key="font" usesAppearanceFont="YES"/>
@ -266,7 +134,7 @@
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MWn-i4-CYn">
<rect key="frame" x="136" y="215" width="114" height="32"/>
<rect key="frame" x="136" y="230" width="114" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Uninstall" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="w6z-A1-CZt">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -277,11 +145,11 @@
</connections>
</button>
<progressIndicator wantsLayer="YES" fixedFrame="YES" maxValue="100" doubleValue="50" style="bar" translatesAutoresizingMaskIntoConstraints="NO" id="DtR-XE-DfU">
<rect key="frame" x="16" y="81" width="307" height="35"/>
<rect key="frame" x="16" y="96" width="307" height="35"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</progressIndicator>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vgX-bN-KyC">
<rect key="frame" x="244" y="215" width="85" height="32"/>
<rect key="frame" x="244" y="230" width="85" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Install" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="omz-9K-nb4">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -292,7 +160,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wDl-KZ-OP0">
<rect key="frame" x="21" y="292" width="304" height="14"/>
<rect key="frame" x="21" y="307" width="304" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="*Disable Sleep Proxy Client" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="kZm-NL-hOA">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -303,7 +171,7 @@
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wxL-7U-AGQ">
<rect key="frame" x="45" y="250" width="280" height="11"/>
<rect key="frame" x="21" y="265" width="304" height="11"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="*Require CloverDaemon" id="yQ9-cU-wtc">
<font key="font" metaFont="label" size="9"/>
@ -312,7 +180,7 @@
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="y9x-U8-ayg">
<rect key="frame" x="21" y="314" width="304" height="16"/>
<rect key="frame" x="21" y="329" width="304" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="*Make filesystem read-write" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="v3W-6S-CK6">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -323,7 +191,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8Je-uC-CnS">
<rect key="frame" x="15" y="263" width="166" height="27"/>
<rect key="frame" x="15" y="278" width="166" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Read daemon log" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UZY-ie-enb">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -333,33 +201,8 @@
<action selector="readDaemonLog:" target="tSJ-3G-dnL" id="Mo0-RL-dK0"/>
</connections>
</button>
<textField autoresizesSubviews="NO" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K34-kh-yUP" customClass="FWTextField" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="33" y="522" width="292" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingHead" selectable="YES" allowsUndo="NO" focusRingType="none" title="N/A" id="EX6-6q-G8U">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="304"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="l6m-qm-d70">
<rect key="frame" x="17" y="428" width="186" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="*auto mount" bezelStyle="regularSquare" imagePosition="left" inset="2" id="tdl-nw-YFd">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="autoMount:" target="tSJ-3G-dnL" id="FNN-jm-HUm"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="eYq-qu-d4Z">
<rect key="frame" x="179" y="263" width="149" height="27"/>
<rect key="frame" x="179" y="278" width="149" height="27"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Read bdmesg" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhg-iF-USh">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -370,7 +213,7 @@
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="V27-tg-6O6">
<rect key="frame" x="61" y="11" width="224" height="15"/>
<rect key="frame" x="61" y="9" width="224" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Label" id="goU-fD-Ng6">
<font key="font" metaFont="menu" size="11"/>
@ -379,7 +222,7 @@
</textFieldCell>
</textField>
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f2Z-bB-hZf">
<rect key="frame" x="16" y="9" width="18" height="18"/>
<rect key="frame" x="16" y="7" width="18" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSInfo" imagePosition="only" alignment="center" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="8hx-sN-OfR">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -390,7 +233,7 @@
</connections>
</button>
<button focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zcm-bV-rzR">
<rect key="frame" x="304" y="9" width="18" height="18"/>
<rect key="frame" x="304" y="7" width="18" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSStopProgressFreestandingTemplate" imagePosition="only" alignment="center" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="2fO-JJ-w1L">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -400,21 +243,450 @@
<action selector="closeApp:" target="tSJ-3G-dnL" id="Hjx-e6-JXH"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tPD-gh-zbP">
<rect key="frame" x="33" y="561" width="291" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" title="N/A" id="EFW-lW-i6c">
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="PGs-4a-XRc" customClass="LITabView" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="0.0" y="522" width="342" height="120"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="Tab" identifier="" id="BAk-3x-mLp">
<view key="view" id="ENG-5U-eLE">
<rect key="frame" x="0.0" y="0.0" width="342" height="120"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f5t-Ia-85K">
<rect key="frame" x="18" y="101" width="306" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Current revision" id="Re2-vf-XQ6">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G6z-Xp-lnm">
<rect key="frame" x="18" y="78" width="306" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot Device:" id="omZ-xs-Wjn">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" placeholderIntrinsicWidth="300" placeholderIntrinsicHeight="16" translatesAutoresizingMaskIntoConstraints="NO" id="5CM-EI-thb">
<rect key="frame" x="18" y="39" width="306" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="config path:" id="iii-3P-wo8">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField autoresizesSubviews="NO" focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="K34-kh-yUP" customClass="FWTextField" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="30" y="20" width="294" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingHead" selectable="YES" allowsUndo="NO" focusRingType="none" title="N/A" id="EX6-6q-G8U">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="304"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tPD-gh-zbP">
<rect key="frame" x="30" y="56" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" title="N/A" id="EFW-lW-i6c">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</tabViewItem>
<tabViewItem label="View" identifier="" id="0yV-f2-RVT">
<view key="view" ambiguous="YES" id="P12-rN-3e4">
<rect key="frame" x="0.0" y="0.0" width="342" height="120"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8Ws-KM-1ul">
<rect key="frame" x="18" y="101" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="System Serial Number:" id="GfB-HS-3EW">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0u3-c1-rfb">
<rect key="frame" x="30" y="79" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="PZZ-nm-ERe">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OFF-nz-jvo">
<rect key="frame" x="18" y="57" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Model:" id="3Sk-aU-UkS">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SQN-cD-fjL">
<rect key="frame" x="30" y="39" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="oPZ-3Y-89o">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8Ns-5X-cAP">
<rect key="frame" x="18" y="20" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="board-id:" id="r4l-Ce-RMS">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MXF-sZ-EBb">
<rect key="frame" x="30" y="0.0" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="okN-IH-2al">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</tabViewItem>
<tabViewItem label="Item 2" identifier="" id="BEi-Mi-0vu">
<view key="view" id="YPe-Eg-Yeo">
<rect key="frame" x="0.0" y="0.0" width="342" height="120"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="QsD-p5-3ia">
<rect key="frame" x="18" y="101" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="OEM Vendor:" id="uAa-hl-4j0">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="84n-SC-fET">
<rect key="frame" x="30" y="79" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="HZg-rD-gZv">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kIt-ye-HGa">
<rect key="frame" x="18" y="57" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="OEM Product:" id="AQC-bY-XBg">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kfr-wj-0XK">
<rect key="frame" x="18" y="20" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="OEM Board:" id="eKw-DA-nv3">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Aad-0P-4R6">
<rect key="frame" x="30" y="39" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="Label" id="J7N-7a-sdN">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GcV-id-YTZ">
<rect key="frame" x="30" y="0.0" width="294" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="Label" id="0dT-GZ-Ytt">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</tabViewItem>
<tabViewItem label="Item 3" identifier="" id="Jgk-Bx-tyS">
<view key="view" id="4NV-GX-O1K">
<rect key="frame" x="0.0" y="0.0" width="342" height="120"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="SjP-er-6Hp">
<rect key="frame" x="18" y="101" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="NVRAM:" id="THE-We-1UH">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="00r-9S-unY">
<rect key="frame" x="18" y="64" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot type:" id="pWw-6m-fZo">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="88K-Sj-rjo">
<rect key="frame" x="18" y="27" width="306" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="firmware:" id="kyW-hT-U5H">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</tabViewItem>
</tabViewItems>
<connections>
<outlet property="delegate" destination="tSJ-3G-dnL" id="8es-BM-oQc"/>
</connections>
</tabView>
<segmentedControl verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Nu3-4z-pbg">
<rect key="frame" x="256" y="497" width="69" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<segmentedCell key="cell" controlSize="small" borderStyle="border" alignment="left" style="rounded" trackingMode="momentary" id="3O5-bI-89P">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<segments>
<segment image="NSLeftFacingTriangleTemplate" width="31"/>
<segment image="NSRightFacingTriangleTemplate" width="31" tag="1"/>
</segments>
</segmentedCell>
<connections>
<action selector="selectTabInfo:" target="tSJ-3G-dnL" id="3Xr-u6-Maa"/>
</connections>
</segmentedControl>
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="vwp-hc-6yE" customClass="LITabView" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="0.0" y="358" width="342" height="113"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem identifier="Mount" id="F4n-I1-4Gq">
<view key="view" ambiguous="YES" id="E05-QZ-1bf">
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mcY-kx-lap" customClass="FWPopUpButton" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="155" y="68" width="170" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="Hzi-CJ-xVH">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<menu key="menu" id="Vb3-8W-CMc"/>
</popUpButtonCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="189"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="mountESP:" target="tSJ-3G-dnL" id="Wd0-O9-Tfa"/>
</connections>
</popUpButton>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="M1w-uF-TFN">
<rect key="frame" x="21" y="74" width="122" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Mount" id="s5K-bS-gZa">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Sj4-Yw-RpL">
<rect key="frame" x="21" y="58" width="52" height="11"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="(ESP)" id="TTH-hz-cX2">
<font key="font" metaFont="label" size="9"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="l6m-qm-d70">
<rect key="frame" x="21" y="9" width="304" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="*auto mount" bezelStyle="regularSquare" imagePosition="left" inset="2" id="tdl-nw-YFd">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="autoMount:" target="tSJ-3G-dnL" id="FNN-jm-HUm"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Zc5-Dl-jIh">
<rect key="frame" x="185" y="34" width="143" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="umount" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhl-e0-nVD">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="umount:" target="tSJ-3G-dnL" id="KqE-Db-Uf1"/>
</connections>
</button>
</subviews>
</view>
</tabViewItem>
<tabViewItem identifier="Theme" id="Th2-UC-6Hh">
<view key="view" id="hLu-g7-21T">
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3iW-Mp-ZEr">
<rect key="frame" x="21" y="74" width="303" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Theme:" id="7yo-8b-ZHc">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Zs-Un-dNa" customClass="FWTextField" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="20" y="46" width="199" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="DVf-rV-Hrc">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
<real key="value" value="199"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
</subviews>
</view>
</tabViewItem>
<tabViewItem identifier="Sound" id="T2L-eV-Vwg">
<view key="view" id="0ws-um-xJI">
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="TUv-Cs-cf7">
<rect key="frame" x="18" y="53" width="307" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="hlk-UE-ZPw" id="7ZL-JE-fT7">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<menu key="menu" id="zSa-aR-ghV">
<items>
<menuItem title="Item 1" state="on" id="hlk-UE-ZPw"/>
<menuItem title="Item 2" id="Z3z-TW-nfP"/>
<menuItem title="Item 3" id="Hcf-6X-UU6"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="soundDeviceSelected:" target="tSJ-3G-dnL" id="psL-M9-FnG"/>
</connections>
</popUpButton>
<slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Qos-VY-rkt" customClass="SoundSlider" customModule="Clover" customModuleProvider="target">
<rect key="frame" x="91" y="2" width="231" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<sliderCell key="cell" controlSize="mini" state="on" alignment="left" maxValue="100" doubleValue="49.494949494949495" tickMarkPosition="above" numberOfTickMarks="100" allowsTickMarkValuesOnly="YES" sliderType="linear" id="ttF-2D-IVS"/>
<connections>
<action selector="soundSliderDidMove:" target="tSJ-3G-dnL" id="zC1-Ai-Zcr"/>
</connections>
</slider>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ok2-So-CvK">
<rect key="frame" x="15" y="91" width="292" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="Startup Sound" id="Vif-FP-OaO">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zab-LD-DM9">
<rect key="frame" x="20" y="2" width="15" height="15"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="Speaker" id="mBv-AG-gpg"/>
</imageView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DSs-NW-pIa">
<rect key="frame" x="42" y="4" width="37" height="11"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="0%" id="vRT-SW-j4L">
<font key="font" metaFont="label" size="9"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XgO-ZG-KMv">
<rect key="frame" x="18" y="25" width="306" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Volume level:" id="ebr-lB-pTD">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="D50-Ay-tcj">
<rect key="frame" x="18" y="79" width="292" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Device:" id="sIi-by-bNC">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
</tabViewItem>
</tabViewItems>
</tabView>
<segmentedControl verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4ox-0p-Q9L">
<rect key="frame" x="18" y="477" width="104" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="dvq-Ib-bsz">
<font key="font" metaFont="system"/>
<segments>
<segment width="32"/>
<segment width="32" selected="YES" tag="1"/>
<segment width="32"/>
</segments>
</segmentedCell>
<connections>
<action selector="selectFuncTab:" target="tSJ-3G-dnL" id="J4r-xS-rRa"/>
</connections>
</segmentedControl>
<box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="pyx-t7-n7o">
<rect key="frame" x="19" y="347" width="304" height="5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</box>
</subviews>
</view>
<connections>
<outlet property="delegate" destination="Fye-KY-AQk" id="aX8-mH-8mg"/>
</connections>
<point key="canvasLocation" x="43" y="406"/>
<point key="canvasLocation" x="43" y="415.5"/>
</window>
<customObject id="Fye-KY-AQk" customClass="SettingsWindowController" customModule="Clover" customModuleProvider="target">
<connections>
@ -425,21 +697,35 @@
<connections>
<outlet property="appVersionField" destination="V27-tg-6O6" id="pxR-3a-E0x"/>
<outlet property="autoMountButton" destination="l6m-qm-d70" id="0qW-yE-Mqu"/>
<outlet property="boardIdField" destination="MXF-sZ-EBb" id="vbJ-VJ-QcR"/>
<outlet property="bootDeviceField" destination="tPD-gh-zbP" id="vYU-oa-H3q"/>
<outlet property="bootTypeField" destination="00r-9S-unY" id="ukc-fU-Jdl"/>
<outlet property="checkNowButton" destination="7kg-2N-6IM" id="cuk-26-Lah"/>
<outlet property="closeButton" destination="zcm-bV-rzR" id="wwB-lu-oT7"/>
<outlet property="configPathField" destination="K34-kh-yUP" id="zkK-f3-0uj"/>
<outlet property="currentRevField" destination="f5t-Ia-85K" id="D7C-Ny-Ehi"/>
<outlet property="disbaleSleepProxyButton" destination="wDl-KZ-OP0" id="neq-3a-Zq9"/>
<outlet property="disksPopUp" destination="mcY-kx-lap" id="Ie2-4t-td5"/>
<outlet property="firmwareVendorfield" destination="88K-Sj-rjo" id="aQy-Dd-8G5"/>
<outlet property="infoButton" destination="f2Z-bB-hZf" id="pBL-T9-zoS"/>
<outlet property="installCloverButton" destination="zDK-XE-o2Z" id="cJu-LK-DPo"/>
<outlet property="installDaemonButton" destination="vgX-bN-KyC" id="dPG-M5-L7J"/>
<outlet property="lastUpdateCheckField" destination="HPk-Vu-vf0" id="oFD-7Z-UMC"/>
<outlet property="makeRootRWButton" destination="y9x-U8-ayg" id="MWS-t0-efx"/>
<outlet property="modelField" destination="SQN-cD-fjL" id="HaD-SS-j8b"/>
<outlet property="nativeNVRAMField" destination="SjP-er-6Hp" id="7W6-DR-kpm"/>
<outlet property="oemBoardIdField" destination="GcV-id-YTZ" id="yvt-rO-i17"/>
<outlet property="oemProductField" destination="Aad-0P-4R6" id="O85-Y0-ZXY"/>
<outlet property="oemVendorField" destination="84n-SC-fET" id="UbL-NZ-faa"/>
<outlet property="progressBar" destination="DtR-XE-DfU" id="7sf-c8-y5u"/>
<outlet property="runAtLoginButton" destination="g5h-bF-3le" id="tXL-6T-4Mj"/>
<outlet property="soundField" destination="WMZ-zj-8k6" id="fJF-TL-2W6"/>
<outlet property="snField" destination="0u3-c1-rfb" id="TUb-GS-mTb"/>
<outlet property="soundDevicePopUp" destination="TUv-Cs-cf7" id="k70-dz-twN"/>
<outlet property="soundVolumeField" destination="DSs-NW-pIa" id="JED-7V-T4Y"/>
<outlet property="soundVolumeSlider" destination="Qos-VY-rkt" id="RQv-Be-e3q"/>
<outlet property="tabViewFunc" destination="vwp-hc-6yE" id="gQE-Kf-hSJ"/>
<outlet property="tabViewFuncSelector" destination="4ox-0p-Q9L" id="Tes-Eu-6Tt"/>
<outlet property="tabViewInfo" destination="PGs-4a-XRc" id="ghG-r0-tYY"/>
<outlet property="themeField" destination="0Zs-Un-dNa" id="gHl-ys-oZv"/>
<outlet property="timeIntervalPopUp" destination="1qf-uO-CvA" id="774-SY-GdB"/>
<outlet property="unInstallDaemonButton" destination="MWn-i4-CYn" id="r2Y-WW-wd9"/>
@ -451,6 +737,9 @@
</objects>
<resources>
<image name="NSInfo" width="32" height="32"/>
<image name="NSLeftFacingTriangleTemplate" width="9" height="12"/>
<image name="NSRightFacingTriangleTemplate" width="9" height="12"/>
<image name="NSStopProgressFreestandingTemplate" width="14" height="14"/>
<image name="Speaker" width="32" height="32"/>
</resources>
</document>

161
CloverApp/Clover/IO.swift Normal file
View File

@ -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<CFMutableDictionary>?
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..<data.count {
if data[i] != 0x00 {
cleanedData.append(data[i])
}
}
cleanedData.append(0x00)
return String(bytes: cleanedData, encoding: .utf8)
}
return nil
}
/// Get IODeviceTree:/efi/platform Dictionary.
fileprivate func getEFIPlatform() -> 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<CFMutableDictionary>?
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..<data.count {
if data[i] != 0x00 {
cleanedData.append(data[i])
}
}
cleanedData.append(0x00)
return String(bytes: cleanedData, encoding: .utf8)
}
return nil
}
/// Get motherboard Model string.
func getEFIModel() -> String? {
if let data = getEFIPlatform()?.object(forKey: "Model") as? Data {
var cleanedData = Data()
for i in 0..<data.count {
if data[i] != 0x00 {
cleanedData.append(data[i])
}
}
cleanedData.append(0x00)
return String(bytes: cleanedData, encoding: .utf8)
}
return nil
}
/// Get macOS board-id string.
func getEFIBoardID() -> String? {
if let data = getEFIPlatform()?.object(forKey: "board-id") as? Data {
var cleanedData = Data()
for i in 0..<data.count {
if data[i] != 0x00 {
cleanedData.append(data[i])
}
}
cleanedData.append(0x00)
return String(bytes: cleanedData, encoding: .utf8)
}
return nil
}
/// Determine if the bootloader is a (known) legacy firmware
func isLegacyFirmware() -> 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
}

View File

@ -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)
}
}
}
}

View File

@ -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)

View File

@ -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)
}
}
}
}

View File

@ -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

View File

@ -74,7 +74,7 @@ func getLatestReleases(reply: @escaping (String?, String?, String?, String?) ->
print("appvers: \(appvers)")
*/
reply(bootlink, bootvers, applink, appvers)
});
})
task.resume()
}

View File

@ -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 {
}
}

View File

@ -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
}

View File

@ -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
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -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 = "<group>"; };
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>"; };
95A9A87D23B63F570060F1CA /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
/* 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 = (

View File

@ -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"

View File

@ -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)

View File

@ -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 = "<group>"; };
95524B8F23805232005F6425 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = ../../Clover/Extensions.swift; sourceTree = "<group>"; };
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 = "<group>"; };
/* 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;

View File

@ -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())

View File

@ -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;

View File

@ -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";

View File

@ -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.";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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 liniezione di estensioni del kernel dalle cartelle di Clover.";
"FSInject.efi" = "Abilita liniezione 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.";

View File

@ -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";

View File

@ -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" = "지금 확인";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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" = "Проверь сейчас";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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";

View File

@ -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" = "现在检查";

View File

@ -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";

View File

@ -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*

View File

@ -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)";

View File

@ -15,7 +15,7 @@
// TODO: redone in swift as swift command line are now small in size, with no hurry...
#import <Foundation/Foundation.h>
#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]];

View File

@ -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)";
};