core: update qvm-block code for HAL API
Use QubesDB to get list of devices, call libvirt methods to attach/detach devices.
This commit is contained in:
parent
b4e0833cb7
commit
d4ab70ae9d
@ -21,6 +21,9 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
import string
|
||||||
|
from lxml import etree
|
||||||
|
from lxml.etree import ElementTree, SubElement, Element
|
||||||
|
|
||||||
from qubes import QubesException
|
from qubes import QubesException
|
||||||
from qubes import vmm
|
from qubes import vmm
|
||||||
@ -37,6 +40,11 @@ import xen.lowlevel.xs
|
|||||||
|
|
||||||
BLKSIZE = 512
|
BLKSIZE = 512
|
||||||
|
|
||||||
|
# all frontends, prefer xvdi
|
||||||
|
# TODO: get this from libvirt driver?
|
||||||
|
AVAILABLE_FRONTENDS = ['xvd'+c for c in
|
||||||
|
string.lowercase[8:]+string.lowercase[:8]]
|
||||||
|
|
||||||
def mbytes_to_kmg(size):
|
def mbytes_to_kmg(size):
|
||||||
if size > 1024:
|
if size > 1024:
|
||||||
return "%d GiB" % (size/1024)
|
return "%d GiB" % (size/1024)
|
||||||
@ -207,127 +215,144 @@ def block_find_unused_frontend(vm = None):
|
|||||||
assert vm is not None
|
assert vm is not None
|
||||||
assert vm.is_running()
|
assert vm.is_running()
|
||||||
|
|
||||||
vbd_list = vmm.xs.ls('', '/local/domain/%d/device/vbd' % vm.xid)
|
xml = vm.libvirt_domain.XMLDesc()
|
||||||
# xvd* devices
|
parsed_xml = etree.fromstring(xml)
|
||||||
major = 202
|
used = [target.get('dev', None) for target in
|
||||||
# prefer xvdi
|
parsed_xml.xpath("//domain/devices/disk/target")]
|
||||||
for minor in range(8*16,254,16)+range(0,8*16,16):
|
for dev in AVAILABLE_FRONTENDS:
|
||||||
if vbd_list is None or str(major << 8 | minor) not in vbd_list:
|
if dev not in used:
|
||||||
return block_devid_to_name(major << 8 | minor)
|
return dev
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def block_list(vm = None, system_disks = False):
|
def block_list_vm(vm, system_disks = False):
|
||||||
device_re = re.compile(r"^[a-z0-9-]{1,12}$")
|
name_re = re.compile(r"^[a-z0-9-]{1,12}$")
|
||||||
|
device_re = re.compile(r"^[a-z0-9/-]{1,64}$")
|
||||||
# FIXME: any better idea of desc_re?
|
# FIXME: any better idea of desc_re?
|
||||||
desc_re = re.compile(r"^.{1,255}$")
|
desc_re = re.compile(r"^.{1,255}$")
|
||||||
mode_re = re.compile(r"^[rw]$")
|
mode_re = re.compile(r"^[rw]$")
|
||||||
|
|
||||||
xs_trans = vmm.xs.transaction_start()
|
assert vm is not None
|
||||||
|
|
||||||
vm_list = []
|
if not vm.is_running():
|
||||||
if vm is not None:
|
return []
|
||||||
if not vm.is_running():
|
|
||||||
vmm.xs.transaction_end(xs_trans)
|
|
||||||
return []
|
|
||||||
else:
|
|
||||||
vm_list = [ str(vm.xid) ]
|
|
||||||
else:
|
|
||||||
vm_list = vmm.xs.ls(xs_trans, '/local/domain')
|
|
||||||
|
|
||||||
devices_list = {}
|
devices_list = {}
|
||||||
for xid in vm_list:
|
|
||||||
vm_name = vmm.xs.read(xs_trans, '/local/domain/%s/name' % xid)
|
|
||||||
vm_devices = vmm.xs.ls(xs_trans, '/local/domain/%s/qubes-block-devices' % xid)
|
|
||||||
if vm_devices is None:
|
|
||||||
continue
|
|
||||||
for device in vm_devices:
|
|
||||||
# Sanitize device name
|
|
||||||
if not device_re.match(device):
|
|
||||||
print >> sys.stderr, "Invalid device name in VM '%s'" % vm_name
|
|
||||||
continue
|
|
||||||
|
|
||||||
device_size = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/size' % (xid, device))
|
untrusted_devices = vm.qdb.multiread('/qubes-block-devices/')
|
||||||
device_desc = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/desc' % (xid, device))
|
|
||||||
device_mode = vmm.xs.read(xs_trans, '/local/domain/%s/qubes-block-devices/%s/mode' % (xid, device))
|
|
||||||
|
|
||||||
if device_size is None or device_desc is None or device_mode is None:
|
def get_dev_item(dev, item):
|
||||||
print >> sys.stderr, "Missing field in %s device parameters" % device
|
return untrusted_devices.get(
|
||||||
|
'/qubes-block-devices/%s/%s' % (dev, item),
|
||||||
|
None)
|
||||||
|
|
||||||
|
untrusted_devices_names = list(set(map(lambda x: x.split("/")[2],
|
||||||
|
untrusted_devices.keys())))
|
||||||
|
for untrusted_dev_name in untrusted_devices_names:
|
||||||
|
if name_re.match(untrusted_dev_name):
|
||||||
|
dev_name = untrusted_dev_name
|
||||||
|
untrusted_device_size = get_dev_item(dev_name, 'size')
|
||||||
|
untrusted_device_desc = get_dev_item(dev_name, 'desc')
|
||||||
|
untrusted_device_mode = get_dev_item(dev_name, 'mode')
|
||||||
|
untrusted_device_device = get_dev_item(dev_name, 'device')
|
||||||
|
if untrusted_device_desc is None or untrusted_device_mode is None\
|
||||||
|
or untrusted_device_size is None:
|
||||||
|
print >>sys.stderr, "Missing field in %s device parameters" %\
|
||||||
|
dev_name
|
||||||
continue
|
continue
|
||||||
if not device_size.isdigit():
|
if untrusted_device_device is None:
|
||||||
print >> sys.stderr, "Invalid %s device size in VM '%s'" % (device, vm_name)
|
untrusted_device_device = '/dev/' + dev_name
|
||||||
|
if not device_re.match(untrusted_device_device):
|
||||||
|
print >> sys.stderr, "Invalid %s device path in VM '%s'" % (
|
||||||
|
dev_name, vm.name)
|
||||||
continue
|
continue
|
||||||
if not desc_re.match(device_desc):
|
device_device = untrusted_device_device
|
||||||
print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (device, vm_name)
|
if not untrusted_device_size.isdigit():
|
||||||
|
print >> sys.stderr, "Invalid %s device size in VM '%s'" % (
|
||||||
|
dev_name, vm.name)
|
||||||
continue
|
continue
|
||||||
if not mode_re.match(device_mode):
|
device_size = int(untrusted_device_size)
|
||||||
print >> sys.stderr, "Invalid %s device mode in VM '%s'" % (device, vm_name)
|
if not desc_re.match(untrusted_device_desc):
|
||||||
|
print >> sys.stderr, "Invalid %s device desc in VM '%s'" % (
|
||||||
|
dev_name, vm.name)
|
||||||
continue
|
continue
|
||||||
# Check if we know major number for this device; attach will work without this, but detach and check_attached don't
|
device_desc = untrusted_device_desc
|
||||||
if block_name_to_majorminor(device) == (0, 0):
|
if not mode_re.match(untrusted_device_mode):
|
||||||
print >> sys.stderr, "Unsupported device %s:%s" % (vm_name, device)
|
print >> sys.stderr, "Invalid %s device mode in VM '%s'" % (
|
||||||
|
dev_name, vm.name)
|
||||||
continue
|
continue
|
||||||
|
device_mode = untrusted_device_mode
|
||||||
|
|
||||||
if not system_disks:
|
if not system_disks:
|
||||||
if xid == '0' and device_desc.startswith(system_path["qubes_base_dir"]):
|
if vm.qid == 0 and device_desc.startswith(system_path[
|
||||||
|
"qubes_base_dir"]):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
visible_name = "%s:%s" % (vm_name, device)
|
visible_name = "%s:%s" % (vm.name, dev_name)
|
||||||
devices_list[visible_name] = {"name": visible_name, "xid":int(xid),
|
devices_list[visible_name] = {
|
||||||
"vm": vm_name, "device":device, "size":int(device_size),
|
"name": visible_name,
|
||||||
"desc":device_desc, "mode":device_mode}
|
"vm": vm.name,
|
||||||
|
"device": device_device,
|
||||||
|
"size": device_size,
|
||||||
|
"desc": device_desc,
|
||||||
|
"mode": device_mode
|
||||||
|
}
|
||||||
|
|
||||||
vmm.xs.transaction_end(xs_trans)
|
|
||||||
return devices_list
|
return devices_list
|
||||||
|
|
||||||
def block_check_attached(backend_vm, device, backend_xid = None):
|
def block_list(qvmc = None, vm = None, system_disks = False):
|
||||||
if backend_xid is None:
|
if vm is not None:
|
||||||
backend_xid = backend_vm.xid
|
if not vm.is_running():
|
||||||
xs_trans = vmm.xs.transaction_start()
|
return []
|
||||||
vm_list = vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vbd' % backend_xid)
|
else:
|
||||||
if vm_list is None:
|
vm_list = [ vm ]
|
||||||
vmm.xs.transaction_end(xs_trans)
|
else:
|
||||||
return None
|
if qvmc is None:
|
||||||
device_majorminor = None
|
raise QubesException("You must pass either qvm or vm argument")
|
||||||
try:
|
vm_list = qvmc.values()
|
||||||
device_majorminor = block_name_to_majorminor(device)
|
|
||||||
except:
|
|
||||||
# Unknown devices will be compared directly - perhaps it is a filename?
|
|
||||||
pass
|
|
||||||
for vm_xid in vm_list:
|
|
||||||
for devid in vmm.xs.ls(xs_trans, '/local/domain/%d/backend/vbd/%s' % (backend_xid, vm_xid)):
|
|
||||||
(tmp_major, tmp_minor) = (0, 0)
|
|
||||||
phys_device = vmm.xs.read(xs_trans, '/local/domain/%d/backend/vbd/%s/%s/physical-device' % (backend_xid, vm_xid, devid))
|
|
||||||
dev_params = vmm.xs.read(xs_trans, '/local/domain/%d/backend/vbd/%s/%s/params' % (backend_xid, vm_xid, devid))
|
|
||||||
if phys_device and phys_device.find(':'):
|
|
||||||
(tmp_major, tmp_minor) = phys_device.split(":")
|
|
||||||
tmp_major = int(tmp_major, 16)
|
|
||||||
tmp_minor = int(tmp_minor, 16)
|
|
||||||
else:
|
|
||||||
# perhaps not ready yet - check params
|
|
||||||
if not dev_params:
|
|
||||||
# Skip not-phy devices
|
|
||||||
continue
|
|
||||||
elif not dev_params.startswith('/dev/'):
|
|
||||||
# will compare params directly
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
(tmp_major, tmp_minor) = block_name_to_majorminor(dev_params.lstrip('/dev/'))
|
|
||||||
|
|
||||||
if (device_majorminor and (tmp_major, tmp_minor) == device_majorminor) or \
|
devices_list = {}
|
||||||
(device_majorminor is None and dev_params == device):
|
for vm in vm_list:
|
||||||
#TODO
|
devices_list.update(block_list_vm(vm, system_disks))
|
||||||
vm_name = xl_ctx.domid_to_name(int(vm_xid))
|
return devices_list
|
||||||
frontend = block_devid_to_name(int(devid))
|
|
||||||
vmm.xs.transaction_end(xs_trans)
|
def block_check_attached(qvmc, device):
|
||||||
return {"xid":int(vm_xid), "frontend": frontend, "devid": int(devid), "vm": vm_name}
|
"""
|
||||||
vmm.xs.transaction_end(xs_trans)
|
|
||||||
|
@type qvmc: QubesVmCollection
|
||||||
|
"""
|
||||||
|
if qvmc is None:
|
||||||
|
# TODO: ValueError
|
||||||
|
raise QubesException("You need to pass qvmc argument")
|
||||||
|
|
||||||
|
for vm in qvmc.values():
|
||||||
|
libvirt_domain = vm.libvirt_domain
|
||||||
|
if libvirt_domain:
|
||||||
|
xml = vm.libvirt_domain.XMLDesc()
|
||||||
|
parsed_xml = etree.fromstring(xml)
|
||||||
|
disks = parsed_xml.xpath("//domain/devices/disk")
|
||||||
|
for disk in disks:
|
||||||
|
backend_name = 'dom0'
|
||||||
|
# FIXME: move <domain/> into <source/>
|
||||||
|
if disk.find('domain') is not None:
|
||||||
|
backend_name = disk.find('domain').get('name')
|
||||||
|
source = disk.find('source')
|
||||||
|
if disk.get('type') == 'file':
|
||||||
|
path = source.get('file')
|
||||||
|
elif disk.get('type') == 'block':
|
||||||
|
path = source.get('dev')
|
||||||
|
else:
|
||||||
|
# TODO: logger
|
||||||
|
print >>sys.stderr, "Unknown disk type '%s' attached to " \
|
||||||
|
"VM '%s'" % (source.get('type'),
|
||||||
|
vm.name)
|
||||||
|
continue
|
||||||
|
if backend_name == device['vm'] and path == device['device']:
|
||||||
|
return {
|
||||||
|
"frontend": disk.find('target').get('dev'),
|
||||||
|
"vm": vm}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def block_attach(vm, backend_vm, device, frontend=None, mode="w", auto_detach=False, wait=True):
|
def device_attach_check(vm, backend_vm, device, frontend, mode):
|
||||||
device_attach_check(vm, backend_vm, device, frontend)
|
|
||||||
do_block_attach(vm, backend_vm, device, frontend, mode, auto_detach, wait)
|
|
||||||
|
|
||||||
def device_attach_check(vm, backend_vm, device, frontend):
|
|
||||||
""" Checks all the parameters, dies on errors """
|
""" Checks all the parameters, dies on errors """
|
||||||
if not vm.is_running():
|
if not vm.is_running():
|
||||||
raise QubesException("VM %s not running" % vm.name)
|
raise QubesException("VM %s not running" % vm.name)
|
||||||
@ -335,105 +360,67 @@ def device_attach_check(vm, backend_vm, device, frontend):
|
|||||||
if not backend_vm.is_running():
|
if not backend_vm.is_running():
|
||||||
raise QubesException("VM %s not running" % backend_vm.name)
|
raise QubesException("VM %s not running" % backend_vm.name)
|
||||||
|
|
||||||
def do_block_attach(vm, backend_vm, device, frontend, mode, auto_detach, wait):
|
if device['mode'] == 'r' and mode == 'w':
|
||||||
|
raise QubesException("Cannot attach read-only device in read-write "
|
||||||
|
"mode")
|
||||||
|
|
||||||
|
def block_attach(qvmc, vm, device, frontend=None, mode="w", auto_detach=False, wait=True):
|
||||||
|
backend_vm = qvmc.get_vm_by_name(device['vm'])
|
||||||
|
device_attach_check(vm, backend_vm, device, frontend, mode)
|
||||||
if frontend is None:
|
if frontend is None:
|
||||||
frontend = block_find_unused_frontend(vm)
|
frontend = block_find_unused_frontend(vm)
|
||||||
if frontend is None:
|
if frontend is None:
|
||||||
raise QubesException("No unused frontend found")
|
raise QubesException("No unused frontend found")
|
||||||
else:
|
else:
|
||||||
# Check if any device attached at this frontend
|
# Check if any device attached at this frontend
|
||||||
if vmm.xs.read('', '/local/domain/%d/device/vbd/%d/state' % (vm.xid, block_name_to_devid(frontend))) == '4':
|
xml = vm.libvirt_domain.XMLDesc()
|
||||||
|
parsed_xml = etree.fromstring(xml)
|
||||||
|
disks = parsed_xml.xpath("//domain/devices/disk/target[@dev='%s']" %
|
||||||
|
frontend)
|
||||||
|
if len(disks):
|
||||||
raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
|
raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
|
||||||
|
|
||||||
# Check if this device is attached to some domain
|
# Check if this device is attached to some domain
|
||||||
attached_vm = block_check_attached(backend_vm, device)
|
attached_vm = block_check_attached(qvmc, device)
|
||||||
if attached_vm:
|
if attached_vm:
|
||||||
if auto_detach:
|
if auto_detach:
|
||||||
block_detach(None, attached_vm['devid'], vm_xid=attached_vm['xid'])
|
block_detach(attached_vm['vm'], attached_vm['frontend'])
|
||||||
else:
|
else:
|
||||||
raise QubesException("Device %s from %s already connected to VM %s as %s" % (device, backend_vm.name, attached_vm['vm'], attached_vm['frontend']))
|
raise QubesException("Device %s from %s already connected to VM "
|
||||||
|
"%s as %s" % (device['device'],
|
||||||
|
backend_vm.name, attached_vm['vm'], attached_vm['frontend']))
|
||||||
|
|
||||||
if device.startswith('/'):
|
disk = Element("disk")
|
||||||
backend_dev = 'script:file:' + device
|
disk.set('type', 'block')
|
||||||
else:
|
disk.set('device', 'disk')
|
||||||
backend_dev = 'phy:/dev/' + device
|
SubElement(disk, 'driver').set('name', 'phy')
|
||||||
|
SubElement(disk, 'source').set('dev', device['device'])
|
||||||
|
SubElement(disk, 'target').set('dev', frontend)
|
||||||
|
if backend_vm.qid != 0:
|
||||||
|
SubElement(disk, 'domain').set('name', device['vm'])
|
||||||
|
vm.libvirt_domain.attachDevice(etree.tostring(disk, encoding='utf-8'))
|
||||||
|
|
||||||
xl_cmd = [ '/usr/sbin/xl', 'block-attach', vm.name, backend_dev, frontend, mode, str(backend_vm.xid) ]
|
def block_detach(vm, frontend = "xvdi"):
|
||||||
subprocess.check_call(xl_cmd)
|
|
||||||
if wait:
|
|
||||||
be_path = '/local/domain/%d/backend/vbd/%d/%d' % (backend_vm.xid, vm.xid, block_name_to_devid(frontend))
|
|
||||||
# There is no way to use xenstore watch with a timeout, so must check in a loop
|
|
||||||
interval = 0.100
|
|
||||||
# 5sec timeout
|
|
||||||
timeout = 5/interval
|
|
||||||
while timeout > 0:
|
|
||||||
be_state = vmm.xs.read('', be_path + '/state')
|
|
||||||
hotplug_state = vmm.xs.read('', be_path + '/hotplug-status')
|
|
||||||
if be_state is None:
|
|
||||||
raise QubesException("Backend device disappeared, something weird happened")
|
|
||||||
elif int(be_state) == 4:
|
|
||||||
# Ok
|
|
||||||
return
|
|
||||||
elif int(be_state) > 4:
|
|
||||||
# Error
|
|
||||||
error = vmm.xs.read('', '/local/domain/%d/error/backend/vbd/%d/%d/error' % (backend_vm.xid, vm.xid, block_name_to_devid(frontend)))
|
|
||||||
if error is not None:
|
|
||||||
raise QubesException("Error while connecting block device: " + error)
|
|
||||||
else:
|
|
||||||
raise QubesException("Unknown error while connecting block device")
|
|
||||||
elif hotplug_state == 'error':
|
|
||||||
hotplug_error = vmm.xs.read('', be_path + '/hotplug-error')
|
|
||||||
if hotplug_error:
|
|
||||||
raise QubesException("Error while connecting block device: " + hotplug_error)
|
|
||||||
else:
|
|
||||||
raise QubesException("Unknown hotplug error while connecting block device")
|
|
||||||
time.sleep(interval)
|
|
||||||
timeout -= interval
|
|
||||||
raise QubesException("Timeout while waiting for block defice connection")
|
|
||||||
|
|
||||||
def block_detach(vm, frontend = "xvdi", vm_xid = None):
|
xml = vm.libvirt_domain.XMLDesc()
|
||||||
# Get XID if not provided already
|
parsed_xml = etree.fromstring(xml)
|
||||||
if vm_xid is None:
|
attached = parsed_xml.xpath("//domain/devices/disk")
|
||||||
if not vm.is_running():
|
for disk in attached:
|
||||||
raise QubesException("VM %s not running" % vm.name)
|
if frontend is not None and disk.find('target').get('dev') != frontend:
|
||||||
# FIXME: potential race
|
# Not the device we are looking for
|
||||||
vm_xid = vm.xid
|
|
||||||
|
|
||||||
# Check if this device is really connected
|
|
||||||
if not vmm.xs.read('', '/local/domain/%d/device/vbd/%d/state' % (vm_xid, block_name_to_devid(frontend))) == '4':
|
|
||||||
# Do nothing - device already detached
|
|
||||||
return
|
|
||||||
|
|
||||||
xl_cmd = [ '/usr/sbin/xl', 'block-detach', str(vm_xid), str(frontend)]
|
|
||||||
subprocess.check_call(xl_cmd)
|
|
||||||
|
|
||||||
def block_detach_all(vm, vm_xid = None):
|
|
||||||
""" Detach all non-system devices"""
|
|
||||||
# Get XID if not provided already
|
|
||||||
if vm_xid is None:
|
|
||||||
if not vm.is_running():
|
|
||||||
raise QubesException("VM %s not running" % vm.name)
|
|
||||||
# FIXME: potential race
|
|
||||||
vm_xid = vm.xid
|
|
||||||
|
|
||||||
xs_trans = vmm.xs.transaction_start()
|
|
||||||
devices = vmm.xs.ls(xs_trans, '/local/domain/%d/device/vbd' % vm_xid)
|
|
||||||
if devices is None:
|
|
||||||
return
|
|
||||||
devices_to_detach = []
|
|
||||||
for devid in devices:
|
|
||||||
# check if this is system disk
|
|
||||||
be_path = vmm.xs.read(xs_trans, '/local/domain/%d/device/vbd/%s/backend' % (vm_xid, devid))
|
|
||||||
assert be_path is not None
|
|
||||||
be_params = vmm.xs.read(xs_trans, be_path + '/params')
|
|
||||||
if be_path.startswith('/local/domain/0/') and be_params is not None and be_params.startswith(system_path["qubes_base_dir"]):
|
|
||||||
# system disk
|
|
||||||
continue
|
continue
|
||||||
devices_to_detach.append(devid)
|
if frontend is None:
|
||||||
vmm.xs.transaction_end(xs_trans)
|
# ignore system disks
|
||||||
for devid in devices_to_detach:
|
if disk.find('domain') == None and \
|
||||||
xl_cmd = [ '/usr/sbin/xl', 'block-detach', str(vm_xid), devid]
|
disk.find('source').get('dev').startswith(system_path[
|
||||||
subprocess.check_call(xl_cmd)
|
"qubes_base_dir"]):
|
||||||
|
continue
|
||||||
|
vm.libvirt_domain.detachDevice(etree.tostring(disk, encoding='utf-8'))
|
||||||
|
|
||||||
|
def block_detach_all(vm):
|
||||||
|
""" Detach all non-system devices"""
|
||||||
|
|
||||||
|
block_detach(vm, None)
|
||||||
|
|
||||||
####### USB devices ######
|
####### USB devices ######
|
||||||
|
|
||||||
|
@ -70,14 +70,13 @@ def main():
|
|||||||
print >> sys.stderr, "Only one of -l -a/-A -d is allowed!"
|
print >> sys.stderr, "Only one of -l -a/-A -d is allowed!"
|
||||||
exit (1)
|
exit (1)
|
||||||
|
|
||||||
if options.do_attach or options.do_detach:
|
qvm_collection = QubesVmCollection()
|
||||||
qvm_collection = QubesVmCollection()
|
qvm_collection.lock_db_for_reading()
|
||||||
qvm_collection.lock_db_for_reading()
|
qvm_collection.load()
|
||||||
qvm_collection.load()
|
qvm_collection.unlock_db()
|
||||||
qvm_collection.unlock_db()
|
|
||||||
|
|
||||||
if options.do_attach:
|
if options.do_attach:
|
||||||
if (len (args) != 2):
|
if len(args) != 2:
|
||||||
parser.error ("You must provide vm name and device!")
|
parser.error ("You must provide vm name and device!")
|
||||||
vm = qvm_collection.get_vm_by_name(args[0])
|
vm = qvm_collection.get_vm_by_name(args[0])
|
||||||
if vm is None:
|
if vm is None:
|
||||||
@ -90,12 +89,10 @@ def main():
|
|||||||
(dev['vm'], dev['device']) = args[1].split(":")
|
(dev['vm'], dev['device']) = args[1].split(":")
|
||||||
dev['mode'] = 'w'
|
dev['mode'] = 'w'
|
||||||
else:
|
else:
|
||||||
dev_list = block_list()
|
dev_list = block_list(qvm_collection)
|
||||||
if not args[1] in dev_list.keys():
|
if not args[1] in dev_list.keys():
|
||||||
parser.error ("Invalid device name: %s" % args[1])
|
parser.error ("Invalid device name: %s" % args[1])
|
||||||
dev = dev_list[args[1]]
|
dev = dev_list[args[1]]
|
||||||
backend_vm = qvm_collection.get_vm_by_name(dev['vm'])
|
|
||||||
assert backend_vm is not None
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if options.frontend:
|
if options.frontend:
|
||||||
kwargs['frontend'] = options.frontend
|
kwargs['frontend'] = options.frontend
|
||||||
@ -105,7 +102,7 @@ def main():
|
|||||||
kwargs['mode'] = dev['mode']
|
kwargs['mode'] = dev['mode']
|
||||||
kwargs['auto_detach'] = options.auto_detach
|
kwargs['auto_detach'] = options.auto_detach
|
||||||
try:
|
try:
|
||||||
block_attach(vm, backend_vm, dev['device'], **kwargs)
|
block_attach(qvm_collection, vm, dev, **kwargs)
|
||||||
except QubesException as e:
|
except QubesException as e:
|
||||||
print >> sys.stderr, "ERROR: %s" % str(e)
|
print >> sys.stderr, "ERROR: %s" % str(e)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -125,26 +122,28 @@ def main():
|
|||||||
block_detach_all(vm)
|
block_detach_all(vm)
|
||||||
else:
|
else:
|
||||||
# Maybe device?
|
# Maybe device?
|
||||||
dev_list = block_list()
|
dev_list = block_list(qvm_collection)
|
||||||
if not args[0] in dev_list.keys():
|
if not args[0] in dev_list.keys():
|
||||||
parser.error ("Invalid VM or device name: %s" % args[0])
|
parser.error ("Invalid VM or device name: %s" % args[0])
|
||||||
dev = dev_list[args[0]]
|
dev = dev_list[args[0]]
|
||||||
attached_to = block_check_attached(None, dev['device'], backend_xid = dev['xid'])
|
attached_to = block_check_attached(qvm_collection, dev)
|
||||||
if attached_to is None:
|
if attached_to is None:
|
||||||
print >> sys.stderr, "WARNING: Device not connected to any VM"
|
print >> sys.stderr, "WARNING: Device not connected to any VM"
|
||||||
exit(0)
|
exit(0)
|
||||||
block_detach(None, attached_to['devid'], vm_xid=attached_to['xid'])
|
block_detach(attached_to['vm'], attached_to['frontend'])
|
||||||
else:
|
else:
|
||||||
# do_list
|
# do_list
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
parser.error ("Too many parameters")
|
parser.error ("Too many parameters")
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
kwargs['qvmc'] = qvm_collection
|
||||||
kwargs['system_disks'] = options.system_disks
|
kwargs['system_disks'] = options.system_disks
|
||||||
for dev in block_list(**kwargs).values():
|
for dev in block_list(**kwargs).values():
|
||||||
attached_to = block_check_attached(None, dev['device'], backend_xid = dev['xid'])
|
attached_to = block_check_attached(qvm_collection, dev)
|
||||||
attached_to_str = ""
|
attached_to_str = ""
|
||||||
if attached_to:
|
if attached_to:
|
||||||
attached_to_str = " (attached to '%s' as '%s')" % (attached_to['vm'], attached_to['frontend'])
|
attached_to_str = " (attached to '%s' as '%s')" % (
|
||||||
|
attached_to['vm'].name, attached_to['frontend'])
|
||||||
size_str = bytes_to_kmg(dev['size'])
|
size_str = bytes_to_kmg(dev['size'])
|
||||||
print "%s\t%s %s%s" % (dev['name'], dev['desc'], size_str, attached_to_str)
|
print "%s\t%s %s%s" % (dev['name'], dev['desc'], size_str, attached_to_str)
|
||||||
exit (0)
|
exit (0)
|
||||||
|
Loading…
Reference in New Issue
Block a user