tools/edit-livecd | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+)
New commits: commit f8981306621b0543a66a4b1959755adcf0f25c91 Author: Joey Boggs jboggs@redhat.com Date: Tue Jun 1 21:20:25 2010 -0400
add edit-livecd
edit-livecd is used for opening up livecd images to add and/or edit files with out having to rebuild the iso image.
This script is useful for people who don't have the development and yum infrastructure/repos set up to build livecd's from scratch. This is especially useful for custom livecd images.
diff --git a/tools/edit-livecd b/tools/edit-livecd new file mode 100755 index 0000000..809b015 --- /dev/null +++ b/tools/edit-livecd @@ -0,0 +1,350 @@ +#!/usr/bin/python -tt +# +# edit livecd: Edit a livecd to insert files +# +# Copyright 2009, Red Hat Inc. +# Written by Perry Myers <pmyers at redhat.com> & David Huff <dhuff at redhat.com> +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Library General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +import os +import sys +import tempfile +import shutil +import subprocess +import optparse +import logging + +from imgcreate.debug import * +from imgcreate.fs import * +from imgcreate.live import * + +class ExistingSparseLoopbackDisk(SparseLoopbackDisk): + """don't want to expand the disk""" + def __init__(self, lofile, size): + SparseLoopbackDisk.__init__(self, lofile, size) + + def create(self): + #self.expand(create = True) + LoopbackDisk.create(self) + +class LiveImageEditor(LiveImageCreator): + """class for editing LiveCD images. + + We need an instance of LiveImageCreator however we do not have a kickstart + file nor do we need to create a new image. We just want to reuse some of + LiveImageCreators methods on an existing livecd image. + + """ + + def __init__(self, name): + """Initialize a LiveImageEditor instance. + + creates a dummy instance of LiveImageCreator + We do not initialize any sub classes b/c we have no ks file. + + """ + self.name = name + + self.tmpdir = "/var/tmp" + """The directory in which all temporary files will be created.""" + + self.skip_compression = False + """Controls whether to use squashfs to compress the image.""" + + self.skip_minimize = False + """Controls whether an image minimizing snapshot should be created.""" + + self._isofstype = "iso9660" + self.__isodir = None + + self._ImageCreator__builddir = None + """working directory""" + + self._ImageCreator_instroot = None + """where the extfs.img is mounted for modification""" + + self._ImageCreator_outdir = None + """where final iso gets written""" + + self._ImageCreator__bindmounts = [] + + self._LoopImageCreator__imagedir = None + """dir for the extfs.img""" + + self._LoopImageCreator__blocksize = 4096 + self._LoopImageCreator__fslabel = None + self._LoopImageCreator__instloop = None + self._LoopImageCreator__fstype = None + self._LoopImageCreator__image_size = None + + self._LiveImageCreatorBase__isodir = None + """directory where the iso is staged""" + + # properties + def __get_image(self): + if self._LoopImageCreator__imagedir is None: + self.__ensure_builddir() + self._LoopImageCreator__imagedir = tempfile.mkdtemp(dir = os.path.abspath(self.tmpdir), prefix = self.name + "-") + return self._LoopImageCreator__imagedir + "/ext3fs.img" + _image = property(__get_image) + """The location of the image file""" + + + def _get_fstype(self): + dev_null = os.open("/dev/null", os.O_WRONLY) + try: + out = subprocess.Popen(["/sbin/blkid", self._image], + stdout = subprocess.PIPE, + stderr = dev_null).communicate()[0] + for word in out.split(): + if word.startswith("TYPE"): + self._LoopImageCreator__fstype = word.split("=")[1].strip(""") + + except IOError, e: + raise CreatorError("Failed to determine fsimage TYPE: %s" % e ) + + + def _get_fslable(self): + dev_null = os.open("/dev/null", os.O_WRONLY) + try: + out = subprocess.Popen(["/sbin/e2label", self._image], + stdout = subprocess.PIPE, + stderr = dev_null).communicate()[0] + + self._LoopImageCreator__fslable = out.strip() + + except IOError, e: + raise CreatorError("Failed to determine fsimage TYPE: %s" % e ) + + + def __ensure_builddir(self): + if not self._ImageCreator__builddir is None: + return + + try: + self._ImageCreator__builddir = tempfile.mkdtemp(dir = os.path.abspath(self.tmpdir), + prefix = "edit-livecd-") + except OSError, (err, msg): + raise CreatorError("Failed create build directory in %s: %s" % + (self.tmpdir, msg)) + + + def _run_script(self, script): + + (fd, path) = tempfile.mkstemp(prefix = "script-", + dir = self._instroot + "/tmp") + + logging.debug("copying script to install root: %s" % path) + shutil.copy(os.path.abspath(script), path) + os.close(fd) + os.chmod(path, 0700) + + script = "/tmp/" + os.path.basename(path) + + + try: + subprocess.call([script], preexec_fn = self._chroot) + except OSError, e: + raise CreatorError("Failed to execute script %s, %s " % (script, e)) + finally: + os.unlink(path) + + + def mount(self, base_on, cachedir = None): + """mount existing file system. + + we have to override mount b/c we are not creating an new install root + nor do we need to setup the file system, ie makedirs(/etc/, /boot, ...), + nor do we want to overwrite fstab, or create selinuxfs + + We also need to get some info about the image before we + can mount it. + + """ + + if not base_on: + raise CreatorError("No base livecd image specified") + + self.__ensure_builddir() + + self._ImageCreator_instroot = self._ImageCreator__builddir + "/install_root" + self._LoopImageCreator__imagedir = self._ImageCreator__builddir + "/ex" + self._ImageCreator_outdir = self._ImageCreator__builddir + "/out" + + makedirs(self._ImageCreator_instroot) + makedirs(self._LoopImageCreator__imagedir) + makedirs(self._ImageCreator_outdir) + + LiveImageCreator._base_on(self, base_on) + + self._LoopImageCreator__image_size = os.stat(self._image)[stat.ST_SIZE] + self._get_fstype() + self._get_fslable() + self.fslabel = self._LoopImageCreator__fslable + + self._LoopImageCreator__instloop = ExtDiskMount(ExistingSparseLoopbackDisk(self._image, + self._LoopImageCreator__image_size), + self._ImageCreator_instroot, + self._fstype, + self._LoopImageCreator__blocksize, + self.fslabel) + try: + self._LoopImageCreator__instloop.mount() + except MountError, e: + raise CreatorError("Failed to loopback mount '%s' : %s" % + (self._image, e)) + + cachesrc = cachedir or (self._ImageCreator__builddir + "/yum-cache") + makedirs(cachesrc) + + for (f, dest) in [("/sys", None), ("/proc", None), + ("/dev/pts", None), ("/dev/shm", None), + (cachesrc, "/var/cache/yum")]: + self._ImageCreator__bindmounts.append(BindChrootMount(f, self._instroot, dest)) + + self._do_bindmounts() + + os.symlink("../proc/mounts", self._instroot + "/etc/mtab") + + self.__copy_cd_root(base_on) + + + def __copy_cd_root(self, base_on): + """helper function to root content of the base liveCD to ISOdir""" + + isoloop = DiskMount(LoopbackDisk(base_on, 0), self._mkdtemp()) + self._LiveImageCreatorBase__isodir = self._ImageCreator__builddir + "/iso" + + try: + isoloop.mount() + # legacy LiveOS filesystem layout support, remove for F9 or F10 + if os.path.exists(isoloop.mountdir + "/squashfs.img"): + squashimg = isoloop.mountdir + "/squashfs.img" + else: + squashimg = isoloop.mountdir + "/LiveOS/squashfs.img" + + #copy over everything but squashimg + shutil.copytree(isoloop.mountdir, + self._LiveImageCreatorBase__isodir, + ignore=shutil.ignore_patterns("squashfs.img", "osmin.img")) + except MountError, e: + raise CreatorError("Failed to loopback mount '%s' : %s" % + (base_on, e)) + + finally: + isoloop.cleanup() + + +def parse_options(args): + parser = optparse.OptionParser(usage = "%prog [-s=<script.sh>] <LIVECD.iso>") + + parser.add_option("-n", "--name", type="string", dest="name", + help="name of new livecd (don't include .iso will be added)") + + parser.add_option("-o", "--output", type="string", dest="output", + help="specify the output dir") + + parser.add_option("-s", "--script", type="string", dest="script", + help="specify script to run chrooted in the livecd fsimage") + + parser.add_option("-t", "--tmpdir", type="string", + dest="tmpdir", default="/var/tmp", + help="Temporary directory to use (default: /var/tmp)") + + parser.add_option("", "--skip-compression", action="store_true", dest="skip_compression") + + parser.add_option("", "--skip-minimize", action="store_true", dest="skip_minimize") + + setup_logging(parser) + + (options, args) = parser.parse_args() + + if len(args) != 1: + parser.print_usage() + sys.exit(1) + + return (args[0], options) + +def rebuild_iso_symlinks(isodir): + # remove duplicate files and rebuild symlinks to reduce iso size + efi_vmlinuz = "%s/EFI/boot/vmlinuz0" % isodir + isolinux_vmlinuz = "%s/isolinux/vmlinuz0" % isodir + efi_initrd = "%s/EFI/boot/initrd0.img" % isodir + isolinux_initrd = "%s/isolinux/initrd0.img" % isodir + + os.remove(efi_vmlinuz) + os.remove(efi_initrd) + os.symlink(isolinux_vmlinuz,efi_vmlinuz) + os.symlink(isolinux_initrd,efi_initrd) + + +def main(): + (livecd, options) = parse_options(sys.argv[1:]) + + if os.geteuid () != 0: + print >> sys.stderr, "You must run edit-livecd as root" + return 1 + + if options.name: + name = options.name + else: + name = os.path.basename(livecd) + ".edited" + + if options.output: + output = options.output + else: + output = os.path.dirname(livecd) + + + editor = LiveImageEditor(name) + editor.tmpdir = os.path.abspath(options.tmpdir) + editor.skip_compression = options.skip_compression + editor.skip_minimize = options.skip_minimize + + try: + editor.mount(livecd, cachedir = None) + if options.script: + print "Running edit script '%s'" % options.script + editor._run_script(options.script) + else: + print "Launching shell. Exit to continue." + print "----------------------------------" + editor.launch_shell() + rebuild_iso_symlinks(editor._LiveImageCreatorBase__isodir) + editor.unmount() + editor.package(output) + except CreatorError, e: + logging.error(u"Error editing Live CD : %s" % e) + return 1 + finally: + editor.cleanup() + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) + + +arch = rpmUtils.arch.getBaseArch() +if arch in ("i386", "x86_64"): + LiveImageCreator = x86LiveImageCreator +elif arch in ("ppc",): + LiveImageCreator = ppcLiveImageCreator +elif arch in ("ppc64",): + LiveImageCreator = ppc64LiveImageCreator +else: + raise CreatorError("Architecture not supported!")
livecd@lists.fedoraproject.org