2 # live.py : LiveImageCreator class for creating Live CD images
4 # Copyright 2007-2012, Red Hat, Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; version 2 of the License.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Library General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 from imgcreate
.errors
import *
29 from imgcreate
.fs
import *
30 from imgcreate
.creator
import *
32 class LiveImageCreatorBase(LoopImageCreator
):
33 """A base class for LiveCD image creators.
35 This class serves as a base class for the architecture-specific LiveCD
36 image creator subclass, LiveImageCreator.
38 LiveImageCreator creates a bootable ISO containing the system image,
39 bootloader, bootloader configuration, kernel and initramfs.
43 def __init__(self
, ks
, name
, fslabel
=None, releasever
=None, tmpdir
="/tmp",
44 title
="Linux", product
="Linux", useplugins
=False, cacheonly
=False,
46 """Initialise a LiveImageCreator instance.
48 This method takes the same arguments as LoopImageCreator.__init__().
51 LoopImageCreator
.__init
__(self
, ks
, name
,
53 releasever
=releasever
,
55 useplugins
=useplugins
,
59 self
.compress_type
= "xz"
60 """mksquashfs compressor to use."""
62 self
.skip_compression
= False
63 """Controls whether to use squashfs to compress the image."""
65 self
.skip_minimize
= False
66 """Controls whether an image minimizing snapshot should be created.
68 This snapshot can be used when copying the system image from the ISO in
69 order to minimize the amount of data that needs to be copied; simply,
70 it makes it possible to create a version of the image's filesystem with
75 self
._timeout
= kickstart
.get_timeout(self
.ks
, 10)
76 """The bootloader timeout from kickstart."""
78 self
._default
_kernel
= kickstart
.get_default_kernel(self
.ks
, "kernel")
79 """The default kernel type from kickstart."""
83 self
.__modules
= ["=ata", "sym53c8xx", "aic7xxx", "=usb", "=firewire",
84 "=mmc", "=pcmcia", "mptsas", "udf", "virtio_blk",
86 self
.__modules
.extend(kickstart
.get_modules(self
.ks
))
88 self
._isofstype
= "iso9660"
92 self
.product
= product
95 # Hooks for subclasses
97 def _configure_bootloader(self
, isodir
):
98 """Create the architecture specific booloader configuration.
100 This is the hook where subclasses must create the booloader
101 configuration in order to allow a bootable ISO to be built.
103 isodir -- the directory where the contents of the ISO are to be staged
106 raise CreatorError("Bootloader configuration is arch-specific, "
107 "but not implemented for this arch!")
109 def _get_kernel_options(self
):
110 """Return a kernel options string for bootloader configuration.
112 This is the hook where subclasses may specify a set of kernel options
113 which should be included in the images bootloader configuration.
115 A sensible default implementation is provided.
118 r
= kickstart
.get_kernel_args(self
.ks
)
119 if os
.path
.exists(self
._instroot
+ "/usr/bin/rhgb"):
121 if os
.path
.exists(self
._instroot
+ "/usr/bin/plymouth"):
125 def _get_mkisofs_options(self
, isodir
):
126 """Return the architecture specific mkisosfs options.
128 This is the hook where subclasses may specify additional arguments to
129 mkisofs, e.g. to enable a bootable ISO to be built.
131 By default, an empty list is returned.
137 # Helpers for subclasses
139 def _has_checkisomd5(self
):
140 """Check whether checkisomd5 is available in the install root."""
141 def exists(instroot
, path
):
142 return os
.path
.exists(instroot
+ path
)
144 if (exists(self
._instroot
, "/usr/lib/anaconda-runtime/checkisomd5") or
145 exists(self
._instroot
, "/usr/bin/checkisomd5")):
151 # Actual implementation
153 def _base_on(self
, base_on
):
154 """helper function to extract ext3 file system from a live CD ISO"""
155 isoloop
= DiskMount(LoopbackDisk(base_on
, 0), self
._mkdtemp
())
159 except MountError
, e
:
160 raise CreatorError("Failed to loopback mount '%s' : %s" %
163 # Copy the initrd%d.img and xen%d.gz files over to /isolinux
164 # This is because the originals in /boot are removed when the
165 # original .iso was created.
166 src
= isoloop
.mountdir
+ "/isolinux/"
167 dest
= self
.__ensure
_isodir
() + "/isolinux/"
169 pattern
= re
.compile(r
"(initrd\d+\.img|xen\d+\.gz)")
170 files
= [f
for f
in os
.listdir(src
) if pattern
.search(f
)
171 and os
.path
.isfile(src
+f
)]
173 shutil
.copyfile(src
+f
, dest
+f
)
175 # legacy LiveOS filesystem layout support, remove for F9 or F10
176 if os
.path
.exists(isoloop
.mountdir
+ "/squashfs.img"):
177 squashimg
= isoloop
.mountdir
+ "/squashfs.img"
179 squashimg
= isoloop
.mountdir
+ "/LiveOS/squashfs.img"
181 squashloop
= DiskMount(LoopbackDisk(squashimg
, 0), self
._mkdtemp
(), "squashfs")
183 # 'self.compress_type = None' will force reading it from base_on.
184 if self
.compress_type
is None:
185 self
.compress_type
= squashfs_compression_type(squashimg
)
186 if self
.compress_type
== 'undetermined':
187 # Default to 'gzip' for compatibility with older versions.
188 self
.compress_type
= 'gzip'
190 if not squashloop
.disk
.exists():
191 raise CreatorError("'%s' is not a valid live CD ISO : "
192 "squashfs.img doesn't exist" % base_on
)
196 except MountError
, e
:
197 raise CreatorError("Failed to loopback mount squashfs.img "
198 "from '%s' : %s" % (base_on
, e
))
200 # legacy LiveOS filesystem layout support, remove for F9 or F10
201 if os
.path
.exists(squashloop
.mountdir
+ "/os.img"):
202 os_image
= squashloop
.mountdir
+ "/os.img"
204 os_image
= squashloop
.mountdir
+ "/LiveOS/ext3fs.img"
206 if not os
.path
.exists(os_image
):
207 raise CreatorError("'%s' is not a valid live CD ISO : neither "
208 "LiveOS/ext3fs.img nor os.img exist" %
212 shutil
.copyfile(os_image
, self
._image
)
214 raise CreatorError("Failed to copy base live image to %s for modification: %s" %(self
._image
, e
))
219 def _mount_instroot(self
, base_on
= None):
221 LoopImageCreator
._mount
_instroot
(self
, base_on
)
222 self
.__write
_initrd
_conf
(self
._instroot
+ "/etc/sysconfig/mkinitrd")
223 self
.__write
_dracut
_conf
(self
._instroot
+ "/etc/dracut.conf.d/02livecd.conf")
225 def _unmount_instroot(self
):
226 self
.__restore
_file
(self
._instroot
+ "/etc/sysconfig/mkinitrd")
227 self
.__restore
_file
(self
._instroot
+ "/etc/dracut.conf.d/02livecd.conf")
228 LoopImageCreator
._unmount
_instroot
(self
)
230 def __ensure_isodir(self
):
231 if self
.__isodir
is None:
232 self
.__isodir
= self
._mkdtemp
("iso-")
235 def _generate_efiboot(self
, isodir
):
236 """Generate EFI boot images."""
237 if not glob
.glob(self
._instroot
+"/boot/efi/EFI/*/shim.efi"):
238 logging
.error("Missing shim.efi, skipping efiboot.img creation.")
241 # XXX-BCL: does this need --label?
242 subprocess
.call(["mkefiboot", isodir
+ "/EFI/BOOT",
243 isodir
+ "/isolinux/efiboot.img"])
244 subprocess
.call(["mkefiboot", "-a", isodir
+ "/EFI/BOOT",
245 isodir
+ "/isolinux/macboot.img", "-l", self
.product
,
246 "-n", "/usr/share/pixmaps/bootloader/fedora-media.vol",
247 "-i", "/usr/share/pixmaps/bootloader/fedora.icns",
250 def _create_bootconfig(self
):
251 """Configure the image so that it's bootable."""
252 self
._configure
_bootloader
(self
.__ensure
_isodir
())
253 self
._generate
_efiboot
(self
.__ensure
_isodir
())
255 def _get_post_scripts_env(self
, in_chroot
):
256 env
= LoopImageCreator
._get
_post
_scripts
_env
(self
, in_chroot
)
259 env
["LIVE_ROOT"] = self
.__ensure
_isodir
()
263 def __extra_filesystems(self
):
264 return "vfat msdos ";
266 def __extra_drivers(self
):
267 retval
= "sr_mod sd_mod ide-cd cdrom "
268 for module
in self
.__modules
:
270 retval
= retval
+ "ehci_hcd uhci_hcd ohci_hcd "
271 retval
= retval
+ "usb_storage usbhid "
272 elif module
== "=firewire":
273 retval
= retval
+ "firewire-sbp2 firewire-ohci "
274 retval
= retval
+ "sbp2 ohci1394 ieee1394 "
275 elif module
== "=mmc":
276 retval
= retval
+ "mmc_block sdhci sdhci-pci "
277 elif module
== "=pcmcia":
278 retval
= retval
+ "pata_pcmcia "
280 retval
= retval
+ module
+ " "
283 def __restore_file(self
,path
):
288 if os
.path
.exists(path
+ '.rpmnew'):
289 os
.rename(path
+ '.rpmnew', path
)
291 def __write_initrd_conf(self
, path
):
292 if not os
.path
.exists(os
.path
.dirname(path
)):
293 makedirs(os
.path
.dirname(path
))
295 f
.write('LIVEOS="yes"\n')
296 f
.write('PROBE="no"\n')
297 f
.write('MODULES+="' + self
.__extra
_filesystems
() + '"\n')
298 f
.write('MODULES+="' + self
.__extra
_drivers
() + '"\n')
301 def __write_dracut_conf(self
, path
):
302 if not os
.path
.exists(os
.path
.dirname(path
)):
303 makedirs(os
.path
.dirname(path
))
305 f
.write('filesystems+="' + self
.__extra
_filesystems
() + ' "\n')
306 f
.write('drivers+="' + self
.__extra
_drivers
() + ' "\n')
307 f
.write('add_dracutmodules+=" dmsquash-live pollcdrom "')
310 def __create_iso(self
, isodir
):
311 iso
= self
._outdir
+ "/" + self
.name
+ ".iso"
313 args
= ["/usr/bin/mkisofs",
315 "-hide-rr-moved", "-hide-joliet-trans-tbl",
319 args
.extend(self
._get
_mkisofs
_options
(isodir
))
320 if self
._isofstype
== "udf":
321 args
.append("-allow-limited-size")
325 if subprocess
.call(args
) != 0:
326 raise CreatorError("ISO creation failed!")
328 if os
.path
.exists("/usr/bin/isohybrid"):
329 if os
.path
.exists(isodir
+ "/isolinux/efiboot.img"):
330 subprocess
.call(["/usr/bin/isohybrid", "-u", "-m", iso
])
332 subprocess
.call(["/usr/bin/isohybrid", iso
])
334 self
.__implant
_md
5sum
(iso
)
336 def __implant_md5sum(self
, iso
):
337 """Implant an isomd5sum."""
338 if os
.path
.exists("/usr/bin/implantisomd5"):
339 implantisomd5
= "/usr/bin/implantisomd5"
340 elif os
.path
.exists("/usr/lib/anaconda-runtime/implantisomd5"):
341 implantisomd5
= "/usr/lib/anaconda-runtime/implantisomd5"
343 logging
.warn("isomd5sum not installed; not setting up mediacheck")
346 subprocess
.call([implantisomd5
, iso
])
348 def _stage_final_image(self
):
350 makedirs(self
.__ensure
_isodir
() + "/LiveOS")
354 if not self
.skip_minimize
:
355 create_image_minimizer(self
.__isodir
+ "/LiveOS/osmin.img",
356 self
._image
, self
.compress_type
,
357 tmpdir
= self
.tmpdir
)
359 if self
.skip_compression
:
360 shutil
.move(self
._image
, self
.__isodir
+ "/LiveOS/ext3fs.img")
361 if os
.stat(self
.__isodir
+ "/LiveOS/ext3fs.img").st_size
>= 4*1024*1024*1024:
362 self
._isofstype
= "udf"
363 logging
.warn("Switching to UDF due to size of LiveOS/ext3fs.img")
365 makedirs(os
.path
.join(os
.path
.dirname(self
._image
), "LiveOS"))
366 shutil
.move(self
._image
,
367 os
.path
.join(os
.path
.dirname(self
._image
),
368 "LiveOS", "ext3fs.img"))
369 mksquashfs(os
.path
.dirname(self
._image
),
370 self
.__isodir
+ "/LiveOS/squashfs.img",
372 if os
.stat(self
.__isodir
+ "/LiveOS/squashfs.img").st_size
>= 4*1024*1024*1024:
373 self
._isofstype
= "udf"
374 logging
.warn("Switching to UDF due to size of LiveOS/squashfs.img")
377 self
.__create
_iso
(self
.__isodir
)
379 shutil
.rmtree(self
.__isodir
, ignore_errors
= True)
382 class x86LiveImageCreator(LiveImageCreatorBase
):
383 """ImageCreator for x86 machines"""
384 def __init__(self
, *args
, **kwargs
):
385 LiveImageCreatorBase
.__init
__(self
, *args
, **kwargs
)
388 def _get_mkisofs_options(self
, isodir
):
389 options
= [ "-b", "isolinux/isolinux.bin",
390 "-c", "isolinux/boot.cat",
391 "-no-emul-boot", "-boot-info-table",
392 "-boot-load-size", "4" ]
393 if os
.path
.exists(isodir
+ "/isolinux/efiboot.img"):
394 options
.extend([ "-eltorito-alt-boot",
395 "-e", "isolinux/efiboot.img",
397 "-eltorito-alt-boot",
398 "-e", "isolinux/macboot.img",
402 def _get_required_packages(self
):
403 return ["syslinux"] \
404 + LiveImageCreatorBase
._get
_required
_packages
(self
)
406 def _get_isolinux_stanzas(self
, isodir
):
409 def __find_syslinux_menu(self
):
410 for menu
in ("vesamenu.c32", "menu.c32"):
411 for dir in ("/usr/lib/syslinux/", "/usr/share/syslinux/"):
412 if os
.path
.isfile(self
._instroot
+ dir + menu
):
415 raise CreatorError("syslinux not installed : "
416 "no suitable *menu.c32 found")
418 def __find_syslinux_mboot(self
):
420 # We only need the mboot module if we have any xen hypervisors
422 if not glob
.glob(self
._instroot
+ "/boot/xen.gz*"):
427 def __copy_syslinux_files(self
, isodir
, menu
, mboot
= None):
428 files
= ["isolinux.bin", menu
]
433 if os
.path
.exists(self
._instroot
+ "/usr/lib/syslinux/" + f
):
434 path
= self
._instroot
+ "/usr/lib/syslinux/" + f
435 elif os
.path
.exists(self
._instroot
+ "/usr/share/syslinux/" + f
):
436 path
= self
._instroot
+ "/usr/share/syslinux/" + f
437 if not os
.path
.isfile(path
):
438 raise CreatorError("syslinux not installed : "
439 "%s not found" % path
)
441 shutil
.copy(path
, isodir
+ "/isolinux/")
443 def __copy_syslinux_background(self
, isodest
):
444 background_path
= self
._instroot
+ \
445 "/usr/share/anaconda/boot/syslinux-vesa-splash.jpg"
447 if not os
.path
.exists(background_path
):
448 # fallback to F13 location
449 background_path
= self
._instroot
+ \
450 "/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg"
452 if not os
.path
.exists(background_path
):
455 shutil
.copyfile(background_path
, isodest
)
459 def __copy_kernel_and_initramfs(self
, isodir
, version
, index
):
460 bootdir
= self
._instroot
+ "/boot"
462 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
463 isodir
+ "/isolinux/vmlinuz" + index
)
466 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
467 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
468 isodir
+ "/isolinux/initrd" + index
+ ".img")
470 elif os
.path
.exists(bootdir
+ "/initrd-" + version
+ ".img"):
471 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
472 isodir
+ "/isolinux/initrd" + index
+ ".img")
473 elif not self
.base_on
:
474 logging
.error("No initrd or initramfs found for %s" % (version
,))
477 if os
.path
.exists(bootdir
+ "/xen.gz-" + version
[:-3]):
478 shutil
.copyfile(bootdir
+ "/xen.gz-" + version
[:-3],
479 isodir
+ "/isolinux/xen" + index
+ ".gz")
482 return (is_xen
, isDracut
)
484 def __is_default_kernel(self
, kernel
, kernels
):
485 if len(kernels
) == 1:
488 if kernel
== self
._default
_kernel
:
491 if kernel
.startswith("kernel-") and kernel
[7:] == self
._default
_kernel
:
496 def __get_basic_syslinux_config(self
, **args
):
500 menu background %(background)s
501 menu autoboot Starting %(title)s in # second{,s}. Press any key to interrupt.
512 menu color border * #00000000 #00000000 none
513 menu color sel 0 #ffffffff #00000000 none
514 menu color title 0 #ff7ba3d0 #00000000 none
515 menu color tabmsg 0 #ff3a6496 #00000000 none
516 menu color unsel 0 #84b8ffff #00000000 none
517 menu color hotsel 0 #84b8ffff #00000000 none
518 menu color hotkey 0 #ffffffff #00000000 none
519 menu color help 0 #ffffffff #00000000 none
520 menu color scrollbar 0 #ffffffff #ff355594 none
521 menu color timeout 0 #ffffffff #00000000 none
522 menu color timeout_msg 0 #ffffffff #00000000 none
523 menu color cmdmark 0 #84b8ffff #00000000 none
524 menu color cmdline 0 #ffffffff #00000000 none
526 menu tabmsg Press Tab for full configuration options on menu items.
530 def __get_image_stanza(self
, is_xen
, isDracut
, **args
):
532 args
["rootlabel"] = "live:CDLABEL=%(fslabel)s" % args
534 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
537 template
= """label %(short)s
539 kernel vmlinuz%(index)s
540 append initrd=initrd%(index)s.img root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s
543 template
= """label %(short)s
546 append xen%(index)s.gz --- vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s --- initrd%(index)s.img
549 template
+= """ text help
553 return template
% args
555 def __get_image_stanzas(self
, isodir
):
557 kernels
= self
._get
_kernel
_versions
()
558 for kernel
in kernels
:
559 for version
in kernels
[kernel
]:
560 versions
.append(version
)
562 kernel_options
= self
._get
_kernel
_options
()
564 checkisomd5
= self
._has
_checkisomd
5()
566 # Stanzas for insertion into the config template
572 for version
in versions
:
573 (is_xen
, isDracut
) = self
.__copy
_kernel
_and
_initramfs
(isodir
, version
, index
)
575 self
._isDracut
= isDracut
577 default
= self
.__is
_default
_kernel
(kernel
, kernels
)
581 elif kernel
.startswith("kernel-"):
582 long = "%s (%s)" % (self
.product
, kernel
[7:])
584 long = "%s (%s)" % (self
.product
, kernel
)
586 # tell dracut not to ask for LUKS passwords or activate mdraid sets
588 kern_opts
= kernel_options
+ " rd.luks=0 rd.md=0 rd.dm=0"
590 kern_opts
= kernel_options
592 linux
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
593 fslabel
= self
.fslabel
,
595 liveargs
= kern_opts
,
596 long = "^Start " + long,
597 short
= "linux" + index
,
603 linux
[-1] += " menu default\n"
605 basic
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
606 fslabel
= self
.fslabel
,
608 liveargs
= kern_opts
,
609 long = "Start " + long + " in ^basic graphics mode.",
610 short
= "basic" + index
,
611 extra
= "xdriver=vesa nomodeset",
612 help = "Try this option out if you're having trouble starting.",
616 check
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
617 fslabel
= self
.fslabel
,
619 liveargs
= kern_opts
,
620 long = "^Test this media & start " + long,
621 short
= "check" + index
,
622 extra
= "rd.live.check",
628 index
= str(int(index
) + 1)
630 return (linux
, basic
, check
)
632 def __get_memtest_stanza(self
, isodir
):
633 memtest
= glob
.glob(self
._instroot
+ "/boot/memtest86*")
637 shutil
.copyfile(memtest
[0], isodir
+ "/isolinux/memtest")
639 return """label memtest
640 menu label Run a ^memory test.
642 If your system is having issues, an problem with your
643 system's memory may be the cause. Use this utility to
644 see if the memory is working correctly.
649 def __get_local_stanza(self
, isodir
):
650 return """label local
651 menu label Boot from ^local drive
655 def _configure_syslinux_bootloader(self
, isodir
):
656 """configure the boot loader"""
657 makedirs(isodir
+ "/isolinux")
659 menu
= self
.__find
_syslinux
_menu
()
661 self
.__copy
_syslinux
_files
(isodir
, menu
,
662 self
.__find
_syslinux
_mboot
())
665 if self
.__copy
_syslinux
_background
(isodir
+ "/isolinux/splash.jpg"):
666 background
= "splash.jpg"
668 cfg
= self
.__get
_basic
_syslinux
_config
(menu
= menu
,
669 background
= background
,
671 timeout
= self
._timeout
* 10)
672 cfg
+= "menu separator\n"
674 linux
, basic
, check
= self
.__get
_image
_stanzas
(isodir
)
675 # Add linux stanzas to main menu
678 cfg
+= "menu separator\n"
680 cfg
+= """menu begin ^Troubleshooting
681 menu title Troubleshooting
683 # Add basic video and check to submenu
684 for b
, c
in zip(basic
, check
):
689 cfg
+= self
.__get
_memtest
_stanza
(isodir
)
690 cfg
+= "menu separator\n"
692 cfg
+= self
.__get
_local
_stanza
(isodir
)
693 cfg
+= self
._get
_isolinux
_stanzas
(isodir
)
695 cfg
+= """menu separator
697 menu label Return to ^main menu.
701 cfgf
= open(isodir
+ "/isolinux/isolinux.cfg", "w")
707 if not self
._efiarch
:
708 # for most things, we want them named boot$efiarch
709 efiarch
= {"i386": "IA32", "x86_64": "X64"}
710 self
._efiarch
= efiarch
[rpmUtils
.arch
.getBaseArch()]
713 def __copy_efi_files(self
, isodir
):
714 """ Copy the efi files into /EFI/BOOT/
715 If any of them are missing, return False.
723 files
= [("/boot/efi/EFI/*/shim.efi", "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
,)),
724 ("/boot/efi/EFI/*/gcdx64.efi", "/EFI/BOOT/grubx64.efi"),
725 ("/boot/efi/EFI/*/fonts/unicode.pf2", "/EFI/BOOT/fonts/"),
727 makedirs(isodir
+"/EFI/BOOT/fonts/")
728 for src
, dest
in files
:
729 src_glob
= glob
.glob(self
._instroot
+src
)
731 missing
.append("Missing EFI file (%s)" % (src
,))
734 shutil
.copy(src_glob
[0], isodir
+dest
)
735 map(logging
.error
, missing
)
738 def __get_basic_efi_config(self
, **args
):
742 function load_video {
756 set timeout=%(timeout)d
757 ### END /etc/grub.d/00_header ###
759 search --no-floppy --set=root -l '%(isolabel)s'
761 ### BEGIN /etc/grub.d/10_linux ###
764 def __get_efi_image_stanza(self
, **args
):
766 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
768 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
769 return """menuentry '%(long)s' --class fedora --class gnu-linux --class gnu --class os {
770 linuxefi /isolinux/vmlinuz%(index)s root=%(rootlabel)s %(liveargs)s %(extra)s
771 initrdefi /isolinux/initrd%(index)s.img
775 def __get_efi_image_stanzas(self
, isodir
, name
):
776 # FIXME: this only supports one kernel right now...
778 kernel_options
= self
._get
_kernel
_options
()
779 checkisomd5
= self
._has
_checkisomd
5()
783 for index
in range(0, 9):
784 # we don't support xen kernels
785 if os
.path
.exists("%s/EFI/BOOT/xen%d.gz" %(isodir
, index
)):
787 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
788 liveargs
= kernel_options
,
790 extra
= "", index
= index
)
792 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
793 liveargs
= kernel_options
,
794 long = "Verify and Boot " + name
,
795 extra
= "rd.live.check",
801 def _configure_efi_bootloader(self
, isodir
):
802 """Set up the configuration for an EFI bootloader"""
803 if self
.__copy
_efi
_files
(isodir
):
804 shutil
.rmtree(isodir
+ "/EFI")
805 logging
.warn("Failed to copy EFI files, no EFI Support will be included.")
808 cfg
= self
.__get
_basic
_efi
_config
(isolabel
= self
.fslabel
,
809 timeout
= self
._timeout
)
810 cfg
+= self
.__get
_efi
_image
_stanzas
(isodir
, self
.name
)
812 cfgf
= open(isodir
+ "/EFI/BOOT/grub.cfg", "w")
816 # first gen mactel machines get the bootloader name wrong apparently
817 if rpmUtils
.arch
.getBaseArch() == "i386":
818 os
.link(isodir
+ "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
),
819 isodir
+ "/EFI/BOOT/BOOT.efi")
822 def _configure_bootloader(self
, isodir
):
823 self
._configure
_syslinux
_bootloader
(isodir
)
824 self
._configure
_efi
_bootloader
(isodir
)
826 class ppcLiveImageCreator(LiveImageCreatorBase
):
827 def _get_mkisofs_options(self
, isodir
):
828 return [ "-hfs", "-no-desktop", "-part",
829 "-map", isodir
+ "/ppc/mapping",
830 "-hfs-bless", isodir
+ "/ppc/mac",
831 "-hfs-volid", self
.fslabel
]
833 def _get_required_packages(self
):
834 return ["yaboot"] + \
835 LiveImageCreatorBase
._get
_required
_packages
(self
)
837 def _get_excluded_packages(self
):
838 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
839 return ["memtest86+"] + \
840 LiveImageCreatorBase
._get
_excluded
_packages
(self
)
842 def __copy_boot_file(self
, destdir
, file):
843 for dir in ["/usr/share/ppc64-utils",
844 "/usr/lib/anaconda-runtime/boot"]:
845 path
= self
._instroot
+ dir + "/" + file
846 if not os
.path
.exists(path
):
850 shutil
.copy(path
, destdir
)
853 raise CreatorError("Unable to find boot file " + file)
855 def __kernel_bits(self
, kernel
):
856 testpath
= (self
._instroot
+ "/lib/modules/" +
857 kernel
+ "/kernel/arch/powerpc/platforms")
859 if not os
.path
.exists(testpath
):
860 return { "32" : True, "64" : False }
862 return { "32" : False, "64" : True }
864 def __copy_kernel_and_initramfs(self
, destdir
, version
):
866 bootdir
= self
._instroot
+ "/boot"
870 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
871 destdir
+ "/vmlinuz")
873 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
874 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
875 destdir
+ "/initrd.img")
878 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
879 destdir
+ "/initrd.img")
883 def __get_basic_yaboot_config(self
, **args
):
885 init-message = "Welcome to %(name)s"
889 def __get_image_stanza(self
, **args
):
891 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
893 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
896 image=/ppc/ppc%(bit)s/vmlinuz
898 initrd=/ppc/ppc%(bit)s/initrd.img
900 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
904 def __write_yaboot_config(self
, isodir
, bit
, isDracut
= False):
905 cfg
= self
.__get
_basic
_yaboot
_config
(name
= self
.name
,
906 timeout
= self
._timeout
* 100)
908 kernel_options
= self
._get
_kernel
_options
()
910 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
913 long = "Run from image",
916 liveargs
= kernel_options
,
919 if self
._has
_checkisomd
5():
920 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
922 short
= "rd.live.check",
923 long = "Verify and run from image",
924 extra
= "rd.live.check",
926 liveargs
= kernel_options
,
929 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
933 def __write_not_supported(self
, isodir
, bit
):
934 makedirs(isodir
+ "/ppc/ppc" + bit
)
936 message
= "Sorry, this LiveCD does not support your hardware"
938 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
939 f
.write('init-message = "' + message
+ '"')
943 def __write_dualbits_yaboot_config(isodir
, **args
):
945 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
949 image=/ppc/ppc64/vmlinuz
952 initrd=/ppc/ppc64/initrd.img
955 image=/ppc/ppc32/vmlinuz
957 initrd=/ppc/ppc32/initrd.img
961 f
= open(isodir
+ "/etc/yaboot.conf", "w")
965 def _configure_bootloader(self
, isodir
):
966 """configure the boot loader"""
967 havekernel
= { 32: False, 64: False }
969 self
.__copy
_boot
_file
(isodir
+ "/ppc", "mapping")
970 self
.__copy
_boot
_file
(isodir
+ "/ppc", "bootinfo.txt")
971 self
.__copy
_boot
_file
(isodir
+ "/ppc/mac", "ofboot.b")
973 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
974 isodir
+ "/ppc/mac/yaboot")
976 makedirs(isodir
+ "/ppc/chrp")
977 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
978 isodir
+ "/ppc/chrp/yaboot")
980 subprocess
.call(["/usr/sbin/addnote", isodir
+ "/ppc/chrp/yaboot"])
983 # FIXME: ppc should support multiple kernels too...
985 kernel
= self
._get
_kernel
_versions
().values()[0][0]
987 kernel_bits
= self
.__kernel
_bits
(kernel
)
989 for (bit
, present
) in kernel_bits
.items():
991 self
.__write
_not
_supported
(isodir
, bit
)
994 isDracut
= self
.__copy
_kernel
_and
_initramfs
(isodir
+ "/ppc/ppc" + bit
, kernel
)
995 self
.__write
_yaboot
_config
(isodir
, bit
, isDracut
)
997 makedirs(isodir
+ "/etc")
998 if kernel_bits
["32"] and not kernel_bits
["64"]:
999 shutil
.copyfile(isodir
+ "/ppc/ppc32/yaboot.conf",
1000 isodir
+ "/etc/yaboot.conf")
1001 elif kernel_bits
["64"] and not kernel_bits
["32"]:
1002 shutil
.copyfile(isodir
+ "/ppc/ppc64/yaboot.conf",
1003 isodir
+ "/etc/yaboot.conf")
1005 self
.__write
_dualbits
_yaboot
_config
(isodir
,
1007 timeout
= self
._timeout
* 100)
1010 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
1013 class ppc64LiveImageCreator(ppcLiveImageCreator
):
1014 def _get_excluded_packages(self
):
1016 # while kernel.ppc and kernel.ppc64 co-exist,
1017 # we can't have both
1018 return ["kernel.ppc"] + \
1019 ppcLiveImageCreator
._get
_excluded
_packages
(self
)
1021 arch
= rpmUtils
.arch
.getBaseArch()
1022 if arch
in ("i386", "x86_64"):
1023 LiveImageCreator
= x86LiveImageCreator
1024 elif arch
in ("ppc",):
1025 LiveImageCreator
= ppcLiveImageCreator
1026 elif arch
in ("ppc64",):
1027 LiveImageCreator
= ppc64LiveImageCreator
1028 elif arch
.startswith('arm'):
1029 LiveImageCreator
= LiveImageCreatorBase
1032 raise CreatorError("Architecture not supported!")