[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[PATCH 2/3] lorax: Build a boot image for Macs



From: Matthew Garrett <mjg redhat com>

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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]