Revise basic video change to fix issue with default menu item
[livecd.git] / imgcreate / live.py
blobe4e0c2e7d14f815669fe0b7ee59ede600a2a5e4b
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.
19 import os
20 import os.path
21 import glob
22 import shutil
23 import subprocess
24 import logging
26 from imgcreate.errors import *
27 from imgcreate.fs import *
28 from imgcreate.creator import *
30 class LiveImageCreatorBase(LoopImageCreator):
31 """A base class for LiveCD image creators.
33 This class serves as a base class for the architecture-specific LiveCD
34 image creator subclass, LiveImageCreator.
36 LiveImageCreator creates a bootable ISO containing the system image,
37 bootloader, bootloader configuration, kernel and initramfs.
39 """
41 def __init__(self, *args):
42 """Initialise a LiveImageCreator instance.
44 This method takes the same arguments as ImageCreator.__init__().
46 """
47 LoopImageCreator.__init__(self, *args)
49 self.compress_type = "gzip"
50 """mksquashfs compressor to use."""
52 self.skip_compression = False
53 """Controls whether to use squashfs to compress the image."""
55 self.skip_minimize = False
56 """Controls whether an image minimizing snapshot should be created.
58 This snapshot can be used when copying the system image from the ISO in
59 order to minimize the amount of data that needs to be copied; simply,
60 it makes it possible to create a version of the image's filesystem with
61 no spare space.
63 """
65 self._timeout = kickstart.get_timeout(self.ks, 10)
66 """The bootloader timeout from kickstart."""
68 self._default_kernel = kickstart.get_default_kernel(self.ks, "kernel")
69 """The default kernel type from kickstart."""
71 self.__isodir = None
73 self.__modules = ["=ata", "sym53c8xx", "aic7xxx", "=usb", "=firewire", "=mmc", "=pcmcia", "mptsas", "udf"]
74 self.__modules.extend(kickstart.get_modules(self.ks))
76 self._isofstype = "iso9660"
79 # Hooks for subclasses
81 def _configure_bootloader(self, isodir):
82 """Create the architecture specific booloader configuration.
84 This is the hook where subclasses must create the booloader
85 configuration in order to allow a bootable ISO to be built.
87 isodir -- the directory where the contents of the ISO are to be staged
89 """
90 raise CreatorError("Bootloader configuration is arch-specific, "
91 "but not implemented for this arch!")
93 def _get_kernel_options(self):
94 """Return a kernel options string for bootloader configuration.
96 This is the hook where subclasses may specify a set of kernel options
97 which should be included in the images bootloader configuration.
99 A sensible default implementation is provided.
102 r = kickstart.get_kernel_args(self.ks)
103 if os.path.exists(self._instroot + "/usr/bin/rhgb"):
104 r += " rhgb"
105 if os.path.exists(self._instroot + "/usr/bin/plymouth"):
106 r += " rhgb"
107 return r
109 def _get_mkisofs_options(self, isodir):
110 """Return the architecture specific mkisosfs options.
112 This is the hook where subclasses may specify additional arguments to
113 mkisofs, e.g. to enable a bootable ISO to be built.
115 By default, an empty list is returned.
118 return []
121 # Helpers for subclasses
123 def _has_checkisomd5(self):
124 """Check whether checkisomd5 is available in the install root."""
125 def exists(instroot, path):
126 return os.path.exists(instroot + path)
128 if (exists(self._instroot, "/usr/lib/anaconda-runtime/checkisomd5") or
129 exists(self._instroot, "/usr/bin/checkisomd5")):
130 return True
132 return False
135 # Actual implementation
137 def _base_on(self, base_on):
138 """helper function to extract ext3 file system from a live CD ISO"""
139 isoloop = DiskMount(LoopbackDisk(base_on, 0), self._mkdtemp())
141 try:
142 isoloop.mount()
143 except MountError, e:
144 raise CreatorError("Failed to loopback mount '%s' : %s" %
145 (base_on, e))
147 # legacy LiveOS filesystem layout support, remove for F9 or F10
148 if os.path.exists(isoloop.mountdir + "/squashfs.img"):
149 squashimg = isoloop.mountdir + "/squashfs.img"
150 else:
151 squashimg = isoloop.mountdir + "/LiveOS/squashfs.img"
153 squashloop = DiskMount(LoopbackDisk(squashimg, 0), self._mkdtemp(), "squashfs")
155 try:
156 if not squashloop.disk.exists():
157 raise CreatorError("'%s' is not a valid live CD ISO : "
158 "squashfs.img doesn't exist" % base_on)
160 try:
161 squashloop.mount()
162 except MountError, e:
163 raise CreatorError("Failed to loopback mount squashfs.img "
164 "from '%s' : %s" % (base_on, e))
166 # legacy LiveOS filesystem layout support, remove for F9 or F10
167 if os.path.exists(squashloop.mountdir + "/os.img"):
168 os_image = squashloop.mountdir + "/os.img"
169 else:
170 os_image = squashloop.mountdir + "/LiveOS/ext3fs.img"
172 if not os.path.exists(os_image):
173 raise CreatorError("'%s' is not a valid live CD ISO : neither "
174 "LiveOS/ext3fs.img nor os.img exist" %
175 base_on)
177 try:
178 shutil.copyfile(os_image, self._image)
179 except IOError, e:
180 raise CreatorError("Failed to copy base live image to %s for modification: %s" %(self._image, e))
181 finally:
182 squashloop.cleanup()
183 isoloop.cleanup()
185 def _mount_instroot(self, base_on = None):
186 LoopImageCreator._mount_instroot(self, base_on)
187 self.__write_initrd_conf(self._instroot + "/etc/sysconfig/mkinitrd")
188 self.__write_dracut_conf(self._instroot + "/etc/dracut.conf")
190 def _unmount_instroot(self):
191 self.__restore_file(self._instroot + "/etc/sysconfig/mkinitrd")
192 self.__restore_file(self._instroot + "/etc/dracut.conf")
193 LoopImageCreator._unmount_instroot(self)
195 def __ensure_isodir(self):
196 if self.__isodir is None:
197 self.__isodir = self._mkdtemp("iso-")
198 return self.__isodir
200 def _create_bootconfig(self):
201 """Configure the image so that it's bootable."""
202 self._configure_bootloader(self.__ensure_isodir())
204 def _get_post_scripts_env(self, in_chroot):
205 env = LoopImageCreator._get_post_scripts_env(self, in_chroot)
207 if not in_chroot:
208 env["LIVE_ROOT"] = self.__ensure_isodir()
210 return env
212 def __extra_filesystems(self):
213 return "squashfs ext4 ext3 ext2 vfat msdos ";
215 def __extra_drivers(self):
216 retval = "sr_mod sd_mod ide-cd cdrom "
217 for module in self.__modules:
218 if module == "=usb":
219 retval = retval + "ehci_hcd uhci_hcd ohci_hcd "
220 retval = retval + "usb_storage usbhid "
221 elif module == "=firewire":
222 retval = retval + "firewire-sbp2 firewire-ohci "
223 retval = retval + "sbp2 ohci1394 ieee1394 "
224 elif module == "=mmc":
225 retval = retval + "mmc_block sdhci sdhci-pci "
226 elif module == "=pcmcia":
227 retval = retval + "pata_pcmcia "
228 else:
229 retval = retval + module + " "
230 return retval
232 def __restore_file(self,path):
233 try:
234 os.unlink(path)
235 except:
236 pass
237 if os.path.exists(path + '.rpmnew'):
238 os.rename(path + '.rpmnew', path)
240 def __write_initrd_conf(self, path):
241 if not os.path.exists(os.path.dirname(path)):
242 makedirs(os.path.dirname(path))
243 f = open(path, "a")
244 f.write('LIVEOS="yes"\n')
245 f.write('PROBE="no"\n')
246 f.write('MODULES+="' + self.__extra_filesystems() + '"\n')
247 f.write('MODULES+="' + self.__extra_drivers() + '"\n')
248 f.close()
250 def __write_dracut_conf(self, path):
251 if not os.path.exists(os.path.dirname(path)):
252 makedirs(os.path.dirname(path))
253 f = open(path, "a")
254 f.write('filesystems+="' + self.__extra_filesystems() + ' "\n')
255 f.write('drivers+="' + self.__extra_drivers() + ' "\n')
256 f.close()
258 def __create_iso(self, isodir):
259 iso = self._outdir + "/" + self.name + ".iso"
261 args = ["/usr/bin/mkisofs",
262 "-J", "-r",
263 "-hide-rr-moved", "-hide-joliet-trans-tbl",
264 "-V", self.fslabel,
265 "-o", iso]
267 args.extend(self._get_mkisofs_options(isodir))
268 if self._isofstype == "udf":
269 args.append("-allow-limited-size")
271 args.append(isodir)
273 if subprocess.call(args) != 0:
274 raise CreatorError("ISO creation failed!")
276 if os.path.exists("/usr/bin/isohybrid"):
277 subprocess.call(["/usr/bin/isohybrid", iso])
279 self.__implant_md5sum(iso)
281 def __implant_md5sum(self, iso):
282 """Implant an isomd5sum."""
283 if os.path.exists("/usr/bin/implantisomd5"):
284 implantisomd5 = "/usr/bin/implantisomd5"
285 elif os.path.exists("/usr/lib/anaconda-runtime/implantisomd5"):
286 implantisomd5 = "/usr/lib/anaconda-runtime/implantisomd5"
287 else:
288 logging.warn("isomd5sum not installed; not setting up mediacheck")
289 return
291 subprocess.call([implantisomd5, iso])
293 def _stage_final_image(self):
294 try:
295 makedirs(self.__ensure_isodir() + "/LiveOS")
297 self._resparse()
299 if not self.skip_minimize:
300 create_image_minimizer(self.__isodir + "/LiveOS/osmin.img", self._image, self.compress_type)
302 if self.skip_compression:
303 shutil.move(self._image, self.__isodir + "/LiveOS/ext3fs.img")
304 if os.stat(self.__isodir + "/LiveOS/ext3fs.img").st_size >= 4*1024*1024*1024:
305 self._isofstype = "udf"
306 logging.warn("Switching to UDF due to size of LiveOS/ext3fs.img")
307 else:
308 makedirs(os.path.join(os.path.dirname(self._image), "LiveOS"))
309 shutil.move(self._image,
310 os.path.join(os.path.dirname(self._image),
311 "LiveOS", "ext3fs.img"))
312 mksquashfs(os.path.dirname(self._image),
313 self.__isodir + "/LiveOS/squashfs.img",
314 self.compress_type)
315 if os.stat(self.__isodir + "/LiveOS/squashfs.img").st_size >= 4*1024*1024*1024:
316 self._isofstype = "udf"
317 logging.warn("Switching to UDF due to size of LiveOS/squashfs.img")
320 self.__create_iso(self.__isodir)
321 finally:
322 shutil.rmtree(self.__isodir, ignore_errors = True)
323 self.__isodir = None
325 class x86LiveImageCreator(LiveImageCreatorBase):
326 """ImageCreator for x86 machines"""
327 def _get_mkisofs_options(self, isodir):
328 return [ "-b", "isolinux/isolinux.bin",
329 "-c", "isolinux/boot.cat",
330 "-no-emul-boot", "-boot-info-table",
331 "-boot-load-size", "4" ]
333 def _get_required_packages(self):
334 return ["syslinux"] + LiveImageCreatorBase._get_required_packages(self)
336 def _get_isolinux_stanzas(self, isodir):
337 return ""
339 def __find_syslinux_menu(self):
340 for menu in ("vesamenu.c32", "menu.c32"):
341 for dir in ("/usr/lib/syslinux/", "/usr/share/syslinux/"):
342 if os.path.isfile(self._instroot + dir + menu):
343 return menu
345 raise CreatorError("syslinux not installed : "
346 "no suitable *menu.c32 found")
348 def __find_syslinux_mboot(self):
350 # We only need the mboot module if we have any xen hypervisors
352 if not glob.glob(self._instroot + "/boot/xen.gz*"):
353 return None
355 return "mboot.c32"
357 def __copy_syslinux_files(self, isodir, menu, mboot = None):
358 files = ["isolinux.bin", menu]
359 if mboot:
360 files += [mboot]
362 for f in files:
363 if os.path.exists(self._instroot + "/usr/lib/syslinux/" + f):
364 path = self._instroot + "/usr/lib/syslinux/" + f
365 elif os.path.exists(self._instroot + "/usr/share/syslinux/" + f):
366 path = self._instroot + "/usr/share/syslinux/" + f
367 if not os.path.isfile(path):
368 raise CreatorError("syslinux not installed : "
369 "%s not found" % path)
371 shutil.copy(path, isodir + "/isolinux/")
373 def __copy_syslinux_background(self, isodest):
374 background_path = self._instroot + \
375 "/usr/share/anaconda/syslinux-vesa-splash.jpg"
377 if not os.path.exists(background_path):
378 # fallback to F13 location
379 background_path = self._instroot + \
380 "/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg"
382 if not os.path.exists(background_path):
383 return False
385 shutil.copyfile(background_path, isodest)
387 return True
389 def __copy_kernel_and_initramfs(self, isodir, version, index):
390 bootdir = self._instroot + "/boot"
392 shutil.copyfile(bootdir + "/vmlinuz-" + version,
393 isodir + "/isolinux/vmlinuz" + index)
395 isDracut = False
396 if os.path.exists(bootdir + "/initramfs-" + version + ".img"):
397 shutil.copyfile(bootdir + "/initramfs-" + version + ".img",
398 isodir + "/isolinux/initrd" + index + ".img")
399 isDracut = True
400 else:
401 shutil.copyfile(bootdir + "/initrd-" + version + ".img",
402 isodir + "/isolinux/initrd" + index + ".img")
404 is_xen = False
405 if os.path.exists(bootdir + "/xen.gz-" + version[:-3]):
406 shutil.copyfile(bootdir + "/xen.gz-" + version[:-3],
407 isodir + "/isolinux/xen" + index + ".gz")
408 is_xen = True
410 return (is_xen, isDracut)
412 def __is_default_kernel(self, kernel, kernels):
413 if len(kernels) == 1:
414 return True
416 if kernel == self._default_kernel:
417 return True
419 if kernel.startswith("kernel-") and kernel[7:] == self._default_kernel:
420 return True
422 return False
424 def __get_basic_syslinux_config(self, **args):
425 return """
426 default %(menu)s
427 timeout %(timeout)d
429 %(background)s
430 menu title Welcome to %(name)s!
431 menu color border 0 #ffffffff #00000000
432 menu color sel 7 #ffffffff #ff000000
433 menu color title 0 #ffffffff #00000000
434 menu color tabmsg 0 #ffffffff #00000000
435 menu color unsel 0 #ffffffff #00000000
436 menu color hotsel 0 #ff000000 #ffffffff
437 menu color hotkey 7 #ffffffff #ff000000
438 menu color timeout_msg 0 #ffffffff #00000000
439 menu color timeout 0 #ffffffff #00000000
440 menu color cmdline 0 #ffffffff #00000000
441 menu hidden
442 menu hiddenrow 5
443 """ % args
445 def __get_image_stanza(self, is_xen, isDracut, **args):
446 if isDracut:
447 args["rootlabel"] = "live:CDLABEL=%(fslabel)s" % args
448 else:
449 args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
451 if not is_xen:
452 template = """label %(short)s
453 menu label %(long)s
454 kernel vmlinuz%(index)s
455 append initrd=initrd%(index)s.img root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(xdriver)s %(extra)s
457 else:
458 template = """label %(short)s
459 menu label %(long)s
460 kernel mboot.c32
461 append xen%(index)s.gz --- vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(xdriver)s %(extra)s --- initrd%(index)s.img
463 return template % args
465 def __get_image_stanzas(self, isodir):
466 versions = []
467 kernels = self._get_kernel_versions()
468 for kernel in kernels:
469 for version in kernels[kernel]:
470 versions.append(version)
472 kernel_options = self._get_kernel_options()
474 checkisomd5 = self._has_checkisomd5()
476 cfg = ""
478 index = "0"
479 for version in versions:
480 (is_xen, isDracut) = self.__copy_kernel_and_initramfs(isodir, version, index)
481 if index == "0":
482 self._isDracut = isDracut
484 default = self.__is_default_kernel(kernel, kernels)
486 if default:
487 long = "Boot"
488 elif kernel.startswith("kernel-"):
489 long = "Boot %s(%s)" % (self.name, kernel[7:])
490 else:
491 long = "Boot %s(%s)" % (self.name, kernel)
493 # Basic video driver
494 basic = "system with basic video driver"
495 xdriver = "xdriver=vesa nomodeset"
498 # tell dracut not to ask for LUKS passwords or activate mdraid sets
499 if isDracut:
500 kern_opts = kernel_options + " rd_NO_LUKS rd_NO_MD rd_NO_DM"
501 else:
502 kern_opts = kernel_options
504 cfg += self.__get_image_stanza(is_xen, isDracut,
505 fslabel = self.fslabel,
506 isofstype = "auto",
507 liveargs = kern_opts,
508 long = long,
509 short = "linux" + index,
510 basicvideo = "",
511 xdriver = "",
512 extra = "",
513 index = index)
515 if default:
516 cfg += "menu default\n"
518 cfg += self.__get_image_stanza(is_xen, isDracut,
519 fslabel = self.fslabel,
520 isofstype = "auto",
521 liveargs = kern_opts,
522 long = long,
523 short = "linux" + index,
524 basicvideo = basic,
525 xdriver = xdriver,
526 extra = "",
527 index = index)
529 if checkisomd5:
530 cfg += self.__get_image_stanza(is_xen, isDracut,
531 fslabel = self.fslabel,
532 isofstype = "auto",
533 liveargs = kernel_options,
534 long = "Verify and " + long,
535 short = "check" + index,
536 basicvideo = "",
537 xdriver = "",
538 extra = "check",
539 index = index)
541 index = str(int(index) + 1)
543 return cfg
545 def __get_memtest_stanza(self, isodir):
546 memtest = glob.glob(self._instroot + "/boot/memtest86*")
547 if not memtest:
548 return ""
550 shutil.copyfile(memtest[0], isodir + "/isolinux/memtest")
552 return """label memtest
553 menu label Memory Test
554 kernel memtest
557 def __get_local_stanza(self, isodir):
558 return """label local
559 menu label Boot from local drive
560 localboot 0xffff
563 def _configure_syslinux_bootloader(self, isodir):
564 """configure the boot loader"""
565 makedirs(isodir + "/isolinux")
567 menu = self.__find_syslinux_menu()
569 self.__copy_syslinux_files(isodir, menu,
570 self.__find_syslinux_mboot())
572 background = ""
573 if self.__copy_syslinux_background(isodir + "/isolinux/splash.jpg"):
574 background = "menu background splash.jpg"
576 cfg = self.__get_basic_syslinux_config(menu = menu,
577 background = background,
578 name = self.name,
579 timeout = self._timeout * 10)
581 cfg += self.__get_image_stanzas(isodir)
582 cfg += self.__get_memtest_stanza(isodir)
583 cfg += self.__get_local_stanza(isodir)
584 cfg += self._get_isolinux_stanzas(isodir)
586 cfgf = open(isodir + "/isolinux/isolinux.cfg", "w")
587 cfgf.write(cfg)
588 cfgf.close()
590 def __copy_efi_files(self, isodir):
591 if not os.path.exists(self._instroot + "/boot/efi/EFI/redhat/grub.efi"):
592 return False
593 shutil.copy(self._instroot + "/boot/efi/EFI/redhat/grub.efi",
594 isodir + "/EFI/boot/grub.efi")
595 shutil.copy(self._instroot + "/boot/grub/splash.xpm.gz",
596 isodir + "/EFI/boot/splash.xpm.gz")
598 return True
600 def __get_basic_efi_config(self, **args):
601 return """
602 default=0
603 splashimage=/EFI/boot/splash.xpm.gz
604 timeout %(timeout)d
605 hiddenmenu
607 """ %args
609 def __get_efi_image_stanza(self, **args):
610 if self._isDracut:
611 args["rootlabel"] = "live:LABEL=%(fslabel)s" % args
612 else:
613 args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
614 return """title %(long)s
615 kernel /EFI/boot/vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s
616 initrd /EFI/boot/initrd%(index)s.img
617 """ %args
619 def __get_efi_image_stanzas(self, isodir, name):
620 # FIXME: this only supports one kernel right now...
622 kernel_options = self._get_kernel_options()
623 checkisomd5 = self._has_checkisomd5()
625 cfg = ""
627 for index in range(0, 9):
628 # we don't support xen kernels
629 if os.path.exists("%s/EFI/boot/xen%d.gz" %(isodir, index)):
630 continue
631 cfg += self.__get_efi_image_stanza(fslabel = self.fslabel,
632 isofstype = "auto",
633 liveargs = kernel_options,
634 long = name,
635 extra = "", index = index)
636 if checkisomd5:
637 cfg += self.__get_efi_image_stanza(fslabel = self.fslabel,
638 isofstype = "auto",
639 liveargs = kernel_options,
640 long = "Verify and Boot " + name,
641 extra = "check",
642 index = index)
643 break
645 return cfg
647 def _configure_efi_bootloader(self, isodir):
648 """Set up the configuration for an EFI bootloader"""
649 makedirs(isodir + "/EFI/boot")
651 if not self.__copy_efi_files(isodir):
652 shutil.rmtree(isodir + "/EFI")
653 return
655 for f in os.listdir(isodir + "/isolinux"):
656 os.link("%s/isolinux/%s" %(isodir, f),
657 "%s/EFI/boot/%s" %(isodir, f))
660 cfg = self.__get_basic_efi_config(name = self.name,
661 timeout = self._timeout)
662 cfg += self.__get_efi_image_stanzas(isodir, self.name)
664 cfgf = open(isodir + "/EFI/boot/grub.conf", "w")
665 cfgf.write(cfg)
666 cfgf.close()
668 # first gen mactel machines get the bootloader name wrong apparently
669 if rpmUtils.arch.getBaseArch() == "i386":
670 os.link(isodir + "/EFI/boot/grub.efi", isodir + "/EFI/boot/boot.efi")
671 os.link(isodir + "/EFI/boot/grub.conf", isodir + "/EFI/boot/boot.conf")
673 # for most things, we want them named boot$efiarch
674 efiarch = {"i386": "ia32", "x86_64": "x64"}
675 efiname = efiarch[rpmUtils.arch.getBaseArch()]
676 os.rename(isodir + "/EFI/boot/grub.efi", isodir + "/EFI/boot/boot%s.efi" %(efiname,))
677 os.link(isodir + "/EFI/boot/grub.conf", isodir + "/EFI/boot/boot%s.conf" %(efiname,))
680 def _configure_bootloader(self, isodir):
681 self._configure_syslinux_bootloader(isodir)
682 self._configure_efi_bootloader(isodir)
684 class ppcLiveImageCreator(LiveImageCreatorBase):
685 def _get_mkisofs_options(self, isodir):
686 return [ "-hfs", "-no-desktop", "-part",
687 "-map", isodir + "/ppc/mapping",
688 "-hfs-bless", isodir + "/ppc/mac",
689 "-hfs-volid", self.fslabel ]
691 def _get_required_packages(self):
692 return ["yaboot"] + \
693 LiveImageCreatorBase._get_required_packages(self)
695 def _get_excluded_packages(self):
696 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
697 return ["memtest86+"] + \
698 LiveImageCreatorBase._get_excluded_packages(self)
700 def __copy_boot_file(self, destdir, file):
701 for dir in ["/usr/share/ppc64-utils",
702 "/usr/lib/anaconda-runtime/boot"]:
703 path = self._instroot + dir + "/" + file
704 if not os.path.exists(path):
705 continue
707 makedirs(destdir)
708 shutil.copy(path, destdir)
709 return
711 raise CreatorError("Unable to find boot file " + file)
713 def __kernel_bits(self, kernel):
714 testpath = (self._instroot + "/lib/modules/" +
715 kernel + "/kernel/arch/powerpc/platforms")
717 if not os.path.exists(testpath):
718 return { "32" : True, "64" : False }
719 else:
720 return { "32" : False, "64" : True }
722 def __copy_kernel_and_initramfs(self, destdir, version):
723 isDracut = False
724 bootdir = self._instroot + "/boot"
726 makedirs(destdir)
728 shutil.copyfile(bootdir + "/vmlinuz-" + version,
729 destdir + "/vmlinuz")
731 if os.path.exists(bootdir + "/initramfs-" + version + ".img"):
732 shutil.copyfile(bootdir + "/initramfs-" + version + ".img",
733 destdir + "/initrd.img")
734 isDracut = True
735 else:
736 shutil.copyfile(bootdir + "/initrd-" + version + ".img",
737 destdir + "/initrd.img")
739 return isDracut
741 def __get_basic_yaboot_config(self, **args):
742 return """
743 init-message = "Welcome to %(name)s"
744 timeout=%(timeout)d
745 """ % args
747 def __get_image_stanza(self, **args):
748 if args["isDracut"]:
749 args["rootlabel"] = "live:LABEL=%(fslabel)s" % args
750 else:
751 args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
752 return """
754 image=/ppc/ppc%(bit)s/vmlinuz
755 label=%(short)s
756 initrd=/ppc/ppc%(bit)s/initrd.img
757 read-only
758 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
759 """ % args
762 def __write_yaboot_config(self, isodir, bit, isDracut = False):
763 cfg = self.__get_basic_yaboot_config(name = self.name,
764 timeout = self._timeout * 100)
766 kernel_options = self._get_kernel_options()
768 cfg += self.__get_image_stanza(fslabel = self.fslabel,
769 isofstype = "auto",
770 short = "linux",
771 long = "Run from image",
772 extra = "",
773 bit = bit,
774 liveargs = kernel_options,
775 isDracut = isDracut)
777 if self._has_checkisomd5():
778 cfg += self.__get_image_stanza(fslabel = self.fslabel,
779 isofstype = "auto",
780 short = "check",
781 long = "Verify and run from image",
782 extra = "check",
783 bit = bit,
784 liveargs = kernel_options,
785 isDracut = isDracut)
787 f = open(isodir + "/ppc/ppc" + bit + "/yaboot.conf", "w")
788 f.write(cfg)
789 f.close()
791 def __write_not_supported(self, isodir, bit):
792 makedirs(isodir + "/ppc/ppc" + bit)
794 message = "Sorry, this LiveCD does not support your hardware"
796 f = open(isodir + "/ppc/ppc" + bit + "/yaboot.conf", "w")
797 f.write('init-message = "' + message + '"')
798 f.close()
801 def __write_dualbits_yaboot_config(isodir, **args):
802 cfg = """
803 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
804 timeout=%(timeout)d
805 default=linux
807 image=/ppc/ppc64/vmlinuz
808 label=linux64
809 alias=linux
810 initrd=/ppc/ppc64/initrd.img
811 read-only
813 image=/ppc/ppc32/vmlinuz
814 label=linux32
815 initrd=/ppc/ppc32/initrd.img
816 read-only
817 """ % args
819 f = open(isodir + "/etc/yaboot.conf", "w")
820 f.write(cfg)
821 f.close()
823 def _configure_bootloader(self, isodir):
824 """configure the boot loader"""
825 havekernel = { 32: False, 64: False }
827 self.__copy_boot_file(isodir + "/ppc", "mapping")
828 self.__copy_boot_file(isodir + "/ppc", "bootinfo.txt")
829 self.__copy_boot_file(isodir + "/ppc/mac", "ofboot.b")
831 shutil.copyfile(self._instroot + "/usr/lib/yaboot/yaboot",
832 isodir + "/ppc/mac/yaboot")
834 makedirs(isodir + "/ppc/chrp")
835 shutil.copyfile(self._instroot + "/usr/lib/yaboot/yaboot",
836 isodir + "/ppc/chrp/yaboot")
838 subprocess.call(["/usr/sbin/addnote", isodir + "/ppc/chrp/yaboot"])
841 # FIXME: ppc should support multiple kernels too...
843 kernel = self._get_kernel_versions().values()[0][0]
845 kernel_bits = self.__kernel_bits(kernel)
847 for (bit, present) in kernel_bits.items():
848 if not present:
849 self.__write_not_supported(isodir, bit)
850 continue
852 isDracut = self.__copy_kernel_and_initramfs(isodir + "/ppc/ppc" + bit, kernel)
853 self.__write_yaboot_config(isodir, bit, isDracut)
855 makedirs(isodir + "/etc")
856 if kernel_bits["32"] and not kernel_bits["64"]:
857 shutil.copyfile(isodir + "/ppc/ppc32/yaboot.conf",
858 isodir + "/etc/yaboot.conf")
859 elif kernel_bits["64"] and not kernel_bits["32"]:
860 shutil.copyfile(isodir + "/ppc/ppc64/yaboot.conf",
861 isodir + "/etc/yaboot.conf")
862 else:
863 self.__write_dualbits_yaboot_config(isodir,
864 name = self.name,
865 timeout = self._timeout * 100)
868 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
871 class ppc64LiveImageCreator(ppcLiveImageCreator):
872 def _get_excluded_packages(self):
873 # FIXME:
874 # while kernel.ppc and kernel.ppc64 co-exist,
875 # we can't have both
876 return ["kernel.ppc"] + \
877 ppcLiveImageCreator._get_excluded_packages(self)
879 arch = rpmUtils.arch.getBaseArch()
880 if arch in ("i386", "x86_64"):
881 LiveImageCreator = x86LiveImageCreator
882 elif arch in ("ppc",):
883 LiveImageCreator = ppcLiveImageCreator
884 elif arch in ("ppc64",):
885 LiveImageCreator = ppc64LiveImageCreator
886 else:
887 raise CreatorError("Architecture not supported!")