Is there any objections to including this script in livecd-toosls? We have seen a good amount of interest in something like this.
-D On 03/09/2010 04:25 PM, Joey Boggs wrote: > Resubmitting the edit-livecd script with the latest updates. > > 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, like the ovirt-node project[1]. > > We agree that changes to packaging and binaries should always be done by > modifying kickstart and rebuilding the image via livecd-creator. But if all > you want to do is add/edit a config file, public key for SSH, or change the > root password this can be done with the edit-livecd script. > > This is the second generation of the edit-livecd tool that replaces our > original bash script with a python version and aims to reuse as much as the > livecd-creator libraries as possible. The main reason for the new creator > class is to avoid the need for a kisckstart file in order to edit an existing > livecd image. > > [1] http://ovirt.org > > --- > Makefile | 2 + > tools/edit-livecd | 350 > +++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 352 insertions(+), 0 deletions(-) > create mode 100755 tools/edit-livecd > > diff --git a/Makefile b/Makefile > index 991b27b..62e7fd8 100644 > --- a/Makefile > +++ b/Makefile > @@ -25,6 +25,7 @@ install: man > $(INSTALL_PROGRAM) -D tools/image-creator > $(DESTDIR)/usr/bin/image-creator > $(INSTALL_PROGRAM) -D tools/livecd-iso-to-disk.sh > $(DESTDIR)/usr/bin/livecd-iso-to-disk > $(INSTALL_PROGRAM) -D tools/livecd-iso-to-pxeboot.sh > $(DESTDIR)/usr/bin/livecd-iso-to-pxeboot > + $(INSTALL_PROGRAM) -D tools/edit-livecd $(DESTDIR)/usr/bin/edit-livecd > $(INSTALL_DATA) -D AUTHORS > $(DESTDIR)/usr/share/doc/livecd-tools-$(VERSION)/AUTHORS > $(INSTALL_DATA) -D COPYING > $(DESTDIR)/usr/share/doc/livecd-tools-$(VERSION)/COPYING > $(INSTALL_DATA) -D README > $(DESTDIR)/usr/share/doc/livecd-tools-$(VERSION)/README > @@ -40,6 +41,7 @@ uninstall: > rm -f $(DESTDIR)/usr/bin/livecd-creator > rm -rf $(DESTDIR)/usr/lib/livecd-creator > rm -rf $(DESTDIR)/usr/share/doc/livecd-tools-$(VERSION) > + rm -f $(DESTDIR)/usr/bin/edit-livecd > > dist : all > git archive --format=tar --prefix=livecd-tools-$(VERSION)/ HEAD | bzip2 > -9v> livecd-tools-$(VERSION).tar.bz2 > diff --git a/tools/edit-livecd b/tools/edit-livecd > new file mode 100755 > index 0000000..920522c > --- /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<[email protected]> & David Huff<[email protected]> > +# > +# > +# 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 mailing list [email protected] https://admin.fedoraproject.org/mailman/listinfo/livecd
