dom0/qvm-usb: detach operation appears to work
This commit is contained in:
parent
89b78d9426
commit
9d77b3dd3c
@ -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
|
||||
|
||||
|
@ -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 ######
|
||||
|
||||
|
@ -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'])
|
||||
|
@ -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
49
misc/xl-qvm-usb-detach.py
Executable 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))
|
||||
|
Loading…
Reference in New Issue
Block a user