mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-06-21 22:50:51 +10:00
Add Reboot Prompt in GUI after Root Patching
This commit is contained in:
@@ -38,6 +38,10 @@
|
|||||||
- After OS updates, Patcher will detect whether system requires root patches and prompt you
|
- After OS updates, Patcher will detect whether system requires root patches and prompt you
|
||||||
- Implemented via Launch Agent in `/Library/LaunchAgents`
|
- Implemented via Launch Agent in `/Library/LaunchAgents`
|
||||||
- OpenCore-Patcher.app will be copied to `/Library/Application Support/Dortania` for storage
|
- OpenCore-Patcher.app will be copied to `/Library/Application Support/Dortania` for storage
|
||||||
|
- Add Reboot Prompt in GUI after Root Patching
|
||||||
|
- Remove manual root unpatching
|
||||||
|
- Removed due to reliablity issues
|
||||||
|
- `bless` based reversion still supported in Big Sur+
|
||||||
|
|
||||||
## 0.4.3
|
## 0.4.3
|
||||||
- Increment Binaries:
|
- Increment Binaries:
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ To run the project from source, see here: [Build and run from source](./SOURCE.m
|
|||||||
* Catalyst that started OpenCore Legacy Patcher
|
* Catalyst that started OpenCore Legacy Patcher
|
||||||
* [arter97](https://github.com/arter97/)
|
* [arter97](https://github.com/arter97/)
|
||||||
* [SimpleMSR](https://github.com/arter97/SimpleMSR/) to disable firmware throttling in Nehalem+ MacBooks without batteries
|
* [SimpleMSR](https://github.com/arter97/SimpleMSR/) to disable firmware throttling in Nehalem+ MacBooks without batteries
|
||||||
|
* [Mr.Macintosh](https://mrmacintosh.com)
|
||||||
|
* Endless hours helping architect and troubleshoot many portions of the project
|
||||||
* MacRumors and Unsupported Mac Communities
|
* MacRumors and Unsupported Mac Communities
|
||||||
* Endless testing, reporting issues
|
* Endless testing, reporting issues
|
||||||
* Apple
|
* Apple
|
||||||
|
|||||||
@@ -76,6 +76,20 @@ class wx_python_gui:
|
|||||||
self.app.ExitMainLoop()
|
self.app.ExitMainLoop()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
def reboot_system(self, event=None):
|
||||||
|
self.popup = wx.MessageDialog(
|
||||||
|
self.frame,
|
||||||
|
"Root Patcher finished successfully\n\nWould you like to reboot now?\n\nNote: This will close all open applications, remember to save them or manually reboot once you're ready",
|
||||||
|
"Reboot?",
|
||||||
|
wx.YES_NO | wx.ICON_INFORMATION
|
||||||
|
)
|
||||||
|
self.popup.SetYesNoLabels("Reboot", "Ignore")
|
||||||
|
answer = self.popup.ShowModal()
|
||||||
|
if answer == wx.ID_YES:
|
||||||
|
# Reboots with Count Down prompt (user can still dismiss if needed)
|
||||||
|
subprocess.call(['osascript', '-e', 'tell app "loginwindow" to «event aevtrrst»'])
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
def reset_window(self):
|
def reset_window(self):
|
||||||
self.frame.DestroyChildren()
|
self.frame.DestroyChildren()
|
||||||
self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN)
|
self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN)
|
||||||
@@ -130,6 +144,7 @@ class wx_python_gui:
|
|||||||
|
|
||||||
extension = ""
|
extension = ""
|
||||||
if event:
|
if event:
|
||||||
|
if event.GetEventObject() != wx.Menu:
|
||||||
if event.GetEventObject().GetLabel() == "Start Root Patching":
|
if event.GetEventObject().GetLabel() == "Start Root Patching":
|
||||||
extension = " --gui_patch"
|
extension = " --gui_patch"
|
||||||
elif event.GetEventObject().GetLabel() == "Revert Root Patches":
|
elif event.GetEventObject().GetLabel() == "Revert Root Patches":
|
||||||
@@ -905,6 +920,9 @@ class wx_python_gui:
|
|||||||
pass
|
pass
|
||||||
sys.stdout = self.stock_stdout
|
sys.stdout = self.stock_stdout
|
||||||
sys.stderr = self.stock_stderr
|
sys.stderr = self.stock_stderr
|
||||||
|
if self.constants.root_patcher_succeded is True:
|
||||||
|
print("- Root Patcher finished successfully")
|
||||||
|
self.reboot_system()
|
||||||
self.return_to_main_menu.Enable()
|
self.return_to_main_menu.Enable()
|
||||||
|
|
||||||
wx.GetApp().Yield()
|
wx.GetApp().Yield()
|
||||||
@@ -984,6 +1002,9 @@ class wx_python_gui:
|
|||||||
pass
|
pass
|
||||||
sys.stdout = self.stock_stdout
|
sys.stdout = self.stock_stdout
|
||||||
sys.stderr = self.stock_stderr
|
sys.stderr = self.stock_stderr
|
||||||
|
if self.constants.root_patcher_succeded is True:
|
||||||
|
print("- Root Patcher finished successfully")
|
||||||
|
self.reboot_system()
|
||||||
self.return_to_main_menu.Enable()
|
self.return_to_main_menu.Enable()
|
||||||
|
|
||||||
wx.GetApp().Yield()
|
wx.GetApp().Yield()
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ class Constants:
|
|||||||
self.set_content_caching = False # Set Content Caching
|
self.set_content_caching = False # Set Content Caching
|
||||||
self.allow_nvme_fixing = True # Allow NVMe Kernel Space Patches
|
self.allow_nvme_fixing = True # Allow NVMe Kernel Space Patches
|
||||||
self.disable_xcpm = False # Disable XCPM (X86PlatformPlugin.kext)
|
self.disable_xcpm = False # Disable XCPM (X86PlatformPlugin.kext)
|
||||||
|
self.root_patcher_succeded = False # Determine if root patcher succeeded
|
||||||
|
|
||||||
self.legacy_accel_support = [
|
self.legacy_accel_support = [
|
||||||
os_data.os_data.mojave,
|
os_data.os_data.mojave,
|
||||||
|
|||||||
+4
-102
@@ -24,6 +24,7 @@ class PatchSysVolume:
|
|||||||
self.validate = False
|
self.validate = False
|
||||||
self.added_legacy_kexts = False
|
self.added_legacy_kexts = False
|
||||||
self.root_supports_snapshot = utilities.check_if_root_is_apfs_snapshot()
|
self.root_supports_snapshot = utilities.check_if_root_is_apfs_snapshot()
|
||||||
|
self.constants.root_patcher_succeded = False # Reset Variable each time we start
|
||||||
|
|
||||||
# GUI will detect hardware patches betfore starting PatchSysVolume()
|
# GUI will detect hardware patches betfore starting PatchSysVolume()
|
||||||
# However the TUI will not, so allow for data to be passed in manually avoiding multiple calls
|
# However the TUI will not, so allow for data to be passed in manually avoiding multiple calls
|
||||||
@@ -90,10 +91,6 @@ class PatchSysVolume:
|
|||||||
if Path(self.mount_extensions).exists():
|
if Path(self.mount_extensions).exists():
|
||||||
print("- Root Volume is already mounted")
|
print("- Root Volume is already mounted")
|
||||||
if patch is True:
|
if patch is True:
|
||||||
# Root Volume unpatching is unreliable due to being a live volume
|
|
||||||
# Only worth while on Big Sur as '--last-sealed-snapshot' is hit or miss
|
|
||||||
if self.constants.detected_os == os_data.os_data.big_sur and self.root_supports_snapshot is True and utilities.check_seal() is True:
|
|
||||||
self.backup_volume()
|
|
||||||
self.patch_root_vol()
|
self.patch_root_vol()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -108,10 +105,6 @@ class PatchSysVolume:
|
|||||||
if Path(self.mount_extensions).exists():
|
if Path(self.mount_extensions).exists():
|
||||||
print("- Successfully mounted the Root Volume")
|
print("- Successfully mounted the Root Volume")
|
||||||
if patch is True:
|
if patch is True:
|
||||||
# Root Volume unpatching is unreliable due to being a live volume
|
|
||||||
# Only worth while on Big Sur as '--last-sealed-snapshot' is hit or miss
|
|
||||||
if self.constants.detected_os == os_data.os_data.big_sur and self.root_supports_snapshot is True and utilities.check_seal() is True:
|
|
||||||
self.backup_volume()
|
|
||||||
self.patch_root_vol()
|
self.patch_root_vol()
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -127,96 +120,6 @@ class PatchSysVolume:
|
|||||||
if self.constants.gui_mode is False:
|
if self.constants.gui_mode is False:
|
||||||
input("- Press [ENTER] to exit: ")
|
input("- Press [ENTER] to exit: ")
|
||||||
|
|
||||||
def backup_volume(self):
|
|
||||||
for location in sys_patch_data.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(
|
|
||||||
utilities.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(
|
|
||||||
utilities.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(
|
|
||||||
utilities.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 sys_patch_data.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(utilities.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(utilities.elevated(["mv", location_old_path, f"{location_old_path}-Patched"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
||||||
|
|
||||||
print(f"- Renaming {location}-Backup")
|
|
||||||
utilities.process_status(utilities.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(utilities.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(utilities.elevated(["rm", "-r", f"{copy_path}/__MACOSX"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
||||||
|
|
||||||
else:
|
|
||||||
print(f"- Failed to find {location_zip}, unable to unpatch")
|
|
||||||
if self.validate is False:
|
|
||||||
self.rebuild_snapshot()
|
|
||||||
else:
|
|
||||||
print("- Could not find Extensions.zip, cannot manually unpatch root volume")
|
|
||||||
|
|
||||||
def unpatch_root_vol(self):
|
def unpatch_root_vol(self):
|
||||||
if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True:
|
if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True:
|
||||||
print("- Reverting to last signed APFS snapshot")
|
print("- Reverting to last signed APFS snapshot")
|
||||||
@@ -225,14 +128,12 @@ class PatchSysVolume:
|
|||||||
print("- Unable to revert root volume patches")
|
print("- Unable to revert root volume patches")
|
||||||
print("Reason for unpatch Failure:")
|
print("Reason for unpatch Failure:")
|
||||||
print(result.stdout.decode())
|
print(result.stdout.decode())
|
||||||
print("- Failed to revert snapshot via bless, falling back on manual restoration")
|
print("- Failed to revert snapshot via Apple's 'bless' command")
|
||||||
self.manual_root_patch_revert()
|
|
||||||
else:
|
else:
|
||||||
self.clean_skylight_plugins()
|
self.clean_skylight_plugins()
|
||||||
|
self.constants.root_patcher_succeded = True
|
||||||
print("- Unpatching complete")
|
print("- Unpatching complete")
|
||||||
print("\nPlease reboot the machine for patches to take effect")
|
print("\nPlease reboot the machine for patches to take effect")
|
||||||
else:
|
|
||||||
self.manual_root_patch_revert()
|
|
||||||
|
|
||||||
def rebuild_snapshot(self):
|
def rebuild_snapshot(self):
|
||||||
print("- Rebuilding Kernel Cache (This may take some time)")
|
print("- Rebuilding Kernel Cache (This may take some time)")
|
||||||
@@ -282,6 +183,7 @@ class PatchSysVolume:
|
|||||||
utilities.process_status(utilities.elevated(["update_dyld_shared_cache", "-root", f"{self.mount_location}/"]))
|
utilities.process_status(utilities.elevated(["update_dyld_shared_cache", "-root", f"{self.mount_location}/"]))
|
||||||
print("- Patching complete")
|
print("- Patching complete")
|
||||||
print("\nPlease reboot the machine for patches to take effect")
|
print("\nPlease reboot the machine for patches to take effect")
|
||||||
|
self.constants.root_patcher_succeded = True
|
||||||
if self.constants.gui_mode is False:
|
if self.constants.gui_mode is False:
|
||||||
input("\nPress [ENTER] to continue")
|
input("\nPress [ENTER] to continue")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user