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 ext4 xfs btrfs";
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
,
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
,
786 long = "Start " + self
.product
,
787 extra
= "", index
= index
)
789 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
790 liveargs
= kernel_options
,
791 long = "Test this media & start " + self
.product
,
792 extra
= "rd.live.check",
795 submenu 'Troubleshooting -->' {
797 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
798 liveargs
= kernel_options
,
799 long = "Start " + self
.product
+ " in basic graphics mode",
800 extra
= "nomodeset", index
= index
)
808 def _configure_efi_bootloader(self
, isodir
):
809 """Set up the configuration for an EFI bootloader"""
810 if self
.__copy
_efi
_files
(isodir
):
811 shutil
.rmtree(isodir
+ "/EFI")
812 logging
.warn("Failed to copy EFI files, no EFI Support will be included.")
815 cfg
= self
.__get
_basic
_efi
_config
(isolabel
= self
.fslabel
,
816 timeout
= self
._timeout
)
817 cfg
+= self
.__get
_efi
_image
_stanzas
(isodir
, self
.name
)
819 cfgf
= open(isodir
+ "/EFI/BOOT/grub.cfg", "w")
823 # first gen mactel machines get the bootloader name wrong apparently
824 if rpmUtils
.arch
.getBaseArch() == "i386":
825 os
.link(isodir
+ "/EFI/BOOT/BOOT%s.efi" % (self
.efiarch
),
826 isodir
+ "/EFI/BOOT/BOOT.efi")
829 def _configure_bootloader(self
, isodir
):
830 self
._configure
_syslinux
_bootloader
(isodir
)
831 self
._configure
_efi
_bootloader
(isodir
)
833 class ppcLiveImageCreator(LiveImageCreatorBase
):
834 def _get_mkisofs_options(self
, isodir
):
835 return [ "-hfs", "-no-desktop", "-part",
836 "-map", isodir
+ "/ppc/mapping",
837 "-hfs-bless", isodir
+ "/ppc/mac",
838 "-hfs-volid", self
.fslabel
]
840 def _get_required_packages(self
):
841 return ["yaboot"] + \
842 LiveImageCreatorBase
._get
_required
_packages
(self
)
844 def _get_excluded_packages(self
):
845 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
846 return ["memtest86+"] + \
847 LiveImageCreatorBase
._get
_excluded
_packages
(self
)
849 def __copy_boot_file(self
, destdir
, file):
850 for dir in ["/usr/share/ppc64-utils",
851 "/usr/lib/anaconda-runtime/boot"]:
852 path
= self
._instroot
+ dir + "/" + file
853 if not os
.path
.exists(path
):
857 shutil
.copy(path
, destdir
)
860 raise CreatorError("Unable to find boot file " + file)
862 def __kernel_bits(self
, kernel
):
863 testpath
= (self
._instroot
+ "/lib/modules/" +
864 kernel
+ "/kernel/arch/powerpc/platforms")
866 if not os
.path
.exists(testpath
):
867 return { "32" : True, "64" : False }
869 return { "32" : False, "64" : True }
871 def __copy_kernel_and_initramfs(self
, destdir
, version
):
873 bootdir
= self
._instroot
+ "/boot"
877 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
878 destdir
+ "/vmlinuz")
880 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
881 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
882 destdir
+ "/initrd.img")
885 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
886 destdir
+ "/initrd.img")
890 def __get_basic_yaboot_config(self
, **args
):
892 init-message = "Welcome to %(name)s"
896 def __get_image_stanza(self
, **args
):
898 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
900 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
903 image=/ppc/ppc%(bit)s/vmlinuz
905 initrd=/ppc/ppc%(bit)s/initrd.img
907 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
911 def __write_yaboot_config(self
, isodir
, bit
, isDracut
= False):
912 cfg
= self
.__get
_basic
_yaboot
_config
(name
= self
.name
,
913 timeout
= self
._timeout
* 100)
915 kernel_options
= self
._get
_kernel
_options
()
917 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
920 long = "Run from image",
923 liveargs
= kernel_options
,
926 if self
._has
_checkisomd
5():
927 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
929 short
= "rd.live.check",
930 long = "Verify and run from image",
931 extra
= "rd.live.check",
933 liveargs
= kernel_options
,
936 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
940 def __write_not_supported(self
, isodir
, bit
):
941 makedirs(isodir
+ "/ppc/ppc" + bit
)
943 message
= "Sorry, this LiveCD does not support your hardware"
945 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
946 f
.write('init-message = "' + message
+ '"')
950 def __write_dualbits_yaboot_config(isodir
, **args
):
952 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
956 image=/ppc/ppc64/vmlinuz
959 initrd=/ppc/ppc64/initrd.img
962 image=/ppc/ppc32/vmlinuz
964 initrd=/ppc/ppc32/initrd.img
968 f
= open(isodir
+ "/etc/yaboot.conf", "w")
972 def _configure_bootloader(self
, isodir
):
973 """configure the boot loader"""
974 havekernel
= { 32: False, 64: False }
976 self
.__copy
_boot
_file
(isodir
+ "/ppc", "mapping")
977 self
.__copy
_boot
_file
(isodir
+ "/ppc", "bootinfo.txt")
978 self
.__copy
_boot
_file
(isodir
+ "/ppc/mac", "ofboot.b")
980 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
981 isodir
+ "/ppc/mac/yaboot")
983 makedirs(isodir
+ "/ppc/chrp")
984 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
985 isodir
+ "/ppc/chrp/yaboot")
987 subprocess
.call(["/usr/sbin/addnote", isodir
+ "/ppc/chrp/yaboot"])
990 # FIXME: ppc should support multiple kernels too...
992 kernel
= self
._get
_kernel
_versions
().values()[0][0]
994 kernel_bits
= self
.__kernel
_bits
(kernel
)
996 for (bit
, present
) in kernel_bits
.items():
998 self
.__write
_not
_supported
(isodir
, bit
)
1001 isDracut
= self
.__copy
_kernel
_and
_initramfs
(isodir
+ "/ppc/ppc" + bit
, kernel
)
1002 self
.__write
_yaboot
_config
(isodir
, bit
, isDracut
)
1004 makedirs(isodir
+ "/etc")
1005 if kernel_bits
["32"] and not kernel_bits
["64"]:
1006 shutil
.copyfile(isodir
+ "/ppc/ppc32/yaboot.conf",
1007 isodir
+ "/etc/yaboot.conf")
1008 elif kernel_bits
["64"] and not kernel_bits
["32"]:
1009 shutil
.copyfile(isodir
+ "/ppc/ppc64/yaboot.conf",
1010 isodir
+ "/etc/yaboot.conf")
1012 self
.__write
_dualbits
_yaboot
_config
(isodir
,
1014 timeout
= self
._timeout
* 100)
1017 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
1020 class ppc64LiveImageCreator(ppcLiveImageCreator
):
1021 def _get_excluded_packages(self
):
1023 # while kernel.ppc and kernel.ppc64 co-exist,
1024 # we can't have both
1025 return ["kernel.ppc"] + \
1026 ppcLiveImageCreator
._get
_excluded
_packages
(self
)
1028 arch
= rpmUtils
.arch
.getBaseArch()
1029 if arch
in ("i386", "x86_64"):
1030 LiveImageCreator
= x86LiveImageCreator
1031 elif arch
in ("ppc",):
1032 LiveImageCreator
= ppcLiveImageCreator
1033 elif arch
in ("ppc64",):
1034 LiveImageCreator
= ppc64LiveImageCreator
1035 elif arch
.startswith('arm'):
1036 LiveImageCreator
= LiveImageCreatorBase
1039 raise CreatorError("Architecture not supported!")