mirror of
https://github.com/dortania/OpenCore-Legacy-Patcher.git
synced 2026-04-13 20:28:21 +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 = [
|
||||
"com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
||||
"com.dortania.opencore-legacy-patcher.rsr-monitor.plist",
|
||||
"com.dortania.opencore-legacy-patcher.macos-update.plist",
|
||||
"entitlements.plist",
|
||||
"launcher.sh",
|
||||
"OC-Patcher-TUI.icns",
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
- Add support for detecting T1 Security Chips in DFU mode
|
||||
- Update non-Metal Binaries for macOS Sonoma:
|
||||
- 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:
|
||||
- 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 logging
|
||||
import sys
|
||||
import plistlib
|
||||
import threading
|
||||
import subprocess
|
||||
|
||||
from resources import defaults, utilities, validation, constants
|
||||
from resources.sys_patch import sys_patch, sys_patch_auto
|
||||
from pathlib import Path
|
||||
|
||||
from data import model_array, os_data
|
||||
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
|
||||
@@ -41,6 +45,11 @@ class arguments:
|
||||
self._sys_unpatch_handler()
|
||||
return
|
||||
|
||||
if self.args.prepare_for_update:
|
||||
logging.info("Preparing host for macOS update")
|
||||
self._clean_le_handler()
|
||||
return
|
||||
|
||||
if self.args.auto_patch:
|
||||
self._sys_patch_auto_handler()
|
||||
return
|
||||
@@ -88,6 +97,46 @@ class arguments:
|
||||
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:
|
||||
"""
|
||||
Start config building process
|
||||
|
||||
@@ -35,6 +35,7 @@ class BuildWiredNetworking:
|
||||
|
||||
# Always enable due to chance of hot-plugging
|
||||
self._usb_ecm_dongles()
|
||||
self._i210_handling()
|
||||
|
||||
|
||||
def _usb_ecm_dongles(self) -> None:
|
||||
@@ -48,6 +49,21 @@ class BuildWiredNetworking:
|
||||
# - 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)
|
||||
|
||||
|
||||
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:
|
||||
"""
|
||||
On-Model Hardware Detection Handling
|
||||
|
||||
@@ -288,6 +288,10 @@ class Constants:
|
||||
def rsr_monitor_launch_daemon_path(self):
|
||||
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
|
||||
@property
|
||||
def pci_ssdt_path(self):
|
||||
|
||||
@@ -61,7 +61,7 @@ class InitializeLoggingSupport:
|
||||
"""
|
||||
|
||||
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
|
||||
base_path = Path("/Users/Shared")
|
||||
else:
|
||||
@@ -71,7 +71,7 @@ class InitializeLoggingSupport:
|
||||
try:
|
||||
base_path.mkdir()
|
||||
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")
|
||||
|
||||
self.log_filepath = Path(f"{base_path}/{self.log_filename}").expanduser()
|
||||
@@ -194,6 +194,7 @@ class InitializeLoggingSupport:
|
||||
logging.info('#' * str_len)
|
||||
|
||||
logging.info("Log file set:")
|
||||
logging.info(f" {self.log_filepath}")
|
||||
# Display relative path to avoid disclosing user's username
|
||||
try:
|
||||
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))
|
||||
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 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:
|
||||
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)
|
||||
|
||||
# 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
|
||||
logging.info("- Setting permissions on 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))
|
||||
utilities.process_status(utilities.elevated(["chown", "root:wheel", "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
services = {
|
||||
self.constants.auto_patch_launch_agent_path: "/Library/LaunchAgents/com.dortania.opencore-legacy-patcher.auto-patch.plist",
|
||||
self.constants.update_launch_daemon_path: "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.macos-update.plist",
|
||||
**({ 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
|
||||
if self._create_rsr_monitor_daemon() is True:
|
||||
logging.info("- Copying rsr-monitor.plist Launch Daemon to /Library/LaunchDaemons/")
|
||||
if Path("/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist").exists():
|
||||
logging.info("- Deleting existing rsr-monitor.plist")
|
||||
utilities.process_status(utilities.elevated(["rm", "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
if not Path("/Library/LaunchDaemons/").exists():
|
||||
logging.info("- Creating /Library/LaunchDaemons/")
|
||||
utilities.process_status(utilities.elevated(["mkdir", "-p", "/Library/LaunchDaemons/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
utilities.process_status(utilities.elevated(["cp", self.constants.rsr_monitor_launch_daemon_path, "/Library/LaunchDaemons/"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
for service in services:
|
||||
name = Path(service).name
|
||||
logging.info(f"- Installing {name}")
|
||||
if Path(services[service]).exists():
|
||||
logging.info(f" - Existing service found, removing")
|
||||
utilities.process_status(utilities.elevated(["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(["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
|
||||
logging.info("- Setting permissions on rsr-monitor.plist")
|
||||
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", "/Library/LaunchDaemons/com.dortania.opencore-legacy-patcher.rsr-monitor.plist"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
# Set the permissions on the service
|
||||
utilities.process_status(utilities.elevated(["chmod", "644", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
utilities.process_status(utilities.elevated(["chown", "root:wheel", services[service]], stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||
|
||||
# Making app alias
|
||||
# Simply an easy way for users to notice the app
|
||||
|
||||
@@ -580,6 +580,7 @@ def check_cli_args():
|
||||
# sys_patch args
|
||||
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("--prepare_for_update", help="Prepares host for macOS update, ex. clean /Library/Extensions", action="store_true", required=False)
|
||||
|
||||
# validation args
|
||||
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)
|
||||
|
||||
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
|
||||
else:
|
||||
return args
|
||||
|
||||
Reference in New Issue
Block a user