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.
724 files
= [("/boot/efi/EFI/*/shim.efi", "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
,)),
725 ("/boot/efi/EFI/*/gcdx64.efi", "/EFI/BOOT/grubx64.efi"),
726 ("/boot/efi/EFI/*/fonts/unicode.pf2", "/EFI/BOOT/fonts/"),
727 ("/boot/grub/splash.xpm.gz", "/EFI/BOOT"),
729 makedirs(isodir
+"/EFI/BOOT/fonts/")
730 for src
, dest
in files
:
731 src_glob
= glob
.glob(self
._instroot
+src
)
733 missing
.append("Missing EFI file (%s)" % (src
,))
736 shutil
.copy(src_glob
[0], isodir
+dest
)
737 map(logging
.error
, missing
)
740 def __get_basic_efi_config(self
, **args
):
744 function load_video {
758 set timeout=%(timeout)d
759 ### END /etc/grub.d/00_header ###
761 search --no-floppy --set=root -l '%(isolabel)s'
763 ### BEGIN /etc/grub.d/10_linux ###
766 def __get_efi_image_stanza(self
, **args
):
768 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
770 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
771 return """menuentry '%(long)s' --class fedora --class gnu-linux --class gnu --class os {
772 linuxefi /isolinux/vmlinuz%(index)s root=%(rootlabel)s %(liveargs)s %(extra)s
773 initrdefi /isolinux/initrd%(index)s.img
777 def __get_efi_image_stanzas(self
, isodir
, name
):
778 # FIXME: this only supports one kernel right now...
780 kernel_options
= self
._get
_kernel
_options
()
781 checkisomd5
= self
._has
_checkisomd
5()
785 for index
in range(0, 9):
786 # we don't support xen kernels
787 if os
.path
.exists("%s/EFI/BOOT/xen%d.gz" %(isodir
, index
)):
789 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
790 liveargs
= kernel_options
,
792 extra
= "", index
= index
)
794 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
795 liveargs
= kernel_options
,
796 long = "Verify and Boot " + name
,
797 extra
= "rd.live.check",
803 def _configure_efi_bootloader(self
, isodir
):
804 """Set up the configuration for an EFI bootloader"""
805 if self
.__copy
_efi
_files
(isodir
):
806 shutil
.rmtree(isodir
+ "/EFI")
807 raise CreatorError("Failed to copy EFI files")
809 cfg
= self
.__get
_basic
_efi
_config
(isolabel
= self
.fslabel
,
810 timeout
= self
._timeout
)
811 cfg
+= self
.__get
_efi
_image
_stanzas
(isodir
, self
.name
)
813 cfgf
= open(isodir
+ "/EFI/BOOT/grub.cfg", "w")
817 # first gen mactel machines get the bootloader name wrong apparently
818 if rpmUtils
.arch
.getBaseArch() == "i386":
819 os
.link(isodir
+ "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
),
820 isodir
+ "/EFI/BOOT/BOOT.efi")
823 def _configure_bootloader(self
, isodir
):
824 self
._configure
_syslinux
_bootloader
(isodir
)
825 self
._configure
_efi
_bootloader
(isodir
)
827 class ppcLiveImageCreator(LiveImageCreatorBase
):
828 def _get_mkisofs_options(self
, isodir
):
829 return [ "-hfs", "-no-desktop", "-part",
830 "-map", isodir
+ "/ppc/mapping",
831 "-hfs-bless", isodir
+ "/ppc/mac",
832 "-hfs-volid", self
.fslabel
]
834 def _get_required_packages(self
):
835 return ["yaboot"] + \
836 LiveImageCreatorBase
._get
_required
_packages
(self
)
838 def _get_excluded_packages(self
):
839 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
840 return ["memtest86+"] + \
841 LiveImageCreatorBase
._get
_excluded
_packages
(self
)
843 def __copy_boot_file(self
, destdir
, file):
844 for dir in ["/usr/share/ppc64-utils",
845 "/usr/lib/anaconda-runtime/boot"]:
846 path
= self
._instroot
+ dir + "/" + file
847 if not os
.path
.exists(path
):
851 shutil
.copy(path
, destdir
)
854 raise CreatorError("Unable to find boot file " + file)
856 def __kernel_bits(self
, kernel
):
857 testpath
= (self
._instroot
+ "/lib/modules/" +
858 kernel
+ "/kernel/arch/powerpc/platforms")
860 if not os
.path
.exists(testpath
):
861 return { "32" : True, "64" : False }
863 return { "32" : False, "64" : True }
865 def __copy_kernel_and_initramfs(self
, destdir
, version
):
867 bootdir
= self
._instroot
+ "/boot"
871 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
872 destdir
+ "/vmlinuz")
874 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
875 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
876 destdir
+ "/initrd.img")
879 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
880 destdir
+ "/initrd.img")
884 def __get_basic_yaboot_config(self
, **args
):
886 init-message = "Welcome to %(name)s"
890 def __get_image_stanza(self
, **args
):
892 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
894 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
897 image=/ppc/ppc%(bit)s/vmlinuz
899 initrd=/ppc/ppc%(bit)s/initrd.img
901 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
905 def __write_yaboot_config(self
, isodir
, bit
, isDracut
= False):
906 cfg
= self
.__get
_basic
_yaboot
_config
(name
= self
.name
,
907 timeout
= self
._timeout
* 100)
909 kernel_options
= self
._get
_kernel
_options
()
911 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
914 long = "Run from image",
917 liveargs
= kernel_options
,
920 if self
._has
_checkisomd
5():
921 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
923 short
= "rd.live.check",
924 long = "Verify and run from image",
925 extra
= "rd.live.check",
927 liveargs
= kernel_options
,
930 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
934 def __write_not_supported(self
, isodir
, bit
):
935 makedirs(isodir
+ "/ppc/ppc" + bit
)
937 message
= "Sorry, this LiveCD does not support your hardware"
939 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
940 f
.write('init-message = "' + message
+ '"')
944 def __write_dualbits_yaboot_config(isodir
, **args
):
946 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
950 image=/ppc/ppc64/vmlinuz
953 initrd=/ppc/ppc64/initrd.img
956 image=/ppc/ppc32/vmlinuz
958 initrd=/ppc/ppc32/initrd.img
962 f
= open(isodir
+ "/etc/yaboot.conf", "w")
966 def _configure_bootloader(self
, isodir
):
967 """configure the boot loader"""
968 havekernel
= { 32: False, 64: False }
970 self
.__copy
_boot
_file
(isodir
+ "/ppc", "mapping")
971 self
.__copy
_boot
_file
(isodir
+ "/ppc", "bootinfo.txt")
972 self
.__copy
_boot
_file
(isodir
+ "/ppc/mac", "ofboot.b")
974 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
975 isodir
+ "/ppc/mac/yaboot")
977 makedirs(isodir
+ "/ppc/chrp")
978 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
979 isodir
+ "/ppc/chrp/yaboot")
981 subprocess
.call(["/usr/sbin/addnote", isodir
+ "/ppc/chrp/yaboot"])
984 # FIXME: ppc should support multiple kernels too...
986 kernel
= self
._get
_kernel
_versions
().values()[0][0]
988 kernel_bits
= self
.__kernel
_bits
(kernel
)
990 for (bit
, present
) in kernel_bits
.items():
992 self
.__write
_not
_supported
(isodir
, bit
)
995 isDracut
= self
.__copy
_kernel
_and
_initramfs
(isodir
+ "/ppc/ppc" + bit
, kernel
)
996 self
.__write
_yaboot
_config
(isodir
, bit
, isDracut
)
998 makedirs(isodir
+ "/etc")
999 if kernel_bits
["32"] and not kernel_bits
["64"]:
1000 shutil
.copyfile(isodir
+ "/ppc/ppc32/yaboot.conf",
1001 isodir
+ "/etc/yaboot.conf")
1002 elif kernel_bits
["64"] and not kernel_bits
["32"]:
1003 shutil
.copyfile(isodir
+ "/ppc/ppc64/yaboot.conf",
1004 isodir
+ "/etc/yaboot.conf")
1006 self
.__write
_dualbits
_yaboot
_config
(isodir
,
1008 timeout
= self
._timeout
* 100)
1011 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
1014 class ppc64LiveImageCreator(ppcLiveImageCreator
):
1015 def _get_excluded_packages(self
):
1017 # while kernel.ppc and kernel.ppc64 co-exist,
1018 # we can't have both
1019 return ["kernel.ppc"] + \
1020 ppcLiveImageCreator
._get
_excluded
_packages
(self
)
1022 arch
= rpmUtils
.arch
.getBaseArch()
1023 if arch
in ("i386", "x86_64"):
1024 LiveImageCreator
= x86LiveImageCreator
1025 elif arch
in ("ppc",):
1026 LiveImageCreator
= ppcLiveImageCreator
1027 elif arch
in ("ppc64",):
1028 LiveImageCreator
= ppc64LiveImageCreator
1029 elif arch
.startswith('arm'):
1030 LiveImageCreator
= LiveImageCreatorBase
1033 raise CreatorError("Architecture not supported!")