mkefiboot: Make Apple boot images appear in the startup preferences

There's a small amount of additional metadata required for the Mac boot
images to appear as bootable devices in the startup preferencs, so add
support for generating that.

Signed-off-by: Brian C. Lane <bcl@redhat.com>
This commit is contained in:
Matthew Garrett 2012-03-21 20:34:32 -04:00 committed by Brian C. Lane
parent b856297986
commit bb18614c3b
2 changed files with 31 additions and 5 deletions

View File

@ -19,7 +19,7 @@ ${make_efiboot("images/macboot.img", imgtype="apple")}
eficonf = "%s/BOOT%s.conf" % (EFIBOOTDIR, efiarch) eficonf = "%s/BOOT%s.conf" % (EFIBOOTDIR, efiarch)
args = "--label=ANACONDA" args = "--label=ANACONDA"
if disk: args += " --disk" if disk: args += " --disk"
if imgtype == "apple": args += " --apple --icon=%s" % APPLE_EFI_ICON if imgtype == "apple": args += ' --apple --icon=%s --product="%s %s"' % (APPLE_EFI_ICON, product.name, product.version)
%> %>
%if include_kernel: %if include_kernel:
copy ${KERNELDIR}/vmlinuz ${EFIBOOTDIR} copy ${KERNELDIR}/vmlinuz ${EFIBOOTDIR}

View File

@ -27,27 +27,51 @@ def mkefiboot(bootdir, outfile, label):
'''Make an EFI boot image with the contents of bootdir in EFI/BOOT''' '''Make an EFI boot image with the contents of bootdir in EFI/BOOT'''
mkdosimg(None, outfile, label=label, graft={'EFI/BOOT':bootdir}) mkdosimg(None, outfile, label=label, graft={'EFI/BOOT':bootdir})
def mkmacboot(bootdir, outfile, label, icon=None): def mkmacboot(bootdir, outfile, label, icon=None, product='Generic'):
'''Make an EFI boot image for Apple's EFI implementation''' '''Make an EFI boot image for Apple's EFI implementation'''
graft = {'EFI/BOOT':bootdir} graft = {'EFI/BOOT':bootdir}
if icon: if icon:
graft['.VolumeIcon.icns'] = icon graft['.VolumeIcon.icns'] = icon
mkhfsimg(None, outfile, label=label, graft=graft) mkhfsimg(None, outfile, label=label, graft=graft)
macbless(outfile) macmunge(outfile, product)
# To make an HFS+ image bootable, we need to fill in parts of the # To make an HFS+ image bootable, we need to fill in parts of the
# HFSPlusVolumeHeader structure - specifically, finderInfo[0,1,5]. # HFSPlusVolumeHeader structure - specifically, finderInfo[0,1,5].
# For details, see Technical Note TN1150: HFS Plus Volume Format # For details, see Technical Note TN1150: HFS Plus Volume Format
# http://developer.apple.com/library/mac/#technotes/tn/tn1150.html # http://developer.apple.com/library/mac/#technotes/tn/tn1150.html
def macbless(imgfile): #
# Additionally, we want to do some fixups to make it play nicely with
# the startup disk preferences panel.
def macmunge(imgfile, product):
'''"bless" the EFI bootloader inside the given Mac EFI boot image, by '''"bless" the EFI bootloader inside the given Mac EFI boot image, by
writing its inode info into the HFS+ volume header.''' writing its inode info into the HFS+ volume header.'''
# Get the inode number for the boot image and its parent directory # Get the inode number for the boot image and its parent directory
with LoopDev(imgfile) as loopdev: with LoopDev(imgfile) as loopdev:
with Mount(loopdev) as mnt: with Mount(loopdev) as mnt:
loader = glob.glob(os.path.join(mnt,'EFI/BOOT/BOOT*.efi'))[0] loader = glob.glob(os.path.join(mnt,'EFI/BOOT/BOOT*.efi'))[0]
config = glob.glob(os.path.join(mnt,'EFI/BOOT/BOOT*.conf'))[0]
blessnode = os.stat(loader).st_ino blessnode = os.stat(loader).st_ino
dirnode = os.stat(os.path.dirname(loader)).st_ino dirnode = os.stat(os.path.dirname(loader)).st_ino
with open(os.path.join(mnt,'mach_kernel'), 'w') as kernel:
kernel.write('Dummy kernel for booting')
sysdir = os.path.join(mnt,'System/Library/CoreServices/')
os.makedirs(sysdir)
with open(os.path.join(sysdir,'SystemVersion.plist'), 'w') as plist:
plist.write('''<?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>ProductBuildVersion</key>
<string></string>
<key>ProductName</key>
<string>Linux</string>
<key>ProductVersion</key>
<string>%s</string>
</dict>
</plist>
''' % (product,))
os.link(loader, os.path.join(sysdir,'boot.efi'))
os.link(config, os.path.join(sysdir,'boot.conf'))
# format data properly (big-endian UInt32) # format data properly (big-endian UInt32)
nodedata = struct.pack(">i", blessnode) nodedata = struct.pack(">i", blessnode)
dirdata = struct.pack(">i", dirnode) dirdata = struct.pack(">i", dirnode)
@ -88,6 +112,8 @@ if __name__ == '__main__':
help="filesystem label to use (default: %(default)s)") help="filesystem label to use (default: %(default)s)")
parser.add_argument("-i", "--icon", metavar="ICONFILE", parser.add_argument("-i", "--icon", metavar="ICONFILE",
help="icon file to include (for Apple EFI image)") help="icon file to include (for Apple EFI image)")
parser.add_argument("-p", "--product", metavar="PRODUCT",
help="product name to use (for Apple EFI image)")
parser.add_argument("bootdir", metavar="EFIBOOTDIR", parser.add_argument("bootdir", metavar="EFIBOOTDIR",
help="input directory (will become /EFI/BOOT in the image)") help="input directory (will become /EFI/BOOT in the image)")
parser.add_argument("outfile", metavar="OUTPUTFILE", parser.add_argument("outfile", metavar="OUTPUTFILE",
@ -102,7 +128,7 @@ if __name__ == '__main__':
print "Warning: --icon is only useful for Apple EFI images" print "Warning: --icon is only useful for Apple EFI images"
# do the thing! # do the thing!
if opt.imgtype == "apple": if opt.imgtype == "apple":
mkmacboot(opt.bootdir, opt.outfile, opt.label, opt.icon) mkmacboot(opt.bootdir, opt.outfile, opt.label, opt.icon, opt.product)
else: else:
mkefiboot(opt.bootdir, opt.outfile, opt.label) mkefiboot(opt.bootdir, opt.outfile, opt.label)
if opt.disk: if opt.disk: