dom0/qvm-usb: detach operation appears to work

This commit is contained in:
Alexandre Bezroutchko 2012-10-12 23:34:18 +02:00
parent 89b78d9426
commit 9d77b3dd3c
5 changed files with 91 additions and 28 deletions

View File

@ -74,7 +74,7 @@ Known issues
* Virtual USB devices (ones created by PVUSB frontend) may be listed
* The installation/configuration is not persistent, not retained between reboots
* No logging / audit trail?
* When an attached device is physically unplugged, USB port remains mapped but not displayed in the list
* When an attached device is physically unplugged, USB port remains mapped but not displayed in the list. If device is plugged back it continues to work. Unlisted device cannot be detached.
* We are not attaching actual devices, but USB ports (different behavior from VMWare, might be confusing)
* After device is detached from the frontend and returned back to the backend it is not usable there

View File

@ -494,7 +494,7 @@ def usb_list():
xs.transaction_end(xs_trans)
return devices_list
def usb_check_attached(backend_vm, device):
def usb_check_attached(xs_trans, backend_vm, device):
"""
Checks if the given device in the given backend attached to any frontend.
Parameters:
@ -503,12 +503,11 @@ def usb_check_attached(backend_vm, device):
Returns None or a dictionary:
vm - the name of the frontend domain
xid - xid of the frontend domain
frontend - frontend device number
devid - frontend port number
frontend - frontend device number FIXME
devid - frontend port number FIXME
"""
# sample xs content: /local/domain/0/backend/vusb/4/0/port/1 = "7-5"
attached_dev = None
xs_trans = xs.transaction_start()
vms = xs.ls(xs_trans, '/local/domain/%d/backend/vusb' % backend_vm)
if vms is None:
xs.transaction_end(xs_trans)
@ -540,7 +539,6 @@ def usb_check_attached(backend_vm, device):
continue
attached_dev = {"xid":int(vm), "frontend": frontend, "devid": device, "vm": vm_name}
break
xs.transaction_end(xs_trans)
return attached_dev
#def usb_check_frontend_busy(vm, front_dev, port):
@ -551,12 +549,12 @@ def usb_check_attached(backend_vm, device):
# # return xs.read('', '/local/domain/%d/device/vusb/%d/state' % (vm.xid, frontend)) == '4'
# return False
def usb_find_unused_frontend(backend_vm_xid, vm_xid):
def usb_find_unused_frontend(xs_trans, backend_vm_xid, vm_xid):
"""
Find an unused frontend/port to link the given backend with the given frontend.
Create new frontend if needed.
Creates new frontend if needed.
Returns frontend specification in <device>-<port> format.
"""
xs_trans='' # FIXME
last_frontend_dev = -1
frontend_devs = xs.ls(xs_trans, "/local/domain/%d/device/vusb" % vm_xid)
@ -589,19 +587,23 @@ def usb_find_unused_frontend(backend_vm_xid, vm_xid):
def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=True):
device_attach_check(vm, backend_vm, device, frontend)
xs_trans = xs.transaction_start()
if frontend is None:
frontend = usb_find_unused_frontend(backend_vm.xid, vm.xid)
frontend = usb_find_unused_frontend(xs_trans, backend_vm.xid, vm.xid)
else:
# Check if any device attached at this frontend
#if usb_check_frontend_busy(vm, frontend):
# raise QubesException("Frontend %s busy in VM %s, detach it first" % (frontend, vm.name))
xs.transaction_end(xs_trans)
raise NotImplementedError("Explicit USB frontend specification is not implemented yet")
# Check if this device is attached to some domain
attached_vm = usb_check_attached(backend_vm.xid, device)
attached_vm = usb_check_attached(xs_trans, backend_vm.xid, device)
xs.transaction_end(xs_trans)
if attached_vm:
if auto_detach:
usb_detach(None, attached_vm['devid'], vm_xid=attached_vm['xid'])
usb_detach(backend_vm, attached_vm)
else:
raise QubesException("Device %s from %s already connected to VM %s as %s" % (device, backend_vm.name, attached_vm['vm'], attached_vm['frontend']))
@ -609,11 +611,12 @@ def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=Tr
xl_cmd = [ '/usr/lib/qubes/xl-qvm-usb-attach.py', str(vm.xid), device, frontend, str(backend_vm.xid) ]
subprocess.check_call(xl_cmd)
def usb_detach(vm, frontend, vm_xid = None):
raise NotImplementedError()
def usb_detach(backend_vm, attachment):
xl_cmd = [ '/usr/lib/qubes/xl-qvm-usb-detach.py', str(attachment['xid']), attachment['devid'], attachment['frontend'], str(backend_vm.xid) ]
subprocess.check_call(xl_cmd)
def usb_detach_all(vm, vm_xid = None):
raise NotImplementedError()
def usb_detach_all(vm):
raise NotImplementedError("Detaching all devices from a given VM is not implemented yet")
####### QubesWatch ######

View File

