Bump Makefile for 033.
[livecd.git] / imgcreate / live.py
blob36fef63dc87f6365f790770dfca8f706be389742
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 = "zlib"
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 %(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 %(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)
494 # tell dracut not to ask for LUKS passwords or activate mdraid sets
495 if isDracut:
496 kern_opts = kernel_options + " rd_NO_LUKS rd_NO_MD rd_NO_DM"
497 else:
498 kern_opts = kernel_options
500 cfg += self.__get_image_stanza(is_xen, isDracut,
501 fslabel = self.fslabel,
502 isofstype = "auto",
503 liveargs = kern_opts,
504 long = long,
505 short = "linux" + index,
506 extra = "",
507 index = index)
509 if default:
510 cfg += "menu default\n"
512 if checkisomd5:
513 cfg += self.__get_image_stanza(is_xen, isDracut,
514 fslabel = self.fslabel,
515 isofstype = "auto",
516 liveargs = kernel_options,
517 long = "Verify and " + long,
518 short = "check" + index,
519 extra = "check",
520 index = index)
522 index = str(int(index) + 1)
524 return cfg
526 def __get_memtest_stanza(self, isodir):
527 memtest = glob.glob(self._instroot + "/boot/memtest86*")
528 if not memtest:
529 return ""
531 shutil.copyfile(memtest[0], isodir + "/isolinux/memtest")
533 return """label memtest
534 menu label Memory Test
535 kernel memtest
538 def __get_local_stanza(self, isodir):
539 return """label local
540 menu label Boot from local drive
541 localboot 0xffff
544 def _configure_syslinux_bootloader(self, isodir):
545 """configure the boot loader"""
546 makedirs(isodir + "/isolinux")
548 menu = self.__find_syslinux_menu()
550 self.__copy_syslinux_files(isodir, menu,
551 self.__find_syslinux_mboot())
553 background = ""
554 if self.__copy_syslinux_background(isodir + "/isolinux/splash.jpg"):
555 background = "menu background splash.jpg"
557 cfg = self.__get_basic_syslinux_config(menu = menu,
558 background = background,
559 name = self.name,
560 timeout = self._timeout * 10)
562 cfg += self.__get_image_stanzas(isodir)
563 cfg += self.__get_memtest_stanza(isodir)
564 cfg += self.__get_local_stanza(isodir)
565 cfg += self._get_isolinux_stanzas(isodir)
567 cfgf = open(isodir + "/isolinux/isolinux.cfg", "w")
568 cfgf.write(cfg)
569 cfgf.close()
571 def __copy_efi_files(self, isodir):
572 if not os.path.exists(self._instroot + "/boot/efi/EFI/redhat/grub.efi"):
573 return False
574 shutil.copy(self._instroot + "/boot/efi/EFI/redhat/grub.efi",
575 isodir + "/EFI/boot/grub.efi")
576 shutil.copy(self._instroot + "/boot/grub/splash.xpm.gz",
577 isodir + "/EFI/boot/splash.xpm.gz")
579 return True
581 def __get_basic_efi_config(self, **args):
582 return """
583 default=0
584 splashimage=/EFI/boot/splash.xpm.gz
585 timeout %(timeout)d
586 hiddenmenu
588 """ %args
590 def __get_efi_image_stanza(self, **args):
591 if self._isDracut:
592 args["rootlabel"] = "live:LABEL=%(fslabel)s" % args
593 else:
594 args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
595 return """title %(long)s
596 kernel /EFI/boot/vmlinuz%(index)s root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s
597 initrd /EFI/boot/initrd%(index)s.img
598 """ %args
600 def __get_efi_image_stanzas(self, isodir, name):
601 # FIXME: this only supports one kernel right now...
603 kernel_options = self._get_kernel_options()
604 checkisomd5 = self._has_checkisomd5()
606 cfg = ""
608 for index in range(0, 9):
609 # we don't support xen kernels
610 if os.path.exists("%s/EFI/boot/xen%d.gz" %(isodir, index)):
611 continue
612 cfg += self.__get_efi_image_stanza(fslabel = self.fslabel,
613 isofstype = "auto",
614 liveargs = kernel_options,
615 long = name,
616 extra = "", index = index)
617 if checkisomd5:
618 cfg += self.__get_efi_image_stanza(fslabel = self.fslabel,
619 isofstype = "auto",
620 liveargs = kernel_options,
621 long = "Verify and Boot " + name,
622 extra = "check",
623 index = index)
624 break
626 return cfg
628 def _configure_efi_bootloader(self, isodir):
629 """Set up the configuration for an EFI bootloader"""
630 makedirs(isodir + "/EFI/boot")
632 if not self.__copy_efi_files(isodir):
633 shutil.rmtree(isodir + "/EFI")
634 return
636 for f in os.listdir(isodir + "/isolinux"):
637 os.link("%s/isolinux/%s" %(isodir, f),
638 "%s/EFI/boot/%s" %(isodir, f))
641 cfg = self.__get_basic_efi_config(name = self.name,
642 timeout = self._timeout)
643 cfg += self.__get_efi_image_stanzas(isodir, self.name)
645 cfgf = open(isodir + "/EFI/boot/grub.conf", "w")
646 cfgf.write(cfg)
647 cfgf.close()
649 # first gen mactel machines get the bootloader name wrong apparently
650 if rpmUtils.arch.getBaseArch() == "i386":
651 os.link(isodir + "/EFI/boot/grub.efi", isodir + "/EFI/boot/boot.efi")
652 os.link(isodir + "/EFI/boot/grub.conf", isodir + "/EFI/boot/boot.conf")
654 # for most things, we want them named boot$efiarch
655 efiarch = {"i386": "ia32", "x86_64": "x64"}
656 efiname = efiarch[rpmUtils.arch.getBaseArch()]
657 os.rename(isodir + "/EFI/boot/grub.efi", isodir + "/EFI/boot/boot%s.efi" %(efiname,))
658 os.link(isodir + "/EFI/boot/grub.conf", isodir + "/EFI/boot/boot%s.conf" %(efiname,))
661 def _configure_bootloader(self, isodir):
662 self._configure_syslinux_bootloader(isodir)
663 self._configure_efi_bootloader(isodir)
665 class ppcLiveImageCreator(LiveImageCreatorBase):
666 def _get_mkisofs_options(self, isodir):
667 return [ "-hfs", "-no-desktop", "-part",
668 "-map", isodir + "/ppc/mapping",
669 "-hfs-bless", isodir + "/ppc/mac",
670 "-hfs-volid", self.fslabel ]
672 def _get_required_packages(self):
673 return ["yaboot"] + \
674 LiveImageCreatorBase._get_required_packages(self)
676 def _get_excluded_packages(self):
677 # kind of hacky, but exclude memtest86+ on ppc so it can stay in cfg
678 return ["memtest86+"] + \
679 LiveImageCreatorBase._get_excluded_packages(self)
681 def __copy_boot_file(self, destdir, file):
682 for dir in ["/usr/share/ppc64-utils",
683 "/usr/lib/anaconda-runtime/boot"]:
684 path = self._instroot + dir + "/" + file
685 if not os.path.exists(path):
686 continue
688 makedirs(destdir)
689 shutil.copy(path, destdir)
690 return
692 raise CreatorError("Unable to find boot file " + file)
694 def __kernel_bits(self, kernel):
695 testpath = (self._instroot + "/lib/modules/" +
696 kernel + "/kernel/arch/powerpc/platforms")
698 if not os.path.exists(testpath):
699 return { "32" : True, "64" : False }
700 else:
701 return { "32" : False, "64" : True }
703 def __copy_kernel_and_initramfs(self, destdir, version):
704 isDracut = False
705 bootdir = self._instroot + "/boot"
707 makedirs(destdir)
709 shutil.copyfile(bootdir + "/vmlinuz-" + version,
710 destdir + "/vmlinuz")
712 if os.path.exists(bootdir + "/initramfs-" + version + ".img"):
713 shutil.copyfile(bootdir + "/initramfs-" + version + ".img",
714 destdir + "/initrd.img")
715 isDracut = True
716 else:
717 shutil.copyfile(bootdir + "/initrd-" + version + ".img",
718 destdir + "/initrd.img")
720 return isDracut
722 def __get_basic_yaboot_config(self, **args):
723 return """
724 init-message = "Welcome to %(name)s"
725 timeout=%(timeout)d
726 """ % args
728 def __get_image_stanza(self, **args):
729 if args["isDracut"]:
730 args["rootlabel"] = "live:LABEL=%(fslabel)s" % args
731 else:
732 args["rootlabel"] = "CDLABEL=%(fslabel)s" % args
733 return """
735 image=/ppc/ppc%(bit)s/vmlinuz
736 label=%(short)s
737 initrd=/ppc/ppc%(bit)s/initrd.img
738 read-only
739 append="root=%(rootlabel)s rootfstype=%(isofstype)s %(liveargs)s %(extra)s"
740 """ % args
743 def __write_yaboot_config(self, isodir, bit, isDracut = False):
744 cfg = self.__get_basic_yaboot_config(name = self.name,
745 timeout = self._timeout * 100)
747 kernel_options = self._get_kernel_options()
749 cfg += self.__get_image_stanza(fslabel = self.fslabel,
750 isofstype = "auto",
751 short = "linux",
752 long = "Run from image",
753 extra = "",
754 bit = bit,
755 liveargs = kernel_options,
756 isDracut = isDracut)
758 if self._has_checkisomd5():
759 cfg += self.__get_image_stanza(fslabel = self.fslabel,
760 isofstype = "auto",
761 short = "check",
762 long = "Verify and run from image",
763 extra = "check",
764 bit = bit,
765 liveargs = kernel_options,
766 isDracut = isDracut)
768 f = open(isodir + "/ppc/ppc" + bit + "/yaboot.conf", "w")
769 f.write(cfg)
770 f.close()
772 def __write_not_supported(self, isodir, bit):
773 makedirs(isodir + "/ppc/ppc" + bit)
775 message = "Sorry, this LiveCD does not support your hardware"
777 f = open(isodir + "/ppc/ppc" + bit + "/yaboot.conf", "w")
778 f.write('init-message = "' + message + '"')
779 f.close()
782 def __write_dualbits_yaboot_config(isodir, **args):
783 cfg = """
784 init-message = "\nWelcome to %(name)s!\nUse 'linux32' for 32-bit kernel.\n\n"
785 timeout=%(timeout)d
786 default=linux
788 image=/ppc/ppc64/vmlinuz
789 label=linux64
790 alias=linux
791 initrd=/ppc/ppc64/initrd.img
792 read-only
794 image=/ppc/ppc32/vmlinuz
795 label=linux32
796 initrd=/ppc/ppc32/initrd.img
797 read-only
798 """ % args
800 f = open(isodir + "/etc/yaboot.conf", "w")
801 f.write(cfg)
802 f.close()
804 def _configure_bootloader(self, isodir):
805 """configure the boot loader"""
806 havekernel = { 32: False, 64: False }
808 self.__copy_boot_file(isodir + "/ppc", "mapping")
809 self.__copy_boot_file(isodir + "/ppc", "bootinfo.txt")
810 self.__copy_boot_file(isodir + "/ppc/mac", "ofboot.b")
812 shutil.copyfile(self._instroot + "/usr/lib/yaboot/yaboot",
813 isodir + "/ppc/mac/yaboot")
815 makedirs(isodir + "/ppc/chrp")
816 shutil.copyfile(self._instroot + "/usr/lib/yaboot/yaboot",
817 isodir + "/ppc/chrp/yaboot")
819 subprocess.call(["/usr/sbin/addnote", isodir + "/ppc/chrp/yaboot"])
822 # FIXME: ppc should support multiple kernels too...
824 kernel = self._get_kernel_versions().values()[0][0]
826 kernel_bits = self.__kernel_bits(kernel)
828 for (bit, present) in kernel_bits.items():
829 if not present:
830 self.__write_not_supported(isodir, bit)
831 continue
833 isDracut = self.__copy_kernel_and_initramfs(isodir + "/ppc/ppc" + bit, kernel)
834 self.__write_yaboot_config(isodir, bit, isDracut)
836 makedirs(isodir + "/etc")
837 if kernel_bits["32"] and not kernel_bits["64"]:
838 shutil.copyfile(isodir + "/ppc/ppc32/yaboot.conf",
839 isodir + "/etc/yaboot.conf")
840 elif kernel_bits["64"] and not kernel_bits["32"]:
841 shutil.copyfile(isodir + "/ppc/ppc64/yaboot.conf",
842 isodir + "/etc/yaboot.conf")
843 else:
844 self.__write_dualbits_yaboot_config(isodir,
845 name = self.name,
846 timeout = self._timeout * 100)
849 # FIXME: build 'netboot' images with kernel+initrd, like mk-images.ppc
852 class ppc64LiveImageCreator(ppcLiveImageCreator):
853 def _get_excluded_packages(self):
854 # FIXME:
855 # while kernel.ppc and kernel.ppc64 co-exist,
856 # we can't have both
857 return ["kernel.ppc"] + \
858 ppcLiveImageCreator._get_excluded_packages(self)
860 arch = rpmUtils.arch.getBaseArch()
861 if arch in ("i386", "x86_64"):
862 LiveImageCreator = x86LiveImageCreator
863 elif arch in ("ppc",):
864 LiveImageCreator = ppcLiveImageCreator
865 elif arch in ("ppc64",):
866 LiveImageCreator = ppc64LiveImageCreator
867 else:
868 raise CreatorError("Architecture not supported!")