This commit is contained in:
committed by
Git OBS Bridge
parent
241ee9df04
commit
d7002a96b9
470
domUloader.py
470
domUloader.py
@@ -1,39 +1,35 @@
|
||||
#!/usr/bin/env python
|
||||
# domUloader.py
|
||||
"""Loader for kernel and (optional) ramdisk from domU filesystem
|
||||
|
||||
Given a physical disk (or disk image) for a domU and the path of a kernel and
|
||||
optional ramdisk, copies the kernel and ramdisk from the domU disk to a
|
||||
temporary location in dom0.
|
||||
|
||||
The --entry parameter specifies the location of the kernel (and optional
|
||||
ramdisk) within the domU filesystem. dev is the disk as seen by domU.
|
||||
Filenames are relative to that filesystem.
|
||||
|
||||
The disk is passed as the last parameter. It must be a block device or raw
|
||||
disk image. More complex disk images (QCOW, VMDK, etc) must already be
|
||||
configured via blktap and presented as a block device.
|
||||
|
||||
The script writes an sxpr specifying the locations of the copied kernel and
|
||||
ramdisk into the file specified by --output (default is stdout).
|
||||
|
||||
Limitations:
|
||||
- It is assumed both kernel and ramdisk are on the same filesystem.
|
||||
- domUs might use LVM; the script currently does not have support for setting
|
||||
up LVM mappings for domUs; it's not trivial and we might risk namespace
|
||||
conflicts. If you want to use LVM inside domUs, set up a small non-LVM boot
|
||||
partition and specify it in bootentry.
|
||||
|
||||
Uses bootentry = [dev:]kernel[,initrd] to get a kernel [and initrd]
|
||||
from a domU filesystem to boot it for Xen.
|
||||
dev is the disk as seen by domU, filenames are relative to
|
||||
that filesystem. The script uses the disk settings from the
|
||||
config file to find the domU filesystems.
|
||||
The bootentry is passed to the script using --entry=
|
||||
Optionally, dev: can be omitted; the script then looks at the
|
||||
root filesystem, parses /etc/fstab to resolve the path to the
|
||||
kernel [and the initrd]. Obviously, the paths relative to the
|
||||
domU root filesystem needs to be specified for the kernel
|
||||
and initrd filenames.
|
||||
The script uses kpartx (multipath-tools) to create mappings for devices that
|
||||
are exported as whole disk devices that are partitioned.
|
||||
|
||||
The root FS is passed using --root=, the filesystem setup in
|
||||
--disks=. The disks list is a python list
|
||||
[[uname, dev, mode, backend], [uname, dev, mode, backend], ...]
|
||||
passed as a string. The script writes an sxpr specifying the
|
||||
locations of the copied kernel and initrd into the file
|
||||
specified by --output (default is stdout).
|
||||
|
||||
Limitations:
|
||||
- It is assumed both kernel and initrd are on the same filesystem.
|
||||
- domUs might use LVM; the script currently does not have support
|
||||
for setting up LVM mappings for domUs; it's not trivial and we
|
||||
might risk namespace conflicts. If you want to use LVM inside domUs,
|
||||
set up a small non-LVM boot partition and specify it in bootentry.
|
||||
|
||||
The script uses kpartx (multipath-tools) to create mappings for
|
||||
devices that are exported as whole disk devices that are partitioned.
|
||||
|
||||
(c) 01/2006 Novell Inc
|
||||
License: GNU GPL
|
||||
Author: Kurt Garloff <garloff@suse.de>
|
||||
(c) 01/2006 Novell Inc
|
||||
License: GNU GPL
|
||||
Author: Kurt Garloff <garloff@suse.de>
|
||||
"""
|
||||
|
||||
import os, sys, getopt
|
||||
@@ -44,23 +40,21 @@ import time
|
||||
|
||||
# Global options
|
||||
quiet = False
|
||||
dryrun = False
|
||||
verbose = False
|
||||
dryrun = False
|
||||
tmpdir = '/var/lib/xen/tmp'
|
||||
|
||||
# List of partitions
|
||||
# It's created by setting up the all the devices from the xen disk
|
||||
# config; every entry creates on Wholedisk object, which does necessary
|
||||
# preparatory steps such as losetup and kpartx -a; then a Partition
|
||||
# object is setup for every partition (which may be one or several per
|
||||
# Wholedisk); it references the Wholedisk if needed; python reference
|
||||
# counting will take care of the cleanup.
|
||||
partitions = []
|
||||
|
||||
# Helper functions
|
||||
|
||||
def error(s):
|
||||
print >> sys.stderr, "domUloader error: %s" % s
|
||||
|
||||
def verbose_print(s):
|
||||
if verbose:
|
||||
print >> sys.stderr, "domUloader: %s" % s
|
||||
|
||||
def traildigits(strg):
|
||||
"Return the trailing digits, used to split the partition number off"
|
||||
"""Return the trailing digits, used to split the partition number off"""
|
||||
idx = len(strg)-1
|
||||
while strg[idx].isdigit():
|
||||
if len == 0:
|
||||
@@ -68,33 +62,49 @@ def traildigits(strg):
|
||||
idx -= 1
|
||||
return strg[idx+1:]
|
||||
|
||||
def isWholedisk(domUname):
|
||||
"Determines whether dev is a wholedisk dev"
|
||||
return not domUname[-1:].isdigit()
|
||||
def getWholedisk(part):
|
||||
while len(part) and part[len(part)-1].isdigit():
|
||||
part = part[:-1]
|
||||
return part
|
||||
|
||||
#def isWholedisk(domUname):
|
||||
# """Determines whether dev is a wholedisk dev"""
|
||||
# return not domUname[-1:].isdigit()
|
||||
|
||||
def findPart(dev):
|
||||
"Find device dev in list of partitions"
|
||||
if len(dev) > 5 and dev[:5] == "/dev/":
|
||||
dev = dev[5:]
|
||||
for part in partitions:
|
||||
if dev == part.domname:
|
||||
return part
|
||||
return None
|
||||
|
||||
class Wholedisk:
|
||||
"Class representing a whole disk that has partitions"
|
||||
def __init__(self, domname, physdev, loopfile = None):
|
||||
"Class representing a whole disk that may have partitions"
|
||||
def __init__(self, vdev, pdev):
|
||||
"c'tor: set up"
|
||||
self.domname = domname
|
||||
self.physdev = physdev
|
||||
self.loopfile = loopfile
|
||||
self.mapped = 0
|
||||
self.pcount = self.scanpartitions()
|
||||
self.is_blk = (S_ISBLK(os.stat(pdev)[ST_MODE]))
|
||||
self.ldev = None
|
||||
self.vdev = vdev
|
||||
self.pdev = pdev
|
||||
self.mapped = 0
|
||||
self.partitions = []
|
||||
self.pcount = self.scanpartitions()
|
||||
|
||||
def physdev(self):
|
||||
"""Gets the physical device used to access the device from dom0"""
|
||||
if self.ldev:
|
||||
return self.ldev
|
||||
return self.pdev
|
||||
|
||||
def findPart(self, vdev):
|
||||
"Find device dev in list of partitions"
|
||||
if len(vdev) > 5 and vdev[:5] == "/dev/":
|
||||
vdev = vdev[5:]
|
||||
for part in self.partitions:
|
||||
if vdev == part.vdev:
|
||||
return part
|
||||
return None
|
||||
|
||||
def loopsetup(self):
|
||||
"Setup the loop mapping"
|
||||
if self.loopfile and not self.physdev:
|
||||
"""Sets up the loop mapping for a disk image.
|
||||
|
||||
Will raise if no loopbacks are available.
|
||||
"""
|
||||
if not self.is_blk and not self.ldev:
|
||||
# Loops through all loopback devices, attempting to
|
||||
# find a free one to set up. Don't scan for free and
|
||||
# then try to set it up as a separate step - too racy!
|
||||
@@ -104,28 +114,29 @@ class Wholedisk:
|
||||
if not os.path.exists(ldev):
|
||||
break
|
||||
i += 1
|
||||
fd = os.popen("losetup %s %s 2> /dev/null" % (ldev, self.loopfile))
|
||||
fd = os.popen("losetup %s %s 2> /dev/null" % (ldev, self.pdev))
|
||||
if not fd.close():
|
||||
if verbose:
|
||||
print "domUloader: losetup %s %s" % (ldev, self.loopfile)
|
||||
self.physdev = ldev
|
||||
verbose_print("losetup %s %s" % (ldev, self.pdev))
|
||||
self.ldev = ldev
|
||||
break
|
||||
if not self.physdev:
|
||||
raise RuntimeError("domUloader: No free loop device found")
|
||||
if not self.ldev:
|
||||
raise RuntimeError("No free loop device found")
|
||||
|
||||
def loopclean(self):
|
||||
"Delete the loop mapping"
|
||||
if self.loopfile and self.physdev:
|
||||
if verbose:
|
||||
print "domUloader: losetup -d %s" % self.physdev
|
||||
"""Delete the loop mapping.
|
||||
|
||||
Will never raise.
|
||||
"""
|
||||
if self.ldev:
|
||||
verbose_print("losetup -d %s" % self.ldev)
|
||||
# Even seemingly innocent queries like "losetup /dev/loop0"
|
||||
# can temporarily block the loopback and cause transient
|
||||
# failures deleting the loopback, hence the retry logic.
|
||||
retries = 10
|
||||
while retries:
|
||||
fd = os.popen("losetup -d %s" % self.physdev)
|
||||
fd = os.popen("losetup -d %s" % self.ldev)
|
||||
if not fd.close():
|
||||
self.physdev = None
|
||||
self.ldev = None
|
||||
break
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
@@ -137,25 +148,27 @@ class Wholedisk:
|
||||
self.loopsetup()
|
||||
# TODO: We could use fdisk -l instead and look at the type of
|
||||
# partitions; this way we could also detect LVM and support it.
|
||||
fd = os.popen("kpartx -l %s" % self.physdev)
|
||||
fd = os.popen("kpartx -l %s" % self.physdev())
|
||||
pcount = 0
|
||||
for line in fd.readlines():
|
||||
line = line.strip()
|
||||
verbose_print("kpartx -l: %s" % (line,))
|
||||
(pname, params) = line.split(':')
|
||||
pno = int(traildigits(pname.strip()))
|
||||
#if pname.rfind('/') != -1:
|
||||
# pname = pname[pname.rfind('/')+1:]
|
||||
#pname = self.physdev[:self.physdev.rfind('/')] + '/' + pname
|
||||
#pname = self.pdev[:self.pdev.rfind('/')] + '/' + pname
|
||||
pname = "/dev/mapper/" + pname
|
||||
partitions.append(Partition(self, self.domname + '%i' % pno, pname))
|
||||
verbose_print("Found partition: vdev %s, pdev %s" % ('%s%i' % (self.vdev, pno), pname))
|
||||
self.partitions.append(Partition(self, '%s%i' % (self.vdev, pno), pname))
|
||||
pcount += 1
|
||||
fd.close()
|
||||
if not pcount:
|
||||
if self.loopfile:
|
||||
if self.ldev:
|
||||
ref = self
|
||||
else:
|
||||
ref = None
|
||||
partitions.append(Partition(ref, self.domname, self.physdev))
|
||||
self.partitions.append(Partition(ref, self.vdev, self.pdev))
|
||||
return pcount
|
||||
|
||||
def activatepartitions(self):
|
||||
@@ -163,22 +176,23 @@ class Wholedisk:
|
||||
if not self.mapped:
|
||||
self.loopsetup()
|
||||
if self.pcount:
|
||||
if verbose:
|
||||
print "domUloader: kpartx -a %s" % self.physdev
|
||||
fd = os.popen("kpartx -a %s" % self.physdev)
|
||||
verbose_print("kpartx -a %s" % self.physdev())
|
||||
fd = os.popen("kpartx -a %s" % self.physdev())
|
||||
fd.close()
|
||||
self.mapped += 1
|
||||
|
||||
def deactivatepartitions(self):
|
||||
"Remove device-mapper mappings and loop mapping"
|
||||
"""Remove device-mapper mappings and loop mapping.
|
||||
|
||||
Will never raise.
|
||||
"""
|
||||
if not self.mapped:
|
||||
return
|
||||
self.mapped -= 1
|
||||
if not self.mapped:
|
||||
if self.pcount:
|
||||
if verbose:
|
||||
print "domUloader: kpartx -d %s" % self.physdev
|
||||
fd = os.popen("kpartx -d %s" % self.physdev)
|
||||
verbose_print("kpartx -d %s" % self.physdev())
|
||||
fd = os.popen("kpartx -d %s" % self.physdev())
|
||||
fd.close()
|
||||
self.loopclean()
|
||||
|
||||
@@ -189,24 +203,20 @@ class Wholedisk:
|
||||
|
||||
def __repr__(self):
|
||||
"string representation for debugging"
|
||||
strg = "[" + self.domname + ","
|
||||
if self.physdev:
|
||||
strg += self.physdev
|
||||
strg += ","
|
||||
if self.loopfile:
|
||||
strg += self.loopfile
|
||||
strg = "[" + self.vdev + "," + self.pdev + ","
|
||||
if self.ldev:
|
||||
strg += self.ldev
|
||||
strg += "," + str(self.pcount) + ",mapped %ix]" % self.mapped
|
||||
return strg
|
||||
|
||||
class Partition:
|
||||
"""Class representing a domU filesystem (partition) that can be
|
||||
mounted in dom0"""
|
||||
def __init__(self, whole = None, domname = None,
|
||||
physdev = None):
|
||||
def __init__(self, whole = None, vdev = None, pdev = None):
|
||||
"c'tor: setup"
|
||||
self.wholedisk = whole
|
||||
self.domname = domname
|
||||
self.physdev = physdev
|
||||
self.wholedisk = whole
|
||||
self.vdev = vdev
|
||||
self.pdev = pdev
|
||||
self.mountpoint = None
|
||||
|
||||
def __del__(self):
|
||||
@@ -219,7 +229,7 @@ class Partition:
|
||||
|
||||
def __repr__(self):
|
||||
"string representation for debugging"
|
||||
strg = "[" + self.domname + "," + self.physdev + ","
|
||||
strg = "[" + self.vdev + "," + self.pdev + ","
|
||||
if self.mountpoint:
|
||||
strg += "mounted on " + self.mountpoint + ","
|
||||
else:
|
||||
@@ -235,171 +245,69 @@ class Partition:
|
||||
return
|
||||
if self.wholedisk:
|
||||
self.wholedisk.activatepartitions()
|
||||
mtpt = tempfile.mkdtemp(prefix = "%s." % self.domname, dir = tmpdir)
|
||||
mtpt = tempfile.mkdtemp(prefix = "%s." % self.vdev, dir = tmpdir)
|
||||
mopts = ""
|
||||
if fstype:
|
||||
mopts += " -t %s" % fstype
|
||||
mopts += " -o %s" % options
|
||||
if verbose:
|
||||
print "domUloader: mount %s %s %s" % (mopts, self.physdev, mtpt)
|
||||
fd = os.popen("mount %s %s %s" % (mopts, self.physdev, mtpt))
|
||||
verbose_print("mount %s %s %s" % (mopts, self.pdev, mtpt))
|
||||
fd = os.popen("mount %s %s %s" % (mopts, self.pdev, mtpt))
|
||||
err = fd.close()
|
||||
if err:
|
||||
raise RuntimeError("domUloader: Error %i from mount %s %s on %s" % \
|
||||
(err, mopts, self.physdev, mtpt))
|
||||
raise RuntimeError("Error %i from mount %s %s on %s" % \
|
||||
(err, mopts, self.pdev, mtpt))
|
||||
self.mountpoint = mtpt
|
||||
|
||||
def umount(self):
|
||||
"umount filesystem at self.mountpoint"
|
||||
"""umount filesystem at self.mountpoint"""
|
||||
if not self.mountpoint:
|
||||
return
|
||||
if verbose:
|
||||
print "domUloader: umount %s" % self.mountpoint
|
||||
verbose_print("umount %s" % self.mountpoint)
|
||||
fd = os.popen("umount %s" % self.mountpoint)
|
||||
err = fd.close()
|
||||
os.rmdir(self.mountpoint)
|
||||
try:
|
||||
os.rmdir(self.mountpoint)
|
||||
except:
|
||||
pass
|
||||
if err:
|
||||
raise RuntimeError("domUloader: Error %i from umount %s" % \
|
||||
(err, self.mountpoint))
|
||||
self.mountpoint = None
|
||||
error("Error %i from umount %s" % (err, self.mountpoint))
|
||||
else:
|
||||
self.mountpoint = None
|
||||
if self.wholedisk:
|
||||
self.wholedisk.deactivatepartitions()
|
||||
|
||||
|
||||
def setupOneDisk(cfg):
|
||||
"""Sets up one exported disk (incl. partitions if existing)
|
||||
@param cfg: 4-tuple (uname, dev, mode, backend)"""
|
||||
from xen.util.blkif import blkdev_uname_to_file
|
||||
values = cfg[0].split(':')
|
||||
if len(values) == 2:
|
||||
(type, dev) = values
|
||||
else:
|
||||
(type, subtype, dev) = values
|
||||
(loopfile, physdev) = (None, None)
|
||||
if type == "tap":
|
||||
if subtype == "aio":
|
||||
# FIXME: if device, "/dev/" may need to be prepended
|
||||
mode = os.stat(dev)[ST_MODE]
|
||||
if S_ISBLK(mode):
|
||||
physdev = dev
|
||||
else:
|
||||
loopfile = dev
|
||||
else:
|
||||
raise RuntimeError("domUloader: domUloader supports 'tap' only with 'aio'.")
|
||||
if type == "file":
|
||||
loopfile = dev
|
||||
elif type == "phy":
|
||||
physdev = blkdev_uname_to_file(cfg[0])
|
||||
wdisk = Wholedisk(cfg[1], physdev, loopfile)
|
||||
|
||||
def setupDisks(vbds):
|
||||
"""Create a list of all disks from the disk config:
|
||||
@param vbds: The disk config as list of 4-tuples
|
||||
(uname, dev, mode, backend)"""
|
||||
disks = eval(vbds)
|
||||
for disk in disks:
|
||||
setupOneDisk(disk)
|
||||
if verbose:
|
||||
print "Partitions: " + str(partitions)
|
||||
|
||||
class Fstab:
|
||||
"Class representing an fstab"
|
||||
|
||||
class FstabEntry:
|
||||
"Class representing one fstab line"
|
||||
def __init__(self, line):
|
||||
"c'tor: parses one line"
|
||||
spline = line.split()
|
||||
self.dev, self.mtpt, self.fstype, self.opts = \
|
||||
spline[0], spline[1], spline[2], spline[3]
|
||||
if len(self.mtpt) > 1:
|
||||
self.mtpt = self.mtpt.rstrip('/')
|
||||
|
||||
def __init__(self, filename):
|
||||
"c'tor: parses fstab"
|
||||
self.entries = []
|
||||
fd = open(filename)
|
||||
for line in fd.readlines():
|
||||
line = line.strip()
|
||||
if len(line) == 0 or line[0] == '#':
|
||||
continue
|
||||
self.entries.append(Fstab.FstabEntry(line))
|
||||
|
||||
def find(self, fname):
|
||||
"Looks for matching filesystem in fstab"
|
||||
matchlen = 0
|
||||
match = None
|
||||
fnmlst = fname.split('/')
|
||||
for fs in self.entries:
|
||||
entlst = fs.mtpt.split('/')
|
||||
# '/' needs special treatment :-(
|
||||
if entlst == ['','']:
|
||||
entlst = ['']
|
||||
entln = len(entlst)
|
||||
if len(fnmlst) >= entln and fnmlst[:entln] == entlst \
|
||||
and entln > matchlen:
|
||||
match = fs
|
||||
matchlen = entln
|
||||
if not match:
|
||||
return (None, None)
|
||||
return (match.dev, match.mtpt)
|
||||
|
||||
def fsFromFstab(kernel, initrd, root):
|
||||
"""Investigate rootFS fstab, check for filesystem that contains the kernel
|
||||
and return it; also returns adapted kernel and initrd path.
|
||||
"""
|
||||
part = findPart(root)
|
||||
if not part:
|
||||
raise RuntimeError("domUloader: Root fs %s not exported?" % root)
|
||||
part.mount()
|
||||
if not os.access(part.mountpoint + '/etc/fstab', os.R_OK):
|
||||
part.umount()
|
||||
raise RuntimeError("domUloader: /etc/fstab not found on %s" % root)
|
||||
fstab = Fstab(part.mountpoint + '/etc/fstab')
|
||||
(dev, fs) = fstab.find(kernel)
|
||||
if not fs:
|
||||
raise RuntimeError("domUloader: no matching filesystem for image %s found in fstab" % kernel)
|
||||
#return (None, kernel, initrd)
|
||||
if fs == '/':
|
||||
ln = 0
|
||||
# this avoids the stupid /dev/root problem
|
||||
dev = root
|
||||
else:
|
||||
ln = len(fs)
|
||||
kernel = kernel[ln:]
|
||||
if initrd:
|
||||
initrd = initrd[ln:]
|
||||
if verbose:
|
||||
print "fsFromFstab: %s %s -- %s,%s" % (dev, fs, kernel, initrd)
|
||||
return (kernel, initrd, dev)
|
||||
|
||||
def parseEntry(entry):
|
||||
"disects bootentry and returns kernel, initrd, filesys"
|
||||
fs = None
|
||||
initrd = None
|
||||
"disects bootentry and returns vdev, kernel, ramdisk"
|
||||
def bad():
|
||||
raise RuntimeError, "Malformed --entry"
|
||||
fsspl = entry.split(':')
|
||||
if len(fsspl) > 1:
|
||||
fs = fsspl[0]
|
||||
entry = fsspl[1]
|
||||
if len(fsspl) != 2:
|
||||
bad()
|
||||
vdev = fsspl[0]
|
||||
entry = fsspl[1]
|
||||
enspl = entry.split(',')
|
||||
if len(enspl) not in (1, 2):
|
||||
bad()
|
||||
# Prepend '/' if missing
|
||||
kernel = enspl[0]
|
||||
if kernel == '':
|
||||
bad()
|
||||
if kernel[0] != '/':
|
||||
kernel = '/' + kernel
|
||||
ramdisk = None
|
||||
if len(enspl) > 1:
|
||||
initrd = enspl[1]
|
||||
if initrd[0] != '/':
|
||||
initrd = '/' + initrd
|
||||
return kernel, initrd, fs
|
||||
ramdisk = enspl[1]
|
||||
if ramdisk != '' and ramdisk[0] != '/':
|
||||
ramdisk = '/' + ramdisk
|
||||
return vdev, kernel, ramdisk
|
||||
|
||||
def copyFile(src, dst):
|
||||
"Wrapper for shutil.filecopy"
|
||||
import shutil
|
||||
if verbose:
|
||||
print "domUloader: cp %s %s" % (src, dst)
|
||||
verbose_print("cp %s %s" % (src, dst))
|
||||
stat = os.stat(src)
|
||||
if stat.st_size > 16*1024*1024:
|
||||
raise RuntimeError("domUloader: Too large file %s (%s larger than 16MB)" \
|
||||
raise RuntimeError("Too large file %s (%s larger than 16MB)" \
|
||||
% (src, stat.st_size))
|
||||
try:
|
||||
shutil.copyfile(src, dst)
|
||||
@@ -407,36 +315,37 @@ def copyFile(src, dst):
|
||||
os.unlink(dst)
|
||||
raise()
|
||||
|
||||
def copyKernelAndInitrd(fs, kernel, initrd):
|
||||
"""Finds fs in list of partitions, mounts the partition, copies
|
||||
kernel [and initrd] off to dom0 files, umounts the parition again,
|
||||
def copyKernelAndRamdisk(disk, vdev, kernel, ramdisk):
|
||||
"""Finds vdev in list of partitions, mounts the partition, copies
|
||||
kernel [and ramdisk] off to dom0 files, umounts the parition again,
|
||||
and returns sxpr pointing to these copies."""
|
||||
verbose_print("copyKernelAndRamdisk(%s, %s, %s, %s)" % (disk, vdev, kernel, ramdisk))
|
||||
if dryrun:
|
||||
return "linux (kernel vmlinuz.dummy) (ramdisk initrd.dummy)"
|
||||
import shutil
|
||||
part = findPart(fs)
|
||||
return "linux (kernel kernel.dummy) (ramdisk ramdisk.dummy)"
|
||||
part = disk.findPart(vdev)
|
||||
if not part:
|
||||
raise RuntimeError("domUloader: Filesystem %s not exported\n" % fs)
|
||||
raise RuntimeError("Partition '%s' does not exist" % vdev)
|
||||
part.mount()
|
||||
try:
|
||||
(fd, knm) = tempfile.mkstemp(prefix = "vmlinuz.", dir = tmpdir)
|
||||
(fd, knm) = tempfile.mkstemp(prefix = "kernel.", dir = tmpdir)
|
||||
os.close(fd)
|
||||
copyFile(part.mountpoint + kernel, knm)
|
||||
except:
|
||||
os.unlink(knm)
|
||||
part.umount()
|
||||
raise
|
||||
if not quiet:
|
||||
print "Copy kernel %s from %s to %s for booting" % \
|
||||
(kernel, fs, knm)
|
||||
print "Copy kernel %s from %s to %s for booting" % (kernel, vdev, knm)
|
||||
sxpr = "linux (kernel %s)" % knm
|
||||
if (initrd):
|
||||
if ramdisk:
|
||||
try:
|
||||
(fd, inm) = tempfile.mkstemp(prefix = "initrd.", dir = tmpdir)
|
||||
(fd, inm) = tempfile.mkstemp(prefix = "ramdisk.", dir = tmpdir)
|
||||
os.close(fd)
|
||||
copyFile(part.mountpoint + initrd, inm)
|
||||
copyFile(part.mountpoint + ramdisk, inm)
|
||||
except:
|
||||
os.unlink(knm)
|
||||
os.unlink(inm)
|
||||
part.umount()
|
||||
raise
|
||||
sxpr += "(ramdisk %s)" % inm
|
||||
part.umount()
|
||||
@@ -448,46 +357,49 @@ def main(argv):
|
||||
def usage():
|
||||
"Help output (usage info)"
|
||||
global verbose, quiet, dryrun
|
||||
print >> sys.stderr, "domUloader usage: domUloader --disks=disklist [--root=rootFS]\n" \
|
||||
+ " --entry=kernel[,initrd] [--output=fd] [--quiet] [--dryrun] [--verbose] [--help]\n"
|
||||
print >> sys.stderr, "domUloader usage: domUloader [--output=fd] [--quiet] [--dryrun] [--verbose]\n" +\
|
||||
"[--help] --entry=dev:kernel[,ramdisk] physdisk [virtdisk]\n"
|
||||
print >> sys.stderr, __doc__
|
||||
|
||||
#print "domUloader " + str(argv)
|
||||
try:
|
||||
(optlist, args) = getopt.gnu_getopt(argv, 'qvh', \
|
||||
('disks=', 'root=', 'entry=', 'output=',
|
||||
'tmpdir=', 'help', 'quiet', 'dryrun', 'verbose'))
|
||||
('entry=', 'output=', 'tmpdir=', 'help', 'quiet', 'dryrun', 'verbose'))
|
||||
except:
|
||||
usage()
|
||||
sys.exit(1)
|
||||
|
||||
entry = None
|
||||
output = None
|
||||
root = None
|
||||
disks = None
|
||||
pdisk = None
|
||||
vdisk = None
|
||||
|
||||
for (opt, oarg) in optlist:
|
||||
if opt in ('-h', '--help'):
|
||||
usage()
|
||||
sys.exit(0)
|
||||
sys.exit(1)
|
||||
elif opt in ('-q', '--quiet'):
|
||||
quiet = True
|
||||
elif opt in ('-n', '--dryrun'):
|
||||
dryrun = True
|
||||
elif opt in ('-v', '--verbose'):
|
||||
verbose = True
|
||||
elif opt == '--root':
|
||||
root = oarg
|
||||
elif opt == '--output':
|
||||
output = oarg
|
||||
elif opt == '--disks':
|
||||
disks = oarg
|
||||
elif opt == '--entry':
|
||||
entry = oarg
|
||||
elif opt == '--tmpdir':
|
||||
tmpdir = oarg
|
||||
|
||||
if not entry or not disks:
|
||||
verbose_print(str(argv))
|
||||
|
||||
if args:
|
||||
if len(args) == 2:
|
||||
pdisk = args[1]
|
||||
elif len(args) == 3:
|
||||
pdisk = args[1]
|
||||
vdisk = args[2]
|
||||
|
||||
if not entry or not pdisk:
|
||||
usage()
|
||||
sys.exit(1)
|
||||
|
||||
@@ -500,22 +412,34 @@ def main(argv):
|
||||
os.mkdir(tmpdir)
|
||||
os.chmod(tmpdir, 0750)
|
||||
|
||||
# We assume kernel and initrd are on the same FS,
|
||||
# so only one fs
|
||||
kernel, initrd, fs = parseEntry(entry)
|
||||
setupDisks(disks)
|
||||
if not fs:
|
||||
if not root:
|
||||
usage()
|
||||
raise RuntimeError("domUloader: No root= to parse fstab and no disk in bootentry")
|
||||
sys.exit(1)
|
||||
kernel, initrd, fs = fsFromFstab(kernel, initrd, root)
|
||||
vdev, kernel, ramdisk = parseEntry(entry)
|
||||
if not vdisk:
|
||||
vdisk = getWholedisk(vdev)
|
||||
verbose_print("vdisk not specified; guessing '%s' based on '%s'" % (vdisk, vdev))
|
||||
if not vdev.startswith(vdisk):
|
||||
error("Virtual disk '%s' does not match entry '%s'" % (vdisk, entry))
|
||||
sys.exit(1)
|
||||
disk = Wholedisk(vdisk, pdisk)
|
||||
|
||||
sxpr = copyKernelAndInitrd(fs, kernel, initrd)
|
||||
sys.stdout.flush()
|
||||
os.write(fd, sxpr)
|
||||
r = 0
|
||||
try:
|
||||
sxpr = copyKernelAndRamdisk(disk, vdev, kernel, ramdisk)
|
||||
os.write(fd, sxpr)
|
||||
except Exception, e:
|
||||
error(str(e))
|
||||
r = 1
|
||||
|
||||
for part in disk.partitions:
|
||||
part.wholedisk = None
|
||||
del disk
|
||||
|
||||
return r
|
||||
|
||||
# Call main if called (and not imported)
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
|
||||
r = 1
|
||||
try:
|
||||
r = main(sys.argv)
|
||||
except Exception, e:
|
||||
error(str(e))
|
||||
sys.exit(r)
|
||||
|
Reference in New Issue
Block a user