@ -30,8 +30,8 @@ def main():
usage = "usage: %prog -l [options]\n"\
"usage: %prog -a [options] <vm-name> <device-vm-name>:<device>\n"\
"usage: %prog -d [options] <device-vm-name>:<device>\n"\
"usage: %prog -d [options] <vm-name>\n"\
"List/set VM USB devices."
# "usage: %prog -d [options] <vm-name>\n"\
parser = OptionParser (usage)
parser.add_option ("-l", "--list", action="store_true", dest="do_list", default=False)
@ -69,6 +69,7 @@ def main():
vm = qvm_collection.get_vm_by_name(args[0])
if vm is None:
parser.error ("Invalid VM name: %s" % args[0])
# FIXME: here we assume that device is always in form "domain:dev", which can be changed in the future
if args[1].find(":") < 0:
parser.error ("Invalid device syntax: %s" % args[1])
@ -78,6 +79,7 @@ def main():
dev = dev_list[args[1]]
backend_vm = qvm_collection.get_vm_by_name(dev['vm'])
assert backend_vm is not None
kwargs = {}
# if options.frontend:
# kwargs['frontend'] = options.frontend
@ -95,29 +97,37 @@ def main():
# Check if provided name is VM
vm = qvm_collection.get_vm_by_name(args[0])
if vm is not None:
kwargs = {}
if options.frontend:
kwargs['frontend'] = options.frontend
usb_detach(vm, **kwargs)
else:
usb_detach_all(vm)
#kwargs = {}
#if options.frontend:
# kwargs['frontend'] = options.frontend
# usb_detach(vm, **kwargs)
#else:
usb_detach_all(vm)
else:
# Maybe device?
# Maybe usbvm:device?
# FIXME: nasty copy-paste from attach code half a page above
# FIXME: here we assume that device is always in form "domain:dev", which can be changed in the future
if args[0].find(":") < 0:
parser.error ("Invalid device syntax: %s" % args[0])
dev_list = usb_list()
if not args[0] in dev_list.keys():
parser.error ("Invalid VM or device name: %s" % args[0])
parser.error ("Invalid device name: %s" % args[0])
dev = dev_list[args[0]]
attached_to = usb_check_attached(backend_xid, dev['device'])
backend_vm = qvm_collection.get_vm_by_name(dev['vm'])
assert backend_vm is not None
attached_to = usb_check_attached('', backend_vm.xid, dev['device'])
if attached_to is None:
print >> sys.stderr, "WARNING: Device not connected to any VM"
exit(0)
usb_detach(None, attached_to['devid'], vm_xid=attached_to['xid'])
usb_detach(backend_vm, attached_to)
else:
if len(args) > 0:
parser.error ("Too many parameters")
# do_list
for dev in usb_list().values():
attached_to = usb_check_attached(dev['xid'], dev['device'])
attached_to = usb_check_attached('', dev['xid'], dev['device'])
attached_to_str = ""
if attached_to:
attached_to_str = " (attached to %s:%s)" % (attached_to['vm'], attached_to['frontend'])

View File

@ -7,5 +7,6 @@
# Copy files
cp misc/xl-qvm-usb-attach.py /usr/lib/qubes/xl-qvm-usb-attach.py
cp misc/xl-qvm-usb-detach.py /usr/lib/qubes/xl-qvm-usb-detach.py
cp dom0/qvm-core/qubesutils.py /usr/lib64/python2.6/site-packages/qubes/qubesutils.py
cp dom0/qvm-tools/qvm-usb /usr/bin/qvm-usb

49
misc/xl-qvm-usb-detach.py Executable file
View File

@ -0,0 +1,49 @@
#!/usr/bin/python
##
## This script is for dom0
## The syntax is modelled after "xl block-attach"
## FIXME: should be modelled after block-detach instead
##
import sys
import os
import xen.lowlevel.xl
# parse command line
if (len(sys.argv)<4) or (len(sys.argv)>5):
print 'usage: xl-qvm-usb-detach.py <frontendvm-xid> <backendvm-device> <frontendvm-device> [<backendvm-xid>]'
sys.exit(1)
frontendvm_xid=sys.argv[1]
backendvm_device=sys.argv[2]
frontend=sys.argv[3].split('-')
if len(frontend)!=2:
print 'Error: frontendvm-device must be in <controller>-<port> format'
sys.exit(1)
(controller, port)=frontend
if len(sys.argv)>4:
backendvm_xid=int(sys.argv[4])
backendvm_name=xen.lowlevel.xl.ctx().domid_to_name(backendvm_xid)
else:
backendvm_xid=0
cmd = "/usr/lib/qubes/vusb-ctl.py unbind '%s'" % backendvm_device
if backendvm_xid == 0:
os.system("sudo %s" % cmd)
else:
from qubes.qubes import QubesVmCollection
qvm_collection = QubesVmCollection()
qvm_collection.lock_db_for_reading()
qvm_collection.load()
qvm_collection.unlock_db()
# launch
qvm_collection.get_vm_by_name(backendvm_name).run("root: %s" % cmd)
# FIXME: command injection
os.system("xenstore-write /local/domain/%s/backend/vusb/%s/%s/port/%s ''"
% (backendvm_xid, frontendvm_xid, controller, port))