Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 1 addition & 31 deletions src/bugs.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
# Allow the recoveryOS we use
ALLOWED_RECOVERYOS_VERSIONS = ("13.5",)

GGATE_VALIDATION_MIN = "27.0"

PROMOTION_DEVICES = {
"j314cap",
"j314sap",
Expand Down Expand Up @@ -79,31 +77,7 @@ def request_upgrade():
p_message("macOS Sonoma versions prior to 14.2 on this machine.")
print()

def run_checks_ggate_validation(main):
if main.sysinfo.macos_ver and split_ver(main.sysinfo.macos_ver) < split_ver(GGATE_VALIDATION_MIN):
logging.info("bugs: Tahoe or lower")
return
p_error("macOS Golden Gate detected!")
print()
p_warning("Apple has changed how the boot picker and Startup Disk applications detect")
p_warning('"valid" macOS installs. When using either from macOS 27, your Asahi partition')
p_warning("will not be visible! We believe this to be a bug, and have filed a report.")
print()
p_message("If you are running the installer because you have noticed that your Asahi partition")
p_message("has disappeared, do not stress. Your Asahi partition is still there, and you have")
p_message("not lost any data. The Apple Silicon boot picker is a macOS application running")
p_message("in the default boot volume's recovery environment and therefore still works if")
p_message("your default boot disk is macOS 26 and below or Asahi.")
print()
p_message("If you have a secondary installation of macOS 26 or below, set this as your default")
p_message("Startup Disk to restore access to Asahi. If this is your only install, it is possible")
p_message("that the Fallback recoveryOS is still using macOS 26 or older, and in that case you can")
p_message("enter it by turning off the machine, rapidly pressing and releasing the power button, then")
p_message('holding it until the "Loading startup options..." message appears')
print()
exit(1)

def run_checks_promotion(main):
def run_checks(main):
if main.sysinfo.device_class not in PROMOTION_DEVICES:
logging.info("bugs: Not a ProMotion device")
return
Expand All @@ -126,7 +100,3 @@ def run_checks_promotion(main):

request_upgrade()
sys.exit(1)

def run_checks(main):
run_checks_ggate_validation(main)
run_checks_promotion(main)
37 changes: 37 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ class Device:
"j180dap": Device("13.4", False), # Mac Pro (M2 Ultra, 2023)
}

# Asahi Linux does not support running in a virtual machine, this option
# exists only for development of the installer itself.
if os.environ.get("ALLOW_VM", None):
CHIP_MIN_VER[0xfe00] = "12.0"
DEVICES["vma2macosap"] = Device("12.0", False)

IPSW_VERSIONS = [
IPSW("12.3.1",
"12.1",
Expand Down Expand Up @@ -437,6 +443,29 @@ def action_repair_or_upgrade(self, oses, upgrade):
# Go for step2 again
self.step2()

def action_set_vol_bootable(self, oses):
choices = {str(i): f"{p.desc}\n {str(o)}" for i, (p, o) in enumerate(oses)}

if len(choices) > 1:
print()
p_question("Choose an install to fix macOS 27 compatibility on:")
idx = self.choice("Installed OS", choices)
else:
idx = list(choices.keys())[0]

self.part, osi = oses[int(idx)]

self.dutil.remount_rw(osi.system)
fsctl_set_bootable(osi.system, True)
print()
p_success(f"macOS 27 fix applied. System Settings caches the bootability state,")
p_success(f"so you may need to reboot before the os becomes visible")
p_success(f"Press enter to continue.")
self.input()
print()

return True

def action_rebuild_vendorfw(self, oses):
choices = {str(i): f"{p.desc}\n {str(o)}" for i, (p, o) in enumerate(oses)}

Expand Down Expand Up @@ -977,6 +1006,7 @@ def main_loop(self):
parts_empty_apfs = []
parts_resizable = []
oses_incomplete = []
oses_non_vol_boot = []
oses_upgradable = []
oses_vendorfw = []

Expand Down Expand Up @@ -1055,6 +1085,8 @@ def main_loop(self):
p_plain(f" Extra partitions: {' '.join('#' + str(i.index) for i in os.attached_partitions)}")
if os.stub and os.m1n1_ver:
oses_vendorfw.append((p, os))
if os.stub and not os.sys_vol_bootable:
oses_non_vol_boot.append((p, os))
if os.stub and os.m1n1_ver and os.m1n1_ver != self.m1n1_ver:
oses_upgradable.append((p, os))
elif os.stub and not (os.bp and os.bp.get("coih", None)):
Expand Down Expand Up @@ -1095,6 +1127,9 @@ def main_loop(self):
if oses_vendorfw:
actions["v"] = "Rebuild vendor firmware package"
default = default or "v"
if oses_non_vol_boot:
actions["7"] = "Fix macOS 27 boot picker compatibility"
default = default or "7"

if not actions:
p_error("No actions available on this system.")
Expand Down Expand Up @@ -1125,6 +1160,8 @@ def main_loop(self):
return self.action_wipe()
elif act == "v":
return self.action_rebuild_vendorfw(oses_vendorfw)
elif act == "7":
return self.action_set_vol_bootable(oses_non_vol_boot)
elif act == "q":
return False

Expand Down
6 changes: 5 additions & 1 deletion src/osenum.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class OSInfo:
paired: bool = False
admin_users: object = None
attached_partitions: list = None
sys_vol_bootable: bool = False

def update_admin_users(self):
try:
Expand Down Expand Up @@ -225,7 +226,10 @@ def collect_os(self, part, volumes, vgid):
except FileNotFoundError:
logging.info(f" Not Found")
continue

try:
osi.sys_vol_bootable = fsctl_is_bootable(mounts["System"])
except Exception as e:
logging.warning(f" Failed to get VolBootable: {e}")
osi.update_admin_users()

try:
Expand Down
2 changes: 2 additions & 0 deletions src/stub.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ def install_files(self, cur_os):
except:
p_error("Failed to apply extended attributes, logo will not work.")

fsctl_set_bootable(self.osi.system, True)

p_progress("Setting up Data volume...")
logging.info("Setting up Data volume")

Expand Down
19 changes: 19 additions & 0 deletions src/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,22 @@ def extract_tree(self, src, dest):

if self.verbose:
self.flush_progress()
c_fsctl = None
def fsctl_apfs_bootable(path, cmd):
global c_fsctl
if c_fsctl is None:
sysdll = CDLL("libSystem.B.dylib", use_errno=True)
func = sysdll.fsctl
func.restype = c_int
func.argtypes = (c_char_p, c_ulong, POINTER(c_int), c_uint)
c_fsctl = func
c_cmd = c_int(cmd)
err = c_fsctl(path.encode(), 0xc0044a57, byref(c_cmd), 0)
if err == -1:
raise Exception(f'fsctl call failed, errno: {get_errno()}')
return c_cmd.value

def fsctl_is_bootable(path):
return fsctl_apfs_bootable(path, 0) == 1
def fsctl_set_bootable(path, val):
fsctl_apfs_bootable(path, 1 if val else -1)
Loading