From 0e3d4244e767c33329b2fe29f480b06b1d010b1b Mon Sep 17 00:00:00 2001 From: Mykola Grymalyuk Date: Thu, 21 Apr 2022 15:35:11 -0600 Subject: [PATCH] Add Reboot Prompt in GUI after Root Patching --- CHANGELOG.md | 4 ++ README.md | 2 + gui/gui_main.py | 29 +++++++++-- resources/constants.py | 1 + resources/sys_patch.py | 106 ++--------------------------------------- 5 files changed, 36 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c05b703..8bb2d15ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ - After OS updates, Patcher will detect whether system requires root patches and prompt you - Implemented via Launch Agent in `/Library/LaunchAgents` - 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 - Increment Binaries: diff --git a/README.md b/README.md index 0a9075e58..f3d0e786f 100644 --- a/README.md +++ b/README.md @@ -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 * [arter97](https://github.com/arter97/) * [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 * Endless testing, reporting issues * Apple diff --git a/gui/gui_main.py b/gui/gui_main.py index 9ab5e3227..5b3f270b3 100644 --- a/gui/gui_main.py +++ b/gui/gui_main.py @@ -76,6 +76,20 @@ class wx_python_gui: self.app.ExitMainLoop() 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): self.frame.DestroyChildren() self.frame.SetSize(self.WINDOW_WIDTH_MAIN, self.WINDOW_HEIGHT_MAIN) @@ -130,10 +144,11 @@ class wx_python_gui: extension = "" if event: - if event.GetEventObject().GetLabel() == "Start Root Patching": - extension = " --gui_patch" - elif event.GetEventObject().GetLabel() == "Revert Root Patches": - extension = " --gui_unpatch" + if event.GetEventObject() != wx.Menu: + if event.GetEventObject().GetLabel() == "Start Root Patching": + extension = " --gui_patch" + elif event.GetEventObject().GetLabel() == "Revert Root Patches": + extension = " --gui_unpatch" if self.constants.launcher_script is None: args_string = f"'{self.constants.launcher_binary}'{extension}" @@ -905,6 +920,9 @@ class wx_python_gui: pass sys.stdout = self.stock_stdout 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() wx.GetApp().Yield() @@ -984,6 +1002,9 @@ class wx_python_gui: pass sys.stdout = self.stock_stdout 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() wx.GetApp().Yield() diff --git a/resources/constants.py b/resources/constants.py index 46dfb4bd4..4c7e45740 100644 --- a/resources/constants.py +++ b/resources/constants.py @@ -192,6 +192,7 @@ class Constants: self.set_content_caching = False # Set Content Caching self.allow_nvme_fixing = True # Allow NVMe Kernel Space Patches self.disable_xcpm = False # Disable XCPM (X86PlatformPlugin.kext) + self.root_patcher_succeded = False # Determine if root patcher succeeded self.legacy_accel_support = [ os_data.os_data.mojave, diff --git a/resources/sys_patch.py b/resources/sys_patch.py index 5eb1afe02..47d6f54b4 100644 --- a/resources/sys_patch.py +++ b/resources/sys_patch.py @@ -24,6 +24,7 @@ class PatchSysVolume: self.validate = False self.added_legacy_kexts = False 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() # 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(): print("- Root Volume is already mounted") 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() return True else: @@ -108,10 +105,6 @@ class PatchSysVolume: if Path(self.mount_extensions).exists(): print("- Successfully mounted the Root Volume") 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() return True else: @@ -127,96 +120,6 @@ class PatchSysVolume: if self.constants.gui_mode is False: 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): if self.constants.detected_os > os_data.os_data.catalina and self.root_supports_snapshot is True: print("- Reverting to last signed APFS snapshot") @@ -225,14 +128,12 @@ 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.manual_root_patch_revert() + print("- Failed to revert snapshot via Apple's 'bless' command") else: self.clean_skylight_plugins() + self.constants.root_patcher_succeded = True print("- Unpatching complete") print("\nPlease reboot the machine for patches to take effect") - else: - self.manual_root_patch_revert() def rebuild_snapshot(self): 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}/"])) print("- Patching complete") print("\nPlease reboot the machine for patches to take effect") + self.constants.root_patcher_succeded = True if self.constants.gui_mode is False: input("\nPress [ENTER] to continue")