Note lz4 compression in help
[livecd.git] / tools / edit-livecd
blobf1287bf7edb1deabccf9eb9fedc08197220e5ee0
1 #!/usr/bin/python -tt
3 # edit-liveos: Edit a LiveOS to insert files or to clone an instance onto a new
4 # iso image file.
6 # Copyright 2009, Red Hat Inc.
7 # Written by Perry Myers <pmyers at redhat.com> & David Huff <dhuff at redhat.com>
8 # Cloning code added by Frederick Grose <fgrose at sugarlabs.org>
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; version 2 of the License.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU Library General Public License for more details.
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 import os
25 import sys
26 import stat
27 import tempfile
28 import shutil
29 import subprocess
30 import optparse
31 import logging
32 import rpm
33 import glob
35 from imgcreate.debug import *
36 from imgcreate.errors import *
37 from imgcreate.fs import *
38 from imgcreate.live import *
39 from imgcreate.creator import *
40 import imgcreate.kickstart as kickstart
41 from imgcreate import read_kickstart
43 class ExistingSparseLoopbackDisk(SparseLoopbackDisk):
44 """don't want to expand the disk"""
45 def __init__(self, lofile, size):
46 SparseLoopbackDisk.__init__(self, lofile, size)
48 def create(self):
49 #self.expand(create = True)
50 LoopbackDisk.create(self)
52 class LiveImageEditor(LiveImageCreator):
53 """class for editing LiveOS images.
55 We need an instance of LiveImageCreator, however, we do not have a kickstart
56 file and we may not need to create a new image. We just want to reuse some
57 of LiveImageCreators methods on an existing LiveOS image.
59 """
61 def __init__(self, name, docleanup=True):
62 """Initialize a LiveImageEditor instance.
64 creates a dummy instance of LiveImageCreator
65 We do not initialize any sub classes b/c we have no ks file.
67 """
68 self.name = name
70 self.tmpdir = "/var/tmp"
71 """The directory in which all temporary files will be created."""
73 self.clone = False
74 """Signals when to copy a running LiveOS image as base."""
76 self._include = None
77 """A string of file or directory paths to include in __copy_img_root."""
79 self._builder = os.getlogin()
80 """The name of the Remix builder for _branding.
81 Default = os.getlogin()"""
83 self.compress_type = None
84 """mksquashfs compressor to use. Use 'None' to force reading of the
85 existing image, or enter a -p --compress_type value to override the
86 current compression or lack thereof. Compression type options vary with
87 the version of the kernel and SquashFS used."""
89 self.skip_compression = False
90 """Controls whether to use squashfs to compress the image."""
92 self.skip_minimize = False
93 """Controls whether an image minimizing snapshot should be created."""
95 self._isofstype = "iso9660"
96 self.__isodir = None
98 self._ImageCreator__builddir = None
99 """working directory"""
101 self._ImageCreator_outdir = None
102 """where final iso gets written"""
104 self._ImageCreator__bindmounts = []
106 self._LoopImageCreator__blocksize = 4096
107 self._LoopImageCreator__fslabel = None
108 self._LoopImageCreator__instloop = None
109 self._LoopImageCreator__fstype = None
110 self._LoopImageCreator__image_size = None
112 self.__instroot = None
114 self._LiveImageCreatorBase__isodir = None
115 """directory where the iso is staged"""
117 self.ks = None
118 """optional kickstart file as a recipe for editing the image"""
120 self._ImageCreator__selinux_mountpoint = "/sys/fs/selinux"
121 with open("/proc/self/mountinfo", "r") as f:
122 for line in f.readlines():
123 fields = line.split()
124 if fields[-2] == "selinuxfs":
125 self.__ImageCreator__selinux_mountpoint = fields[4]
126 break
128 self.docleanup = docleanup
130 # properties
131 def __get_image(self):
132 if self._LoopImageCreator__imagedir is None:
133 self.__ensure_builddir()
134 self._LoopImageCreator__imagedir = \
135 tempfile.mkdtemp(dir = os.path.abspath(self.tmpdir),
136 prefix = self.name + "-")
137 rtn = self._LoopImageCreator__imagedir + "/ext3fs.img"
138 return rtn
139 _image = property(__get_image)
140 """The location of the filesystem image file."""
142 def _get_fslabel(self):
143 dev_null = os.open("/dev/null", os.O_WRONLY)
144 try:
145 out = subprocess.Popen(["/sbin/e2label", self._image],
146 stdout = subprocess.PIPE,
147 stderr = dev_null).communicate()[0]
149 self._LoopImageCreator__fslabel = out.strip()
151 except IOError, e:
152 raise CreatorError("Failed to determine fsimage LABEL: %s" % e )
153 finally:
154 os.close(dev_null)
156 def __ensure_builddir(self):
157 if not self._ImageCreator__builddir is None:
158 return
160 try:
161 self._ImageCreator__builddir = tempfile.mkdtemp(dir = os.path.abspath(self.tmpdir),
162 prefix = "edit-liveos-")
163 except OSError, (err, msg):
164 raise CreatorError("Failed create build directory in %s: %s" %
165 (self.tmpdir, msg))
167 def _run_script(self, script):
169 (fd, path) = tempfile.mkstemp(prefix = "script-",
170 dir = self._instroot + "/tmp")
172 logging.debug("copying script to install root: %s" % path)
173 shutil.copy(os.path.abspath(script), path)
174 os.close(fd)
175 os.chmod(path, 0700)
177 script = "/tmp/" + os.path.basename(path)
179 try:
180 subprocess.call([script], preexec_fn = self._chroot)
181 except OSError, e:
182 raise CreatorError("Failed to execute script %s, %s " % (script, e))
183 finally:
184 os.unlink(path)
186 def mount(self, base_on, cachedir = None):
187 """mount existing file system.
189 We have to override mount b/c we many not be creating an new install
190 root nor do we need to setup the file system, i.e., makedirs(/etc/,
191 /boot, ...), nor do we want to overwrite fstab, or create selinuxfs.
193 We also need to get some info about the image before we can mount it.
195 base_on -- the <LIVEIMG.src> a LiveOS.iso file or an attached LiveOS
196 device, such as, /dev/live for a currently running image.
198 cachedir -- a directory in which to store a Yum cache;
199 Not used in edit-liveos.
203 if not base_on:
204 raise CreatorError("No base LiveOS image specified.")
206 self.__ensure_builddir()
208 self._ImageCreator_instroot = self._ImageCreator__builddir + "/install_root"
209 self._LoopImageCreator__imagedir = self._ImageCreator__builddir + "/ex"
210 self._ImageCreator_outdir = self._ImageCreator__builddir + "/out"
212 makedirs(self._ImageCreator_instroot)
213 makedirs(self._LoopImageCreator__imagedir)
214 makedirs(self._ImageCreator_outdir)
216 if self.clone:
217 # Need to clone base_on into ext3fs.img at this point
218 self._LoopImageCreator__fslabel = self.name
219 self._base_on(base_on)
220 else:
221 LiveImageCreator._base_on(self, base_on)
222 self._LoopImageCreator__fstype = get_fsvalue(self._image, 'TYPE')
223 self._get_fslabel()
225 self.fslabel = self._LoopImageCreator__fslabel
226 if self._LoopImageCreator__image_size == None:
227 self._LoopImageCreator__image_size = os.stat(self._image)[stat.ST_SIZE]
229 self._LoopImageCreator__instloop = ExtDiskMount(
230 ExistingSparseLoopbackDisk(self._image,
231 self._LoopImageCreator__image_size),
232 self._ImageCreator_instroot,
233 self._fstype,
234 self._LoopImageCreator__blocksize,
235 self.fslabel,
236 self.tmpdir)
237 try:
238 self._LoopImageCreator__instloop.mount()
239 except MountError, e:
240 raise CreatorError("Failed to loopback mount '%s' : %s" %
241 (self._image, e))
243 cachesrc = cachedir or (self._ImageCreator__builddir + "/yum-cache")
244 makedirs(cachesrc)
246 for (f, dest) in [("/sys", None), ("/proc", None),
247 ("/dev/pts", None), ("/dev/shm", None),
248 (cachesrc, "/var/cache/yum")]:
249 self._ImageCreator__bindmounts.append(BindChrootMount(f, self._instroot, dest))
251 self._do_bindmounts()
253 os.symlink("../proc/mounts", self._instroot + "/etc/mtab")
255 self.__copy_img_root(base_on)
256 self._brand(self._builder)
258 def _base_on(self, base_on):
259 """Clone the running LiveOS image as the basis for the new image."""
261 self.__fstype = 'ext4'
262 self.__image_size = 4096L * 1024 * 1024
263 self.__blocksize = 4096
265 self.__instloop = ExtDiskMount(SparseLoopbackDisk(self._image,
266 self.__image_size),
267 self._instroot,
268 self.__fstype,
269 self.__blocksize,
270 self.fslabel,
271 self.tmpdir)
272 try:
273 self.__instloop.mount()
274 except MountError, e:
275 raise CreatorError("Failed to loopback mount '%s' : %s" %
276 (self._image, e))
278 subprocess.call(['rsync', '-ptgorlHASx', '--specials', '--progress',
279 '--include', '/*/',
280 '--exclude', '/etc/mtab',
281 '--exclude', '/etc/blkid/*',
282 '--exclude', '/dev/*',
283 '--exclude', '/proc/*',
284 '--exclude', '/home/*',
285 '--exclude', '/media/*',
286 '--exclude', '/mnt/live',
287 '--exclude', '/sys/*',
288 '--exclude', '/tmp/*',
289 '--exclude', '/.liveimg*',
290 '--exclude', '/.autofsck',
291 '/', self._instroot])
292 subprocess.call(['sync'])
294 self._ImageCreator__create_minimal_dev()
296 self.__instloop.cleanup()
299 def __copy_img_root(self, base_on):
300 """helper function to copy root content of the base LiveIMG to
301 ISOdir"""
303 ignore_list = ['ext3fs.img', 'squashfs.img', 'osmin.img', 'home.img',
304 'overlay-*']
306 if self.clone:
307 ignore_list.remove('home.img')
308 includes = 'boot, /EFI, /syslinux, /LiveOS'
309 if self._include:
310 includes += ", " + self._include
312 imgmnt = DiskMount(RawDisk(0, base_on), self._mkdtemp())
313 else:
314 imgmnt = DiskMount(LoopbackDisk(base_on, 0), self._mkdtemp())
316 self._LiveImageCreatorBase__isodir = self._ImageCreator__builddir + "/iso"
318 try:
319 imgmnt.mount()
320 except MountError, e:
321 raise CreatorError("Failed to mount '%s' : %s" % (base_on, e))
322 else:
323 # include specified files or directories
324 if self.clone:
325 baseimg = os.path.join(imgmnt.mountdir, 'LiveOS',
326 'squashfs.img')
327 # 'self.compress_type = None' will force reading it from
328 # base_on.
329 if self.compress_type is None:
330 self.compress_type = squashfs_compression_type(baseimg)
331 if self.compress_type == 'undetermined':
332 # 'gzip' for compatibility with older versions.
333 self.compress_type = 'gzip'
335 dst = self._LiveImageCreatorBase__isodir
336 print includes
337 for fd in includes.split(', /'):
338 src = os.path.join(imgmnt.mountdir, fd)
339 if os.path.isfile(src):
340 shutil.copy2(src, os.path.join(dst, fd))
341 elif os.path.isdir(src):
342 shutil.copytree(src, os.path.join(dst, fd),
343 symlinks=True,
344 ignore=shutil.ignore_patterns(
345 *ignore_list))
346 else:
347 #copy over everything but squashfs.img or ext3fs.img
348 shutil.copytree(imgmnt.mountdir,
349 self._LiveImageCreatorBase__isodir,
350 ignore=shutil.ignore_patterns(*ignore_list))
351 subprocess.call(['sync'])
352 finally:
353 imgmnt.cleanup()
356 def _brand (self, _builder):
357 """Adjust the image branding to show its variation from original
358 source by builder and build date."""
360 self.fslabel = self.name
361 dt = time.strftime('%d-%b-%Y')
363 lst = ['isolinux/isolinux.cfg', 'syslinux/syslinux.cfg',
364 'syslinux/extlinux.conf']
365 for f in lst:
366 fpath = os.path.join(self._LiveImageCreatorBase__isodir, f)
367 if os.path.exists(fpath):
368 break
370 # Get build name from boot configuration file.
371 try:
372 cfgf = open(fpath, 'r')
373 except IOError, e:
374 raise CreatorError("Failed to open '%s' : %s" % (fpath, e))
375 else:
376 release = None
377 for line in cfgf:
378 i = line.find('Welcome to ')
379 if i > -1:
380 release = line[i+11:-2]
381 break
382 cfgf.close()
383 if not release:
384 return
386 ntext = dt.translate(None, '-') + '-' + _builder + '-Remix-' + release
388 # Update fedora-release message with Remix details.
389 releasefiles = '/etc/fedora-release, /etc/generic-release'
390 if self._releasefile:
391 releasefiles += ', ' + self._releasefile
392 for fn in releasefiles.split(', '):
393 if os.path.exists(fn):
394 try:
395 with open(self._instroot + fn, 'r') as f:
396 text = ntext + '\n' + f.read()
397 open(f.name, 'w').write(text)
398 except IOError, e:
399 raise CreatorError("Failed to open or write '%s' : %s" %
400 (f.name, e))
402 self._releasefile = ntext
403 self.name += '-' + os.uname()[4] + '-' + time.strftime('%Y%m%d.%H%M')
406 def _configure_bootloader(self, isodir):
407 """Restore the boot configuration files for an iso image boot."""
409 bootfolder = os.path.join(isodir, 'isolinux')
410 oldpath = os.path.join(isodir, 'syslinux')
411 if os.path.exists(oldpath):
412 os.rename(oldpath, bootfolder)
414 cfgf = os.path.join(bootfolder, 'isolinux.cfg')
415 for f in ['syslinux.cfg', 'extlinux.conf']:
416 src = os.path.join(bootfolder, f)
417 if os.path.exists(src):
418 os.rename(src, cfgf)
420 args = ['/bin/sed', '-i']
421 if self._releasefile:
422 args.append('-e')
423 args.append('s/Welcome to .*/Welcome to ' + self._releasefile + '!/')
424 if self.clone:
425 args.append('-e')
426 args.append('s/rootfstype=[^ ]* [^ ]*/rootfstype=auto ro/')
427 args.append('-e')
428 args.append('s/\(r*d*.*live.*ima*ge*\) .* quiet/\1 quiet/')
429 args.append('-e')
430 args.append('s/root=[^ ]*/root=live:CDLABEL=' + self.name + '/')
431 if self.ks:
432 # bootloader --append "!opt-to-remove opt-to-add"
433 for param in kickstart.get_kernel_args(self.ks,"").split():
434 if param.startswith('!'):
435 param=param[1:]
436 # remove parameter prefixed with !
437 args.append('-e')
438 args.append("/^ append/s/%s //" % param)
439 # special case for last parameter
440 args.append('-e')
441 args.append("/^ append/s/%s$//" % param)
442 else:
443 # append parameter
444 args.append('-e')
445 args.append("/^ append/s/$/ %s/" % param)
446 args.append(cfgf)
447 dev_null = os.open("/dev/null", os.O_WRONLY)
448 try:
449 subprocess.Popen(args,
450 stdout = subprocess.PIPE,
451 stderr = dev_null).communicate()[0]
452 return 0
454 except IOError, e:
455 raise CreatorError("Failed to configure bootloader file: %s" % e)
456 return 1
457 finally:
458 os.close(dev_null)
460 def _run_pre_scripts(self):
461 for s in kickstart.get_pre_scripts(self.ks):
462 (fd, path) = tempfile.mkstemp(prefix = "ks-script-",
463 dir = self._instroot + "/tmp")
465 os.write(fd, s.script)
466 os.close(fd)
467 os.chmod(path, 0700)
469 env = self._get_post_scripts_env(s.inChroot)
471 if not s.inChroot:
472 env["INSTALL_ROOT"] = self._instroot
473 preexec = None
474 script = path
475 else:
476 preexec = self._chroot
477 script = "/tmp/" + os.path.basename(path)
479 try:
480 subprocess.check_call([s.interp, script],
481 preexec_fn = preexec, env = env)
482 except OSError, e:
483 raise CreatorError("Failed to execute %%post script "
484 "with '%s' : %s" % (s.interp, e.strerror))
485 except subprocess.CalledProcessError, err:
486 if s.errorOnFail:
487 raise CreatorError("%%post script failed with code %d "
488 % err.returncode)
489 logging.warning("ignoring %%post failure (code %d)"
490 % err.returncode)
491 finally:
492 os.unlink(path)
494 class simpleCallback:
495 def __init__(self):
496 self.fdnos = {}
498 def callback(self, what, amount, total, mydata, wibble):
499 if what == rpm.RPMCALLBACK_TRANS_START:
500 pass
502 elif what == rpm.RPMCALLBACK_INST_OPEN_FILE:
503 hdr, path = mydata
504 print "Installing %s\r" % (hdr["name"])
505 fd = os.open(path, os.O_RDONLY)
506 nvr = '%s-%s-%s' % ( hdr['name'], hdr['version'], hdr['release'] )
507 self.fdnos[nvr] = fd
508 return fd
510 elif what == rpm.RPMCALLBACK_INST_CLOSE_FILE:
511 hdr, path = mydata
512 nvr = '%s-%s-%s' % ( hdr['name'], hdr['version'], hdr['release'] )
513 os.close(self.fdnos[nvr])
515 elif what == rpm.RPMCALLBACK_INST_PROGRESS:
516 hdr, path = mydata
517 print "%s: %.5s%% done\r" % (hdr["name"], (float(amount) / total) * 100),
519 def install_rpms(self):
520 if kickstart.exclude_docs(self.ks):
521 rpm.addMacro("_excludedocs", "1")
522 if not kickstart.selinux_enabled(self.ks):
523 rpm.addMacro("__file_context_path", "%{nil}")
524 if kickstart.inst_langs(self.ks) != None:
525 rpm.addMacro("_install_langs", kickstart.inst_langs(self.ks))
526 # start RPM transaction
527 ts=rpm.TransactionSet(self._instroot)
528 for repo in kickstart.get_repos(self.ks):
529 (name, baseurl, mirrorlist, proxy, inc, exc, cost) = repo
530 if baseurl.startswith("file://"):
531 baseurl=baseurl[7:]
532 elif not baseurl.startswith("/"):
533 raise CreatorError("edit-livecd accepts only --baseurl pointing to a local folder with RPMs (not YUM repo)")
534 if not baseurl.endswith("/"):
535 baseurl+="/"
536 for pkg_from_list in kickstart.get_packages(self.ks):
537 # TODO report if package listed in ks is missing
538 for pkg in glob.glob(baseurl+pkg_from_list+"-[0-9]*.rpm"):
539 fdno = os.open(pkg, os.O_RDONLY)
540 hdr = ts.hdrFromFdno(fdno)
541 os.close(fdno)
542 ts.addInstall(hdr,(hdr,pkg), "u")
543 ts.run(self.simpleCallback().callback,'')
545 def parse_options(args):
546 parser = optparse.OptionParser(usage = """
547 %prog [-n=<name>]
548 [-o <output>]
549 [-k <kickstart-file>]
550 [-s <script.sh>]
551 [-t <tmpdir>]
552 [-e <excludes>]
553 [-f <exclude-file>]
554 [-i <includes>]
555 [-r <releasefile>]
556 [-b <builder>]
557 [--clone]
558 [-c <compress_type>]
559 [--skip-compression]
560 [--skip-minimize]
561 <LIVEIMG.src>""")
563 parser.add_option("-n", "--name", type="string", dest="name",
564 help="name of new LiveOS (don't include .iso, it will "
565 "be added)")
567 parser.add_option("-o", "--output", type="string", dest="output",
568 help="specify directory for new iso file.")
570 parser.add_option("-k", "--kickstart", type="string", dest="kscfg",
571 help="Path or url to kickstart config file")
573 parser.add_option("-s", "--script", type="string", dest="script",
574 help="specify script to run chrooted in the LiveOS "
575 "fsimage")
577 parser.add_option("-t", "--tmpdir", type="string",
578 dest="tmpdir", default="/var/tmp",
579 help="Temporary directory to use (default: /var/tmp)")
581 parser.add_option("-e", "--exclude", type="string", dest="exclude",
582 help="Specify directory or file patterns to be excluded "
583 "from the rsync copy of the filesystem.")
585 parser.add_option("-f", "--exclude-file", type="string",
586 dest="exclude_file",
587 help="Specify a file containing file patterns to be "
588 "excluded from the rsync copy of the filesystem.")
590 parser.add_option("-i", "--include", type="string", dest="include",
591 help="Specify directory or file patterns to be included "
592 "in copy_img_root.")
594 parser.add_option("-r", "--releasefile", type="string", dest="releasefile",
595 help="Specify release file/s for branding.")
597 parser.add_option("-b", "--builder", type="string",
598 dest="builder", default=os.getlogin(),
599 help="Specify the builder of a Remix.")
601 parser.add_option("", "--clone", action="store_true", dest="clone",
602 help="Specify that source image is LiveOS block device.")
604 parser.add_option("-c", "--compress_type", type="string",
605 dest="compress_type",
606 help="Specify the compression type for SquashFS. Will "
607 "override the current compression or lack thereof.")
609 parser.add_option("", "--skip-compression", action="store_true",
610 dest="skip_compression", default=False,
611 help="Specify no compression of filesystem, ext3fs.img")
613 parser.add_option("", "--skip-minimize", action="store_true",
614 dest="skip_minimize", default=False,
615 help="Specify no osmin.img minimal snapshot.")
616 parser.add_option("", "--nocleanup", action="store_true",
617 dest="nocleanup", default=False,
618 help="Skip cleanup of temporary files")
620 setup_logging(parser)
622 (options, args) = parser.parse_args()
624 if len(args) != 1:
625 parser.print_usage()
626 sys.exit(1)
628 print args[0]
630 return (args[0], options)
632 def get_fsvalue(filesystem, tag):
633 dev_null = os.open('/dev/null', os.O_WRONLY)
634 args = ['/sbin/blkid', '-s', tag, '-o', 'value', filesystem]
635 try:
636 fs_type = subprocess.Popen(args,
637 stdout=subprocess.PIPE,
638 stderr=dev_null).communicate()[0]
639 except IOError, e:
640 raise CreatorError("Failed to determine fs %s: %s" % value, e )
641 finally:
642 os.close(dev_null)
644 return fs_type.rstrip()
646 def rebuild_iso_symlinks(isodir):
647 # remove duplicate files and rebuild symlinks to reduce iso size
648 efi_vmlinuz = "%s/EFI/BOOT/vmlinuz0" % isodir
649 isolinux_vmlinuz = "%s/isolinux/vmlinuz0" % isodir
650 efi_initrd = "%s/EFI/BOOT/initrd0.img" % isodir
651 isolinux_initrd = "%s/isolinux/initrd0.img" % isodir
653 if os.path.exists(efi_vmlinuz):
654 os.remove(efi_vmlinuz)
655 os.remove(efi_initrd)
656 os.symlink(isolinux_vmlinuz,efi_vmlinuz)
657 os.symlink(isolinux_initrd,efi_initrd)
659 def main():
660 # LiveOS set to <LIVEIMG.src>
661 (LiveOS, options) = parse_options(sys.argv[1:])
663 if os.geteuid () != 0:
664 print >> sys.stderr, "You must run edit-liveos as root"
665 return 1
667 if options.name:
668 name = options.name
669 elif stat.S_ISBLK(os.stat(LiveOS).st_mode):
670 name = get_fsvalue(LiveOS, 'LABEL') + '.edited'
671 else:
672 name = os.path.basename(LiveOS) + ".edited"
674 if options.output:
675 output = options.output
676 else:
677 output = os.path.dirname(LiveOS)
678 if output == '/dev':
679 output = options.tmpdir
681 editor = LiveImageEditor(name, docleanup=not options.nocleanup)
682 editor._exclude = options.exclude
683 editor._exclude_file = options.exclude_file
684 editor._include = options.include
685 editor.clone = options.clone
686 editor.tmpdir = options.tmpdir
687 editor._builder = options.builder
688 editor._releasefile = options.releasefile
689 editor.compress_type = options.compress_type
690 editor.skip_compression = options.skip_compression
691 editor.skip_minimize = options.skip_minimize
693 try:
694 if options.kscfg:
695 editor.ks = read_kickstart(options.kscfg)
696 # part / --size <new rootfs size to be resized to>
697 editor._LoopImageCreator__image_size = kickstart.get_image_size(editor.ks)
698 if options.script:
699 if not os.path.exists(options.script):
700 print "Invalid Script Path '%s'" % options.script
701 return 1
702 editor.mount(LiveOS, cachedir = None)
703 editor._configure_bootloader(editor._LiveImageCreatorBase__isodir)
704 if editor.ks:
705 editor._run_pre_scripts()
706 editor.install_rpms()
707 editor._run_post_scripts()
708 elif options.script:
709 print "Running edit script '%s'" % options.script
710 editor._run_script(options.script)
711 else:
712 print "Launching shell. Exit to continue."
713 print "----------------------------------"
714 editor.launch_shell()
715 rebuild_iso_symlinks(editor._LiveImageCreatorBase__isodir)
716 editor.unmount()
717 editor.package(output)
718 logging.info("%s.iso saved to %s" % (editor.name, output))
719 except CreatorError, e:
720 logging.error(u"Error editing LiveOS : %s" % e)
721 return 1
722 finally:
723 editor.cleanup()
725 return 0
727 if __name__ == "__main__":
728 sys.exit(main())
730 arch = rpmUtils.arch.getBaseArch()
731 if arch in ("i386", "x86_64"):
732 LiveImageCreator = x86LiveImageCreator
733 elif arch in ("ppc",):
734 LiveImageCreator = ppcLiveImageCreator
735 elif arch in ("ppc64",):
736 LiveImageCreator = ppc64LiveImageCreator
737 else:
738 raise CreatorError("Architecture not supported!")