mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-24 03:50:14 +10:00
Add new daemon for update handling
Currently developed to handle bug in macOS Sonoma that fails to clear problamatic kernel extensions in /Library/Extensions which could result in update failures from 14.0 to 14.1
This commit is contained in:
@@ -241,6 +241,7 @@ class CreateBinary:
|
|||||||
whitelist_files = [
|
whitelist_files = [
|
||||||
"com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
"com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
||||||
"com.dortania.opencore-legacy-patcher.rsr-monitor.plist",
|
"com.dortania.opencore-legacy-patcher.rsr-monitor.plist",
|
||||||
|
"com.dortania.opencore-legacy-patcher.macos-update.plist",
|
||||||
"entitlements.plist",
|
"entitlements.plist",
|
||||||
"launcher.sh",
|
"launcher.sh",
|
||||||
"OC-Patcher-TUI.icns",
|
"OC-Patcher-TUI.icns",
|
||||||
|
|||||||
@@ -5,6 +5,12 @@
|
|||||||
- Add support for detecting T1 Security Chips in DFU mode
|
- Add support for detecting T1 Security Chips in DFU mode
|
||||||
- Update non-Metal Binaries for macOS Sonoma:
|
- Update non-Metal Binaries for macOS Sonoma:
|
||||||
- Resolve Photos app crash
|
- Resolve Photos app crash
|
||||||
|
- Add new Launch Daemon for clean up on macOS updates
|
||||||
|
- Resolves KDKless Macs failing to boot after updating from 14.0 to 14.x
|
||||||
|
- `/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.macos-update.plist`
|
||||||
|
- Remove News Widget removal from Control Centre
|
||||||
|
- News Widget no longer crashes on 3802-based GPUs
|
||||||
|
- Resolve i210 NIC support for macOS Sonoma
|
||||||
- Increment Binaries:
|
- Increment Binaries:
|
||||||
- PatcherSupportPkg 1.4.3 - release
|
- PatcherSupportPkg 1.4.3 - release
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?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>AssociatedBundleIdentifiers</key>
|
||||||
|
<string>com.dortania.opencore-legacy-patcher</string>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>com.dortania.opencore-legacy-patcher.rsr-monitor</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/Library/Application Support/Dortania/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher</string>
|
||||||
|
<string>--prepare_for_update</string>
|
||||||
|
</array>
|
||||||
|
<key>WatchPaths</key>
|
||||||
|
<array>
|
||||||
|
<string>/System/Volumes/Update/Update.plist</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -1,12 +1,16 @@
|
|||||||
import threading
|
import sys
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import plistlib
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from resources import defaults, utilities, validation, constants
|
from pathlib import Path
|
||||||
from resources.sys_patch import sys_patch, sys_patch_auto
|
|
||||||
|
from data import model_array, os_data
|
||||||
from resources.build import build
|
from resources.build import build
|
||||||
from data import model_array
|
from resources.sys_patch import sys_patch, sys_patch_auto
|
||||||
|
from resources import defaults, utilities, validation, constants
|
||||||
|
|
||||||
|
|
||||||
# Generic building args
|
# Generic building args
|
||||||
@@ -41,6 +45,11 @@ class arguments:
|
|||||||
self._sys_unpatch_handler()
|
self._sys_unpatch_handler()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self.args.prepare_for_update:
|
||||||
|
logging.info("Preparing host for macOS update")
|
||||||
|
self._clean_le_handler()
|
||||||
|
return
|
||||||
|
|
||||||
if self.args.auto_patch:
|
if self.args.auto_patch:
|
||||||
self._sys_patch_auto_handler()
|
self._sys_patch_auto_handler()
|
||||||
return
|
return
|
||||||
@@ -88,6 +97,46 @@ class arguments:
|
|||||||
sys_patch_auto.AutomaticSysPatch(self.constants).start_auto_patch()
|
sys_patch_auto.AutomaticSysPatch(self.constants).start_auto_patch()
|
||||||
|
|
||||||
|
|
||||||
|
def _clean_le_handler(self) -> None:
|
||||||
|
"""
|
||||||
|
Check if software update is staged
|
||||||
|
If so, clean /Library/Extensions
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.constants.detected_os < os_data.os_data.sonoma:
|
||||||
|
logging.info("Host doesn't require cleaning, skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
update_config = "/System/Volumes/Update/Update.plist"
|
||||||
|
if not Path(update_config).exists():
|
||||||
|
logging.info("No update staged, skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
update_staged = plistlib.load(open(update_config, "rb"))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to load update config: {e}")
|
||||||
|
return
|
||||||
|
if "update-asset-attributes" not in update_staged:
|
||||||
|
logging.info("No update staged, skipping")
|
||||||
|
return
|
||||||
|
|
||||||
|
logging.info("Update staged, cleaning /Library/Extensions")
|
||||||
|
|
||||||
|
for kext in Path("/Library/Extensions").glob("*.kext"):
|
||||||
|
if not Path(f"{kext}/Contents/Info.plist").exists():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
kext_plist = plistlib.load(open(f"{kext}/Contents/Info.plist", "rb"))
|
||||||
|
except Exception as e:
|
||||||
|
logging.info(f" - Failed to load plist for {kext.name}: {e}")
|
||||||
|
continue
|
||||||
|
if "GPUCompanionBundles" not in kext_plist:
|
||||||
|
continue
|
||||||
|
logging.info(f" - Removing {kext.name}")
|
||||||
|
subprocess.run(["rm", "-rf", kext])
|
||||||
|
|
||||||
|
|
||||||
def _build_handler(self) -> None:
|
def _build_handler(self) -> None:
|
||||||
"""
|
"""
|
||||||
Start config building process
|
Start config building process
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class BuildWiredNetworking:
|
|||||||
|
|
||||||
# Always enable due to chance of hot-plugging
|
# Always enable due to chance of hot-plugging
|
||||||
self._usb_ecm_dongles()
|
self._usb_ecm_dongles()
|
||||||
|
self._i210_handling()
|
||||||
|
|
||||||
|
|
||||||
def _usb_ecm_dongles(self) -> None:
|
def _usb_ecm_dongles(self) -> None:
|
||||||
@@ -48,6 +49,21 @@ class BuildWiredNetworking:
|
|||||||
# - Kext: AppleUSBECM.kext
|
# - Kext: AppleUSBECM.kext
|
||||||
support.BuildSupport(self.model, self.constants, self.config).enable_kext("ECM-Override.kext", self.constants.ecm_override_version, self.constants.ecm_override_path)
|
support.BuildSupport(self.model, self.constants, self.config).enable_kext("ECM-Override.kext", self.constants.ecm_override_version, self.constants.ecm_override_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _i210_handling(self) -> None:
|
||||||
|
"""
|
||||||
|
PCIe i210 NIC Handling
|
||||||
|
"""
|
||||||
|
# i210 NICs are broke in macOS 14 due to driver kit downgrades
|
||||||
|
# See ECM logic for why it's always enabled
|
||||||
|
if not self.model in smbios_data.smbios_dictionary:
|
||||||
|
return
|
||||||
|
support.BuildSupport(self.model, self.constants, self.config).enable_kext("CatalinaIntelI210Ethernet.kext", self.constants.i210_version, self.constants.i210_path)
|
||||||
|
# Ivy Bridge and newer natively support DriverKit, so set MinKernel to 23.0.0
|
||||||
|
if smbios_data.smbios_dictionary[self.model]["CPU Generation"] >= cpu_data.CPUGen.ivy_bridge.value:
|
||||||
|
support.BuildSupport(self.model, self.constants, self.config).get_kext_by_bundle_path("CatalinaIntelI210Ethernet.kext")["MinKernel"] = "23.0.0"
|
||||||
|
|
||||||
|
|
||||||
def _on_model(self) -> None:
|
def _on_model(self) -> None:
|
||||||
"""
|
"""
|
||||||
On-Model Hardware Detection Handling
|
On-Model Hardware Detection Handling
|
||||||
|
|||||||
@@ -288,6 +288,10 @@ class Constants:
|
|||||||
def rsr_monitor_launch_daemon_path(self):
|
def rsr_monitor_launch_daemon_path(self):
|
||||||
return self.payload_path / Path("com.dortania.opencore-legacy-patcher.rsr-monitor.plist")
|
return self.payload_path / Path("com.dortania.opencore-legacy-patcher.rsr-monitor.plist")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def update_launch_daemon_path(self):
|
||||||
|
return self.payload_path / Path("com.dortania.opencore-legacy-patcher.macos-update.plist")
|
||||||
|
|
||||||
# ACPI
|
# ACPI
|
||||||
@property
|
@property
|
||||||
def pci_ssdt_path(self):
|
def pci_ssdt_path(self):
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class InitializeLoggingSupport:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
base_path = Path("~/Library/Logs").expanduser()
|
base_path = Path("~/Library/Logs").expanduser()
|
||||||
if not base_path.exists():
|
if not base_path.exists() or str(base_path).startswith("/var/root/"):
|
||||||
# Likely in an installer environment, store in /Users/Shared
|
# Likely in an installer environment, store in /Users/Shared
|
||||||
base_path = Path("/Users/Shared")
|
base_path = Path("/Users/Shared")
|
||||||
else:
|
else:
|
||||||
@@ -71,7 +71,7 @@ class InitializeLoggingSupport:
|
|||||||
try:
|
try:
|
||||||
base_path.mkdir()
|
base_path.mkdir()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Failed to create Dortania folder: {e}")
|
print(f"Failed to create Dortania folder: {e}")
|
||||||
base_path = Path("/Users/Shared")
|
base_path = Path("/Users/Shared")
|
||||||
|
|
||||||
self.log_filepath = Path(f"{base_path}/{self.log_filename}").expanduser()
|
self.log_filepath = Path(f"{base_path}/{self.log_filename}").expanduser()
|
||||||
@@ -194,6 +194,7 @@ class InitializeLoggingSupport:
|
|||||||
logging.info('#' * str_len)
|
logging.info('#' * str_len)
|
||||||
|
|
||||||
logging.info("Log file set:")
|
logging.info("Log file set:")
|
||||||
|
logging.info(f" {self.log_filepath}")
|
||||||
# Display relative path to avoid disclosing user's username
|
# Display relative path to avoid disclosing user's username
|
||||||
try:
|
try:
|
||||||
path = self.log_filepath.relative_to(Path.home())
|
path = self.log_filepath.relative_to(Path.home())
|
||||||
|
|||||||
@@ -716,8 +716,6 @@ class PatchSysVolume:
|
|||||||
utilities.process_status(subprocess.run(process, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True))
|
utilities.process_status(subprocess.run(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"]):
|
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()
|
sys_patch_helpers.SysPatchHelpers(self.constants).disable_window_server_caching()
|
||||||
if any(x in required_patches for x in ["Intel Ivy Bridge", "Intel Haswell"]):
|
|
||||||
sys_patch_helpers.SysPatchHelpers(self.constants).remove_news_widgets()
|
|
||||||
if "Metal 3802 Common Extended" in required_patches:
|
if "Metal 3802 Common Extended" in required_patches:
|
||||||
sys_patch_helpers.SysPatchHelpers(self.constants).patch_gpu_compiler_libraries(mount_point=self.mount_location)
|
sys_patch_helpers.SysPatchHelpers(self.constants).patch_gpu_compiler_libraries(mount_point=self.mount_location)
|
||||||
|
|
||||||
|
|||||||
@@ -377,36 +377,28 @@ Please check the Github page for more information about this release."""
|
|||||||
|
|
||||||
subprocess.run(["xattr", "-cr", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
subprocess.run(["xattr", "-cr", "/Library/Application Support/Dortania/OpenCore-Patcher.app"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
# Copy over our launch agent
|
|
||||||
logging.info("- Copying auto-patch.plist Launch Agent to /Library/LaunchAgents/")
|
|
||||||
if Path("/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist").exists():
|
|
||||||
logging.info("- Deleting existing auto-patch.plist")
|
|
||||||
utilities.process_status(utilities.elevated(["rm", "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
||||||
if not Path("/Library/LaunchAgents/").exists():
|
|
||||||
logging.info("- Creating /Library/LaunchAgents/")
|
|
||||||
utilities.process_status(utilities.elevated(["mkdir", "-p", "/Library/LaunchAgents/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
||||||
utilities.process_status(utilities.elevated(["cp", self.constants.auto_patch_launch_agent_path, "/Library/LaunchAgents/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
||||||
|
|
||||||
# Set the permissions on the com.dortania.opencore-legacy-patcher.auto-patch.plist
|
services = {
|
||||||
logging.info("- Setting permissions on auto-patch.plist")
|
self.constants.auto_patch_launch_agent_path: "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
||||||
utilities.process_status(utilities.elevated(["chmod", "644", "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
self.constants.update_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.macos-update.plist",
|
||||||
utilities.process_status(utilities.elevated(["chown", "root:wheel", "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
**({ self.constants.rsr_monitor_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist" } if self._create_rsr_monitor_daemon() else {}),
|
||||||
|
}
|
||||||
|
|
||||||
# Copy over our launch daemon
|
for service in services:
|
||||||
if self._create_rsr_monitor_daemon() is True:
|
name = Path(service).name
|
||||||
logging.info("- Copying rsr-monitor.plist Launch Daemon to /Library/LaunchDaemons/")
|
logging.info(f"- Installing {name}")
|
||||||
if Path("/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist").exists():
|
if Path(services[service]).exists():
|
||||||
logging.info("- Deleting existing rsr-monitor.plist")
|
logging.info(f" - Existing service found, removing")
|
||||||
utilities.process_status(utilities.elevated(["rm", "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
utilities.process_status(utilities.elevated(["rm", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
if not Path("/Library/LaunchDaemons/").exists():
|
# Create parent directories
|
||||||
logging.info("- Creating /Library/LaunchDaemons/")
|
if not Path(services[service]).parent.exists():
|
||||||
utilities.process_status(utilities.elevated(["mkdir", "-p", "/Library/LaunchDaemons/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
logging.info(f" - Creating {Path(services[service]).parent} directory")
|
||||||
utilities.process_status(utilities.elevated(["cp", self.constants.rsr_monitor_launch_daemon_path, "/Library/LaunchDaemons/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
utilities.process_status(utilities.elevated(["mkdir", "-p", Path(services[service]).parent], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
|
utilities.process_status(utilities.elevated(["cp", service, services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
|
|
||||||
# Set the permissions on the com.dortania.opencore-legacy-patcher.rsr-monitor.plist
|
# Set the permissions on the service
|
||||||
logging.info("- Setting permissions on rsr-monitor.plist")
|
utilities.process_status(utilities.elevated(["chmod", "644", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
utilities.process_status(utilities.elevated(["chmod", "644", "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
utilities.process_status(utilities.elevated(["chown", "root:wheel", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
utilities.process_status(utilities.elevated(["chown", "root:wheel", "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
|
||||||
|
|
||||||
# Making app alias
|
# Making app alias
|
||||||
# Simply an easy way for users to notice the app
|
# Simply an easy way for users to notice the app
|
||||||
|
|||||||
@@ -580,6 +580,7 @@ def check_cli_args():
|
|||||||
# sys_patch args
|
# sys_patch args
|
||||||
parser.add_argument("--patch_sys_vol", help="Patches root volume", action="store_true", required=False)
|
parser.add_argument("--patch_sys_vol", help="Patches root volume", action="store_true", required=False)
|
||||||
parser.add_argument("--unpatch_sys_vol", help="Unpatches root volume, EXPERIMENTAL", action="store_true", required=False)
|
parser.add_argument("--unpatch_sys_vol", help="Unpatches root volume, EXPERIMENTAL", action="store_true", required=False)
|
||||||
|
parser.add_argument("--prepare_for_update", help="Prepares host for macOS update, ex. clean /Library/Extensions", action="store_true", required=False)
|
||||||
|
|
||||||
# validation args
|
# validation args
|
||||||
parser.add_argument("--validate", help="Runs Validation Tests for CI", action="store_true", required=False)
|
parser.add_argument("--validate", help="Runs Validation Tests for CI", action="store_true", required=False)
|
||||||
@@ -591,7 +592,14 @@ def check_cli_args():
|
|||||||
parser.add_argument("--update_installed", help="Prompt user to finish updating via GUI", action="store_true", required=False)
|
parser.add_argument("--update_installed", help="Prompt user to finish updating via GUI", action="store_true", required=False)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if not (args.build or args.patch_sys_vol or args.unpatch_sys_vol or args.validate or args.auto_patch):
|
if not (
|
||||||
|
args.build or
|
||||||
|
args.patch_sys_vol or
|
||||||
|
args.unpatch_sys_vol or
|
||||||
|
args.validate or
|
||||||
|
args.auto_patch or
|
||||||
|
args.prepare_for_update
|
||||||
|
):
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return args
|
return args
|
||||||
|
|||||||
Reference in New Issue
Block a user