2 # live.py : LiveImageCreator class for creating Live CD images
4 # Copyright 2007, 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.
27 from imgcreate
.errors
import *
28 from imgcreate
.fs
import *
29 from imgcreate
.creator
import *
31 class LiveImageCreatorBase(LoopImageCreator
):
32 """A base class for LiveCD image creators.
34 This class serves as a base class for the architecture-specific LiveCD
35 image creator subclass, LiveImageCreator.
37 LiveImageCreator creates a bootable ISO containing the system image,
38 bootloader, bootloader configuration, kernel and initramfs.
42 def __init__(self
, ks
, name
, fslabel
=None, releasever
=None, tmpdir
="/tmp",
43 title
="Linux", product
="Linux", useplugins
=False):
44 """Initialise a LiveImageCreator instance.
46 This method takes the same arguments as LoopImageCreator.__init__().
49 LoopImageCreator
.__init
__(self
, ks
, name
,
51 releasever
=releasever
,
53 useplugins
=useplugins
)
55 self
.compress_type
= "xz"
56 """mksquashfs compressor to use."""
58 self
.skip_compression
= False
59 """Controls whether to use squashfs to compress the image."""
61 self
.skip_minimize
= False
62 """Controls whether an image minimizing snapshot should be created.
64 This snapshot can be used when copying the system image from the ISO in
65 order to minimize the amount of data that needs to be copied; simply,
66 it makes it possible to create a version of the image's filesystem with
71 self
._timeout
= kickstart
.get_timeout(self
.ks
, 10)
72 """The bootloader timeout from kickstart."""
74 self
._default
_kernel
= kickstart
.get_default_kernel(self
.ks
, "kernel")
75 """The default kernel type from kickstart."""
79 self
.__modules
= ["=ata", "sym53c8xx", "aic7xxx", "=usb", "=firewire",
80 "=mmc", "=pcmcia", "mptsas", "udf", "virtio_blk",
82 self
.__modules
.extend(kickstart
.get_modules(self
.ks
))
84 self
._isofstype
= "iso9660"
88 self
.product
= product
91 # Hooks for subclasses
93 def _configure_bootloader(self
, isodir
):
94 """Create the architecture specific booloader configuration.
96 This is the hook where subclasses must create the booloader
97 configuration in order to allow a bootable ISO to be built.
99 isodir -- the directory where the contents of the ISO are to be staged
102 raise CreatorError("Bootloader configuration is arch-specific, "
103 "but not implemented for this arch!")
105 def _get_kernel_options(self
):
106 """Return a kernel options string for bootloader configuration.
108 This is the hook where subclasses may specify a set of kernel options
109 which should be included in the images bootloader configuration.
111 A sensible default implementation is provided.
114 r
= kickstart
.get_kernel_args(self
.ks
)
115 if os
.path
.exists(self
._instroot
+ "/usr/bin/rhgb"):
117 if os
.path
.exists(self
._instroot
+ "/usr/bin/plymouth"):
121 def _get_mkisofs_options(self
, isodir
):
122 """Return the architecture specific mkisosfs options.
124 This is the hook where subclasses may specify additional arguments to
125 mkisofs, e.g. to enable a bootable ISO to be built.
127 By default, an empty list is returned.
133 # Helpers for subclasses
135 def _has_checkisomd5(self
):
136 """Check whether checkisomd5 is available in the install root."""
137 def exists(instroot
, path
):
138 return os
.path
.exists(instroot
+ path
)
140 if (exists(self
._instroot
, "/usr/lib/anaconda-runtime/checkisomd5") or
141 exists(self
._instroot
, "/usr/bin/checkisomd5")):
147 # Actual implementation
149 def _base_on(self
, base_on
):
150 """helper function to extract ext3 file system from a live CD ISO"""
151 isoloop
= DiskMount(LoopbackDisk(base_on
, 0), self
._mkdtemp
())
155 except MountError
, e
:
156 raise CreatorError("Failed to loopback mount '%s' : %s" %
159 # Copy the initrd%d.img and xen%d.gz files over to /isolinux
160 # This is because the originals in /boot are removed when the
161 # original .iso was created.
162 src
= isoloop
.mountdir
+ "/isolinux/"
163 dest
= self
.__ensure
_isodir
() + "/isolinux/"
165 pattern
= re
.compile(r
"(initrd\d+\.img|xen\d+\.gz)")
166 files
= [f
for f
in os
.listdir(src
) if pattern
.search(f
)
167 and os
.path
.isfile(src
+f
)]
169 shutil
.copyfile(src
+f
, dest
+f
)
171 # legacy LiveOS filesystem layout support, remove for F9 or F10
172 if os
.path
.exists(isoloop
.mountdir
+ "/squashfs.img"):
173 squashimg
= isoloop
.mountdir
+ "/squashfs.img"
175 squashimg
= isoloop
.mountdir
+ "/LiveOS/squashfs.img"
177 squashloop
= DiskMount(LoopbackDisk(squashimg
, 0), self
._mkdtemp
(), "squashfs")
179 # 'self.compress_type = None' will force reading it from base_on.
180 if self
.compress_type
is None:
181 self
.compress_type
= squashfs_compression_type(squashimg
)
182 if self
.compress_type
== 'undetermined':
183 # Default to 'gzip' for compatibility with older versions.
184 self
.compress_type
= 'gzip'
186 if not squashloop
.disk
.exists():
187 raise CreatorError("'%s' is not a valid live CD ISO : "
188 "squashfs.img doesn't exist" % base_on
)
192 except MountError
, e
:
193 raise CreatorError("Failed to loopback mount squashfs.img "
194 "from '%s' : %s" % (base_on
, e
))
196 # legacy LiveOS filesystem layout support, remove for F9 or F10
197 if os
.path
.exists(squashloop
.mountdir
+ "/os.img"):
198 os_image
= squashloop
.mountdir
+ "/os.img"
200 os_image
= squashloop
.mountdir
+ "/LiveOS/ext3fs.img"
202 if not os
.path
.exists(os_image
):
203 raise CreatorError("'%s' is not a valid live CD ISO : neither "
204 "LiveOS/ext3fs.img nor os.img exist" %
208 shutil
.copyfile(os_image
, self
._image
)
210 raise CreatorError("Failed to copy base live image to %s for modification: %s" %(self
._image
, e
))
215 def _mount_instroot(self
, base_on
= None):
217 LoopImageCreator
._mount
_instroot
(self
, base_on
)
218 self
.__write
_initrd
_conf
(self
._instroot
+ "/etc/sysconfig/mkinitrd")
219 self
.__write
_dracut
_conf
(self
._instroot
+ "/etc/dracut.conf.d/02livecd.conf")
221 def _unmount_instroot(self
):
222 self
.__restore
_file
(self
._instroot
+ "/etc/sysconfig/mkinitrd")
223 self
.__restore
_file
(self
._instroot
+ "/etc/dracut.conf.d/02livecd.conf")
224 LoopImageCreator
._unmount
_instroot
(self
)
226 def __ensure_isodir(self
):
227 if self
.__isodir
is None:
228 self
.__isodir
= self
._mkdtemp
("iso-")
231 def _generate_efiboot(self
, isodir
):
232 """Generate EFI boot images."""
233 if not os
.path
.exists(self
._instroot
+ "/boot/efi/EFI/redhat/grub.efi"):
235 subprocess
.call(["mkefiboot", isodir
+ "/EFI/BOOT",
236 isodir
+ "/isolinux/efiboot.img"])
237 subprocess
.call(["mkefiboot", "-a", isodir
+ "/EFI/BOOT",
238 isodir
+ "/isolinux/macboot.img", "-l", self
.product
,
239 "-n", "/usr/share/pixmaps/bootloader/fedora-media.vol",
240 "-i", "/usr/share/pixmaps/bootloader/fedora.icns",
243 def _create_bootconfig(self
):
244 """Configure the image so that it's bootable."""
245 self
._configure
_bootloader
(self
.__ensure
_isodir
())
246 self
._generate
_efiboot
(self
.__ensure
_isodir
())
248 def _get_post_scripts_env(self
, in_chroot
):
249 env
= LoopImageCreator
._get
_post
_scripts
_env
(self
, in_chroot
)
252 env
["LIVE_ROOT"] = self
.__ensure
_isodir
()
256 def __extra_filesystems(self
):
257 return "squashfs ext4 ext3 ext2 vfat msdos ";
259 def __extra_drivers(self
):
260 retval
= "sr_mod sd_mod ide-cd cdrom "
261 for module
in self
.__modules
:
263 retval
= retval
+ "ehci_hcd uhci_hcd ohci_hcd "
264 retval
= retval
+ "usb_storage usbhid "
265 elif module
== "=firewire":
266 retval
= retval
+ "firewire-sbp2 firewire-ohci "
267 retval
= retval
+ "sbp2 ohci1394 ieee1394 "
268 elif module
== "=mmc":
269 retval
= retval
+ "mmc_block sdhci sdhci-pci "
270 elif module
== "=pcmcia":
271 retval
= retval
+ "pata_pcmcia "
273 retval
= retval
+ module
+ " "
276 def __restore_file(self
,path
):
281 if os
.path
.exists(path
+ '.rpmnew'):
282 os
.rename(path
+ '.rpmnew', path
)
284 def __write_initrd_conf(self
, path
):
285 if not os
.path
.exists(os
.path
.dirname(path
)):
286 makedirs(os
.path
.dirname(path
))
288 f
.write('LIVEOS="yes"\n')
289 f
.write('PROBE="no"\n')
290 f
.write('MODULES+="' + self
.__extra
_filesystems
() + '"\n')
291 f
.write('MODULES+="' + self
.__extra
_drivers
() + '"\n')
294 def __write_dracut_conf(self
, path
):
295 if not os
.path
.exists(os
.path
.dirname(path
)):
296 makedirs(os
.path
.dirname(path
))
298 f
.write('filesystems+="' + self
.__extra
_filesystems
() + ' "\n')
299 f
.write('drivers+="' + self
.__extra
_drivers
() + ' "\n')
300 f
.write('add_dracutmodules+=" dmsquash-live "')
303 def __create_iso(self
, isodir
):
304 iso
= self
._outdir
+ "/" + self
.name
+ ".iso"
306 args
= ["/usr/bin/mkisofs",
308 "-hide-rr-moved", "-hide-joliet-trans-tbl",
312 args
.extend(self
._get
_mkisofs
_options
(isodir
))
313 if self
._isofstype
== "udf":
314 args
.append("-allow-limited-size")
318 if subprocess
.call(args
) != 0:
319 raise CreatorError("ISO creation failed!")
321 if os
.path
.exists("/usr/bin/isohybrid"):
322 if os
.path
.exists(isodir
+ "/isolinux/efiboot.img"):
323 subprocess
.call(["/usr/bin/isohybrid", "-u", "-m", iso
])
325 subprocess
.call(["/usr/bin/isohybrid", iso
])
327 self
.__implant
_md
5sum
(iso
)
329 def __implant_md5sum(self
, iso
):
330 """Implant an isomd5sum."""
331 if os
.path
.exists("/usr/bin/implantisomd5"):
332 implantisomd5
= "/usr/bin/implantisomd5"
333 elif os
.path
.exists("/usr/lib/anaconda-runtime/implantisomd5"):
334 implantisomd5
= "/usr/lib/anaconda-runtime/implantisomd5"
336 logging
.warn("isomd5sum not installed; not setting up mediacheck")
339 subprocess
.call([implantisomd5
, iso
])
341 def _stage_final_image(self
):
343 makedirs(self
.__ensure
_isodir
() + "/LiveOS")
347 if not self
.skip_minimize
:
348 create_image_minimizer(self
.__isodir
+ "/LiveOS/osmin.img",
349 self
._image
, self
.compress_type
,
350 tmpdir
= self
.tmpdir
)
352 if self
.skip_compression
:
353 shutil
.move(self
._image
, self
.__isodir
+ "/LiveOS/ext3fs.img")
354 if os
.stat(self
.__isodir
+ "/LiveOS/ext3fs.img").st_size
>= 4*1024*1024*1024:
355 self
._isofstype
= "udf"
356 logging
.warn("Switching to UDF due to size of LiveOS/ext3fs.img")
358 makedirs(os
.path
.join(os
.path
.dirname(self
._image
), "LiveOS"))
359 shutil
.move(self
._image
,
360 os
.path
.join(os
.path
.dirname(self
._image
),
361 "LiveOS", "ext3fs.img"))
362 mksquashfs(os
.path
.dirname(self
._image
),
363 self
.__isodir
+ "/LiveOS/squashfs.img",
365 if os
.stat(self
.__isodir
+ "/LiveOS/squashfs.img").st_size
>= 4*1024*1024*1024:
366 self
._isofstype
= "udf"
367 logging
.warn("Switching to UDF due to size of LiveOS/squashfs.img")
370 self
.__create
_iso
(self
.__isodir
)
372 shutil
.rmtree(self
.__isodir
, ignore_errors
= True)
375 class x86LiveImageCreator(LiveImageCreatorBase
):
376 """ImageCreator for x86 machines"""
377 def _get_mkisofs_options(self
, isodir
):
378 options
= [ "-b", "isolinux/isolinux.bin",
379 "-c", "isolinux/boot.cat",
380 "-no-emul-boot", "-boot-info-table",
381 "-boot-load-size", "4" ]
382 if os
.path
.exists(isodir
+ "/isolinux/efiboot.img"):
383 options
.extend([ "-eltorito-alt-boot",
384 "-e", "isolinux/efiboot.img",
386 "-eltorito-alt-boot",
387 "-e", "isolinux/macboot.img",
391 def _get_required_packages(self
):
392 return ["syslinux"] + LiveImageCreatorBase
._get
_required
_packages
(self
)
394 def _get_isolinux_stanzas(self
, isodir
):
397 def __find_syslinux_menu(self
):
398 for menu
in ("vesamenu.c32", "menu.c32"):
399 for dir in ("/usr/lib/syslinux/", "/usr/share/syslinux/"):
400 if os
.path
.isfile(self
._instroot
+ dir + menu
):
403 raise CreatorError("syslinux not installed : "
404 "no suitable *menu.c32 found")
406 def __find_syslinux_mboot(self
):
408 # We only need the mboot module if we have any xen hypervisors
410 if not glob
.glob(self
._instroot
+ "/boot/xen.gz*"):
415 def __copy_syslinux_files(self
, isodir
, menu
, mboot
= None):
416 files
= ["isolinux.bin", menu
]
421 if os
.path
.exists(self
._instroot
+ "/usr/lib/syslinux/" + f
):
422 path
= self
._instroot
+ "/usr/lib/syslinux/" + f
423 elif os
.path
.exists(self
._instroot
+ "/usr/share/syslinux/" + f
):
424 path
= self
._instroot
+ "/usr/share/syslinux/" + f
425 if not os
.path
.isfile(path
):
426 raise CreatorError("syslinux not installed : "
427 "%s not found" % path
)
429 shutil
.copy(path
, isodir
+ "/isolinux/")
431 def __copy_syslinux_background(self
, isodest
):
432 background_path
= self
._instroot
+ \
433 "/usr/share/anaconda/boot/syslinux-vesa-splash.jpg"
435 if not os
.path
.exists(background_path
):
436 # fallback to F13 location
437 background_path
= self
._instroot
+ \
438 "/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg"
440 if not os
.path
.exists(background_path
):
443 shutil
.copyfile(background_path
, isodest
)
447 def __copy_kernel_and_initramfs(self
, isodir
, version
, index
):
448 bootdir
= self
._instroot
+ "/boot"
450 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
451 isodir
+ "/isolinux/vmlinuz" + index
)
454 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
455 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
456 isodir
+ "/isolinux/initrd" + index
+ ".img")
458 elif os
.path
.exists(bootdir
+ "/initrd-" + version
+ ".img"):
459 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
460 isodir
+ "/isolinux/initrd" + index
+ ".img")
461 elif not self
.base_on
:
462 logging
.error("No initrd or initramfs found for %s" % (version
,))
465 if os
.path
.exists(bootdir
+ "/xen.gz-" + version
[:-3]):
466 shutil
.copyfile(bootdir
+ "/xen.gz-" + version
[:-3],
467 isodir
+ "/isolinux/xen" + index
+ ".gz")
470 return (is_xen
, isDracut
)
472 def __is_default_kernel(self
, kernel
, kernels
):
473 if len(kernels
) == 1:
476 if kernel
== self
._default
_kernel
:
479 if kernel
.startswith("kernel-") and kernel
[7:] == self
._default
_kernel
:
484 def __get_basic_syslinux_config(self
, **args
):
488 menu background %(background)s
489 menu autoboot Starting %(title)s in # second{,s}. Press any key to interrupt.
500 menu color border * #00000000 #00000000 none
501 menu color sel 0 #ffffffff #00000000 none
502 menu color title 0 #ff7ba3d0 #00000000 none
503 menu color tabmsg 0 #ff3a6496 #00000000 none
504 menu color unsel 0 #84b8ffff #00000000 none
505 menu color hotsel 0 #84b8ffff #00000000 none
506 menu color hotkey 0 #ffffffff #00000000 none
507 menu color help 0 #ffffffff #00000000 none
508 menu color scrollbar 0 #ffffffff #ff355594 none
509 menu color timeout 0 #ffffffff #00000000 none
510 menu color timeout_msg 0 #ffffffff #00000000 none
511 menu color cmdmark 0 #84b8ffff #00000000 none
512 menu color cmdline 0 #ffffffff #00000000 none
514 menu tabmsg Press Tab for full configuration options on menu items.
518 def __get_image_stanza(self
, is_xen
, isDracut
, **args
):
520 args
["rootlabel"] = "live:CDLABEL=%(fslabel)s" % args
522 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
525 template
= """label %(short)s
527 kernel vmlinuz%(index)s
528 append initrd=initrd%(index)s.img root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s
531 template
= """label %(short)s
534 append xen%(index)s.gz --- vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s --- initrd%(index)s.img
537 template
+= """ text help
541 return template
% args
543 def __get_image_stanzas(self
, isodir
):
545 kernels
= self
._get
_kernel
_versions
()
546 for kernel
in kernels
:
547 for version
in kernels
[kernel
]:
548 versions
.append(version
)
550 kernel_options
= self
._get
_kernel
_options
()
552 checkisomd5
= self
._has
_checkisomd
5()
554 # Stanzas for insertion into the config template
560 for version
in versions
:
561 (is_xen
, isDracut
) = self
.__copy
_kernel
_and
_initramfs
(isodir
, version
, index
)
563 self
._isDracut
= isDracut
565 default
= self
.__is
_default
_kernel
(kernel
, kernels
)
569 elif kernel
.startswith("kernel-"):
570 long = "%s (%s)" % (self
.product
, kernel
[7:])
572 long = "%s (%s)" % (self
.product
, kernel
)
574 # tell dracut not to ask for LUKS passwords or activate mdraid sets
576 kern_opts
= kernel_options
+ " rd.luks=0 rd.md=0 rd.dm=0"
578 kern_opts
= kernel_options
580 linux
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
581 fslabel
= self
.fslabel
,
583 liveargs
= kern_opts
,
584 long = "^Start " + long,
585 short
= "linux" + index
,
591 linux
[-1] += " menu default\n"
593 basic
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
594 fslabel
= self
.fslabel
,
596 liveargs
= kern_opts
,
597 long = "Start " + long + " in ^basic graphics mode.",
598 short
= "basic" + index
,
599 extra
= "xdriver=vesa nomodeset",
600 help = "Try this option out if you're having trouble starting.",
604 check
.append(self
.__get
_image
_stanza
(is_xen
, isDracut
,
605 fslabel
= self
.fslabel
,
607 liveargs
= kern_opts
,
608 long = "^Test this media & start " + long,
609 short
= "check" + index
,
610 extra
= "rd.live.check",
616 index
= str(int(index
) + 1)
618 return (linux
, basic
, check
)
620 def __get_memtest_stanza(self
, isodir
):
621 memtest
= glob
.glob(self
._instroot
+ "/boot/memtest86*")
625 shutil
.copyfile(memtest
[0], isodir
+ "/isolinux/memtest")
627 return """label memtest
628 menu label Run a ^memory test.
630 If your system is having issues, an problem with your
631 system's memory may be the cause. Use this utility to
632 see if the memory is working correctly.
637 def __get_local_stanza(self
, isodir
):
638 return """label local
639 menu label Boot from ^local drive
643 def _configure_syslinux_bootloader(self
, isodir
):
644 """configure the boot loader"""
645 makedirs(isodir
+ "/isolinux")
647 menu
= self
.__find
_syslinux
_menu
()
649 self
.__copy
_syslinux
_files
(isodir
, menu
,
650 self
.__find
_syslinux
_mboot
())
653 if self
.__copy
_syslinux
_background
(isodir
+ "/isolinux/splash.jpg"):
654 background
= "splash.jpg"
656 cfg
= self
.__get
_basic
_syslinux
_config
(menu
= menu
,
657 background
= background
,
659 timeout
= self
._timeout
* 10)
660 cfg
+= "menu separator\n"
662 linux
, basic
, check
= self
.__get
_image
_stanzas
(isodir
)
663 # Add linux stanzas to main menu
666 cfg
+= "menu separator\n"
668 cfg
+= """menu begin ^Troubleshooting
669 menu title Troubleshooting
671 # Add basic video and check to submenu
672 for b
, c
in zip(basic
, check
):
677 cfg
+= self
.__get
_memtest
_stanza
(isodir
)
678 cfg
+= "menu separator\n"
680 cfg
+= self
.__get
_local
_stanza
(isodir
)
681 cfg
+= self
._get
_isolinux
_stanzas
(isodir
)
683 cfg
+= """menu separator
685 menu label Return to ^main menu.
689 cfgf
= open(isodir
+ "/isolinux/isolinux.cfg", "w")
693 def __copy_efi_files(self
, isodir
):
694 if not os
.path
.exists(self
._instroot
+ "/boot/efi/EFI/redhat/grub.efi"):
696 shutil
.copy(self
._instroot
+ "/boot/efi/EFI/redhat/grub.efi",
697 isodir
+ "/EFI/BOOT/grub.efi")
699 # Should exist, but if it doesn't we should fail
700 if os
.path
.exists(self
._instroot
+ "/boot/grub/splash.xpm.gz"):
701 shutil
.copy(self
._instroot
+ "/boot/grub/splash.xpm.gz",
702 isodir
+ "/EFI/BOOT/splash.xpm.gz")
706 def __get_basic_efi_config(self
, **args
):
709 splashimage=/EFI/BOOT/splash.xpm.gz
715 def __get_efi_image_stanza(self
, **args
):
717 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
719 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
720 return """title %(long)s
722 kernel /isolinux/vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s
723 initrd /isolinux/initrd%(index)s.img
726 def __get_efi_image_stanzas(self
, isodir
, name
):
727 # FIXME: this only supports one kernel right now...
729 kernel_options
= self
._get
_kernel
_options
()
730 checkisomd5
= self
._has
_checkisomd
5()
734 for index
in range(0, 9):
735 # we don't support xen kernels
736 if os
.path
.exists("%s/EFI/BOOT/xen%d.gz" %(isodir
, index
)):
738 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
740 liveargs
= kernel_options
,
742 extra
= "", index
= index
)
744 cfg
+= self
.__get
_efi
_image
_stanza
(fslabel
= self
.fslabel
,
746 liveargs
= kernel_options
,
747 long = "Verify and Boot " + name
,
748 extra
= "rd.live.check",
754 def _configure_efi_bootloader(self
, isodir
):
755 """Set up the configuration for an EFI bootloader"""
756 makedirs(isodir
+ "/EFI/BOOT")
758 if not self
.__copy
_efi
_files
(isodir
):
759 shutil
.rmtree(isodir
+ "/EFI")
762 cfg
= self
.__get
_basic
_efi
_config
(name
= self
.name
,
763 timeout
= self
._timeout
)
764 cfg
+= self
.__get
_efi
_image
_stanzas
(isodir
, self
.name
)
766 cfgf
= open(isodir
+ "/EFI/BOOT/grub.conf", "w")
770 # first gen mactel machines get the bootloader name wrong apparently
771 if rpmUtils
.arch
.getBaseArch() == "i386":
772 os
.link(isodir
+ "/EFI/BOOT/grub.efi", isodir
+ "/EFI/BOOT/BOOT.efi")
773 os
.link(isodir
+ "/EFI/BOOT/grub.conf", isodir
+ "/EFI/BOOT/BOOT.conf")
775 # for most things, we want them named boot$efiarch
776 efiarch
= {"i386": "IA32", "x86_64": "X64"}
777 efiname
= efiarch
[rpmUtils
.arch
.getBaseArch()]
778 os
.rename(isodir
+ "/EFI/BOOT/grub.efi", isodir
+ "/EFI/BOOT/BOOT%s.efi" %(efiname
,))
779 os
.link(isodir
+ "/EFI/BOOT/grub.conf", isodir
+ "/EFI/BOOT/BOOT%s.conf" %(efiname
,))
782 def _configure_bootloader(self
, isodir
):
783 self
._configure
_syslinux
_bootloader
(isodir
)
784 self
._configure
_efi
_bootloader
(isodir
)
786 class ppcLiveImageCreator(LiveImageCreatorBase
):
787 def _get_mkisofs_options(self
, isodir
):
788 return [ "-hfs", "-no-desktop", "-part",
789 "-map", isodir
+ "/ppc/mapping",
790 "-hfs-bless", isodir
+ "/ppc/mac",
791 "-hfs-volid", self
.fslabel
]
793 def _get_required_packages(self
):
794 return ["yaboot"] + \
795 LiveImageCreatorBase
._get
_required
_packages
(self
)
797 def _get_excluded_packages(self
):
798 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
799 return ["memtest86+"] + \
800 LiveImageCreatorBase
._get
_excluded
_packages
(self
)
802 def __copy_boot_file(self
, destdir
, file):
803 for dir in ["/usr/share/ppc64-utils",
804 "/usr/lib/anaconda-runtime/boot"]:
805 path
= self
._instroot
+ dir + "/" + file
806 if not os
.path
.exists(path
):
810 shutil
.copy(path
, destdir
)
813 raise CreatorError("Unable to find boot file " + file)
815 def __kernel_bits(self
, kernel
):
816 testpath
= (self
._instroot
+ "/lib/modules/" +
817 kernel
+ "/kernel/arch/powerpc/platforms")
819 if not os
.path
.exists(testpath
):
820 return { "32" : True, "64" : False }
822 return { "32" : False, "64" : True }
824 def __copy_kernel_and_initramfs(self
, destdir
, version
):
826 bootdir
= self
._instroot
+ "/boot"
830 shutil
.copyfile(bootdir
+ "/vmlinuz-" + version
,
831 destdir
+ "/vmlinuz")
833 if os
.path
.exists(bootdir
+ "/initramfs-" + version
+ ".img"):
834 shutil
.copyfile(bootdir
+ "/initramfs-" + version
+ ".img",
835 destdir
+ "/initrd.img")
838 shutil
.copyfile(bootdir
+ "/initrd-" + version
+ ".img",
839 destdir
+ "/initrd.img")
843 def __get_basic_yaboot_config(self
, **args
):
845 init-message = "Welcome to %(name)s"
849 def __get_image_stanza(self
, **args
):
851 args
["rootlabel"] = "live:LABEL=%(fslabel)s" % args
853 args
["rootlabel"] = "CDLABEL=%(fslabel)s" % args
856 image=/ppc/ppc%(bit)s/vmlinuz
858 initrd=/ppc/ppc%(bit)s/initrd.img
860 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
864 def __write_yaboot_config(self
, isodir
, bit
, isDracut
= False):
865 cfg
= self
.__get
_basic
_yaboot
_config
(name
= self
.name
,
866 timeout
= self
._timeout
* 100)
868 kernel_options
= self
._get
_kernel
_options
()
870 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
873 long = "Run from image",
876 liveargs
= kernel_options
,
879 if self
._has
_checkisomd
5():
880 cfg
+= self
.__get
_image
_stanza
(fslabel
= self
.fslabel
,
882 short
= "rd.live.check",
883 long = "Verify and run from image",
884 extra
= "rd.live.check",
886 liveargs
= kernel_options
,
889 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
893 def __write_not_supported(self
, isodir
, bit
):
894 makedirs(isodir
+ "/ppc/ppc" + bit
)
896 message
= "Sorry, this LiveCD does not support your hardware"
898 f
= open(isodir
+ "/ppc/ppc" + bit
+ "/yaboot.conf", "w")
899 f
.write('init-message = "' + message
+ '"')
903 def __write_dualbits_yaboot_config(isodir
, **args
):
905 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
909 image=/ppc/ppc64/vmlinuz
912 initrd=/ppc/ppc64/initrd.img
915 image=/ppc/ppc32/vmlinuz
917 initrd=/ppc/ppc32/initrd.img
921 f
= open(isodir
+ "/etc/yaboot.conf", "w")
925 def _configure_bootloader(self
, isodir
):
926 """configure the boot loader"""
927 havekernel
= { 32: False, 64: False }
929 self
.__copy
_boot
_file
(isodir
+ "/ppc", "mapping")
930 self
.__copy
_boot
_file
(isodir
+ "/ppc", "bootinfo.txt")
931 self
.__copy
_boot
_file
(isodir
+ "/ppc/mac", "ofboot.b")
933 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
934 isodir
+ "/ppc/mac/yaboot")
936 makedirs(isodir
+ "/ppc/chrp")
937 shutil
.copyfile(self
._instroot
+ "/usr/lib/yaboot/yaboot",
938 isodir
+ "/ppc/chrp/yaboot")
940 subprocess
.call(["/usr/sbin/addnote", isodir
+ "/ppc/chrp/yaboot"])
943 # FIXME: ppc should support multiple kernels too...
945 kernel
= self
._get
_kernel
_versions
().values()[0][0]
947 kernel_bits
= self
.__kernel
_bits
(kernel
)
949 for (bit
, present
) in kernel_bits
.items():
951 self
.__write
_not
_supported
(isodir
, bit
)
954 isDracut
= self
.__copy
_kernel
_and
_initramfs
(isodir
+ "/ppc/ppc" + bit
, kernel
)
955 self
.__write
_yaboot
_config
(isodir
, bit
, isDracut
)
957 makedirs(isodir
+ "/etc")
958 if kernel_bits
["32"] and not kernel_bits
["64"]:
959 shutil
.copyfile(isodir
+ "/ppc/ppc32/yaboot.conf",
960 isodir
+ "/etc/yaboot.conf")
961 elif kernel_bits
["64"] and not kernel_bits
["32"]:
962 shutil
.copyfile(isodir
+ "/ppc/ppc64/yaboot.conf",
963 isodir
+ "/etc/yaboot.conf")
965 self
.__write
_dualbits
_yaboot
_config
(isodir
,
967 timeout
= self
._timeout
* 100)
970 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
973 class ppc64LiveImageCreator(ppcLiveImageCreator
):
974 def _get_excluded_packages(self
):
976 # while kernel.ppc and kernel.ppc64 co-exist,
978 return ["kernel.ppc"] + \
979 ppcLiveImageCreator
._get
_excluded
_packages
(self
)
981 arch
= rpmUtils
.arch
.getBaseArch()
982 if arch
in ("i386", "x86_64"):
983 LiveImageCreator
= x86LiveImageCreator
984 elif arch
in ("ppc",):
985 LiveImageCreator
= ppcLiveImageCreator
986 elif arch
in ("ppc64",):
987 LiveImageCreator
= ppc64LiveImageCreator
988 elif arch
.startswith('arm'):
989 LiveImageCreator
= LiveImageCreatorBase
992 raise CreatorError("Architecture not supported!")