From: Matthew Garrett <mjg@xxxxxxxxxx> Older EFI Macs won't EFI boot from El-Torito images and so require an HFS+ image with a blessed bootloader. This creates a minimal HFS+ filesystem with similar contents to the FAT one and sets it up appropriately. --- lorax.spec | 1 + src/pylorax/__init__.py | 78 ++++++++++++++++++++++++++++++++++++++------- src/pylorax/constants.py | 1 + src/pylorax/images.py | 16 ++++++--- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/lorax.spec b/lorax.spec index 93ab71f..d8a08ef 100644 --- a/lorax.spec +++ b/lorax.spec @@ -30,6 +30,7 @@ Requires: xz %ifarch %{ix86} x86_64 Requires: syslinux >= 4.02-5 +Requires: hfsplus-tools %endif %ifarch %{sparc} diff --git a/src/pylorax/__init__.py b/src/pylorax/__init__.py index 8eb6c7f..c3235a4 100644 --- a/src/pylorax/__init__.py +++ b/src/pylorax/__init__.py @@ -38,6 +38,7 @@ import itertools import glob import math import subprocess +import struct from base import BaseLoraxClass, DataHolder import output @@ -447,6 +448,7 @@ class Lorax(BaseLoraxClass): # create efi images efiboot = None + macboot = None if grubefi and self.efiarch not in ("IA32",): # create efibootdir self.efibootdir = joinpaths(self.outputdir, "EFI/BOOT") @@ -461,7 +463,8 @@ class Lorax(BaseLoraxClass): # create efiboot image with kernel logger.info("creating efiboot image with kernel") efiboot = self.create_efiboot(kernel, initrd, grubefi, splash, - include_kernel=True) + include_kernel=True, + use_hfs=False) if efiboot is None: logger.critical("unable to create efiboot image") @@ -480,19 +483,31 @@ class Lorax(BaseLoraxClass): # create efiboot image without kernel logger.info("creating efiboot image without kernel") efiboot = self.create_efiboot(kernel, initrd, grubefi, splash, - include_kernel=False) + include_kernel=False, + use_hfs=False) if efiboot is None: logger.critical("unable to create efiboot image") sys.exit(1) - # copy efiboot and efidisk to imgdir + logger.info("creating macboot image without kernel") + macboot = self.create_efiboot(kernel, initrd, grubefi, splash, + include_kernel=False, + use_hfs=True) + + if macboot is None: + logger.critical("unable to create macboot image") + sys.exit(1) + + + # copy macboot, efiboot and efidisk to imgdir shutil.copy2(efiboot, self.imgdir) shutil.copy2(efidisk, self.imgdir) + shutil.copy2(macboot, self.imgdir) # create boot iso logger.info("creating boot iso") - i.create_boot(efiboot) + i.create_boot(efiboot, macboot) treeinfo.write() @@ -516,7 +531,9 @@ class Lorax(BaseLoraxClass): return buildarch def create_efiboot(self, kernel, initrd, grubefi, splash, - include_kernel=True): + include_kernel=True, use_hfs=False): + + blessnode = 0 # create the efi tree directory efitree = tempfile.mkdtemp(prefix="efitree.", dir=self.workdir) @@ -564,7 +581,12 @@ class Lorax(BaseLoraxClass): # copy splash.xpm.gz shutil.copy2(splash, efitree) - efiboot = joinpaths(self.workdir, "efiboot.img") + if use_hfs: + imgpath = "macboot.img" + else: + imgpath = "efiboot.img" + + efiboot = joinpaths(self.workdir, imgpath) if os.path.isfile(efiboot): os.unlink(efiboot) @@ -584,16 +606,31 @@ class Lorax(BaseLoraxClass): # mkdosfs needs the size in blocks of 1024 bytes size = int(math.ceil(sizeinbytes / 1024.0)) - cmd = [self.lcmds.MKDOSFS, "-n", "ANACONDA", "-C", efiboot, str(size)] - logger.debug(cmd) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - proc.wait() + if use_hfs: + file = open(efiboot, 'w') + file.seek(sizeinbytes) + file.write(' ') + file.close() + cmd = [self.lcmds.MKFSHFSPLUS, "-v", "ANACONDA", efiboot] + logger.debug(cmd) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) + proc.wait() + else: + cmd = [self.lcmds.MKDOSFS, "-n", "ANACONDA", "-C", efiboot, str(size)] + logger.debug(cmd) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) + proc.wait() # mount the efiboot image efibootdir = tempfile.mkdtemp(prefix="efiboot.", dir=self.workdir) - cmd = [self.lcmds.MOUNT, "-o", "loop,shortname=winnt,umask=0777", - "-t", "vfat", efiboot, efibootdir] + if use_hfs: + cmd = [self.lcmds.MOUNT, "-o", "loop,umask=0777", + "-t", "hfsplus", efiboot, efibootdir] + else: + cmd = [self.lcmds.MOUNT, "-o", "loop,shortname=winnt,umask=0777", + "-t", "vfat", efiboot, efibootdir] + logger.debug(cmd) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) proc.wait() @@ -609,12 +646,29 @@ class Lorax(BaseLoraxClass): if not include_kernel: shutil.copy2(fpath, self.efibootdir) + if use_hfs: + fpath = joinpaths(efibootdir, ".VolumeIcon.icns") + shutil.copy2("/usr/share/pixmaps/bootloader/fedora.icns", fpath) + loaderstat = os.stat(joinpaths(dst, "BOOT{0}.efi".format(self.efiarch))) + blessnode = loaderstat.st_ino + # unmount the efiboot image cmd = [self.lcmds.UMOUNT, efibootdir] logger.debug(cmd) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) proc.wait() + if blessnode != 0: + nodedata = struct.pack(">i", blessnode) + dirdata = struct.pack(">i", 2) + file = open(efiboot, 'w') + file.seek(0x450) + file.write(dirdata) + file.write(nodedata) + file.seek(0x464) + file.write(dirdata) + file.close() + # remove the work directories shutil.rmtree(efibootdir) #shutil.rmtree(efitree) diff --git a/src/pylorax/constants.py b/src/pylorax/constants.py index b5fe307..4297aa3 100644 --- a/src/pylorax/constants.py +++ b/src/pylorax/constants.py @@ -47,6 +47,7 @@ class LoraxRequiredCommands(dict): self["LOCALEDEF"] = "localedef" self["LOSETUP"] = "losetup" self["MKDOSFS"] = "mkdosfs" + self["MKFSHFSPLUS"] = "mkfs.hfsplus" self["MKISOFS"] = "mkisofs" self["MKFS_EXT4"] = "mkfs.ext4" self["MKSQUASHFS"] = "mksquashfs" diff --git a/src/pylorax/images.py b/src/pylorax/images.py index aaaf461..aee9050 100644 --- a/src/pylorax/images.py +++ b/src/pylorax/images.py @@ -543,16 +543,22 @@ class X86(object): data = {"initrd": joinpaths(PXEBOOTDIR, initrd.fname)} self.treeinfo.add_section(section, data) - def create_boot(self, efiboot=None): + def create_boot(self, efiboot=None, macboot=None): # define efiargs and efigraft - efiargs, efigraft = [], [] - efihybridargs = [] + efiargs, efigraft, efihybridargs = [], [], [] + macargs, machybridargs = [], [] + if efiboot: efiargs = ["-eltorito-alt-boot", "-e", joinpaths(IMAGESDIR, "efiboot.img"), "-no-emul-boot"] efigraft = ["EFI/BOOT={0}/EFI/BOOT".format(self.outputroot)] efihybridargs = ["-u"] + if macboot: + macargs = ["-eltorito-alt-boot", "-e", + joinpaths(IMAGESDIR, "macboot.img"), "--no-emul-boot"] + efihybridargs = ["-m"] + # create boot image boot_fpath = joinpaths(self.outputroot, IMAGESDIR, "boot.iso") @@ -561,7 +567,7 @@ class X86(object): "{0}/isolinux.bin".format(ISOLINUXDIR), "-c", "{0}/boot.cat".format(ISOLINUXDIR), "-no-emul-boot", "-boot-load-size", "4", "-boot-info-table"] + efiargs + \ - ["-R", "-J", "-V", "'{0}'".format(self.product), "-T", + macargs + ["-R", "-J", "-V", "'{0}'".format(self.product), "-T", "-graft-points", "isolinux={0}".format(joinpaths(self.outputroot, ISOLINUXDIR)), "images={0}".format(joinpaths(self.outputroot, IMAGESDIR))] + \ @@ -573,7 +579,7 @@ class X86(object): if os.path.exists(ISOHYBRID): # run isohybrid - cmd = [ISOHYBRID] + efihybridargs + [boot_fpath] + cmd = [ISOHYBRID] + efihybridargs + machybridargs + [boot_fpath] p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.wait() -- 1.7.6 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list