From b962debfad58701668199f6eaa74dbd242f7d5f6 Mon Sep 17 00:00:00 2001 From: Alexandre Bezroutchko Date: Tue, 9 Oct 2012 23:15:47 +0200 Subject: [PATCH] dom0/qvm-usb: implemented usb_check_attached method, now "qvm-usb -l" indicate attachments --- dom0/qvm-core/qubesutils.py | 73 ++++++++++++++++++++++++++++++++++++- dom0/qvm-tools/qvm-usb | 4 +- install_pvusb_hacks.sh | 6 +-- 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/dom0/qvm-core/qubesutils.py b/dom0/qvm-core/qubesutils.py index 7f7956f2..9cdc9a21 100644 --- a/dom0/qvm-core/qubesutils.py +++ b/dom0/qvm-core/qubesutils.py @@ -293,12 +293,18 @@ def block_check_attached(backend_vm, device, backend_xid = None): return None def block_attach(vm, backend_vm, device, frontend=None, mode="w", auto_detach=False, wait=True): + 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 """ if not vm.is_running(): raise QubesException("VM %s not running" % vm.name) if not backend_vm.is_running(): raise QubesException("VM %s not running" % backend_vm.name) +def do_block_attach(vm, backend_vm, device, frontend, mode, auto_detach, wait): if frontend is None: frontend = block_find_unused_frontend(vm) if frontend is None: @@ -432,11 +438,74 @@ def usb_list(): xs.transaction_end(xs_trans) return devices_list -def usb_check_attached(backend_vm, device, backend_xid = None): +def usb_check_attached(backend_vm, device): + # example: /local/domain/0/backend/vusb/4/0/port/1 = "7-5" + ##print "*** usb_check_attached(%s, %s) called" % (str(backend_vm), str(device)) + # FIXME use XS transaction + xs_trans = '' + vms = xs.ls(xs_trans, '/local/domain/%d/backend/vusb' % backend_vm) + ##print "*** usb_check_attached: vms=%s" % str(vms) + if vms is None: + return None + for vm in vms: + # FIXME validate vm? + frontend_devs = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%s' % (backend_vm, vm)) + ##print "*** usb_check_attached: frontend_devs=%s" % str(frontend_devs) + if frontend_devs is None: + continue + for frontend_dev in frontend_devs: + # FIXME validate frontend_dev? + ##print '>>>/local/domain/%d/backend/vusb/%s/%s/port' % (backend_vm, vm, frontend_dev) + ports = xs.ls(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port' % (backend_vm, vm, frontend_dev)) + ##print "*** usb_check_attached: ports=%s" % str(ports) + if ports is None: + continue + for port in ports: + # FIXME validate ports? + dev = xs.read(xs_trans, '/local/domain/%d/backend/vusb/%s/%s/port/%s' % (backend_vm, vm, frontend_dev, port)) + ##print "*** usb_check_attached: port=%s, device=%s" % (port, str(dev)) + if dev == device: + frontend = "%s-%s" % (frontend_dev, port) + return {"xid":int(vm), "frontend": frontend, "devid": device, "vm": "FIXME"} return None +def usb_check_frontend_busy(vm, front_dev, port): + devport = frontend.split("-") + if len(devport) != 2: + raise QubesException("Malformed frontend syntax, must be in device-port format") + # FIXME + # return xs.read('', '/local/domain/%d/device/vusb/%d/state' % (vm.xid, frontend)) == '4' + return False + +def usb_find_unused_frontend(vm): + front_dev = 0 + port = 1 + # FIXME raise QubesException("No unused frontend found") + return '%d-%d' % (front_dev, port) + def usb_attach(vm, backend_vm, device, frontend=None, auto_detach=False, wait=True): - raise NotImplementedError() + device_attach_check(vm, backend_vm, device, frontend) + do_usb_attach(vm, backend_vm, device, frontend, auto_detach, wait) + +def do_usb_attach(vm, backend_vm, device, frontend, auto_detach, wait): + if frontend is None: + frontend = usb_find_unused_frontend(vm) + 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)) + + # Check if this device is attached to some domain + attached_vm = usb_check_attached(backend_vm.xid, device) + if attached_vm: + if auto_detach: + usb_detach(None, attached_vm['devid'], vm_xid=attached_vm['xid']) + else: + raise QubesException("Device %s from %s already connected to VM %s as %s" % (device, backend_vm.name, attached_vm['vm'], attached_vm['frontend'])) + + # FIXME sudo + xl_cmd = [ 'sudo', '/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() diff --git a/dom0/qvm-tools/qvm-usb b/dom0/qvm-tools/qvm-usb index 0bf886bb..dc3ff8c3 100755 --- a/dom0/qvm-tools/qvm-usb +++ b/dom0/qvm-tools/qvm-usb @@ -107,7 +107,7 @@ def main(): if not args[0] in dev_list.keys(): parser.error ("Invalid VM or device name: %s" % args[0]) dev = dev_list[args[0]] - attached_to = usb_check_attached(None, dev['device'], backend_xid = dev['xid']) + attached_to = usb_check_attached(backend_xid, dev['device']) if attached_to is None: print >> sys.stderr, "WARNING: Device not connected to any VM" exit(0) @@ -117,7 +117,7 @@ def main(): parser.error ("Too many parameters") # do_list for dev in usb_list().values(): - attached_to = usb_check_attached(None, dev['device'], backend_xid = dev['xid']) + attached_to = usb_check_attached(dev['xid'], dev['device']) attached_to_str = "" if attached_to: attached_to_str = " (attached to '%s' as '%s')" % (attached_to['vm'], attached_to['frontend']) diff --git a/install_pvusb_hacks.sh b/install_pvusb_hacks.sh index 79635350..4fd853c0 100755 --- a/install_pvusb_hacks.sh +++ b/install_pvusb_hacks.sh @@ -5,7 +5,7 @@ d=/home/abb/qubes-core # Install cp $d/misc/qubes_usb.rules /etc/udev/rules.d/99-qubes_usb.rules -for f in usb_add_change usb_remove ; do +for f in usb_add_change usb_remove xl-qvm-usb-attach.py ; do cp $d/misc/$f /usr/lib/qubes/$f done @@ -17,6 +17,6 @@ udevadm control --reload-rules # Rerun xenstore-rm qubes-usb-devices udevadm trigger --action=change -sleep 1 -xenstore-ls -f qubes-usb-devices +#sleep 1 +#xenstore-ls -f qubes-usb-devices