Implement Root Volume backups

Closes https://github.com/dortania/OpenCore-Legacy-Patcher/issues/378
This commit is contained in:
Mykola Grymalyuk
2021-08-02 16:34:19 -06:00
parent 03f65d1766
commit 33653a7108
7 changed files with 151 additions and 30 deletions
+1 -1
View File
@@ -678,9 +678,9 @@ class BuildOpenCore:
spoofed_model = self.model
if self.constants.override_smbios == "Default":
spoofed_model = self.smbios_set(self.model)
print(f"- Using Model ID: {spoofed_model}")
else:
spoofed_model = self.constants.override_smbios
print(f"- Using Model ID: {spoofed_model}")
try:
spoofed_board = self.constants.board_id[spoofed_model]
print(f"- Using Board ID: {spoofed_board}")
+97 -4
View File
@@ -64,6 +64,8 @@ class PatchSysVolume:
if Path(self.mount_extensions).exists():
print("- Root Volume is already mounted")
if patch is True:
if self.constants.detected_os < self.constants.big_sur or Utilities.check_seal() is True:
self.backup_volume()
self.patch_root_vol()
return True
else:
@@ -76,6 +78,8 @@ class PatchSysVolume:
if Path(self.mount_extensions).exists():
print("- Successfully mounted the Root Volume")
if patch is True:
if self.constants.detected_os < self.constants.big_sur or Utilities.check_seal() is True:
self.backup_volume()
self.patch_root_vol()
return True
else:
@@ -91,6 +95,95 @@ class PatchSysVolume:
if self.constants.gui_mode is False:
input("- Press [ENTER] to exit: ")
def backup_volume(self):
for location in SysPatchArray.BackupLocations:
Utilities.cls()
print("Backing up root volume before patching (This may take some time)")
print(f"- Attempting to backup {location}")
location_zip = f"{location}-Backup.zip"
location_zip_path = Path(self.mount_location) / Path(location_zip)
if location_zip_path.exists():
print(f"- Found existing {location_zip}, skipping")
else:
print(f"- Backing up {location}")
# cp -r ./Extensions ./Extensions-Backup
# ditto -c -k --sequesterRsrc --keepParent ./Extensions-Backup ./Extensions-Backup.zip
# rm -r ./Extensions-Backup
print("- Creating Backup folder")
Utilities.process_status(
self.elevated(
["cp", "-r", f"{self.mount_location}/{location}", f"{self.mount_location}/{location}-Backup"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
)
print("- Zipping Backup folder")
Utilities.process_status(
self.elevated(
["ditto", "-c", "-k", "--sequesterRsrc", "--keepParent", f"{self.mount_location}/{location}-Backup", f"{self.mount_location}/{location_zip}"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
)
print("- Removing Backup folder")
Utilities.process_status(
self.elevated(
["rm", "-r", f"{self.mount_location}/{location}-Backup"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
)
def manual_root_patch_revert(self):
print("- Attempting to revert patches")
if (Path(self.mount_location) / Path("System/Library/Extensions-Backup.zip")).exists():
print("- Verified manual unpatching is available")
for location in SysPatchArray.BackupLocations:
Utilities.cls()
print("Reverting root volume patches (This may take some time)")
print(f"- Attempting to unpatch {location}")
location_zip = f"{location}-Backup.zip"
location_zip_path = Path(self.mount_location) / Path(location_zip)
location_old_path = Path(self.mount_location) / Path(location)
if "PrivateFrameworks" in location:
copy_path = Path(self.mount_location) / Path("System/Library/PrivateFrameworks")
elif "Frameworks" in location:
copy_path = Path(self.mount_location) / Path("System/Library/Frameworks")
else:
copy_path = Path(self.mount_location) / Path("System/Library")
if location_zip_path.exists():
print(f"- Found {location_zip}")
print(f"- Unzipping {location_zip}")
Utilities.process_status(self.elevated(["unzip", location_zip_path, "-d", copy_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
if location_old_path.exists():
print(f"- Renaming {location}")
Utilities.process_status(self.elevated(["mv", location_old_path, f"{location_old_path}-Patched"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
print(f"- Renaming {location}-Backup")
Utilities.process_status(self.elevated(["mv", f"{location_old_path}-Backup", location_old_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
print(f"- Removing {location_old_path}-Patched")
Utilities.process_status(self.elevated(["rm", "-r", f"{location_old_path}-Patched"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
# ditto will create a '__MACOSX' folder
# print("- Removing __MACOSX folder")
# Utilities.process_status(self.elevated(["rm", "-r", f"{copy_path}/__MACOSX"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
else:
print(f"- Failed to find {location_zip}, unable to unpatch")
self.rebuild_snapshot()
else:
print("- Could not find Extensions.zip, cannot manually unpatch root volume")
def unpatch_root_vol(self):
if self.constants.detected_os > self.constants.catalina:
print("- Reverting to last signed APFS snapshot")
@@ -99,13 +192,13 @@ class PatchSysVolume:
print("- Unable to revert root volume patches")
print("Reason for unpatch Failure:")
print(result.stdout.decode())
# print("- Failed to revert snapshot via bless, falling back on manual restoration")
# self.undo_root_patch()
print("- Failed to revert snapshot via bless, falling back on manual restoration")
self.manual_root_patch_revert()
else:
print("- Unpatching complete")
print("\nPlease reboot the machine for patches to take effect")
# else:
# self.undo_root_patch()
else:
self.manual_root_patch_revert()
def rebuild_snapshot(self):
if self.constants.gui_mode is False:
+15
View File
@@ -245,3 +245,18 @@ AddGeneralAccelMojave = [
"IOAcceleratorFamily2.kext",
"IOGraphicsFamily.kext",
]
BackupLocations = [
"System/Library/Extensions",
"System/Library/Frameworks/CoreDisplay.framework",
"System/Library/Frameworks/IOSurface.framework",
"System/Library/Frameworks/OpenGL.framework",
"System/Library/Frameworks/WebKit.framework",
"System/Library/LaunchDaemons",
"System/Library/PrivateFrameworks/DisplayServices.framework",
"System/Library/PrivateFrameworks/GPUSupport.framework",
"System/Library/PrivateFrameworks/SkyLight.framework",
"System/Library/PrivateFrameworks/IOAccelerator.framework",
"System/Library/PrivateFrameworks/AppleGVA.framework",
"System/Library/PrivateFrameworks/AppleGVACore.framework",
]
+19 -7
View File
@@ -65,6 +65,15 @@ def get_disk_path():
return root_mount_path
def check_seal():
# 'Snapshot Sealed' property is only listed on booted snapshots
sealed = subprocess.run(["diskutil", "apfs", "list"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if "Snapshot Sealed: Yes" in sealed.stdout.decode():
return True
else:
return False
def latebloom_detection(model):
if model in ["MacPro4,1", "MacPro5,1", "iMac7,1", "iMac8,1"]:
# These machines are more likely to experience boot hangs, increase delays to accomodate
@@ -73,15 +82,18 @@ def latebloom_detection(model):
lb_delay = "100"
lb_range = "1"
lb_debug = "1"
if get_nvram("boot-args", decode=False):
if "latebloom=" in get_nvram("boot-args", decode=False):
lb_delay = re.search(r"(?:[, ])latebloom=(\d+)", get_nvram("boot-args", decode=False))
boot_args = get_nvram("boot-args", decode=False)
# boot_args = "latebloom=200 lb_range=40 lb_debug=0 keepsyms=1 debug=0x100 -lilubetaall"
if boot_args:
# TODO: This crashes if latebloom=xxx is the very first entry in boot-args
if "latebloom=" in boot_args:
lb_delay = re.search(r"(?:[, ])latebloom=(\d+)", boot_args)
lb_delay = lb_delay[1]
if "lb_range=" in get_nvram("boot-args", decode=False):
lb_range = re.search(r"(?:[, ])lb_range=(\d+)", get_nvram("boot-args", decode=False))
if "lb_range=" in boot_args:
lb_range = re.search(r"(?:[, ])lb_range=(\d+)", boot_args)
lb_range = lb_range[1]
if "lb_debug=" in get_nvram("boot-args", decode=False):
lb_debug = re.search(r"(?:[, ])lb_debug=(\d+)", get_nvram("boot-args", decode=False))
if "lb_debug=" in boot_args:
lb_debug = re.search(r"(?:[, ])lb_debug=(\d+)", boot_args)
lb_debug = lb_debug[1]
return int(lb_delay), int(lb_range), int(lb_debug)