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",
85 "virtio_pci", "virtio_scsi", "virtio_net", "virtio_mmio",
86 "virtio_balloon", "virtio-rng"]
87 self
.__modules
.extend(kickstart
.get_modules(self
.ks
))
89 self
._isofstype
= "iso9660"
93 self
.product
= product
96 # Hooks for subclasses
98 def _configure_bootloader(self
, isodir
):
99 """Create the architecture specific booloader configuration.
101 This is the hook where subclasses must create the booloader
102 configuration in order to allow a bootable ISO to be built.
104 isodir -- the directory where the contents of the ISO are to be staged
107 raise CreatorError("Bootloader configuration is arch-specific, "
108 "but not implemented for this arch!")
110 def _get_kernel_options(self
):
111 """Return a kernel options string for bootloader configuration.
113 This is the hook where subclasses may specify a set of kernel options
114 which should be included in the images bootloader configuration.
116 A sensible default implementation is provided.
119 r
= kickstart
.get_kernel_args(self
.ks
)
120 if os
.path
.exists(self
._instroot
+ "/usr/bin/rhgb"):
122 if os
.path
.exists(self
._instroot
+ "/usr/bin/plymouth"):
126 def _get_mkisofs_options(self
, isodir
):
127 """Return the architecture specific mkisosfs options.
129 This is the hook where subclasses may specify additional arguments to
130 mkisofs, e.g. to enable a bootable ISO to be built.
132 By default, an empty list is returned.
138 # Helpers for subclasses
140 def _has_checkisomd5(self
):
141 """Check whether checkisomd5 is available in the install root."""
142 def exists(instroot
, path
):
143 return os
.path
.exists(instroot
+ path
)
145 if (exists(self
._instroot
, "/usr/lib/anaconda-runtime/checkisomd5") or
146 exists(self
._instroot
, "/usr/bin/checkisomd5")):
152 # Actual implementation
154 def _base_on(self
, base_on
):
155 """helper function to extract ext3 file system from a live CD ISO"""
156 isoloop
= DiskMount(LoopbackDisk(base_on
, 0), self
._mkdtemp
())
160 except MountError
, e
:
161 raise CreatorError("Failed to loopback mount '%s' : %s" %
164 # Copy the initrd%d.img and xen%d.gz files over to /isolinux
165 # This is because the originals in /boot are removed when the
166 # original .iso was created.
167 src
= isoloop
.mountdir
+ "/isolinux/"
168 dest
= self
.__ensure
_isodir
() + "/isolinux/"
170 pattern
= re
.compile(r
"(initrd\d+\.img|xen\d+\.gz)")
171 files
= [f
for f
in os
.listdir(src
) if pattern
.search(f
)
172 and os
.path
.isfile(src
+f
)]
174 shutil
.copyfile(src
+f
, dest
+f
)
176 # legacy LiveOS filesystem layout support, remove for F9 or F10
177 if os
.path
.exists(isoloop
.mountdir
+ "/squashfs.img"):
178 squashimg
= isoloop
.mountdir
+ "/squashfs.img"
180 squashimg
= isoloop
.mountdir
+ "/LiveOS/squashfs.img"
182 squashloop
= DiskMount(LoopbackDisk(squashimg
, 0), self
._mkdtemp
(), "squashfs")
184 # 'self.compress_type = None' will force reading it from base_on.
185 if self
.compress_type
is None:
186 self
.compress_type
= squashfs_compression_type(squashimg
)
187 if self
.compress_type
== 'undetermined':
188 # Default to 'gzip' for compatibility with older versions.
189 self
.compress_type
= 'gzip'
191 if not squashloop
.disk
.exists():
192 raise CreatorError("'%s' is not a valid live CD ISO : "
193 "squashfs.img doesn't exist" % base_on
)
197 except MountError
, e
:
198 raise CreatorError("Failed to loopback mount squashfs.img "
199 "from '%s' : %s" % (base_on
, e
))
201 # legacy LiveOS filesystem layout support, remove for F9 or F10
202 if os
.path
.exists(squashloop
.mountdir
+ "/os.img"):
203 os_image
= squashloop
.mountdir
+ "/os.img"
205 os_image
= squashloop
.mountdir
+ "/LiveOS/ext3fs.img"
207 if not os
.path
.exists(os_image
):
208 raise CreatorError("'%s' is not a valid live CD ISO : neither "
209 "LiveOS/ext3fs.img nor os.img exist" %
213 shutil
.copyfile(os_image
, self
._image
)
215 raise CreatorError("Failed to copy base live image to %s for modification: %s" %(self
._image
, e
))
220 def _mount_instroot(self
, base_on
= None):
222 LoopImageCreator
._mount
_instroot
(self
, base_on
)
223 self
.__write
_initrd
_conf
(self
._instroot
+ "/etc/sysconfig/mkinitrd")
224 self
.__write
_dracut
_conf
(self
._instroot
+ "/etc/dracut.conf.d/02livecd.conf")
226 def _unmount_instroot(self
):
227 self
.__restore
_file
(self
._instroot
+ "/etc/sysconfig/mkinitrd")
228 self
.__restore
_file
(self
._instroot
+ "/etc/dracut.conf.d/02livecd.conf")
229 LoopImageCreator
._unmount
_instroot
(self
)
231 def __ensure_isodir(self
):
232 if self
.__isodir
is None:
233 self
.__isodir
= self
._mkdtemp
("iso-")
236 def _generate_efiboot(self
, isodir
):
237 """Generate EFI boot images."""
238 if not glob
.glob(self
._instroot
+"/boot/efi/EFI/*/shim.efi"):
239 logging
.error("Missing shim.efi, skipping efiboot.img creation.")
242 # XXX-BCL: does this need --label?
243 subprocess
.call(["mkefiboot", isodir
+ "/EFI/BOOT",
244 isodir
+ "/isolinux/efiboot.img"])
245 subprocess
.call(["mkefiboot", "-a", isodir
+ "/EFI/BOOT",
246 isodir
+ "/isolinux/macboot.img", "-l", self
.product
,
247 "-n", "/usr/share/pixmaps/bootloader/fedora-media.vol",
248 "-i", "/usr/share/pixmaps/bootloader/fedora.icns",
251 def _create_bootconfig(self
):
252 """Configure the image so that it's bootable."""
253 self
._configure
_bootloader
(self
.__ensure
_isodir
())
254 self
._generate
_efiboot
(self
.__ensure
_isodir
())
256 def _get_post_scripts_env(self
, in_chroot
):
257 env
= LoopImageCreator
._get
_post
_scripts
_env
(self
, in_chroot
)
260 env
["LIVE_ROOT"] = self
.__ensure
_isodir
()
264 def __extra_filesystems(self
):
265 return "vfat msdos isofs ";
267 def __extra_drivers(self
):
268 retval
= "sr_mod sd_mod ide-cd cdrom "
269 for module
in self
.__modules
:
271 retval
= retval
+ "ehci_hcd uhci_hcd ohci_hcd "
272 retval
= retval
+ "usb_storage usbhid "
273 elif module
== "=firewire":
274 retval
= retval
+ "firewire-sbp2 firewire-ohci "
275 retval
= retval
+ "sbp2 ohci1394 ieee1394 "
276 elif module
== "=mmc":
277 retval
= retval
+ "mmc_block sdhci sdhci-pci "
278 elif module
== "=pcmcia":
279 retval
= retval
+ "pata_pcmcia "
281 retval
= retval
+ module
+ " "
284 def __restore_file(self
,path
):
289 if os
.path
.exists(path
+ '.rpmnew'):
290 os
.rename(path
+ '.rpmnew', path
)
292 def __write_initrd_conf(self
, path
):
293 if not os
.path
.exists(os
.path
.dirname(path
)):
294 makedirs(os
.path
.dirname(path
))
296 f
.write('LIVEOS="yes"\n')
297 f
.write('PROBE="no"\n')
298 f
.write('MODULES+="' + self
.__extra
_filesystems
() + '"\n')
299 f
.write('MODULES+="' + self
.__extra
_drivers
() + '"\n')
302 def __write_dracut_conf(self
, path
):
303 if not os
.path
.exists(os
.path
.dirname(path
)):
304 makedirs(os
.path
.dirname(path
))
306 f
.write('filesystems+="' + self
.__extra
_filesystems
() + ' "\n')
307 f
.write('drivers+="' + self
.__extra
_drivers
() + ' "\n')
308 f
.write('add_dracutmodules+=" dmsquash-live pollcdrom "\n')
309 f
.write('hostonly="no"\n')
310 f
.write('dracut_rescue_image="no"\n')
313 def __create_iso(self
, isodir
):
314 iso
= self
._outdir
+ "/" + self
.name
+ ".iso"
316 args
= ["/usr/bin/mkisofs",
318 "-hide-rr-moved", "-hide-joliet-trans-tbl",
322 args
.extend(self
._get
_mkisofs
_options
(isodir
))
323 if self
._isofstype
== "udf":
324 args
.append("-allow-limited-size")
328 if subprocess
.call(args
) != 0:
329 raise CreatorError("ISO creation failed!")
331 if os
.path
.exists("/usr/bin/isohybrid"):
332 if os
.path
.exists(isodir
+ "/isolinux/efiboot.img"):
333 subprocess
.call(["/usr/bin/isohybrid", "-u", "-m", iso
])
335 subprocess
.call(["/usr/bin/isohybrid", iso
])
337 self
.__implant
_md
5sum
(iso
)
339 def __implant_md5sum(self
, iso
):
340 """Implant an isomd5sum."""
341 if os
.path
.exists("/usr/bin/implantisomd5"):
342 implantisomd5
= "/usr/bin/implantisomd5"
343 elif os
.path
.exists("/usr/lib/anaconda-runtime/implantisomd5"):
344 implantisomd5
= "/usr/lib/anaconda-runtime/implantisomd5"
346 logging
.warn("isomd5sum not installed; not setting up mediacheck")
349 subprocess
.call([implantisomd5
, iso
])
351 def _stage_final_image(self
):
353 makedirs(self
.__ensure
_isodir
() + "/LiveOS")
357 if not self
.skip_minimize
:
358 create_image_minimizer(self
.__isodir
+ "/LiveOS/osmin.img",
359 self
._image
, self
.compress_type
,
360 tmpdir
= self
.tmpdir
)
362 if self
.skip_compression
:
363 shutil
.move(self
._image
, self
.__isodir
+ "/LiveOS/ext3fs.img")
364 if os
.stat(self
.__isodir
+ "/LiveOS/ext3fs.img").st_size
>= 4*1024*1024*1024:
365 self
._isofstype
= "udf"
366 logging
.warn("Switching to UDF due to size of LiveOS/ext3fs.img")
368 makedirs(os
.path
.join(os
.path
.dirname(self
._image
), "LiveOS"))
369 shutil
.move(self
._image
,
370 os
.path
.join(os
.path
.dirname(self
._image
),
371 "LiveOS", "ext3fs.img"))
372 mksquashfs(os
.path
.dirname(self
._image
),
373 self
.__isodir
+ "/LiveOS/squashfs.img",
375 if os
.stat(self
.__isodir
+ "/LiveOS/squashfs.img").st_size
>= 4*1024*1024*1024:
376 self
._isofstype
= "udf"
377 logging
.warn("Switching to UDF due to size of LiveOS/squashfs.img")
380 self
.__create
_iso
(self
.__isodir
)
382 shutil
.rmtree(self
.__isodir
, ignore_errors
= True)
385 class x86LiveImageCreator(LiveImageCreatorBase
):
386 """ImageCreator for x86 machines"""
387 def __init__(self
, *args
, **kwargs
):
388 LiveImageCreatorBase
.__init
__(self
, *args
, **kwargs
)
391 def _get_mkisofs_options(self
, isodir
):
392 options
= [ "-b", "isolinux/isolinux.bin",
393 "-c", "isolinux/boot.cat",
394 "-no-emul-boot", "-boot-info-table",
395 "-boot-load-size", "4" ]
396 if os
.path
.exists(isodir
+ "/isolinux/efiboot.img"):
397 options
.extend([ "-eltorito-alt-boot",
398 "-e", "isolinux/efiboot.img",
400 "-eltorito-alt-boot",
401 "-e", "isolinux/macboot.img",
405 def _get_required_packages(self
):
406 return ["syslinux"] \
407 + LiveImageCreatorBase
._get
_required
_packages
(self
)
409 def _get_isolinux_stanzas(self
, isodir
):
412 def __find_syslinux_menu(self
):
413 for menu
in ("vesamenu.c32", "menu.c32"):
414 for dir in ("/usr/lib/syslinux/", "/usr/share/syslinux/"):
415 if os
.path
.isfile(self
._instroot
+ dir + menu
):
418 raise CreatorError("syslinux not installed : "
419 "no suitable *menu.c32 found")
421 def __find_syslinux_mboot(self
):
423 # We only need the mboot module if we have any xen hypervisors
425 if not glob
.glob(self
._instroot
+ "/boot/xen.gz*"):
430 def __copy_syslinux_files(self
, isodir
, menu
, mboot
= None):
431 files
= ["isolinux.bin", menu
]
436 if os
.path
.exists(self
._instroot
+ "/usr/lib/syslinux/" + f
):
437 path
= self
._instroot
+ "/usr/lib/syslinux/" + f
438 elif os
.path
.exists(self
._instroot
+ "/usr/share/syslinux/" + f
):
439 path
= self
._instroot
+ "/usr/share/syslinux/" + f
440 if not os
.path
.isfile(path
):
441 raise CreatorError("syslinux not installed : "
442 "%s not found" % path
)
444 shutil
.copy(path
, isodir
+ "/isolinux/")
446 def __copy_syslinux_background(self
, isodest
):
447 background_path
= self
._instroot
+ \
448 "/usr/share/anaconda/boot/syslinux-vesa-splash.jpg"
450 if not os
.path
.exists(background_path
):
451 # fallback to F13 location
452 background_path
= self
._instroot
+ \
453 "/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg"
455 if not os
.path
.exists(background_path
):
458 shutil
.copyfile(background_path
, isodest
)
462 def __copy_kernel_and_initramfs(self
, isodir
, version
, index
):
463 bootdir
= self
._instroot
+ "/boot"
465 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
466 isodir
+ "/isolinux/vmlinuz" + index
)
469 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
470 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
471 isodir
+ "/isolinux/initrd" + index
+ ".img")
473 elif os
.path
.exists(bootdir
+ "/initrd-" + version
+ ".img"):
474 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
475 isodir
+ "/isolinux/initrd" + index
+ ".img")
476 elif not self
.base_on
:
477 logging
.error("No initrd or initramfs found for %s" % (version
,))
480 if os
.path
.exists(bootdir
+ "/xen.gz-" + version
[:-3]):
481 shutil
.copyfile(bootdir
+ "/xen.gz-" + version
[:-3],
482 isodir
+ "/isolinux/xen" + index
+ ".gz")
485 return (is_xen
, isDracut
)
487 def __is_default_kernel(self
, kernel
, kernels
):
488 if len(kernels
) == 1:
491 if kernel
== self
._default
_kernel
:
494 if kernel
.startswith("kernel-") and kernel
[7:] == self
._default
_kernel
:
499 def __get_basic_syslinux_config(self
, **args
):
503 menu background %(background)s
504 menu autoboot Starting %(title)s in # second{,s}. Press any key to interrupt.
515 menu color border * #00000000 #00000000 none
516 menu color sel 0 #ffffffff #00000000 none
517 menu color title 0 #ff7ba3d0 #00000000 none
518 menu color tabmsg 0 #ff3a6496 #00000000 none
519 menu color unsel 0 #84b8ffff #00000000 none
520 menu color hotsel 0 #84b8ffff #00000000 none
521 menu color hotkey 0 #ffffffff #00000000 none
522 menu color help 0 #ffffffff #00000000 none
523 menu color scrollbar 0 #ffffffff #ff355594 none
524 menu color timeout 0 #ffffffff #00000000 none
525 menu color timeout_msg 0 #ffffffff #00000000 none
526 menu color cmdmark 0 #84b8ffff #00000000 none
527 menu color cmdline 0 #ffffffff #00000000 none
529 menu tabmsg Press Tab for full configuration options on menu items.
533 def __get_image_stanza(self
, is_xen
, isDracut
, **args
):
535 args
["rootlabel"] = "live:CDLABEL=%(fslabel)s" % args
537 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
540 template
= """label %(short)s
542 kernel vmlinuz%(index)s
543 append initrd=initrd%(index)s.img root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s
546 template
= """label %(short)s
549 append xen%(index)s.gz --- vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s --- initrd%(index)s.img
552 template
+= """ text help
556 return template
% args
558 def __get_image_stanzas(self
, isodir
):
559 kernels
= self
._get
_kernel
_versions
()
560 kernel_options
= self
._get
_kernel
_options
()
561 checkisomd5
= self
._has
_checkisomd
5()
563 # Stanzas for insertion into the config template
569 for kernel
, version
in ((k
,v
) for k
in kernels
for v
in kernels
[k
]):
570 (is_xen
, isDracut
) = self
.__copy
_kernel
_and
_initramfs
(isodir
, version
, index
)
572 self
._isDracut
= isDracut
574 default
= self
.__is
_default
_kernel
(kernel
, kernels
)
578 elif kernel
.startswith("kernel-"):
579 long = "%s (%s)" % (self
.product
, kernel
[7:])
581 long = "%s (%s)" % (self
.product
, kernel
)
583 # tell dracut not to ask for LUKS passwords or activate mdraid sets
585 kern_opts
= kernel_options
+ " rd.luks=0 rd.md=0 rd.dm=0"
587 kern_opts
= kernel_options
589 linux
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
590 fslabel
= self
.fslabel
,
592 liveargs
= kern_opts
,
593 long = "^Start " + long,
594 short
= "linux" + index
,
600 linux
[-1] += " menu default\n"
602 basic
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
603 fslabel
= self
.fslabel
,
605 liveargs
= kern_opts
,
606 long = "Start " + long + " in ^basic graphics mode.",
607 short
= "basic" + index
,
608 extra
= "xdriver=vesa nomodeset",
609 help = "Try this option out if you're having trouble starting.",
613 check
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
614 fslabel
= self
.fslabel
,
616 liveargs
= kern_opts
,
617 long = "^Test this media & start " + long,
618 short
= "check" + index
,
619 extra
= "rd.live.check",
625 index
= str(int(index
) + 1)
627 return (linux
, basic
, check
)
629 def __get_memtest_stanza(self
, isodir
):
630 memtest
= glob
.glob(self
._instroot
+ "/boot/memtest86*")
634 shutil
.copyfile(memtest
[0], isodir
+ "/isolinux/memtest")
636 return """label memtest
637 menu label Run a ^memory test.
639 If your system is having issues, an problem with your
640 system's memory may be the cause. Use this utility to
641 see if the memory is working correctly.
646 def __get_local_stanza(self
, isodir
):
647 return """label local
648 menu label Boot from ^local drive
652 def _configure_syslinux_bootloader(self
, isodir
):
653 """configure the boot loader"""
654 makedirs(isodir
+ "/isolinux")
656 menu
= self
.__find
_syslinux
_menu
()
658 self
.__copy
_syslinux
_files
(isodir
, menu
,
659 self
.__find
_syslinux
_mboot
())
662 if self
.__copy
_syslinux
_background
(isodir
+ "/isolinux/splash.jpg"):
663 background
= "splash.jpg"
665 cfg
= self
.__get
_basic
_syslinux
_config
(menu
= menu
,
666 background
= background
,
668 timeout
= self
._timeout
* 10)
669 cfg
+= "menu separator\n"
671 linux
, basic
, check
= self
.__get
_image
_stanzas
(isodir
)
672 # Add linux stanzas to main menu
675 cfg
+= "menu separator\n"
677 cfg
+= """menu begin ^Troubleshooting
678 menu title Troubleshooting
680 # Add basic video and check to submenu
681 for b
, c
in zip(basic
, check
):
686 cfg
+= self
.__get
_memtest
_stanza
(isodir
)
687 cfg
+= "menu separator\n"
689 cfg
+= self
.__get
_local
_stanza
(isodir
)
690 cfg
+= self
._get
_isolinux
_stanzas
(isodir
)
692 cfg
+= """menu separator
694 menu label Return to ^main menu.
698 cfgf
= open(isodir
+ "/isolinux/isolinux.cfg", "w")
704 if not self
._efiarch
:
705 # for most things, we want them named boot$efiarch
706 efiarch
= {"i386": "IA32", "x86_64": "X64"}
707 self
._efiarch
= efiarch
[rpmUtils
.arch
.getBaseArch()]
710 def __copy_efi_files(self
, isodir
):
711 """ Copy the efi files into /EFI/BOOT/
712 If any of them are missing, return False.
720 files
= [("/boot/efi/EFI/*/shim.efi", "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
,)),
721 ("/boot/efi/EFI/*/gcdx64.efi", "/EFI/BOOT/grubx64.efi"),
722 ("/boot/efi/EFI/*/fonts/unicode.pf2", "/EFI/BOOT/fonts/"),
724 makedirs(isodir
+"/EFI/BOOT/fonts/")
725 for src
, dest
in files
:
726 src_glob
= glob
.glob(self
._instroot
+src
)
728 missing
.append("Missing EFI file (%s)" % (src
,))
731 shutil
.copy(src_glob
[0], isodir
+dest
)
732 map(logging
.error
, missing
)
735 def __get_basic_efi_config(self
, **args
):
739 function load_video {
753 set timeout=%(timeout)d
754 ### END /etc/grub.d/00_header ###
756 search --no-floppy --set=root -l '%(isolabel)s'
758 ### BEGIN /etc/grub.d/10_linux ###
761 def __get_efi_image_stanza(self
, **args
):
763 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
765 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
766 return """menuentry '%(long)s' --class fedora --class gnu-linux --class gnu --class os {
767 linuxefi /isolinux/vmlinuz%(index)s root=%(rootlabel)s %(liveargs)s %(extra)s
768 initrdefi /isolinux/initrd%(index)s.img
772 def __get_efi_image_stanzas(self
, isodir
, name
):
773 # FIXME: this only supports one kernel right now...
775 kernel_options
= self
._get
_kernel
_options
()
776 checkisomd5
= self
._has
_checkisomd
5()
780 for index
in range(0, 9):
781 # we don't support xen kernels
782 if os
.path
.exists("%s/EFI/BOOT/xen%d.gz" %(isodir
, index
)):
784 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
785 liveargs
= kernel_options
,
787 extra
= "", index
= index
)
789 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
790 liveargs
= kernel_options
,
791 long = "Verify and Boot " + name
,
792 extra
= "rd.live.check",
798 def _configure_efi_bootloader(self
, isodir
):
799 """Set up the configuration for an EFI bootloader"""
800 if self
.__copy
_efi
_files
(isodir
):
801 shutil
.rmtree(isodir
+ "/EFI")
802 logging
.warn("Failed to copy EFI files, no EFI Support will be included.")
805 cfg
= self
.__get
_basic
_efi
_config
(isolabel
= self
.fslabel
,
806 timeout
= self
._timeout
)
807 cfg
+= self
.__get
_efi
_image
_stanzas
(isodir
, self
.name
)
809 cfgf
= open(isodir
+ "/EFI/BOOT/grub.cfg", "w")
813 # first gen mactel machines get the bootloader name wrong apparently
814 if rpmUtils
.arch
.getBaseArch() == "i386":
815 os
.link(isodir
+ "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
),
816 isodir
+ "/EFI/BOOT/BOOT.efi")
819 def _configure_bootloader(self
, isodir
):
820 self
._configure
_syslinux
_bootloader
(isodir
)
821 self
._configure
_efi
_bootloader
(isodir
)
823 class ppcLiveImageCreator(LiveImageCreatorBase
):
824 def _get_mkisofs_options(self
, isodir
):
825 return [ "-hfs", "-no-desktop", "-part",
826 "-map", isodir
+ "/ppc/mapping",
827 "-hfs-bless", isodir
+ "/ppc/mac",
828 "-hfs-volid", self
.fslabel
]
830 def _get_required_packages(self
):
831 return ["yaboot"] + \
832 LiveImageCreatorBase
._get
_required
_packages
(self
)
834 def _get_excluded_packages(self
):
835 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
836 return ["memtest86+"] + \
837 LiveImageCreatorBase
._get
_excluded
_packages
(self
)
839 def __copy_boot_file(self
, destdir
, file):
840 for dir in ["/usr/share/ppc64-utils",
841 "/usr/lib/anaconda-runtime/boot"]:
842 path
= self
._instroot
+ dir + "/" + file
843 if not os
.path
.exists(path
):
847 shutil
.copy(path
, destdir
)
850 raise CreatorError("Unable to find boot file " + file)
852 def __kernel_bits(self
, kernel
):
853 testpath
= (self
._instroot
+ "/lib/modules/" +
854 kernel
+ "/kernel/arch/powerpc/platforms")
856 if not os
.path
.exists(testpath
):
857 return { "32" : True, "64" : False }
859 return { "32" : False, "64" : True }
861 def __copy_kernel_and_initramfs(self
, destdir
, version
):
863 bootdir
= self
._instroot
+ "/boot"
867 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
868 destdir
+ "/vmlinuz")
870 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
871 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
872 destdir
+ "/initrd.img")
875 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
876 destdir
+ "/initrd.img")
880 def __get_basic_yaboot_config(self
, **args
):
882 init-message = "Welcome to %(name)s"
886 def __get_image_stanza(self
, **args
):
888 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
890 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
893 image=/ppc/ppc%(bit)s/vmlinuz
895 initrd=/ppc/ppc%(bit)s/initrd.img
897 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
901 def __write_yaboot_config(self
, isodir
, bit
, isDracut
= False):
902 cfg
= self
.__get
_basic
_yaboot
_config
(name
= self
.name
,
903 timeout
= self
._timeout
* 100)
905 kernel_options
= self
._get
_kernel
_options
()
907 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
910 long = "Run from image",
913 liveargs
= kernel_options
,
916 if self
._has
_checkisomd
5():
917 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
919 short
= "rd.live.check",
920 long = "Verify and run from image",
921 extra
= "rd.live.check",
923 liveargs
= kernel_options
,
926 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
930 def __write_not_supported(self
, isodir
, bit
):
931 makedirs(isodir
+ "/ppc/ppc" + bit
)
933 message
= "Sorry, this LiveCD does not support your hardware"
935 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
936 f
.write('init-message = "' + message
+ '"')
940 def __write_dualbits_yaboot_config(isodir
, **args
):
942 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
946 image=/ppc/ppc64/vmlinuz
949 initrd=/ppc/ppc64/initrd.img
952 image=/ppc/ppc32/vmlinuz
954 initrd=/ppc/ppc32/initrd.img
958 f
= open(isodir
+ "/etc/yaboot.conf", "w")
962 def _configure_bootloader(self
, isodir
):
963 """configure the boot loader"""
964 havekernel
= { 32: False, 64: False }
966 self
.__copy
_boot
_file
(isodir
+ "/ppc", "mapping")
967 self
.__copy
_boot
_file
(isodir
+ "/ppc", "bootinfo.txt")
968 self
.__copy
_boot
_file
(isodir
+ "/ppc/mac", "ofboot.b")
970 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
971 isodir
+ "/ppc/mac/yaboot")
973 makedirs(isodir
+ "/ppc/chrp")
974 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
975 isodir
+ "/ppc/chrp/yaboot")
977 subprocess
.call(["/usr/sbin/addnote", isodir
+ "/ppc/chrp/yaboot"])
980 # FIXME: ppc should support multiple kernels too...
982 kernel
= self
._get
_kernel
_versions
().values()[0][0]
984 kernel_bits
= self
.__kernel
_bits
(kernel
)
986 for (bit
, present
) in kernel_bits
.items():
988 self
.__write
_not
_supported
(isodir
, bit
)
991 isDracut
= self
.__copy
_kernel
_and
_initramfs
(isodir
+ "/ppc/ppc" + bit
, kernel
)
992 self
.__write
_yaboot
_config
(isodir
, bit
, isDracut
)
994 makedirs(isodir
+ "/etc")
995 if kernel_bits
["32"] and not kernel_bits
["64"]:
996 shutil
.copyfile(isodir
+ "/ppc/ppc32/yaboot.conf",
997 isodir
+ "/etc/yaboot.conf")
998 elif kernel_bits
["64"] and not kernel_bits
["32"]:
999 shutil
.copyfile(isodir
+ "/ppc/ppc64/yaboot.conf",
1000 isodir
+ "/etc/yaboot.conf")
1002 self
.__write
_dualbits
_yaboot
_config
(isodir
,
1004 timeout
= self
._timeout
* 100)
1007 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
1010 class ppc64LiveImageCreator(ppcLiveImageCreator
):
1011 def _get_excluded_packages(self
):
1013 # while kernel.ppc and kernel.ppc64 co-exist,
1014 # we can't have both
1015 return ["kernel.ppc"] + \
1016 ppcLiveImageCreator
._get
_excluded
_packages
(self
)
1018 arch
= rpmUtils
.arch
.getBaseArch()
1019 if arch
in ("i386", "x86_64"):
1020 LiveImageCreator
= x86LiveImageCreator
1021 elif arch
in ("ppc",):
1022 LiveImageCreator
= ppcLiveImageCreator
1023 elif arch
in ("ppc64",):
1024 LiveImageCreator
= ppc64LiveImageCreator
1025 elif arch
.startswith('arm'):
1026 LiveImageCreator
= LiveImageCreatorBase
1029 raise CreatorError("Architecture not supported!")