subprocess_wrapper.py: Add unified error handling

Additionally adds backend support for Privileged Helper Tool
This commit is contained in:
Mykola Grymalyuk
2024-05-10 16:06:16 -06:00
parent 84e020f7ea
commit abb18a5ad2
17 changed files with 304 additions and 142 deletions

View File

@@ -11,6 +11,8 @@ import subprocess
from pathlib import Path
from . import subprocess_wrapper
from .. import constants
from ..wx_gui import gui_entry
@@ -172,7 +174,7 @@ class arguments:
if "GPUCompanionBundles" not in kext_plist:
continue
logging.info(f" - Removing {kext.name}")
subprocess.run(["/bin/rm", "-rf", kext])
subprocess_wrapper.run_as_root(["/bin/rm", "-rf", kext])
def _build_handler(self) -> None:

View File

@@ -10,7 +10,8 @@ ie. during automated patching
import os
import logging
import plistlib
import subprocess
from . import subprocess_wrapper
from pathlib import Path
@@ -115,12 +116,11 @@ class GlobalEnviromentSettings:
This in turn breaks normal OCLP execution to write to settings file
"""
if os.geteuid() != 0:
if os.geteuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
return
# Set file permission to allow any user to write to log file
result = subprocess.run(["/bin/chmod", "777", self.global_settings_plist], capture_output=True)
result = subprocess_wrapper.run_as_root(["/bin/chmod", "777", self.global_settings_plist], capture_output=True)
if result.returncode != 0:
logging.warning("Failed to fix settings file permissions:")
if result.stderr:
logging.warning(result.stderr.decode("utf-8"))
subprocess_wrapper.log(result)

View File

@@ -9,7 +9,7 @@ import applescript
from pathlib import Path
from . import utilities
from . import utilities, subprocess_wrapper
from .. import constants
@@ -92,7 +92,7 @@ class tui_disk_installation:
def install_opencore(self, full_disk_identifier: str):
# TODO: Apple Script fails in Yosemite(?) and older
logging.info(f"Mounting partition: {full_disk_identifier}")
if self.constants.detected_os >= os_data.os_data.el_capitan and not self.constants.recovery_status:
if self.constants.detected_os >= os_data.os_data.el_capitan and not self.constants.recovery_status and subprocess_wrapper.supports_privileged_helper() is False:
try:
applescript.AppleScript(f'''do shell script "diskutil mount {full_disk_identifier}" with prompt "OpenCore Legacy Patcher needs administrator privileges to mount this volume." with administrator privileges without altering line endings''').run()
except applescript.ScriptError as e:
@@ -105,10 +105,10 @@ class tui_disk_installation:
logging.info("Please disable Safe Mode and try again.")
return
else:
result = subprocess.run(["/usr/sbin/diskutil", "mount", full_disk_identifier], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
result = subprocess_wrapper.run_as_root(["/usr/sbin/diskutil", "mount", full_disk_identifier], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
logging.info("Mount failed")
logging.info(result.stderr.decode())
subprocess_wrapper.log(result)
return
partition_info = plistlib.loads(subprocess.run(["/usr/sbin/diskutil", "info", "-plist", full_disk_identifier], stdout=subprocess.PIPE).stdout.decode().strip().encode())

View File

@@ -18,8 +18,8 @@ from .. import constants
from ..datasets import os_data
from . import (
utilities,
network_handler
network_handler,
subprocess_wrapper
)
KDK_INSTALL_PATH: str = "/Library/Developer/KDKs"
@@ -464,7 +464,7 @@ class KernelDebugKitObject:
if self.passive is True:
return
if os.getuid() != 0:
if os.getuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
logging.warning("Cannot remove KDK, not running as root")
return
@@ -474,10 +474,10 @@ class KernelDebugKitObject:
rm_args = ["/bin/rm", "-rf" if Path(kdk_path).is_dir() else "-f", kdk_path]
result = utilities.elevated(rm_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(rm_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.warning(f"Failed to remove KDK: {kdk_path}")
logging.warning(f"{result.stdout.decode('utf-8')}")
subprocess_wrapper.log(result)
return
logging.info(f"Successfully removed KDK: {kdk_path}")
@@ -545,7 +545,7 @@ class KernelDebugKitObject:
result = subprocess.run(["/usr/bin/hdiutil", "verify", self.constants.kdk_download_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode != 0:
logging.info("Error: Kernel Debug Kit checksum verification failed!")
logging.info(f"Output: {result.stderr.decode('utf-8')}")
subprocess_wrapper.log(result)
msg = "Kernel Debug Kit checksum verification failed, please try again.\n\nIf this continues to fail, ensure you're downloading on a stable network connection (ie. Ethernet)"
logging.info(f"{msg}")
@@ -579,7 +579,7 @@ class KernelDebugKitUtilities:
bool: True if successful, False if not
"""
if os.getuid() != 0:
if os.getuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
logging.warning("Cannot install KDK, not running as root")
return False
@@ -588,12 +588,10 @@ class KernelDebugKitUtilities:
# TODO: Check whether enough disk space is available
result = utilities.elevated(["/usr/sbin/installer", "-pkg", kdk_path, "-target", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(["/usr/sbin/installer", "-pkg", kdk_path, "-target", "/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Failed to install KDK:")
logging.info(result.stdout.decode('utf-8'))
if result.stderr:
logging.info(result.stderr.decode('utf-8'))
subprocess_wrapper.log(result)
return False
return True
@@ -609,20 +607,19 @@ class KernelDebugKitUtilities:
bool: True if successful, False if not
"""
if os.getuid() != 0:
if os.getuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
logging.warning("Cannot install KDK, not running as root")
return False
logging.info(f"Extracting downloaded KDK disk image")
with tempfile.TemporaryDirectory() as mount_point:
result = subprocess.run(["/usr/bin/hdiutil", "attach", kdk_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(["/usr/bin/hdiutil", "attach", kdk_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Failed to mount KDK:")
logging.info(result.stdout.decode('utf-8'))
subprocess_wrapper.log(result)
return False
kdk_pkg_path = Path(f"{mount_point}/KernelDebugKit.pkg")
if not kdk_pkg_path.exists():
logging.warning("Failed to find KDK package in DMG, likely corrupted!!!")
self._unmount_disk_image(mount_point)
@@ -672,12 +669,12 @@ class KernelDebugKitUtilities:
logging.warning("Malformed KDK Info.plist provided, cannot create backup")
return
if os.getuid() != 0:
if os.getuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
logging.warning("Cannot create KDK backup, not running as root")
return
if not Path(KDK_INSTALL_PATH).exists():
subprocess.run(["/bin/mkdir", "-p", KDK_INSTALL_PATH], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root(["/bin/mkdir", "-p", KDK_INSTALL_PATH], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
kdk_dst_name = f"KDK_{kdk_info_dict['version']}_{kdk_info_dict['build']}.pkg"
kdk_dst_path = Path(f"{KDK_INSTALL_PATH}/{kdk_dst_name}")
@@ -687,7 +684,7 @@ class KernelDebugKitUtilities:
logging.info("Backup already exists, skipping")
return
result = utilities.elevated(["/bin/cp", "-R", kdk_path, kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(["/bin/cp", "-R", kdk_path, kdk_dst_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Failed to create KDK backup:")
logging.info(result.stdout.decode('utf-8'))
subprocess_wrapper.log(result)

View File

@@ -18,7 +18,8 @@ from .. import constants
from . import (
analytics_handler,
global_settings
global_settings,
subprocess_wrapper
)
@@ -130,7 +131,7 @@ class InitializeLoggingSupport:
This in turn breaks normal OCLP execution to write to log file
"""
if os.geteuid() != 0:
if os.geteuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
return
paths = [
@@ -139,15 +140,10 @@ class InitializeLoggingSupport:
]
for path in paths:
result = subprocess.run(["/bin/chmod", "777", path], capture_output=True)
result = subprocess_wrapper.run_as_root(["/bin/chmod", "777", path], capture_output=True)
if result.returncode != 0:
logging.error(f"Failed to fix log file permissions")
if result.stdout:
logging.error("STDOUT:")
logging.error(result.stdout.decode("utf-8"))
if result.stderr:
logging.error("STDERR:")
logging.error(result.stderr.decode("utf-8"))
subprocess_wrapper.log(result)
def _initialize_logging_configuration(self, log_to_file: bool = True) -> None:

View File

@@ -12,6 +12,8 @@ import logging
from pathlib import Path
from . import subprocess_wrapper
from .. import constants
@@ -55,8 +57,7 @@ class RoutePayloadDiskImage:
atexit.register(self._unmount_active_dmgs, unmount_all_active=False)
else:
logging.info("Failed to mount payloads.dmg")
logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}")
subprocess_wrapper.log(output)
def _unmount_active_dmgs(self, unmount_all_active: bool = True) -> None:

View File

@@ -0,0 +1,179 @@
"""
subprocess_wrapper.py: Wrapper for subprocess module to better handle errors and output
Additionally handles our Privileged Helper Tool
"""
import os
import enum
import logging
import subprocess
from pathlib import Path
from functools import cache
from . import utilities
OCLP_PRIVILEGED_HELPER = "/Library/PrivilegedHelperTools/com.dortania.opencore-legacy-patcher.privileged-helper"
class PrivilegedHelperErrorCodes(enum.IntEnum):
"""
Error codes for Privileged Helper Tool.
Reference:
payloads/Tools/PrivilegedHelperTool/main.m
"""
OCLP_PHT_ERROR_MISSING_ARGUMENTS = 160
OCLP_PHT_ERROR_SET_UID_MISSING = 161
OCLP_PHT_ERROR_SET_UID_FAILED = 162
OCLP_PHT_ERROR_SELF_PATH_MISSING = 163
OCLP_PHT_ERROR_PARENT_PATH_MISSING = 164
OCLP_PHT_ERROR_SIGNING_INFORMATION_MISSING = 165
OCLP_PHT_ERROR_INVALID_TEAM_ID = 166
OCLP_PHT_ERROR_INVALID_CERTIFICATES = 167
OCLP_PHT_ERROR_COMMAND_MISSING = 168
OCLP_PHT_ERROR_COMMAND_FAILED = 169
OCLP_PHT_ERROR_CATCH_ALL = 170
@cache
def supports_privileged_helper() -> bool:
"""
Check if Privileged Helper Tool is supported.
When privileged helper is officially shipped, this function should always return True.
Something would have gone very wrong if it doesn't exist past that point.
"""
return Path(OCLP_PRIVILEGED_HELPER).exists()
def run(*args, **kwargs) -> subprocess.CompletedProcess:
"""
Basic subprocess.run wrapper.
"""
return subprocess.run(*args, **kwargs)
def run_as_root(*args, **kwargs) -> subprocess.CompletedProcess:
"""
Run subprocess as root.
Note: Full path to first argument is required.
Helper tool does not resolve PATH.
"""
# Check if first argument exists
if not Path(args[0][0]).exists():
raise FileNotFoundError(f"File not found: {args[0][0]}")
if supports_privileged_helper() is False:
# Fall back to old logic
# This should be removed when we start shipping the helper tool officially
if os.getuid() == 0 or utilities.check_cli_args() is not None:
return subprocess.run(*args, **kwargs)
else:
return subprocess.run(["/usr/bin/sudo"] + [args[0][0]] + args[0][1:], **kwargs)
return subprocess.run([OCLP_PRIVILEGED_HELPER] + [args[0][0]] + args[0][1:], **kwargs)
def verify(process_result: subprocess.CompletedProcess) -> None:
"""
Verify process result and raise exception if failed.
"""
if process_result.returncode == 0:
return
log(process_result)
raise Exception(f"Process failed with exit code {process_result.returncode}")
def run_and_verify(*args, **kwargs) -> None:
"""
Run subprocess and verify result.
Asserts on failure.
"""
verify(run(*args, **kwargs))
def run_as_root_and_verify(*args, **kwargs) -> None:
"""
Run subprocess as root and verify result.
Asserts on failure.
"""
verify(run_as_root(*args, **kwargs))
def log(process: subprocess.CompletedProcess) -> None:
"""
Display subprocess error output in formatted string.
"""
for line in generate_log(process).split("\n"):
logging.error(line)
def generate_log(process: subprocess.CompletedProcess) -> str:
"""
Display subprocess error output in formatted string.
Note this function is still used for zero return code errors, since
some software don't ever return non-zero regardless of success.
Format:
Command: <command>
Return Code: <return code>
Standard Output:
<standard output line 1>
<standard output line 2>
...
Standard Error:
<standard error line 1>
<standard error line 2>
...
"""
output = "Subprocess failed.\n"
output += f" Command: {process.args}\n"
output += f" Return Code: {process.returncode}\n"
_returned_error = __resolve_privileged_helper_errors(process.returncode)
if _returned_error:
output += f" Likely Enum: {_returned_error}\n"
output += f" Standard Output:\n"
if process.stdout:
output += __format_output(process.stdout.decode("utf-8"))
else:
output += " None\n"
output += f" Standard Error:\n"
if process.stderr:
output += __format_output(process.stderr.decode("utf-8"))
else:
output += " None\n"
return output
def __resolve_privileged_helper_errors(return_code: int) -> str:
"""
Attempt to resolve Privileged Helper Tool error codes.
"""
if return_code not in [error_code.value for error_code in PrivilegedHelperErrorCodes]:
return None
return PrivilegedHelperErrorCodes(return_code).name
def __format_output(output: str) -> str:
"""
Format output.
"""
if not output:
# Shouldn't happen, but just in case
return " None\n"
_result = "\n".join([f" {line}" for line in output.split("\n") if line not in ["", "\n"]])
if not _result.endswith("\n"):
_result += "\n"
return _result

View File

@@ -41,13 +41,6 @@ def string_to_hex(input_string):
return input_string
def process_status(process_result):
if process_result.returncode != 0:
logging.info(f"Process failed with exit code {process_result.returncode}")
logging.info(f"Please report the issue on the Discord server")
raise Exception(f"Process result: \n{process_result.stdout.decode()}")
def human_fmt(num):
for unit in ["B", "KB", "MB", "GB", "TB", "PB"]:
if abs(num) < 1000.0:
@@ -553,14 +546,6 @@ def check_boot_mode():
except (KeyError, TypeError, plistlib.InvalidFileException):
return None
def elevated(*args, **kwargs) -> subprocess.CompletedProcess:
# When running through our GUI, we run as root, however we do not get uid 0
# Best to assume CLI is running as root
if os.getuid() == 0 or check_cli_args() is not None:
return subprocess.run(*args, **kwargs)
else:
return subprocess.run(["/usr/bin/sudo"] + [args[0][0]] + args[0][1:], **kwargs)
def fetch_staged_update(variant: str = "Update") -> tuple[str, str]:
"""

View File

@@ -13,6 +13,7 @@ from .. import constants
from ..sys_patch import sys_patch_helpers
from ..efi_builder import build
from ..support import subprocess_wrapper
from ..datasets import (
example_data,
@@ -83,7 +84,7 @@ class PatcherValidation:
result = subprocess.run([self.constants.ocvalidate_path, f"{self.constants.opencore_release_folder}/EFI/OC/config.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Error on build!")
logging.info(result.stdout.decode())
subprocess_wrapper.log(result)
raise Exception(f"Validation failed for predefined model: {model}")
else:
logging.info(f"Validation succeeded for predefined model: {model}")
@@ -103,7 +104,7 @@ class PatcherValidation:
result = subprocess.run([self.constants.ocvalidate_path, f"{self.constants.opencore_release_folder}/EFI/OC/config.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Error on build!")
logging.info(result.stdout.decode())
subprocess_wrapper.log(result)
raise Exception(f"Validation failed for predefined model: {self.constants.computer.real_model}")
else:
logging.info(f"Validation succeeded for predefined model: {self.constants.computer.real_model}")
@@ -178,8 +179,7 @@ class PatcherValidation:
if output.returncode != 0:
logging.info("Failed to unmount Universal-Binaries.dmg")
logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}")
subprocess_wrapper.log(output)
raise Exception("Failed to unmount Universal-Binaries.dmg")
@@ -196,8 +196,7 @@ class PatcherValidation:
if output.returncode != 0:
logging.info("Failed to mount Universal-Binaries.dmg")
logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}")
subprocess_wrapper.log(output)
raise Exception("Failed to mount Universal-Binaries.dmg")
@@ -226,8 +225,7 @@ class PatcherValidation:
if output.returncode != 0:
logging.info("Failed to unmount Universal-Binaries.dmg")
logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}")
subprocess_wrapper.log(output)
raise Exception("Failed to unmount Universal-Binaries.dmg")

View File

@@ -49,7 +49,8 @@ from ..datasets import os_data
from ..support import (
utilities,
kdk_handler
kdk_handler,
subprocess_wrapper
)
from . import (
sys_patch_detect,
@@ -126,7 +127,7 @@ class PatchSysVolume:
else:
if self.root_supports_snapshot is True:
logging.info("- Mounting APFS Snapshot as writable")
result = utilities.elevated(["/sbin/mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(["/sbin/mount", "-o", "nobrowse", "-t", "apfs", f"/dev/{self.root_mount_path}", self.mount_location], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode == 0:
logging.info(f"- Mounted APFS Snapshot as writable at: {self.mount_location}")
if Path(self.mount_extensions).exists():
@@ -136,8 +137,7 @@ class PatchSysVolume:
logging.info("- Root Volume appears to have unmounted unexpectedly")
else:
logging.info("- Unable to mount APFS Snapshot as writable")
logging.info("Reason for mount failure:")
logging.info(result.stdout.decode().strip())
subprocess_wrapper.log(result)
return False
@@ -194,7 +194,7 @@ class PatchSysVolume:
if kdk_obj.kdk_already_installed is False:
# We shouldn't get here, but just in case
logging.warning(f"KDK was not installed, but should have been: {kdk_obj.error_msg}")
raise Exception("KDK was not installed, but should have been: {kdk_obj.error_msg}")
raise Exception(f"KDK was not installed, but should have been: {kdk_obj.error_msg}")
kdk_path = Path(kdk_obj.kdk_installed_path) if kdk_obj.kdk_installed_path != "" else None
@@ -222,10 +222,10 @@ class PatchSysVolume:
if save_hid_cs is True and cs_path.exists():
logging.info("- Backing up IOHIDEventDriver CodeSignature")
# Note it's a folder, not a file
utilities.elevated(["/bin/cp", "-r", cs_path, f"{self.constants.payload_path}/IOHIDEventDriver_CodeSignature.bak"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root(["/bin/cp", "-r", cs_path, f"{self.constants.payload_path}/IOHIDEventDriver_CodeSignature.bak"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
logging.info(f"- Merging KDK with Root Volume: {kdk_path.name}")
utilities.elevated(
subprocess_wrapper.run_as_root(
# Only merge '/System/Library/Extensions'
# 'Kernels' and 'KernelSupport' is wasted space for root patching (we don't care above dev kernels)
["/usr/bin/rsync", "-r", "-i", "-a", f"{kdk_path}/System/Library/Extensions/", f"{self.mount_location}/System/Library/Extensions"],
@@ -243,9 +243,9 @@ class PatchSysVolume:
logging.info("- Restoring IOHIDEventDriver CodeSignature")
if not cs_path.exists():
logging.info(" - CodeSignature folder missing, creating")
utilities.elevated(["/bin/mkdir", "-p", cs_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
utilities.elevated(["/bin/cp", "-r", f"{self.constants.payload_path}/IOHIDEventDriver_CodeSignature.bak", cs_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
utilities.elevated(["/bin/rm", "-rf", f"{self.constants.payload_path}/IOHIDEventDriver_CodeSignature.bak"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root(["/bin/mkdir", "-p", cs_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root(["/bin/cp", "-r", f"{self.constants.payload_path}/IOHIDEventDriver_CodeSignature.bak", cs_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root(["/bin/rm", "-rf", f"{self.constants.payload_path}/IOHIDEventDriver_CodeSignature.bak"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _unpatch_root_vol(self):
@@ -257,11 +257,10 @@ class PatchSysVolume:
logging.info("- OS version does not support snapshotting, skipping revert")
logging.info("- Reverting to last signed APFS snapshot")
result = utilities.elevated(["/usr/sbin/bless", "--mount", self.mount_location, "--bootefi", "--last-sealed-snapshot"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(["/usr/sbin/bless", "--mount", self.mount_location, "--bootefi", "--last-sealed-snapshot"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Unable to revert root volume patches")
logging.info("Reason for unpatch Failure:")
logging.info(result.stdout.decode())
subprocess_wrapper.log(result)
logging.info("- Failed to revert snapshot via Apple's 'bless' command")
else:
self._clean_skylight_plugins()
@@ -363,7 +362,7 @@ class PatchSysVolume:
else:
args = ["/usr/sbin/kextcache", "-i", f"{self.mount_location}/"]
result = utilities.elevated(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# kextcache notes:
# - kextcache always returns 0, even if it fails
@@ -374,19 +373,17 @@ class PatchSysVolume:
# - will return -10 if the volume is missing (ie. unmounted by another process)
if result.returncode != 0 or (self.constants.detected_os < os_data.os_data.catalina and "KernelCache ID" not in result.stdout.decode()):
logging.info("- Unable to build new kernel cache")
logging.info(f"\nReason for Patch Failure ({result.returncode}):")
logging.info(result.stdout.decode())
subprocess_wrapper.log(result)
logging.info("")
logging.info("\nPlease reboot the machine to avoid potential issues rerunning the patcher")
return False
if self.skip_root_kmutil_requirement is True:
# Force rebuild the Auxiliary KC
result = utilities.elevated(["/usr/bin/killall", "syspolicyd", "kernelmanagerd"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root(["/usr/bin/killall", "syspolicyd", "kernelmanagerd"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("- Unable to remove kernel extension policy files")
logging.info(f"\nReason for Patch Failure ({result.returncode}):")
logging.info(result.stdout.decode())
subprocess_wrapper.log(result)
logging.info("")
logging.info("\nPlease reboot the machine to avoid potential issues rerunning the patcher")
return False
@@ -411,7 +408,7 @@ class PatchSysVolume:
if self.root_supports_snapshot is True:
logging.info("- Creating new APFS snapshot")
bless = utilities.elevated(
bless = subprocess_wrapper.run_as_root(
[
"/usr/sbin/bless",
"--folder", f"{self.mount_location}/System/Library/CoreServices",
@@ -420,8 +417,7 @@ class PatchSysVolume:
)
if bless.returncode != 0:
logging.info("- Unable to create new snapshot")
logging.info("Reason for snapshot failure:")
logging.info(bless.stdout.decode())
subprocess_wrapper.log(bless)
if "Can't use last-sealed-snapshot or create-snapshot on non system volume" in bless.stdout.decode():
logging.info("- This is an APFS bug with Monterey and newer! Perform a clean installation to ensure your APFS volume is built correctly")
return False
@@ -435,7 +431,7 @@ class PatchSysVolume:
"""
if self.root_mount_path:
logging.info("- Unmounting Root Volume (Don't worry if this fails)")
utilities.elevated(["/usr/sbin/diskutil", "unmount", self.root_mount_path], stdout=subprocess.PIPE).stdout.decode().strip().encode()
subprocess_wrapper.run_as_root(["/usr/sbin/diskutil", "unmount", self.root_mount_path], stdout=subprocess.PIPE)
else:
logging.info("- Skipping Root Volume unmount")
@@ -449,7 +445,7 @@ class PatchSysVolume:
if self.constants.detected_os > os_data.os_data.catalina:
return
logging.info("- Rebuilding dyld shared cache")
utilities.process_status(utilities.elevated(["/usr/bin/update_dyld_shared_cache", "-root", f"{self.mount_location}/"]))
subprocess_wrapper.run_as_root_and_verify(["/usr/bin/update_dyld_shared_cache", "-root", f"{self.mount_location}/"])
def _update_preboot_kernel_cache(self) -> None:
@@ -460,7 +456,7 @@ class PatchSysVolume:
if self.constants.detected_os == os_data.os_data.catalina:
logging.info("- Rebuilding preboot kernel cache")
utilities.process_status(utilities.elevated(["/usr/sbin/kcditto"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/usr/sbin/kcditto"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _clean_skylight_plugins(self) -> None:
@@ -470,11 +466,11 @@ class PatchSysVolume:
if (Path(self.mount_application_support) / Path("SkyLightPlugins/")).exists():
logging.info("- Found SkylightPlugins folder, removing old plugins")
utilities.process_status(utilities.elevated(["/bin/rm", "-Rf", f"{self.mount_application_support}/SkyLightPlugins"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.process_status(utilities.elevated(["/bin/mkdir", f"{self.mount_application_support}/SkyLightPlugins"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", "-Rf", f"{self.mount_application_support}/SkyLightPlugins"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root_and_verify(["/bin/mkdir", f"{self.mount_application_support}/SkyLightPlugins"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
logging.info("- Creating SkylightPlugins folder")
utilities.process_status(utilities.elevated(["/bin/mkdir", "-p", f"{self.mount_application_support}/SkyLightPlugins/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/mkdir", "-p", f"{self.mount_application_support}/SkyLightPlugins/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _delete_nonmetal_enforcement(self) -> None:
@@ -487,7 +483,7 @@ class PatchSysVolume:
result = subprocess.run(["/usr/bin/defaults", "read", "/Library/Preferences/com.apple.CoreDisplay", arg], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout.decode("utf-8").strip()
if result in ["0", "false", "1", "true"]:
logging.info(f"- Removing non-Metal Enforcement Preference: {arg}")
utilities.elevated(["/usr/bin/defaults", "delete", "/Library/Preferences/com.apple.CoreDisplay", arg])
subprocess_wrapper.run_as_root(["/usr/bin/defaults", "delete", "/Library/Preferences/com.apple.CoreDisplay", arg])
def _clean_auxiliary_kc(self) -> None:
@@ -530,15 +526,15 @@ class PatchSysVolume:
relocation_path = "/Library/Relocated Extensions"
if not Path(relocation_path).exists():
utilities.elevated(["/bin/mkdir", relocation_path])
subprocess_wrapper.run_as_root(["/bin/mkdir", relocation_path])
for file in Path("/Library/Extensions").glob("*.kext"):
try:
if datetime.fromtimestamp(file.stat().st_mtime) < datetime(2021, 10, 1):
logging.info(f" - Relocating {file.name} kext to {relocation_path}")
if Path(relocation_path) / Path(file.name).exists():
utilities.elevated(["/bin/rm", "-Rf", relocation_path / Path(file.name)])
utilities.elevated(["/bin/mv", file, relocation_path])
subprocess_wrapper.run_as_root(["/bin/rm", "-Rf", relocation_path / Path(file.name)])
subprocess_wrapper.run_as_root(["/bin/mv", file, relocation_path])
except:
# Some users have the most cursed /L*/E* folders
# ex. Symlinks pointing to symlinks pointing to dead files
@@ -559,8 +555,8 @@ class PatchSysVolume:
if sys_patch_helpers.SysPatchHelpers(self.constants).generate_patchset_plist(patchset, file_name, self.kdk_path):
logging.info("- Writing patchset information to Root Volume")
if Path(destination_path_file).exists():
utilities.process_status(utilities.elevated(["/bin/rm", destination_path_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.process_status(utilities.elevated(["/bin/cp", f"{self.constants.payload_path}/{file_name}", destination_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", destination_path_file], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root_and_verify(["/bin/cp", f"{self.constants.payload_path}/{file_name}", destination_path], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _add_auxkc_support(self, install_file: str, source_folder_path: str, install_patch_directory: str, destination_folder_path: str) -> str:
@@ -727,10 +723,10 @@ class PatchSysVolume:
# Instead, call elevated funtion if string's boolean is True
if required_patches[patch]["Processes"][process] is True:
logging.info(f"- Running Process as Root:\n{process}")
utilities.process_status(utilities.elevated(process.split(" "), stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(process.split(" "), stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
logging.info(f"- Running Process:\n{process}")
utilities.process_status(subprocess.run(process, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True))
subprocess_wrapper.run_and_verify(process, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
if any(x in required_patches for x in ["AMD Legacy GCN", "AMD Legacy Polaris", "AMD Legacy Vega"]):
sys_patch_helpers.SysPatchHelpers(self.constants).disable_window_server_caching()
if "Metal 3802 Common Extended" in required_patches:
@@ -800,25 +796,25 @@ class PatchSysVolume:
if file_name_str.endswith(".framework"):
# merge with rsync
logging.info(f" - Installing: {file_name}")
utilities.elevated(["/usr/bin/rsync", "-r", "-i", "-a", f"{source_folder}/{file_name}", f"{destination_folder}/"], stdout=subprocess.PIPE)
subprocess_wrapper.run_as_root(["/usr/bin/rsync", "-r", "-i", "-a", f"{source_folder}/{file_name}", f"{destination_folder}/"], stdout=subprocess.PIPE)
self._fix_permissions(destination_folder + "/" + file_name)
elif Path(source_folder + "/" + file_name_str).is_dir():
# Applicable for .kext, .app, .plugin, .bundle, all of which are directories
if Path(destination_folder + "/" + file_name).exists():
logging.info(f" - Found existing {file_name}, overwriting...")
utilities.process_status(utilities.elevated(["/bin/rm", "-R", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", "-R", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
logging.info(f" - Installing: {file_name}")
utilities.process_status(utilities.elevated(["/bin/cp", "-R", f"{source_folder}/{file_name}", destination_folder], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/cp", "-R", f"{source_folder}/{file_name}", destination_folder], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self._fix_permissions(destination_folder + "/" + file_name)
else:
# Assume it's an individual file, replace as normal
if Path(destination_folder + "/" + file_name).exists():
logging.info(f" - Found existing {file_name}, overwriting...")
utilities.process_status(utilities.elevated(["/bin/rm", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
logging.info(f" - Installing: {file_name}")
utilities.process_status(utilities.elevated(["/bin/cp", f"{source_folder}/{file_name}", destination_folder], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/cp", f"{source_folder}/{file_name}", destination_folder], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self._fix_permissions(destination_folder + "/" + file_name)
@@ -834,9 +830,9 @@ class PatchSysVolume:
if Path(destination_folder + "/" + file_name).exists():
logging.info(f" - Removing: {file_name}")
if Path(destination_folder + "/" + file_name).is_dir():
utilities.process_status(utilities.elevated(["/bin/rm", "-R", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", "-R", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
utilities.process_status(utilities.elevated(["/bin/rm", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", f"{destination_folder}/{file_name}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _fix_permissions(self, destination_file: Path) -> None:
@@ -850,8 +846,8 @@ class PatchSysVolume:
# Strip recursive arguments
chmod_args.pop(1)
chown_args.pop(1)
utilities.process_status(utilities.elevated(chmod_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.process_status(utilities.elevated(chown_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(chmod_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root_and_verify(chown_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _check_files(self) -> bool:
@@ -882,8 +878,7 @@ class PatchSysVolume:
if output.returncode != 0:
logging.info("- Failed to mount Universal-Binaries.dmg")
logging.info(f"Output: {output.stdout.decode()}")
logging.info(f"Return Code: {output.returncode}")
subprocess_wrapper.log(output)
return False
logging.info("- Mounted Universal-Binaries.dmg")
@@ -923,13 +918,11 @@ class PatchSysVolume:
return True
logging.info("- Failed to merge DortaniaInternal resources")
logging.info(f"Output: {result.stdout.decode()}")
logging.info(f"Return Code: {result.returncode}")
subprocess_wrapper.log(result)
return False
logging.info("- Failed to mount DortaniaInternal resources")
logging.info(f"Output: {result.stdout.decode()}")
logging.info(f"Return Code: {result.returncode}")
subprocess_wrapper.log(result)
if "Authentication error" not in result.stdout.decode():
try:

View File

@@ -29,7 +29,8 @@ from ..support import (
utilities,
updates,
global_settings,
network_handler
network_handler,
subprocess_wrapper
)
@@ -363,16 +364,16 @@ Please check the Github page for more information about this release."""
logging.info(f" - {name} checksums match, skipping")
continue
logging.info(f" - Existing service found, removing")
utilities.process_status(utilities.elevated(["/bin/rm", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Create parent directories
if not Path(services[service]).parent.exists():
logging.info(f" - Creating {Path(services[service]).parent} directory")
utilities.process_status(utilities.elevated(["/bin/mkdir", "-p", Path(services[service]).parent], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.process_status(utilities.elevated(["/bin/cp", service, services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/mkdir", "-p", Path(services[service]).parent], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root_and_verify(["/bin/cp", service, services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Set the permissions on the service
utilities.process_status(utilities.elevated(["/bin/chmod", "644", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
utilities.process_status(utilities.elevated(["/usr/sbin/chown", "root:wheel", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/chmod", "644", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess_wrapper.run_as_root_and_verify(["/usr/sbin/chown", "root:wheel", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if self.constants.launcher_binary.startswith("/Library/Application Support/Dortania/"):
logging.info("- Skipping Patcher Install, already installed")
@@ -384,24 +385,24 @@ Please check the Github page for more information about this release."""
if not Path("Library/Application Support/Dortania").exists():
logging.info("- Creating /Library/Application Support/Dortania/")
utilities.process_status(utilities.elevated(["/bin/mkdir", "-p", "/Library/Application Support/Dortania"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/mkdir", "-p", "/Library/Application Support/Dortania"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
logging.info("- Copying OpenCore Patcher to /Library/Application Support/Dortania/")
if Path("/Library/Application Support/Dortania/OpenCore-Patcher.app").exists():
logging.info("- Deleting existing OpenCore-Patcher")
utilities.process_status(utilities.elevated(["/bin/rm", "-R", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/rm", "-R", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Strip everything after OpenCore-Patcher.app
path = str(self.constants.launcher_binary).split("/Contents/MacOS/OpenCore-Patcher")[0]
logging.info(f"- Copying {path} to /Library/Application Support/Dortania/")
utilities.process_status(utilities.elevated(["/usr/bin/ditto", path, "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/usr/bin/ditto", path, "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if not Path("/Library/Application Support/Dortania/OpenCore-Patcher.app").exists():
# Sometimes the binary the user launches may have a suffix (ie. OpenCore-Patcher 3.app)
# We'll want to rename it to OpenCore-Patcher.app
path = path.split("/")[-1]
logging.info(f"- Renaming {path} to OpenCore-Patcher.app")
utilities.process_status(utilities.elevated(["/bin/mv", f"/Library/Application Support/Dortania/{path}", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/mv", f"/Library/Application Support/Dortania/{path}", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
subprocess.run(["/usr/bin/xattr", "-cr", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -410,7 +411,7 @@ Please check the Github page for more information about this release."""
# If there's already an alias or exiting app, skip
if not Path("/Applications/OpenCore-Patcher.app").exists():
logging.info("- Making app alias")
utilities.process_status(utilities.elevated(["/bin/ln", "-s", "/Library/Application Support/Dortania/OpenCore-Patcher.app", "/Applications/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/ln", "-s", "/Library/Application Support/Dortania/OpenCore-Patcher.app", "/Applications/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
def _create_rsr_monitor_daemon(self) -> bool:

View File

@@ -18,7 +18,8 @@ from ..datasets import os_data
from ..support import (
bplist,
generate_smbios,
utilities
utilities,
subprocess_wrapper
)
@@ -138,9 +139,9 @@ class SysPatchHelpers:
logging.info("Disabling WindowServer Caching")
# Invoke via 'bash -c' to resolve pathing
utilities.elevated(["bash", "-c", "rm -rf /private/var/folders/*/*/*/WindowServer/com.apple.WindowServer"])
subprocess_wrapper.run_as_root(["/bin/bash", "-c", "rm -rf /private/var/folders/*/*/*/WindowServer/com.apple.WindowServer"])
# Disable writing to WindowServer folder
utilities.elevated(["bash", "-c", "chflags uchg /private/var/folders/*/*/*/WindowServer"])
subprocess_wrapper.run_as_root(["/bin/bash", "-c", "chflags uchg /private/var/folders/*/*/*/WindowServer"])
# Reference:
# To reverse write lock:
# 'chflags nouchg /private/var/folders/*/*/*/WindowServer'
@@ -219,9 +220,10 @@ class SysPatchHelpers:
return
logging.info("Installing Kernel Collection syncing utility")
result = utilities.elevated([self.constants.rsrrepair_userspace_path, "--install"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
result = subprocess_wrapper.run_as_root([self.constants.rsrrepair_userspace_path, "--install"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info(f"- Failed to install RSRRepair: {result.stdout.decode()}")
logging.info("- Failed to install RSRRepair")
subprocess_wrapper.log(result)
def patch_gpu_compiler_libraries(self, mount_point: Union[str, Path]):
@@ -282,6 +284,6 @@ class SysPatchHelpers:
src_dir = f"{LIBRARY_DIR}/{file.name}"
if not Path(f"{DEST_DIR}/lib").exists():
utilities.process_status(utilities.elevated(["/bin/cp", "-cR", f"{src_dir}/lib", f"{DEST_DIR}/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
subprocess_wrapper.run_as_root_and_verify(["/bin/cp", "-cR", f"{src_dir}/lib", f"{DEST_DIR}/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
break

View File

@@ -26,6 +26,7 @@ from ..support import (
utilities,
network_handler,
kdk_handler,
subprocess_wrapper
)
@@ -525,7 +526,7 @@ class macOSInstallerFlashFrame(wx.Frame):
result = subprocess.run(["/usr/bin/hdiutil", "attach", kdk_dmg_path, "-mountpoint", mount_point, "-nobrowse"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Failed to mount KDK")
logging.info(result.stdout.decode("utf-8"))
subprocess_wrapper.log(result)
return
logging.info("Copying KDK")
@@ -535,7 +536,7 @@ class macOSInstallerFlashFrame(wx.Frame):
result = subprocess.run(["/usr/bin/hdiutil", "detach", mount_point], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode != 0:
logging.info("Failed to unmount KDK")
logging.info(result.stdout.decode("utf-8"))
subprocess_wrapper.log(result)
return
logging.info("Removing KDK Disk Image")

View File

@@ -24,7 +24,8 @@ from ..support import (
global_settings,
defaults,
generate_smbios,
network_handler
network_handler,
subprocess_wrapper
)
from ..datasets import (
model_array,
@@ -1324,7 +1325,7 @@ Hardware Information:
raise Exception("Test Exception")
def on_mount_root_vol(self, event: wx.Event) -> None:
if os.geteuid() != 0:
if os.geteuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
wx.MessageDialog(self.parent, "Please relaunch as Root to mount the Root Volume", "Error", wx.OK | wx.ICON_ERROR).ShowModal()
else:
#Don't need to pass model as we're bypassing all logic
@@ -1334,7 +1335,7 @@ Hardware Information:
wx.MessageDialog(self.parent, "Root Volume Mount Failed, check terminal output", "Error", wx.OK | wx.ICON_ERROR).ShowModal()
def on_bless_root_vol(self, event: wx.Event) -> None:
if os.geteuid() != 0:
if os.geteuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
wx.MessageDialog(self.parent, "Please relaunch as Root to save changes", "Error", wx.OK | wx.ICON_ERROR).ShowModal()
else:
#Don't need to pass model as we're bypassing all logic

View File

@@ -15,10 +15,12 @@ import packaging.version
from pathlib import Path
from . import gui_about
from .. import constants
from ..wx_gui import gui_about
from ..detections import device_probe
from ..support import subprocess_wrapper
from ..datasets import (
model_array,
@@ -75,7 +77,7 @@ class GenerateMenubar:
self.frame.Bind(wx.EVT_MENU, lambda event: RelaunchApplicationAsRoot(self.frame, self.constants).relaunch(None), relaunchItem)
self.frame.Bind(wx.EVT_MENU, lambda event: subprocess.run(["/usr/bin/open", "--reveal", self.constants.log_filepath]), revealLogItem)
if os.geteuid() == 0:
if os.geteuid() == 0 or subprocess_wrapper.supports_privileged_helper() is True:
relaunchItem.Enable(False)

View File

@@ -13,6 +13,7 @@ from pathlib import Path
from .. import constants
from ..sys_patch import sys_patch_detect
from ..support import subprocess_wrapper
from ..wx_gui import (
gui_main_menu,
@@ -242,7 +243,7 @@ class SysPatchDisplayFrame(wx.Frame):
revert_button.Disable()
# Relaunch as root if not root
if os.geteuid() != 0:
if os.geteuid() != 0 and subprocess_wrapper.supports_privileged_helper() is False:
start_button.Bind(wx.EVT_BUTTON, gui_support.RelaunchApplicationAsRoot(frame, self.constants).relaunch)
revert_button.Bind(wx.EVT_BUTTON, gui_support.RelaunchApplicationAsRoot(frame, self.constants).relaunch)

View File

@@ -20,7 +20,8 @@ from ..wx_gui import (
)
from ..support import (
network_handler,
updates
updates,
subprocess_wrapper
)
@@ -200,7 +201,8 @@ class UpdateFrame(wx.Frame):
["/usr/bin/ditto", "-xk", str(self.constants.payload_path / "OpenCore-Patcher-GUI.app.zip"), str(self.constants.payload_path)], capture_output=True
)
if result.returncode != 0:
logging.error(f"Failed to extract update. Error: {result.stderr.decode('utf-8')}")
logging.error(f"Failed to extract update.")
subprocess_wrapper.log(result)
wx.CallAfter(self.progress_bar_animation.stop_pulse)
wx.CallAfter(self.progress_bar.SetValue, 0)
wx.CallAfter(wx.MessageBox, f"Failed to extract update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR)
@@ -278,7 +280,8 @@ EOF
logging.info("User cancelled update")
wx.CallAfter(wx.MessageBox, "User cancelled update", "Update Cancelled", wx.OK | wx.ICON_INFORMATION)
else:
logging.critical(f"Failed to install update. Error: {result.stderr.decode('utf-8')}")
logging.critical("Failed to install update.")
subprocess_wrapper.log(result)
wx.CallAfter(wx.MessageBox, f"Failed to install update. Error: {result.stderr.decode('utf-8')}", "Critical Error!", wx.OK | wx.ICON_ERROR)
wx.CallAfter(sys.exit, 1)